forked from MapComplete/MapComplete
		
	Merge develop
This commit is contained in:
		
						commit
						f0823f4c4d
					
				
					 524 changed files with 18747 additions and 8546 deletions
				
			
		|  | @ -156,7 +156,7 @@ export class GeoOperations { | |||
|                 const intersection = GeoOperations.calculateIntersection( | ||||
|                     feature, | ||||
|                     otherFeature, | ||||
|                     featureBBox, | ||||
|                     featureBBox | ||||
|                 ) | ||||
|                 if (intersection === null) { | ||||
|                     continue | ||||
|  | @ -195,7 +195,7 @@ export class GeoOperations { | |||
|         console.error( | ||||
|             "Could not correctly calculate the overlap of ", | ||||
|             feature, | ||||
|             ": unsupported type", | ||||
|             ": unsupported type" | ||||
|         ) | ||||
|         return result | ||||
|     } | ||||
|  | @ -224,7 +224,7 @@ export class GeoOperations { | |||
|      */ | ||||
|     public static inside( | ||||
|         pointCoordinate: [number, number] | Feature<Point>, | ||||
|         feature: Feature, | ||||
|         feature: Feature | ||||
|     ): boolean { | ||||
|         // ray-casting algorithm based on
 | ||||
|         // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
 | ||||
|  | @ -302,7 +302,7 @@ export class GeoOperations { | |||
|      */ | ||||
|     public static nearestPoint( | ||||
|         way: Feature<LineString>, | ||||
|         point: [number, number], | ||||
|         point: [number, number] | ||||
|     ): Feature< | ||||
|         Point, | ||||
|         { | ||||
|  | @ -324,11 +324,11 @@ export class GeoOperations { | |||
|     public static forceLineString(way: Feature<LineString | Polygon>): Feature<LineString> | ||||
| 
 | ||||
|     public static forceLineString( | ||||
|         way: Feature<MultiLineString | MultiPolygon>, | ||||
|         way: Feature<MultiLineString | MultiPolygon> | ||||
|     ): Feature<MultiLineString> | ||||
| 
 | ||||
|     public static forceLineString( | ||||
|         way: Feature<LineString | MultiLineString | Polygon | MultiPolygon>, | ||||
|         way: Feature<LineString | MultiLineString | Polygon | MultiPolygon> | ||||
|     ): Feature<LineString | MultiLineString> { | ||||
|         if (way.geometry.type === "Polygon") { | ||||
|             way = { ...way } | ||||
|  | @ -345,11 +345,21 @@ export class GeoOperations { | |||
|         return <any>way | ||||
|     } | ||||
| 
 | ||||
|     public static toCSV(features: Feature[] | FeatureCollection): string { | ||||
|     public static toCSV( | ||||
|         features: Feature[] | FeatureCollection, | ||||
|         options?: { | ||||
|             ignoreTags?: RegExp | ||||
|         } | ||||
|     ): string { | ||||
|         const headerValuesSeen = new Set<string>() | ||||
|         const headerValuesOrdered: string[] = [] | ||||
| 
 | ||||
|         function addH(key) { | ||||
|         function addH(key: string) { | ||||
|             if (options?.ignoreTags) { | ||||
|                 if (key.match(options.ignoreTags)) { | ||||
|                     return | ||||
|                 } | ||||
|             } | ||||
|             if (!headerValuesSeen.has(key)) { | ||||
|                 headerValuesSeen.add(key) | ||||
|                 headerValuesOrdered.push(key) | ||||
|  | @ -448,7 +458,7 @@ export class GeoOperations { | |||
|      */ | ||||
|     public static LineIntersections( | ||||
|         feature: Feature<LineString | MultiLineString | Polygon | MultiPolygon>, | ||||
|         otherFeature: Feature<LineString | MultiLineString | Polygon | MultiPolygon>, | ||||
|         otherFeature: Feature<LineString | MultiLineString | Polygon | MultiPolygon> | ||||
|     ): [number, number][] { | ||||
|         return turf | ||||
|             .lineIntersect(feature, otherFeature) | ||||
|  | @ -485,7 +495,7 @@ export class GeoOperations { | |||
|         locations: | ||||
|             | Feature<LineString> | ||||
|             | Feature<Point, { date?: string; altitude?: number | string }>[], | ||||
|         title?: string, | ||||
|         title?: string | ||||
|     ) { | ||||
|         title = title?.trim() | ||||
|         if (title === undefined || title === "") { | ||||
|  | @ -506,7 +516,7 @@ export class GeoOperations { | |||
|                             type: "Point", | ||||
|                             coordinates: p, | ||||
|                         }, | ||||
|                     }, | ||||
|                     } | ||||
|             ) | ||||
|         } | ||||
|         for (const l of locationsWithMeta) { | ||||
|  | @ -521,7 +531,7 @@ export class GeoOperations { | |||
|             trackPoints.push(trkpt) | ||||
|         } | ||||
|         const header = | ||||
|             "<gpx version=\"1.1\" creator=\"mapcomplete.org\" xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">" | ||||
|             '<gpx version="1.1" creator="mapcomplete.org" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">' | ||||
|         return ( | ||||
|             header + | ||||
|             "\n<name>" + | ||||
|  | @ -539,7 +549,7 @@ export class GeoOperations { | |||
|      */ | ||||
|     public static toGpxPoints( | ||||
|         locations: Feature<Point, { date?: string; altitude?: number | string }>[], | ||||
|         title?: string, | ||||
|         title?: string | ||||
|     ) { | ||||
|         title = title?.trim() | ||||
|         if (title === undefined || title === "") { | ||||
|  | @ -560,7 +570,7 @@ export class GeoOperations { | |||
|             trackPoints.push(trkpt) | ||||
|         } | ||||
|         const header = | ||||
|             "<gpx version=\"1.1\" creator=\"mapcomplete.org\" xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">" | ||||
|             '<gpx version="1.1" creator="mapcomplete.org" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">' | ||||
|         return ( | ||||
|             header + | ||||
|             "\n<name>" + | ||||
|  | @ -648,7 +658,7 @@ export class GeoOperations { | |||
|                 }, | ||||
|             }, | ||||
|             distanceMeter, | ||||
|             { units: "meters" }, | ||||
|             { units: "meters" } | ||||
|         ).geometry.coordinates | ||||
|     } | ||||
| 
 | ||||
|  | @ -683,7 +693,7 @@ export class GeoOperations { | |||
|      */ | ||||
|     static completelyWithin( | ||||
|         feature: Feature<Geometry, any>, | ||||
|         possiblyEnclosingFeature: Feature<Polygon | MultiPolygon, any>, | ||||
|         possiblyEnclosingFeature: Feature<Polygon | MultiPolygon, any> | ||||
|     ): boolean { | ||||
|         return booleanWithin(feature, possiblyEnclosingFeature) | ||||
|     } | ||||
|  | @ -716,8 +726,11 @@ export class GeoOperations { | |||
|         } | ||||
| 
 | ||||
|         if (toSplit.geometry.type === "MultiLineString") { | ||||
|             const lines: Feature<LineString>[][] = toSplit.geometry.coordinates.map(coordinates => | ||||
|                 turf.lineSplit(<LineString> {type: "LineString", coordinates}, boundary).features ) | ||||
|             const lines: Feature<LineString>[][] = toSplit.geometry.coordinates.map( | ||||
|                 (coordinates) => | ||||
|                     turf.lineSplit(<LineString>{ type: "LineString", coordinates }, boundary) | ||||
|                         .features | ||||
|             ) | ||||
|             const splitted: Feature<LineString>[] = [].concat(...lines) | ||||
|             const kept: Feature<LineString>[] = [] | ||||
|             for (const f of splitted) { | ||||
|  | @ -728,7 +741,6 @@ export class GeoOperations { | |||
|                 f.properties = { ...toSplit.properties } | ||||
|                 kept.push(f) | ||||
|             } | ||||
|             console.log(">>>", {lines, splitted, kept}) | ||||
|             return kept | ||||
|         } | ||||
|         if (toSplit.geometry.type === "Polygon" || toSplit.geometry.type == "MultiPolygon") { | ||||
|  | @ -756,7 +768,14 @@ export class GeoOperations { | |||
|      */ | ||||
|     public static featureToCoordinateWithRenderingType( | ||||
|         feature: Feature, | ||||
|         location: "point" | "centroid" | "start" | "end" | "projected_centerpoint" | string, | ||||
|         location: | ||||
|             | "point" | ||||
|             | "centroid" | ||||
|             | "start" | ||||
|             | "end" | ||||
|             | "projected_centerpoint" | ||||
|             | "polygon_centerpoint" | ||||
|             | string | ||||
|     ): [number, number] | undefined { | ||||
|         switch (location) { | ||||
|             case "point": | ||||
|  | @ -769,6 +788,11 @@ export class GeoOperations { | |||
|                     return undefined | ||||
|                 } | ||||
|                 return GeoOperations.centerpointCoordinates(feature) | ||||
|             case "polygon_centerpoint": | ||||
|                 if (feature.geometry.type === "Polygon") { | ||||
|                     return GeoOperations.centerpointCoordinates(feature) | ||||
|                 } | ||||
|                 return undefined | ||||
|             case "projected_centerpoint": | ||||
|                 if ( | ||||
|                     feature.geometry.type === "LineString" || | ||||
|  | @ -777,7 +801,7 @@ export class GeoOperations { | |||
|                     const centerpoint = GeoOperations.centerpointCoordinates(feature) | ||||
|                     const projected = GeoOperations.nearestPoint( | ||||
|                         <Feature<LineString>>feature, | ||||
|                         centerpoint, | ||||
|                         centerpoint | ||||
|                     ) | ||||
|                     return <[number, number]>projected.geometry.coordinates | ||||
|                 } | ||||
|  | @ -954,7 +978,7 @@ export class GeoOperations { | |||
|      * GeoOperations.bearingToHuman(46) // => "NE"
 | ||||
|      */ | ||||
|     public static bearingToHuman( | ||||
|         bearing: number, | ||||
|         bearing: number | ||||
|     ): "N" | "NE" | "E" | "SE" | "S" | "SW" | "W" | "NW" { | ||||
|         while (bearing < 0) { | ||||
|             bearing += 360 | ||||
|  | @ -966,14 +990,21 @@ export class GeoOperations { | |||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * GeoOperations.bearingToHuman(0) // => "N"
 | ||||
|      * GeoOperations.bearingToHuman(-10) // => "N"
 | ||||
|      * GeoOperations.bearingToHuman(-180) // => "S"
 | ||||
|      * GeoOperations.bearingToHuman(181) // => "S"
 | ||||
|      * GeoOperations.bearingToHuman(46) // => "NE"
 | ||||
|      * GeoOperations.bearingToHumanRelative(-207) // => "sharp_right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(-199) // => "behind"
 | ||||
|      * GeoOperations.bearingToHumanRelative(-180) // => "behind"
 | ||||
|      * GeoOperations.bearingToHumanRelative(-10) // => "straight"
 | ||||
|      * GeoOperations.bearingToHumanRelative(0) // => "straight"
 | ||||
|      * GeoOperations.bearingToHumanRelative(181) // => "behind"
 | ||||
|      * GeoOperations.bearingToHumanRelative(40) // => "slight_right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(46) // => "slight_right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(95) // => "right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(140) // => "sharp_right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(158) // => "behind"
 | ||||
|      * | ||||
|      */ | ||||
|     public static bearingToHumanRelative( | ||||
|         bearing: number, | ||||
|         bearing: number | ||||
|     ): | ||||
|         | "straight" | ||||
|         | "slight_right" | ||||
|  | @ -998,9 +1029,11 @@ export class GeoOperations { | |||
|      * const merged = GeoOperations.attemptLinearize(f) | ||||
|      * merged.geometry.coordinates // => [[3.2176208,51.21760169669458],[3.217198532946432,51.218067], [3.216807134449482,51.21849812105347],[3.2164304037883706,51.2189272]]
 | ||||
|      */ | ||||
|     static attemptLinearize(multiLineStringFeature: Feature<MultiLineString>): Feature<LineString | MultiLineString> { | ||||
|     static attemptLinearize( | ||||
|         multiLineStringFeature: Feature<MultiLineString> | ||||
|     ): Feature<LineString | MultiLineString> { | ||||
|         const coors = multiLineStringFeature.geometry.coordinates | ||||
|         if(coors.length === 0) { | ||||
|         if (coors.length === 0) { | ||||
|             console.error(multiLineStringFeature.geometry) | ||||
|             throw "Error: got degenerate multilinestring" | ||||
|         } | ||||
|  | @ -1014,7 +1047,12 @@ export class GeoOperations { | |||
|                 } | ||||
| 
 | ||||
|                 const jLast = coors[j].at(-1) | ||||
|                 if (!(Math.abs(iFirst[0] - jLast[0]) < 0.000001 && Math.abs(iFirst[1] - jLast[1]) < 0.0000001)) { | ||||
|                 if ( | ||||
|                     !( | ||||
|                         Math.abs(iFirst[0] - jLast[0]) < 0.000001 && | ||||
|                         Math.abs(iFirst[1] - jLast[1]) < 0.0000001 | ||||
|                     ) | ||||
|                 ) { | ||||
|                     continue | ||||
|                 } | ||||
|                 coors[j].splice(coors.length - 1, 1) | ||||
|  | @ -1023,7 +1061,7 @@ export class GeoOperations { | |||
|                 continue outer | ||||
|             } | ||||
|         } | ||||
|         if(coors.length === 0) { | ||||
|         if (coors.length === 0) { | ||||
|             throw "No more coordinates found" | ||||
|         } | ||||
| 
 | ||||
|  | @ -1053,12 +1091,12 @@ export class GeoOperations { | |||
|     private static pointInPolygonCoordinates( | ||||
|         x: number, | ||||
|         y: number, | ||||
|         coordinates: [number, number][][], | ||||
|         coordinates: [number, number][][] | ||||
|     ): boolean { | ||||
|         const inside = GeoOperations.pointWithinRing( | ||||
|             x, | ||||
|             y, | ||||
|             /*This is the outer ring of the polygon */ coordinates[0], | ||||
|             /*This is the outer ring of the polygon */ coordinates[0] | ||||
|         ) | ||||
|         if (!inside) { | ||||
|             return false | ||||
|  | @ -1067,7 +1105,7 @@ export class GeoOperations { | |||
|             const inHole = GeoOperations.pointWithinRing( | ||||
|                 x, | ||||
|                 y, | ||||
|                 coordinates[i], /* These are inner rings, aka holes*/ | ||||
|                 coordinates[i] /* These are inner rings, aka holes*/ | ||||
|             ) | ||||
|             if (inHole) { | ||||
|                 return false | ||||
|  | @ -1105,7 +1143,7 @@ export class GeoOperations { | |||
|         feature, | ||||
|         otherFeature, | ||||
|         featureBBox: BBox, | ||||
|         otherFeatureBBox?: BBox, | ||||
|         otherFeatureBBox?: BBox | ||||
|     ): number { | ||||
|         if (feature.geometry.type === "LineString") { | ||||
|             otherFeatureBBox = otherFeatureBBox ?? BBox.get(otherFeature) | ||||
|  | @ -1154,7 +1192,7 @@ export class GeoOperations { | |||
|             let intersection = turf.lineSlice( | ||||
|                 turf.point(intersectionPointsArray[0]), | ||||
|                 turf.point(intersectionPointsArray[1]), | ||||
|                 feature, | ||||
|                 feature | ||||
|             ) | ||||
| 
 | ||||
|             if (intersection == null) { | ||||
|  | @ -1175,7 +1213,7 @@ export class GeoOperations { | |||
|                     otherFeature, | ||||
|                     feature, | ||||
|                     otherFeatureBBox, | ||||
|                     featureBBox, | ||||
|                     featureBBox | ||||
|                 ) | ||||
|             } | ||||
| 
 | ||||
|  | @ -1195,7 +1233,7 @@ export class GeoOperations { | |||
|                     console.log("Applying fallback intersection...") | ||||
|                     const intersection = turf.intersect( | ||||
|                         turf.truncate(feature), | ||||
|                         turf.truncate(otherFeature), | ||||
|                         turf.truncate(otherFeature) | ||||
|                     ) | ||||
|                     if (intersection == null) { | ||||
|                         return null | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue