import { Feature , FeatureCollection , GeometryObject , LineString , MultiPolygon , Point , Polygon , Position } from 'geojson' ; import { AllGeoJSON , area , bbox , bboxPolygon , booleanEqual , booleanPointInPolygon , booleanPointOnLine , centerOfMass , circle , convex , destination , feature , geometry , intersect , lineIntersect , lineOffset , lineString , point , polygon , union , unkinkPolygon , featureCollection , envelope , distance } from '@turf/turf' ; export type BBOX = [ number , number , number , number ] | [ number , number , number , number , number , number ] ; export function getPolygonByPoint ( lonLat ) { return bboxPolygon ( bbox ( point ( lonLat ) ) ) ; } export function getPolygonByPointAndRadius ( lonLat , radius = 0.001 ) { const tPoint = point ( lonLat ) ; return bboxPolygon ( bbox ( circle ( tPoint , radius ) ) ) ; } export function getPolygonByBufferRadius ( polygonSource , radiusInMeteres ) { if ( radiusInMeteres <= 0 ) { return polygon ( polygonSource . coordinates ) ; } const bbox = bboxFromGeoJson ( polygonSource ) ; const bboxedPolygon = polygonFromBBOX ( bbox ) ; const possiblePointsInRadius = featureCollection ( [ ] ) ; bboxedPolygon . coordinates [ 0 ] . forEach ( ( coordinate ) => { const pointByCoordinate = point ( coordinate ) ; const bearings = [ 0 , 90 , 180 , 270 ] ; bearings . forEach ( ( bearing ) => { let destinationPoint = destination ( pointByCoordinate , radiusInMeteres , bearing , { units : 'meters' } ) ; possiblePointsInRadius . features . push ( destinationPoint ) ; } ) ; } ) ; const result = envelope ( possiblePointsInRadius ) ; return result ; } export function convertLineSegmentToThinRectangle ( sourcePolygon , radiusInKm = 0.01 ) { if ( sourcePolygon . geometry . coordinates [ 0 ] . length !== 3 ) { return sourcePolygon ; } const asLine = lineString ( sourcePolygon . geometry . coordinates [ 0 ] . slice ( 1 ) ) ; const lineOnOneSide = lineOffset ( asLine , radiusInKm ) ; const lineOnTheOtherSide = lineOffset ( asLine , - radiusInKm ) ; const thinRectangle = convex ( featureCollection ( [ lineOnOneSide , lineOnTheOtherSide ] ) ) ; return thinRectangle ; } export function getPointByGeometry ( geometry ) { if ( geometry . type === 'FeatureCollection' ) { return < Point > centerOfMass ( < any > geometry ) . geometry ; } else { return < Point > centerOfMass ( feature ( < any > geometry ) ) . geometry ; } } export function bboxFromGeoJson ( geoJson ) { let bboxFromPolygon = bbox ( geoJson ) ; return bboxFromPolygon ; } export function polygonFromBBOX ( bbox ) { const bboxedPolygon = bboxPolygon ( bbox ) ; return bboxedPolygon . geometry ; } export function geojsonMultiPolygonToBBOXPolygon ( multiPolygon ) { const bbox = bboxFromGeoJson ( multiPolygon ) ; const bboxedPolygon = polygonFromBBOX ( bbox ) ; return bboxedPolygon ; } export function geojsonMultiPolygonToFirstPolygon ( multiPolygon ) { return < Polygon > geometry ( 'Polygon' , multiPolygon . coordinates [ 0 ] ) ; } export function geojsonMultiPolygonToPolygons ( multiPolygon ) { const polygons = multiPolygon . coordinates . map ( ( polygonCoordinates ) => { return < Polygon > geometry ( 'Polygon' , polygonCoordinates ) ; } ) ; return polygons ; } export function geojsonPolygonToMultiPolygon ( polygon ) { return < MultiPolygon > geometry ( 'MultiPolygon' , [ polygon . coordinates ] ) ; } export function areCoordinatesNumeric ( coord ) { return coord && ! isNaN ( coord [ 0 ] ) && ! isNaN ( coord [ 1 ] ) && ( Math . abs ( coord [ 0 ] ) !== 999999 ) && ( Math . abs ( coord [ 1 ] ) !== 999999 ) ; } export function getPolygonIntersectionRatio ( extent , footprint ) { let intersection = 0 ; switch ( footprint . type ) { case 'MultiPolygon' : intersection = getPolygonIntersectionRatioWithMultiPolygon ( extent , footprint ) ; break ; case 'LineString' : const intersectPoints = lineIntersect ( footprint , < any > extent ) ; intersection = intersectPoints . features . length / footprint . coordinates . length ; break ; case 'Point' : intersection = + booleanPointInPolygon ( footprint , extent ) ; break ; } return intersection ; } export function calculatePolygonWidth ( extent ) { const [ [ extentTopLeft , extentTopRight ] ] = extent . coordinates ; return Math . round ( distance ( extentTopLeft , extentTopRight , { units : 'meters' } ) ) ; } export function polygonsDontIntersect ( extentPolygon , footprint , overlayCoverage ) { const intersection = getPolygonIntersectionRatio ( extentPolygon , footprint ) ; return intersection < overlayCoverage ; } export function getPolygonIntersectionRatioWithMultiPolygon ( extent , footprint ) { let intersectionArea = 0 ; let extentArea = 1 ; try { const extentPolygon = polygon ( extent . coordinates ) ; const extentPolygons = unkinkPolygon ( extentPolygon ) ; extentArea = area ( extentPolygons ) ; footprint . coordinates . forEach ( coordinates => { const tempPoly = polygon ( coordinates ) ; const intersections = extentPolygons . features . map ( feature => intersect ( feature , tempPoly ) ) ; intersectionArea = intersections . reduce ( ( acc , intersection ) => { if ( intersection ) { acc = booleanEqual ( intersection , tempPoly ) ? extentArea : acc + area ( intersection ) ; } return acc ; } , 0 ) ; } ) ; } catch ( e ) { console . warn ( 'getPolygonIntersectionRatioWithMultiPolygon: turf exception' , e ) ; } return intersectionArea / extentArea > 0.99 ? 1 : intersectionArea / extentArea ; } export function isPointContainedInGeometry ( point , footprint ) { if ( ! Boolean ( footprint ) || ! Boolean ( point ) ) { console . error ( 'isPointContainedInMultiPolygon invalid params' ) ; return false ; } switch ( footprint . type ) { case 'Point' : return booleanEqual ( point , footprint ) ; case 'LineString' : return booleanPointOnLine ( point , footprint ) ; case 'MultiPolygon' : for ( let i = 0 ; i < footprint . coordinates . length ; i ++ ) { const contained = booleanPointInPolygon ( point , polygon ( footprint . coordinates [ i ] ) ) ; if ( contained ) { return true ; } } break ; } return false ; } export function unifyPolygons ( features ) { return union ( features [ 0 ] , features [ 1 ] ) ; } export function calculateLineDistance ( aPoint , bPoint ) { return distance ( aPoint , bPoint ) ; } export function calculateGeometryArea ( polygon ) { return area ( polygon ) ; } export function getDistanceBetweenPoints ( source , destination ) { let distanceInKilometers = 0 ; try { distanceInKilometers = distance ( source , destination , { units : 'kilometers' } ) ; } catch ( e ) { console . warn ( 'getDistanceBetweenPoints: turf exception' , e ) ; } return distanceInKilometers ; } export function getNewPoint ( coordinates ) { return { type : 'Point' , coordinates } ; } export function splitExtent ( extent , deep ) { const polygons = [ ] ; const extentCoord = extent . coordinates [ 0 ] ; const center = getPointByGeometry ( extent ) ; const extnetWithoutLastPoint = extentCoord . slice ( 0 , 4 ) ; extnetWithoutLastPoint . forEach ( point => { const extentFeature = polygonFromBBOX ( [ point [ 0 ] , point [ 1 ] , center . coordinates [ 0 ] , center . coordinates [ 1 ] ] ) ; if ( deep === 1 ) { polygons . push ( extentFeature ) ; } else { polygons . push ( ... splitExtent ( extentFeature , deep - 1 ) ) ; } } ) ; return polygons ; } export const EPSG_4326 = 'EPSG:4326' ; export const EPSG_3857 = 'EPSG:3857' ;