| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | import { OsmCreateAction } from "./OsmChangeAction" | 
					
						
							|  |  |  | import { Tag } from "../../Tags/Tag" | 
					
						
							|  |  |  | import { Changes } from "../Changes" | 
					
						
							|  |  |  | import { ChangeDescription } from "./ChangeDescription" | 
					
						
							|  |  |  | import FeaturePipelineState from "../../State/FeaturePipelineState" | 
					
						
							|  |  |  | import { BBox } from "../../BBox" | 
					
						
							|  |  |  | import { TagsFilter } from "../../Tags/TagsFilter" | 
					
						
							|  |  |  | import { GeoOperations } from "../../GeoOperations" | 
					
						
							|  |  |  | import FeatureSource from "../../FeatureSource/FeatureSource" | 
					
						
							|  |  |  | import StaticFeatureSource from "../../FeatureSource/Sources/StaticFeatureSource" | 
					
						
							|  |  |  | import CreateNewNodeAction from "./CreateNewNodeAction" | 
					
						
							|  |  |  | import CreateNewWayAction from "./CreateNewWayAction" | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | export interface MergePointConfig { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     withinRangeOfM: number | 
					
						
							|  |  |  |     ifMatches: TagsFilter | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |     mode: "reuse_osm_point" | "move_osm_point" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * CreateWayWithPointreuse will create a 'CoordinateInfo' for _every_ point in the way to be created. | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |  * The CoordinateInfo indicates the action to take, e.g.: | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |  * - Create a new point | 
					
						
							|  |  |  |  * - Reuse an existing OSM point (and don't move it) | 
					
						
							|  |  |  |  * - Reuse an existing OSM point (and leave it where it is) | 
					
						
							|  |  |  |  * - Reuse another Coordinate info (and don't do anything else with it) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  | interface CoordinateInfo { | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * The new coordinate | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     lngLat: [number, number] | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * If set: indicates that this point is identical to an earlier point in the way and that that point should be used. | 
					
						
							|  |  |  |      * This is especially needed in closed ways, where the last CoordinateInfo will have '0' as identicalTo | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     identicalTo?: number | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Information about the closebyNode which might be reused | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |     closebyNodes?: { | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |         /** | 
					
						
							|  |  |  |          * Distance in meters between the target coordinate and this candidate coordinate | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         d: number | 
					
						
							|  |  |  |         node: any | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         config: MergePointConfig | 
					
						
							|  |  |  |     }[] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * More or less the same as 'CreateNewWay', except that it'll try to reuse already existing points | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  | export default class CreateWayWithPointReuseAction extends OsmCreateAction { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     public newElementId: string = undefined | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |     public newElementIdNumber: number = undefined | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     private readonly _tags: Tag[] | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * lngLat-coordinates | 
					
						
							|  |  |  |      * @private | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     private _coordinateInfo: CoordinateInfo[] | 
					
						
							|  |  |  |     private _state: FeaturePipelineState | 
					
						
							|  |  |  |     private _config: MergePointConfig[] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constructor( | 
					
						
							|  |  |  |         tags: Tag[], | 
					
						
							|  |  |  |         coordinates: [number, number][], | 
					
						
							|  |  |  |         state: FeaturePipelineState, | 
					
						
							|  |  |  |         config: MergePointConfig[] | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         super(null, true) | 
					
						
							|  |  |  |         this._tags = tags | 
					
						
							|  |  |  |         this._state = state | 
					
						
							|  |  |  |         this._config = config | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |         // The main logic of this class: the coordinateInfo contains all the changes
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         this._coordinateInfo = this.CalculateClosebyNodes(coordinates) | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public async getPreview(): Promise<FeatureSource> { | 
					
						
							|  |  |  |         const features = [] | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         let geometryMoved = false | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         for (let i = 0; i < this._coordinateInfo.length; i++) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             const coordinateInfo = this._coordinateInfo[i] | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             if (coordinateInfo.identicalTo !== undefined) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             if ( | 
					
						
							|  |  |  |                 coordinateInfo.closebyNodes === undefined || | 
					
						
							|  |  |  |                 coordinateInfo.closebyNodes.length === 0 | 
					
						
							|  |  |  |             ) { | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 const newPoint = { | 
					
						
							|  |  |  |                     type: "Feature", | 
					
						
							|  |  |  |                     properties: { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         newpoint: "yes", | 
					
						
							|  |  |  |                         id: "new-geometry-with-reuse-" + i, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                     geometry: { | 
					
						
							|  |  |  |                         type: "Point", | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         coordinates: coordinateInfo.lngLat, | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 features.push(newPoint) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const reusedPoint = coordinateInfo.closebyNodes[0] | 
					
						
							|  |  |  |             if (reusedPoint.config.mode === "move_osm_point") { | 
					
						
							|  |  |  |                 const moveDescription = { | 
					
						
							|  |  |  |                     type: "Feature", | 
					
						
							|  |  |  |                     properties: { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         move: "yes", | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                         "osm-id": reusedPoint.node.properties.id, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         id: "new-geometry-move-existing" + i, | 
					
						
							|  |  |  |                         distance: GeoOperations.distanceBetween( | 
					
						
							|  |  |  |                             coordinateInfo.lngLat, | 
					
						
							|  |  |  |                             reusedPoint.node.geometry.coordinates | 
					
						
							|  |  |  |                         ), | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                     geometry: { | 
					
						
							|  |  |  |                         type: "LineString", | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         coordinates: [reusedPoint.node.geometry.coordinates, coordinateInfo.lngLat], | 
					
						
							|  |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 features.push(moveDescription) | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  |                 // The geometry is moved, the point is reused
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 geometryMoved = true | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 const reuseDescription = { | 
					
						
							|  |  |  |                     type: "Feature", | 
					
						
							|  |  |  |                     properties: { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         move: "no", | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  |                         "osm-id": reusedPoint.node.properties.id, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         id: "new-geometry-reuse-existing" + i, | 
					
						
							|  |  |  |                         distance: GeoOperations.distanceBetween( | 
					
						
							|  |  |  |                             coordinateInfo.lngLat, | 
					
						
							|  |  |  |                             reusedPoint.node.geometry.coordinates | 
					
						
							|  |  |  |                         ), | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                     geometry: { | 
					
						
							|  |  |  |                         type: "LineString", | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         coordinates: [coordinateInfo.lngLat, reusedPoint.node.geometry.coordinates], | 
					
						
							|  |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 features.push(reuseDescription) | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (geometryMoved) { | 
					
						
							|  |  |  |             const coords: [number, number][] = [] | 
					
						
							|  |  |  |             for (const info of this._coordinateInfo) { | 
					
						
							|  |  |  |                 if (info.identicalTo !== undefined) { | 
					
						
							|  |  |  |                     coords.push(coords[info.identicalTo]) | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (info.closebyNodes === undefined || info.closebyNodes.length === 0) { | 
					
						
							|  |  |  |                     coords.push(coords[info.identicalTo]) | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const closest = info.closebyNodes[0] | 
					
						
							|  |  |  |                 if (closest.config.mode === "reuse_osm_point") { | 
					
						
							|  |  |  |                     coords.push(closest.node.geometry.coordinates) | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     coords.push(info.lngLat) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const newGeometry = { | 
					
						
							|  |  |  |                 type: "Feature", | 
					
						
							|  |  |  |                 properties: { | 
					
						
							|  |  |  |                     "resulting-geometry": "yes", | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     id: "new-geometry", | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 }, | 
					
						
							|  |  |  |                 geometry: { | 
					
						
							|  |  |  |                     type: "LineString", | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     coordinates: coords, | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |             features.push(newGeometry) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |         return StaticFeatureSource.fromGeojson(features) | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  |     public async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> { | 
					
						
							| 
									
										
										
										
											2022-02-22 14:13:41 +01:00
										 |  |  |         const theme = this._state?.layoutToUse?.id | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         const allChanges: ChangeDescription[] = [] | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         const nodeIdsToUse: { lat: number; lon: number; nodeId?: number }[] = [] | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         for (let i = 0; i < this._coordinateInfo.length; i++) { | 
					
						
							|  |  |  |             const info = this._coordinateInfo[i] | 
					
						
							|  |  |  |             const lat = info.lngLat[1] | 
					
						
							|  |  |  |             const lon = info.lngLat[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (info.identicalTo !== undefined) { | 
					
						
							|  |  |  |                 nodeIdsToUse.push(nodeIdsToUse[info.identicalTo]) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (info.closebyNodes === undefined || info.closebyNodes[0] === undefined) { | 
					
						
							|  |  |  |                 const newNodeAction = new CreateNewNodeAction([], lat, lon, { | 
					
						
							|  |  |  |                     allowReuseOfPreviouslyCreatedPoints: true, | 
					
						
							|  |  |  |                     changeType: null, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     theme, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 allChanges.push(...(await newNodeAction.CreateChangeDescriptions(changes))) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 nodeIdsToUse.push({ | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     lat, | 
					
						
							|  |  |  |                     lon, | 
					
						
							|  |  |  |                     nodeId: newNodeAction.newElementIdNumber, | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |                 }) | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             const closestPoint = info.closebyNodes[0] | 
					
						
							|  |  |  |             const id = Number(closestPoint.node.properties.id.split("/")[1]) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |             if (closestPoint.config.mode === "move_osm_point") { | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 allChanges.push({ | 
					
						
							|  |  |  |                     type: "node", | 
					
						
							|  |  |  |                     id, | 
					
						
							|  |  |  |                     changes: { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         lat, | 
					
						
							|  |  |  |                         lon, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                     meta: { | 
					
						
							|  |  |  |                         theme, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         changeType: null, | 
					
						
							|  |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 }) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             nodeIdsToUse.push({ lat, lon, nodeId: id }) | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const newWay = new CreateNewWayAction(this._tags, nodeIdsToUse, { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             theme, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-09 01:49:07 +01:00
										 |  |  |         allChanges.push(...(await newWay.CreateChangeDescriptions(changes))) | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  |         this.newElementId = newWay.newElementId | 
					
						
							|  |  |  |         this.newElementIdNumber = newWay.newElementIdNumber | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         return allChanges | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Calculates the main changes. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |     private CalculateClosebyNodes(coordinates: [number, number][]): CoordinateInfo[] { | 
					
						
							|  |  |  |         const bbox = new BBox(coordinates) | 
					
						
							|  |  |  |         const state = this._state | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         const allNodes = [].concat( | 
					
						
							|  |  |  |             ...(state?.featurePipeline?.GetFeaturesWithin("type_node", bbox.pad(1.2)) ?? []) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         const maxDistance = Math.max(...this._config.map((c) => c.withinRangeOfM)) | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |         // Init coordianteinfo with undefined but the same length as coordinates
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         const coordinateInfo: { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             lngLat: [number, number] | 
					
						
							|  |  |  |             identicalTo?: number | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             closebyNodes?: { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 d: number | 
					
						
							|  |  |  |                 node: any | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 config: MergePointConfig | 
					
						
							|  |  |  |             }[] | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         }[] = coordinates.map((_) => undefined) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |         // First loop: gather all information...
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         for (let i = 0; i < coordinates.length; i++) { | 
					
						
							|  |  |  |             if (coordinateInfo[i] !== undefined) { | 
					
						
							|  |  |  |                 // Already seen, probably a duplicate coordinate
 | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const coor = coordinates[i] | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |             // Check closeby (and probably identical) points further in the coordinate list, mark them as duplicate
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             for (let j = i + 1; j < coordinates.length; j++) { | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |                 // We look into the 'future' of the way and mark those 'future' locations as being the same as this location
 | 
					
						
							|  |  |  |                 // The continue just above will make sure they get ignored
 | 
					
						
							|  |  |  |                 // This code is important to 'close' ways
 | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |                 if (GeoOperations.distanceBetween(coor, coordinates[j]) < 0.1) { | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                     coordinateInfo[j] = { | 
					
						
							|  |  |  |                         lngLat: coor, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         identicalTo: i, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     break | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Gather the actual info for this point
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Lets search applicable points and determine the merge mode
 | 
					
						
							|  |  |  |             const closebyNodes: { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 d: number | 
					
						
							|  |  |  |                 node: any | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 config: MergePointConfig | 
					
						
							|  |  |  |             }[] = [] | 
					
						
							|  |  |  |             for (const node of allNodes) { | 
					
						
							|  |  |  |                 const center = node.geometry.coordinates | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |                 const d = GeoOperations.distanceBetween(coor, center) | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 if (d > maxDistance) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 for (const config of this._config) { | 
					
						
							|  |  |  |                     if (d > config.withinRangeOfM) { | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     if (!config.ifMatches.matchesProperties(node.properties)) { | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     closebyNodes.push({ node, d, config }) | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |             // Sort by distance, closest first
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             closebyNodes.sort((n0, n1) => { | 
					
						
							|  |  |  |                 return n0.d - n1.d | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             coordinateInfo[i] = { | 
					
						
							|  |  |  |                 identicalTo: undefined, | 
					
						
							|  |  |  |                 lngLat: coor, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 closebyNodes, | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |         // Second loop: figure out which point moves where without creating conflicts
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         let conflictFree = true | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         do { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             conflictFree = true | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |             for (let i = 0; i < coordinateInfo.length; i++) { | 
					
						
							|  |  |  |                 const coorInfo = coordinateInfo[i] | 
					
						
							|  |  |  |                 if (coorInfo.identicalTo !== undefined) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (coorInfo.closebyNodes === undefined || coorInfo.closebyNodes[0] === undefined) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 for (let j = i + 1; j < coordinates.length; j++) { | 
					
						
							|  |  |  |                     const other = coordinateInfo[j] | 
					
						
							|  |  |  |                     if (other.closebyNodes === undefined || other.closebyNodes[0] === undefined) { | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     if (coorInfo.closebyNodes[0] === undefined) { | 
					
						
							| 
									
										
										
										
											2021-12-06 03:24:33 +01:00
										 |  |  |                         continue | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     if (other.closebyNodes[0].node === coorInfo.closebyNodes[0].node) { | 
					
						
							|  |  |  |                         conflictFree = false | 
					
						
							|  |  |  |                         // We have found a conflict!
 | 
					
						
							|  |  |  |                         // We only keep the closest point
 | 
					
						
							|  |  |  |                         if (other.closebyNodes[0].d > coorInfo.closebyNodes[0].d) { | 
					
						
							|  |  |  |                             other.closebyNodes.shift() | 
					
						
							|  |  |  |                         } else { | 
					
						
							|  |  |  |                             coorInfo.closebyNodes.shift() | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } while (!conflictFree) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return coordinateInfo | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | } |