| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  | import {Tag} from "../../Tags/Tag"; | 
					
						
							|  |  |  | import OsmChangeAction from "./OsmChangeAction"; | 
					
						
							|  |  |  | import {Changes} from "../Changes"; | 
					
						
							|  |  |  | import {ChangeDescription} from "./ChangeDescription"; | 
					
						
							|  |  |  | import {And} from "../../Tags/And"; | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  | import {OsmWay} from "../OsmObject"; | 
					
						
							|  |  |  | import {GeoOperations} from "../../GeoOperations"; | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-18 14:52:09 +02:00
										 |  |  | export default class CreateNewNodeAction extends OsmChangeAction { | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Maps previously created points onto their assigned ID, to reuse the point if uplaoded | 
					
						
							|  |  |  |      * "lat,lon" --> id | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private static readonly previouslyCreatedPoints = new Map<string, number>() | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  |     public newElementId: string = undefined | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |     public newElementIdNumber: number = undefined | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  |     private readonly _basicTags: Tag[]; | 
					
						
							|  |  |  |     private readonly _lat: number; | 
					
						
							|  |  |  |     private readonly _lon: number; | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |     private readonly _snapOnto: OsmWay; | 
					
						
							|  |  |  |     private readonly _reusePointDistance: number; | 
					
						
							| 
									
										
										
										
											2021-10-04 03:12:42 +02:00
										 |  |  |     private meta: { changeType: "create" | "import"; theme: string }; | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |     private readonly _reusePreviouslyCreatedPoint: boolean; | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-04 03:12:42 +02:00
										 |  |  |     constructor(basicTags: Tag[], | 
					
						
							|  |  |  |                 lat: number, lon: number, | 
					
						
							|  |  |  |                 options: { | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |                     allowReuseOfPreviouslyCreatedPoints?: boolean, | 
					
						
							|  |  |  |                     snapOnto?: OsmWay, | 
					
						
							|  |  |  |                     reusePointWithinMeters?: number, | 
					
						
							|  |  |  |                     theme: string, changeType: "create" | "import" | null | 
					
						
							|  |  |  |                 }) { | 
					
						
							| 
									
										
										
										
											2021-11-09 01:49:07 +01:00
										 |  |  |         super(null,basicTags !== undefined && basicTags.length > 0) | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  |         this._basicTags = basicTags; | 
					
						
							|  |  |  |         this._lat = lat; | 
					
						
							|  |  |  |         this._lon = lon; | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  |         if (lat === undefined || lon === undefined) { | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |             throw "Lat or lon are undefined!" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this._snapOnto = options?.snapOnto; | 
					
						
							| 
									
										
										
										
											2021-09-18 02:34:13 +02:00
										 |  |  |         this._reusePointDistance = options?.reusePointWithinMeters ?? 1 | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |         this._reusePreviouslyCreatedPoint = options?.allowReuseOfPreviouslyCreatedPoints ?? (basicTags.length === 0) | 
					
						
							| 
									
										
										
										
											2021-10-04 03:12:42 +02:00
										 |  |  |         this.meta = { | 
					
						
							|  |  |  |             theme: options.theme, | 
					
						
							|  |  |  |             changeType: options.changeType | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |     public static registerIdRewrites(mappings: Map<string, string>) { | 
					
						
							|  |  |  |         const toAdd: [string, number][] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.previouslyCreatedPoints.forEach((oldId, key) => { | 
					
						
							|  |  |  |             if (!mappings.has("node/" + oldId)) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const newId = Number(mappings.get("node/" + oldId).substr("node/".length)) | 
					
						
							|  |  |  |             toAdd.push([key, newId]) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         for (const [key, newId] of toAdd) { | 
					
						
							|  |  |  |             CreateNewNodeAction.previouslyCreatedPoints.set(key, newId) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |     async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> { | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |         if (this._reusePreviouslyCreatedPoint) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const key = this._lat + "," + this._lon | 
					
						
							|  |  |  |             const prev = CreateNewNodeAction.previouslyCreatedPoints | 
					
						
							|  |  |  |             if (prev.has(key)) { | 
					
						
							|  |  |  |                 this.newElementIdNumber = prev.get(key) | 
					
						
							|  |  |  |                 this.newElementId = "node/" + this.newElementIdNumber | 
					
						
							|  |  |  |                 return [] | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  |         const id = changes.getNewID() | 
					
						
							|  |  |  |         const properties = { | 
					
						
							|  |  |  |             id: "node/" + id | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |         this.setElementId(id) | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  |         for (const kv of this._basicTags) { | 
					
						
							|  |  |  |             if (typeof kv.value !== "string") { | 
					
						
							|  |  |  |                 throw "Invalid value: don't use a regex in a preset" | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             properties[kv.key] = kv.value; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |         const newPointChange: ChangeDescription = { | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  |             tags: new And(this._basicTags).asChange(properties), | 
					
						
							|  |  |  |             type: "node", | 
					
						
							|  |  |  |             id: id, | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |             changes: { | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  |                 lat: this._lat, | 
					
						
							|  |  |  |                 lon: this._lon | 
					
						
							| 
									
										
										
										
											2021-10-04 03:12:42 +02:00
										 |  |  |             }, | 
					
						
							|  |  |  |             meta: this.meta | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (this._snapOnto === undefined) { | 
					
						
							|  |  |  |             return [newPointChange] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Project the point onto the way
 | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |         const geojson = this._snapOnto.asGeoJson() | 
					
						
							|  |  |  |         const projected = GeoOperations.nearestPoint(geojson, [this._lon, this._lat]) | 
					
						
							|  |  |  |         const index = projected.properties.index | 
					
						
							|  |  |  |         // We check that it isn't close to an already existing point
 | 
					
						
							|  |  |  |         let reusedPointId = undefined; | 
					
						
							|  |  |  |         const prev = <[number, number]>geojson.geometry.coordinates[index] | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |         if (GeoOperations.distanceBetween(prev, <[number, number]>projected.geometry.coordinates) < this._reusePointDistance) { | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |             // We reuse this point instead!
 | 
					
						
							|  |  |  |             reusedPointId = this._snapOnto.nodes[index] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const next = <[number, number]>geojson.geometry.coordinates[index + 1] | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |         if (GeoOperations.distanceBetween(next, <[number, number]>projected.geometry.coordinates) < this._reusePointDistance) { | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |             // We reuse this point instead!
 | 
					
						
							|  |  |  |             reusedPointId = this._snapOnto.nodes[index + 1] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (reusedPointId !== undefined) { | 
					
						
							|  |  |  |             console.log("Reusing an existing point:", reusedPointId) | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |             this.setElementId(reusedPointId) | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |             return [{ | 
					
						
							|  |  |  |                 tags: new And(this._basicTags).asChange(properties), | 
					
						
							|  |  |  |                 type: "node", | 
					
						
							| 
									
										
										
										
											2021-10-04 03:12:42 +02:00
										 |  |  |                 id: reusedPointId, | 
					
						
							|  |  |  |                 meta: this.meta | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |             }] | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |         const locations = [...this._snapOnto.coordinates] | 
					
						
							|  |  |  |         locations.forEach(coor => coor.reverse()) | 
					
						
							|  |  |  |         console.log("Locations are: ", locations) | 
					
						
							|  |  |  |         const ids = [...this._snapOnto.nodes] | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |         locations.splice(index + 1, 0, [this._lon, this._lat]) | 
					
						
							|  |  |  |         ids.splice(index + 1, 0, id) | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |         // Allright, we have to insert a new point in the way
 | 
					
						
							|  |  |  |         return [ | 
					
						
							|  |  |  |             newPointChange, | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  |                 type: "way", | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |                 id: this._snapOnto.id, | 
					
						
							|  |  |  |                 changes: { | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |                     coordinates: locations, | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |                     nodes: ids | 
					
						
							| 
									
										
										
										
											2021-10-04 03:12:42 +02:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |                 meta: this.meta | 
					
						
							| 
									
										
										
										
											2021-08-07 21:19:01 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         ] | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |     private setElementId(id: number) { | 
					
						
							|  |  |  |         this.newElementIdNumber = id; | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         this.newElementId = "node/" + id | 
					
						
							| 
									
										
										
										
											2021-10-29 16:38:33 +02:00
										 |  |  |         if (!this._reusePreviouslyCreatedPoint) { | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const key = this._lat + "," + this._lon | 
					
						
							|  |  |  |         CreateNewNodeAction.previouslyCreatedPoints.set(key, id) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-15 20:47:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |