import * as L from "leaflet" ; import { GeodesicCore , GeodesicOptions , WGS84Vector } from "./geodesic-core" ; /** detailled information of the current geometry */ export interface Statistics { /** Stores the distance for each individual geodesic line */ distanceArray : number [ ] ; /** overall distance of all lines */ totalDistance : number ; /** number of positions that the geodesic lines are created from */ points : number ; /** number vertices that were created during geometry calculation */ vertices : number ; } export class GeodesicGeometry { readonly geodesic = new GeodesicCore ( ) ; steps : number ; constructor ( options ? ) { this . steps = ( options && options . steps !== undefined ) ? options . steps : 3 ; } param start param dest param iterations return recursiveMidpoint ( start , dest , iterations ) { const geom = [ start , dest ] ; const midpoint = this . geodesic . midpoint ( start , dest ) ; if ( iterations > 0 ) { geom . splice ( 0 , 1 , ... this . recursiveMidpoint ( start , midpoint , iterations - 1 ) ) ; geom . splice ( geom . length - 2 , 2 , ... this . recursiveMidpoint ( midpoint , dest , iterations - 1 ) ) ; } else { geom . splice ( 1 , 0 , midpoint ) ; } return geom ; } param start param dest return line ( start , dest ) { return this . recursiveMidpoint ( start , dest , Math . min ( 8 , this . steps ) ) ; } multiLineString ( latlngs ) { const multiLineString = [ ] ; for ( const linestring of latlngs ) { const segment = [ ] ; for ( let j = 1 ; j < linestring . length ; j ++ ) { segment . splice ( segment . length - 1 , 1 , ... this . line ( linestring [ j - 1 ] , linestring [ j ] ) ) ; } multiLineString . push ( segment ) ; } return multiLineString ; } lineString ( latlngs ) { return this . multiLineString ( [ latlngs ] ) [ 0 ] ; } param startPosition param destPosition splitLine ( startPosition , destPosition ) { const antimeridianWest = { point : new L . LatLng ( 89.9 , - 180.0000001 ) , bearing : 180 } ; const antimeridianEast = { point : new L . LatLng ( 89.9 , 180.0000001 ) , bearing : 180 } ; const start = new L . LatLng ( startPosition . lat , startPosition . lng ) ; const dest = new L . LatLng ( destPosition . lat , destPosition . lng ) ; start . lng = this . geodesic . wrap ( start . lng , 360 ) ; dest . lng = this . geodesic . wrap ( dest . lng , 360 ) ; if ( ( dest . lng - start . lng ) > 180 ) { dest . lng = dest . lng - 360 ; } else if ( ( dest . lng - start . lng ) < - 180 ) { dest . lng = dest . lng + 360 ; } let result = [ [ new L . LatLng ( start . lat , this . geodesic . wrap ( start . lng , 180 ) ) , new L . LatLng ( dest . lat , this . geodesic . wrap ( dest . lng , 180 ) ) ] ] ; if ( ( start . lng >= - 180 ) && ( start . lng <= 180 ) ) { if ( dest . lng < - 180 ) { const bearing = this . geodesic . inverse ( start , dest ) . initialBearing ; const intersection = this . geodesic . intersection ( start , bearing , antimeridianWest . point , antimeridianWest . bearing ) ; if ( intersection ) { result = [ [ start , intersection ] , [ new L . LatLng ( intersection . lat , intersection . lng + 360 ) , new L . LatLng ( dest . lat , dest . lng + 360 ) ] ] ; } } else if ( dest . lng > 180 ) { const bearing = this . geodesic . inverse ( start , dest ) . initialBearing ; const intersection = this . geodesic . intersection ( start , bearing , antimeridianEast . point , antimeridianEast . bearing ) ; if ( intersection ) { result = [ [ start , intersection ] , [ new L . LatLng ( intersection . lat , intersection . lng - 360 ) , new L . LatLng ( dest . lat , dest . lng - 360 ) ] ] ; } } } else if ( ( dest . lng >= - 180 ) && ( dest . lng <= 180 ) ) { if ( start . lng < - 180 ) { const bearing = this . geodesic . inverse ( start , dest ) . initialBearing ; const intersection = this . geodesic . intersection ( start , bearing , antimeridianWest . point , antimeridianWest . bearing ) ; if ( intersection ) { result = [ [ new L . LatLng ( start . lat , start . lng + 360 ) , new L . LatLng ( intersection . lat , intersection . lng + 360 ) ] , [ intersection , dest ] ] ; } } else if ( start . lng > 180 ) { const bearing = this . geodesic . inverse ( start , dest ) . initialBearing ; const intersection = this . geodesic . intersection ( start , bearing , antimeridianWest . point , antimeridianWest . bearing ) ; if ( intersection ) { result = [ [ new L . LatLng ( start . lat , start . lng - 360 ) , new L . LatLng ( intersection . lat , intersection . lng - 360 ) ] , [ intersection , dest ] ] ; } } } return result ; } param multilinestring return splitMultiLineString ( multilinestring ) { const result = [ ] ; for ( const linestring of multilinestring ) { if ( linestring . length === 1 ) { result . push ( linestring ) ; continue ; } let segment = [ ] ; for ( let j = 1 ; j < linestring . length ; j ++ ) { const split = this . splitLine ( linestring [ j - 1 ] , linestring [ j ] ) ; segment . pop ( ) ; segment = segment . concat ( split [ 0 ] ) ; if ( split . length > 1 ) { result . push ( segment ) ; segment = split [ 1 ] ; } } result . push ( segment ) ; } return result ; } param multilinestring returns wrapMultiLineString ( multilinestring ) { const result = [ ] ; for ( const linestring of multilinestring ) { const resultLine = [ ] ; let previous = null ; for ( const point of linestring ) { if ( previous === null ) { resultLine . push ( new L . LatLng ( point . lat , point . lng ) ) ; previous = new L . LatLng ( point . lat , point . lng ) ; } else { const offset = Math . round ( ( point . lng - previous . lng ) / 360 ) ; resultLine . push ( new L . LatLng ( point . lat , point . lng - offset * 360 ) ) ; previous = new L . LatLng ( point . lat , point . lng - offset * 360 ) ; } } result . push ( resultLine ) ; } return result ; } param center param radius return circle ( center , radius ) { const vertices = [ ] ; for ( let i = 0 ; i < this . steps ; i ++ ) { const point = this . geodesic . direct ( center , 360 / this . steps * i , radius ) ; vertices . push ( new L . LatLng ( point . lat , point . lng ) ) ; } vertices . push ( new L . LatLng ( vertices [ 0 ] . lat , vertices [ 0 ] . lng ) ) ; return vertices ; } param linestring return splitCircle ( linestring ) { const result = this . splitMultiLineString ( [ linestring ] ) ; if ( result . length === 3 ) { result [ 2 ] = [ ... result [ 2 ] , ... result [ 0 ] ] ; result . shift ( ) ; } return result ; } param start param dest return distance ( start , dest ) { return this . geodesic . inverse ( new L . LatLng ( start . lat , this . geodesic . wrap ( start . lng , 180 ) ) , new L . LatLng ( dest . lat , this . geodesic . wrap ( dest . lng , 180 ) ) ) . distance ; } multilineDistance ( multilinestring ) { const dist = [ ] ; for ( const linestring of multilinestring ) { let segmentDistance = 0 ; for ( let j = 1 ; j < linestring . length ; j ++ ) { segmentDistance += this . distance ( linestring [ j - 1 ] , linestring [ j ] ) ; } dist . push ( segmentDistance ) ; } return dist ; } updateStatistics ( points , vertices ) { const stats = { } as any ; stats . distanceArray = this . multilineDistance ( points ) ; stats . totalDistance = stats . distanceArray . reduce ( ( x , y ) => x + y , 0 ) ; stats . points = 0 ; for ( const item of points ) { stats . points += item . reduce ( ( x ) => x + 1 , 0 ) ; } stats . vertices = 0 ; for ( const item of vertices ) { stats . vertices += item . reduce ( ( x ) => x + 1 , 0 ) ; } return stats ; } }