| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  | import {OsmCreateAction} from "./OsmChangeAction"; | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  | 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"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export interface MergePointConfig { | 
					
						
							|  |  |  |     withinRangeOfM: number, | 
					
						
							|  |  |  |     ifMatches: TagsFilter, | 
					
						
							|  |  |  |     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. | 
					
						
							|  |  |  |  *  | 
					
						
							|  |  |  |  * The CoordinateInfo indicates the action to take, e.g.: | 
					
						
							|  |  |  |  *  | 
					
						
							|  |  |  |  * - 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) | 
					
						
							|  |  |  |  *  | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  | interface CoordinateInfo { | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * The new coordinate | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01: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 | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01: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 | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         d: number, | 
					
						
							|  |  |  |         node: any, | 
					
						
							|  |  |  |         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 { | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |     private readonly _tags: Tag[]; | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * lngLat-coordinates | 
					
						
							|  |  |  |      * @private | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private _coordinateInfo: CoordinateInfo[]; | 
					
						
							|  |  |  |     private _state: FeaturePipelineState; | 
					
						
							|  |  |  |     private _config: MergePointConfig[]; | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  |      | 
					
						
							|  |  |  |     public newElementId: string = undefined; | 
					
						
							|  |  |  |     public newElementIdNumber: number = undefined | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     constructor(tags: Tag[], | 
					
						
							|  |  |  |                 coordinates: [number, number][], | 
					
						
							|  |  |  |                 state: FeaturePipelineState, | 
					
						
							|  |  |  |                 config: MergePointConfig[] | 
					
						
							|  |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2021-11-09 01:49:07 +01:00
										 |  |  |         super(null,true); | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         this._tags = tags; | 
					
						
							|  |  |  |         this._state = state; | 
					
						
							|  |  |  |         this._config = config; | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |          | 
					
						
							|  |  |  |         // The main logic of this class: the coordinateInfo contains all the changes
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         this._coordinateInfo = this.CalculateClosebyNodes(coordinates); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public async getPreview(): Promise<FeatureSource> { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const features = [] | 
					
						
							|  |  |  |         let geometryMoved = false; | 
					
						
							|  |  |  |         for (let i = 0; i < this._coordinateInfo.length; i++) { | 
					
						
							|  |  |  |             const coordinateInfo = this._coordinateInfo[i]; | 
					
						
							|  |  |  |             if (coordinateInfo.identicalTo !== undefined) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (coordinateInfo.closebyNodes === undefined || coordinateInfo.closebyNodes.length === 0) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const newPoint = { | 
					
						
							|  |  |  |                     type: "Feature", | 
					
						
							|  |  |  |                     properties: { | 
					
						
							|  |  |  |                         "newpoint": "yes", | 
					
						
							|  |  |  |                         id: "new-geometry-with-reuse-" + i | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     geometry: { | 
					
						
							|  |  |  |                         type: "Point", | 
					
						
							|  |  |  |                         coordinates: coordinateInfo.lngLat | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }; | 
					
						
							|  |  |  |                 features.push(newPoint) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const reusedPoint = coordinateInfo.closebyNodes[0] | 
					
						
							|  |  |  |             if (reusedPoint.config.mode === "move_osm_point") { | 
					
						
							|  |  |  |                 const moveDescription = { | 
					
						
							|  |  |  |                     type: "Feature", | 
					
						
							|  |  |  |                     properties: { | 
					
						
							|  |  |  |                         "move": "yes", | 
					
						
							|  |  |  |                         "osm-id": reusedPoint.node.properties.id, | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01: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", | 
					
						
							|  |  |  |                         coordinates: [reusedPoint.node.geometry.coordinates, coordinateInfo.lngLat] | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 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: { | 
					
						
							|  |  |  |                         "move": "no", | 
					
						
							|  |  |  |                         "osm-id": reusedPoint.node.properties.id, | 
					
						
							|  |  |  |                         "id": "new-geometry-reuse-existing" + i, | 
					
						
							|  |  |  |                         "distance":GeoOperations.distanceBetween(coordinateInfo.lngLat, reusedPoint.node.geometry.coordinates) | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     geometry: { | 
					
						
							|  |  |  |                         type: "LineString", | 
					
						
							|  |  |  |                         coordinates: [coordinateInfo.lngLat, reusedPoint.node.geometry.coordinates] | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 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", | 
					
						
							|  |  |  |                     "id": "new-geometry" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 geometry: { | 
					
						
							|  |  |  |                     type: "LineString", | 
					
						
							|  |  |  |                     coordinates: coords | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             features.push(newGeometry) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return new StaticFeatureSource(features, false) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-10 04:00:02 +01:00
										 |  |  |     public async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> { | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         const theme = this._state.layoutToUse.id | 
					
						
							|  |  |  |         const allChanges: ChangeDescription[] = [] | 
					
						
							|  |  |  |         const nodeIdsToUse: { lat: number, lon: number, nodeId?: number }[] = [] | 
					
						
							|  |  |  |         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, | 
					
						
							|  |  |  |                     theme | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 allChanges.push(...(await newNodeAction.CreateChangeDescriptions(changes))) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |                 nodeIdsToUse.push({ | 
					
						
							|  |  |  |                     lat, lon, | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |                     nodeId: newNodeAction.newElementIdNumber | 
					
						
							|  |  |  |                 }) | 
					
						
							| 
									
										
										
										
											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
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											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: { | 
					
						
							|  |  |  |                         lat, lon | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     meta: { | 
					
						
							|  |  |  |                         theme, | 
					
						
							|  |  |  |                         changeType: null | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             nodeIdsToUse.push({lat, lon, nodeId: id}) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const newWay = new CreateNewWayAction(this._tags, nodeIdsToUse, { | 
					
						
							|  |  |  |             theme | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |         const allNodes = [].concat(...state.featurePipeline.GetFeaturesWithin("type_node", bbox.pad(1.2))) | 
					
						
							|  |  |  |         const maxDistance = Math.max(...this._config.map(c => c.withinRangeOfM)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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: { | 
					
						
							|  |  |  |             lngLat: [number, number], | 
					
						
							|  |  |  |             identicalTo?: number, | 
					
						
							|  |  |  |             closebyNodes?: { | 
					
						
							|  |  |  |                 d: number, | 
					
						
							|  |  |  |                 node: any, | 
					
						
							|  |  |  |                 config: MergePointConfig | 
					
						
							|  |  |  |             }[] | 
					
						
							|  |  |  |         }[] = coordinates.map(_ => undefined) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							|  |  |  |                         identicalTo: i | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Gather the actual info for this point
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Lets search applicable points and determine the merge mode
 | 
					
						
							|  |  |  |             const closebyNodes: { | 
					
						
							|  |  |  |                 d: number, | 
					
						
							|  |  |  |                 node: any, | 
					
						
							|  |  |  |                 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 | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     closebyNodes.push({node, d, config}) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							|  |  |  |                 closebyNodes | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |          | 
					
						
							|  |  |  |         // Second loop: figure out which point moves where without creating conflicts
 | 
					
						
							| 
									
										
										
										
											2021-11-04 02:16:07 +01:00
										 |  |  |         let conflictFree = true; | 
					
						
							|  |  |  |         do { | 
					
						
							|  |  |  |             conflictFree = true; | 
					
						
							|  |  |  |             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 | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2021-12-06 03:24:33 +01:00
										 |  |  |                      | 
					
						
							|  |  |  |                     if(coorInfo.closebyNodes[0] === undefined){ | 
					
						
							|  |  |  |                         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 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |