| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  | import { Store, UIEventSource } from "../UIEventSource" | 
					
						
							| 
									
										
										
										
											2024-09-03 01:14:08 +02:00
										 |  |  | import GeocodingProvider, { GeocodingOptions, GeocodeResult } from "./GeocodingProvider" | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  | import { OsmId } from "../../Models/OsmFeature" | 
					
						
							|  |  |  | import { SpecialVisualizationState } from "../../UI/SpecialVisualization" | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  | import { Utils } from "../../Utils" | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 17:31:38 +02:00
										 |  |  | export default class OpenStreetMapIdSearch implements GeocodingProvider { | 
					
						
							| 
									
										
										
										
											2024-09-03 01:14:08 +02:00
										 |  |  |     private static readonly regex = /((https?:\/\/)?(www.)?(osm|openstreetmap).org\/)?(n|node|w|way|r|relation)[/ ]?([0-9]+)/ | 
					
						
							| 
									
										
										
										
											2024-08-29 16:14:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private static readonly types: Readonly<Record<string, "node" | "way" | "relation">> = { | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |         "n": "node", | 
					
						
							|  |  |  |         "w": "way", | 
					
						
							|  |  |  |         "r": "relation", | 
					
						
							| 
									
										
										
										
											2024-08-29 16:14:12 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private readonly _state: SpecialVisualizationState | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constructor(state: SpecialVisualizationState) { | 
					
						
							|  |  |  |         this._state = state | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("osm.org/node/42") // => "node/42"
 | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("https://openstreetmap.org/node/42#map=19/51.204245/3.212731") // => "node/42"
 | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("node/42") // => "node/42"
 | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("way/42") // => "way/42"
 | 
					
						
							| 
									
										
										
										
											2024-08-29 16:14:12 +02:00
										 |  |  |      * OpenStreetMapIdSearch.extractId("n123456789") // => "node/123456789"
 | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("node123456789") // => "node/123456789"
 | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("node 123456789") // => "node/123456789"
 | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("w123456789") // => "way/123456789"
 | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("way123456789") // => "way/123456789"
 | 
					
						
							|  |  |  |      * OpenStreetMapIdSearch.extractId("way 123456789") // => "way/123456789"
 | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |      * OpenStreetMapIdSearch.extractId("https://www.openstreetmap.org/node/5212733638") // => "node/5212733638"
 | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static extractId(query: string): OsmId | undefined { | 
					
						
							|  |  |  |         const match = query.match(OpenStreetMapIdSearch.regex) | 
					
						
							|  |  |  |         if (match) { | 
					
						
							| 
									
										
										
										
											2024-08-29 16:14:12 +02:00
										 |  |  |             let type = match.at(-2) | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |             const id = match.at(-1) | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |             if (type.length === 1) { | 
					
						
							|  |  |  |                 type = OpenStreetMapIdSearch.types[type] | 
					
						
							| 
									
										
										
										
											2024-08-29 16:14:12 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |             return <OsmId>(type + "/" + id) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return undefined | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |     private async getInfoAbout(id: OsmId): Promise<GeocodeResult> { | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |         const [osm_type, osm_id] = id.split("/") | 
					
						
							|  |  |  |         const obj = await this._state.osmObjectDownloader.DownloadObjectAsync(id) | 
					
						
							|  |  |  |         if (obj === "deleted") { | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |             return { | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |                 display_name: id + " was deleted", | 
					
						
							|  |  |  |                 category: "coordinate", | 
					
						
							|  |  |  |                 osm_type: <"node" | "way" | "relation">osm_type, | 
					
						
							|  |  |  |                 osm_id, | 
					
						
							|  |  |  |                 lat: 0, lon: 0, | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |                 source: "osmid", | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         const [lat, lon] = obj.centerpoint() | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |         return { | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |             lat, lon, | 
					
						
							|  |  |  |             display_name: obj.tags.name ?? obj.tags.alt_name ?? obj.tags.local_name ?? obj.tags.ref ?? id, | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |             description: osm_type, | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |             osm_type: <"node" | "way" | "relation">osm_type, | 
					
						
							|  |  |  |             osm_id, | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |             source: "osmid", | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-15 02:26:17 +02:00
										 |  |  |     async search(query: string, options?: GeocodingOptions): Promise<GeocodeResult[]> { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!isNaN(Number(query))) { | 
					
						
							|  |  |  |             const n = Number(query) | 
					
						
							|  |  |  |             return Utils.NoNullInplace(await Promise.all([ | 
					
						
							|  |  |  |                 this.getInfoAbout(`node/${n}`).catch(x => undefined), | 
					
						
							|  |  |  |                 this.getInfoAbout(`way/${n}`).catch(x => undefined), | 
					
						
							|  |  |  |                 this.getInfoAbout(`relation/${n}`).catch(() => undefined), | 
					
						
							|  |  |  |             ])) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const id = OpenStreetMapIdSearch.extractId(query) | 
					
						
							|  |  |  |         if (!id) { | 
					
						
							|  |  |  |             return [] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return [await this.getInfoAbout(id)] | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-03 01:14:08 +02:00
										 |  |  |     suggest?(query: string, options?: GeocodingOptions): Store<GeocodeResult[]> { | 
					
						
							| 
									
										
										
										
											2024-08-25 02:40:56 +02:00
										 |  |  |         return UIEventSource.FromPromise(this.search(query, options)) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |