forked from MapComplete/MapComplete
		
	More work on splitting roads, WIP; refactoring tests
This commit is contained in:
		
							parent
							
								
									e374bb355c
								
							
						
					
					
						commit
						1f93923820
					
				
					 62 changed files with 1163 additions and 823 deletions
				
			
		|  | @ -1,6 +1,7 @@ | |||
| import {Utils} from "../../Utils"; | ||||
| import * as polygon_features from "../../assets/polygon-features.json"; | ||||
| import {UIEventSource} from "../UIEventSource"; | ||||
| import {BBox} from "../GeoOperations"; | ||||
| 
 | ||||
| 
 | ||||
| export abstract class OsmObject { | ||||
|  | @ -9,11 +10,12 @@ export abstract class OsmObject { | |||
|     protected static backendURL = OsmObject.defaultBackend; | ||||
|     private static polygonFeatures = OsmObject.constructPolygonFeatures() | ||||
|     private static objectCache = new Map<string, UIEventSource<OsmObject>>(); | ||||
|     private static referencingWaysCache = new Map<string, UIEventSource<OsmWay[]>>(); | ||||
|     private static referencingRelationsCache = new Map<string, UIEventSource<OsmRelation[]>>(); | ||||
|     private static historyCache = new Map<string, UIEventSource<OsmObject[]>>(); | ||||
|     type: string; | ||||
|     id: number; | ||||
|     /** | ||||
|      * The OSM tags as simple object | ||||
|      */ | ||||
|     tags: {} = {}; | ||||
|     version: number; | ||||
|     public changed: boolean = false; | ||||
|  | @ -37,7 +39,7 @@ export abstract class OsmObject { | |||
|         this.backendURL = url; | ||||
|     } | ||||
| 
 | ||||
|     static DownloadObject(id: string, forceRefresh: boolean = false): UIEventSource<OsmObject> { | ||||
|     public static DownloadObject(id: string, forceRefresh: boolean = false): UIEventSource<OsmObject> { | ||||
|         let src: UIEventSource<OsmObject>; | ||||
|         if (OsmObject.objectCache.has(id)) { | ||||
|             src = OsmObject.objectCache.get(id) | ||||
|  | @ -47,80 +49,62 @@ export abstract class OsmObject { | |||
|                 return src; | ||||
|             } | ||||
|         } else { | ||||
|             src = new UIEventSource<OsmObject>(undefined) | ||||
|             src = UIEventSource.FromPromise(OsmObject.DownloadObjectAsync(id)) | ||||
|         } | ||||
| 
 | ||||
|         OsmObject.objectCache.set(id, src); | ||||
|         return src; | ||||
|     } | ||||
| 
 | ||||
|     static async DownloadObjectAsync(id: string): Promise<OsmObject> { | ||||
|         const splitted = id.split("/"); | ||||
|         const type = splitted[0]; | ||||
|         const idN = Number(splitted[1]); | ||||
|         if (idN < 0) { | ||||
|             return; | ||||
|             return undefined; | ||||
|         } | ||||
| 
 | ||||
|         OsmObject.objectCache.set(id, src); | ||||
|         const newContinuation = (element: OsmObject) => { | ||||
|             src.setData(element) | ||||
|         } | ||||
| 
 | ||||
|         switch (type) { | ||||
|             case("node"): | ||||
|                 new OsmNode(idN).Download(newContinuation); | ||||
|                 break; | ||||
|                 return await new OsmNode(idN).Download(); | ||||
|             case("way"): | ||||
|                 new OsmWay(idN).Download(newContinuation); | ||||
|                 break; | ||||
|                 return await new OsmWay(idN).Download(); | ||||
|             case("relation"): | ||||
|                 new OsmRelation(idN).Download(newContinuation); | ||||
|                 break; | ||||
|                 return await new OsmRelation(idN).Download(); | ||||
|             default: | ||||
|                 throw "Invalid object type:" + type + id; | ||||
|                 throw ("Invalid object type:" + type + id); | ||||
| 
 | ||||
|         } | ||||
|         return src; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Downloads the ways that are using this node. | ||||
|      * Beware: their geometry will be incomplete! | ||||
|      */ | ||||
|     public static DownloadReferencingWays(id: string): UIEventSource<OsmWay[]> { | ||||
|         if (OsmObject.referencingWaysCache.has(id)) { | ||||
|             return OsmObject.referencingWaysCache.get(id); | ||||
|         } | ||||
|         const waysSrc = new UIEventSource<OsmWay[]>([]) | ||||
|         OsmObject.referencingWaysCache.set(id, waysSrc); | ||||
|         Utils.downloadJson(`${OsmObject.backendURL}api/0.6/${id}/ways`) | ||||
|             .then(data => { | ||||
|                 const ways = data.elements.map(wayInfo => { | ||||
|     public static DownloadReferencingWays(id: string): Promise<OsmWay[]> { | ||||
|         return Utils.downloadJson(`${OsmObject.backendURL}api/0.6/${id}/ways`).then( | ||||
|             data => { | ||||
|                 return data.elements.map(wayInfo => { | ||||
|                     const way = new OsmWay(wayInfo.id) | ||||
|                     way.LoadData(wayInfo) | ||||
|                     return way | ||||
|                 }) | ||||
|                 waysSrc.setData(ways) | ||||
|             }) | ||||
|         return waysSrc; | ||||
|             } | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Downloads the relations that are using this feature. | ||||
|      * Beware: their geometry will be incomplete! | ||||
|      */ | ||||
|     public static DownloadReferencingRelations(id: string): UIEventSource<OsmRelation[]> { | ||||
|         if (OsmObject.referencingRelationsCache.has(id)) { | ||||
|             return OsmObject.referencingRelationsCache.get(id); | ||||
|         } | ||||
|         const relsSrc = new UIEventSource<OsmRelation[]>(undefined) | ||||
|         OsmObject.referencingRelationsCache.set(id, relsSrc); | ||||
|         Utils.downloadJson(`${OsmObject.backendURL}api/0.6/${id}/relations`) | ||||
|             .then(data => { | ||||
|                 const rels = data.elements.map(wayInfo => { | ||||
|                     const rel = new OsmRelation(wayInfo.id) | ||||
|                     rel.LoadData(wayInfo) | ||||
|                     rel.SaveExtraData(wayInfo) | ||||
|                     return rel | ||||
|                 }) | ||||
|                 relsSrc.setData(rels) | ||||
|             }) | ||||
|         return relsSrc; | ||||
|     public static async DownloadReferencingRelations(id: string): Promise<OsmRelation[]> { | ||||
|         const data = await Utils.downloadJson(`${OsmObject.backendURL}api/0.6/${id}/relations`) | ||||
|         return data.elements.map(wayInfo => { | ||||
|             const rel = new OsmRelation(wayInfo.id) | ||||
|             rel.LoadData(wayInfo) | ||||
|             rel.SaveExtraData(wayInfo) | ||||
|             return rel | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     public static DownloadHistory(id: string): UIEventSource<OsmObject []> { | ||||
|  | @ -158,18 +142,11 @@ export abstract class OsmObject { | |||
|     } | ||||
| 
 | ||||
|     // bounds should be: [[maxlat, minlon], [minlat, maxlon]] (same as Utils.tile_bounds)
 | ||||
|     public static LoadArea(bounds: [[number, number], [number, number]], callback: (objects: OsmObject[]) => void) { | ||||
|         const minlon = bounds[0][1] | ||||
|         const maxlon = bounds[1][1] | ||||
|         const minlat = bounds[1][0] | ||||
|         const maxlat = bounds[0][0]; | ||||
|         const url = `${OsmObject.backendURL}api/0.6/map.json?bbox=${minlon},${minlat},${maxlon},${maxlat}` | ||||
|         Utils.downloadJson(url).then(data => { | ||||
|             const elements: any[] = data.elements; | ||||
|             const objects = OsmObject.ParseObjects(elements) | ||||
|             callback(objects); | ||||
| 
 | ||||
|         }) | ||||
|     public static async LoadArea(bbox: BBox): Promise<OsmObject[]> { | ||||
|         const url = `${OsmObject.backendURL}api/0.6/map.json?bbox=${bbox.minLon},${bbox.minLat},${bbox.maxLon},${bbox.maxLat}` | ||||
|         const data = await Utils.downloadJson(url) | ||||
|         const elements: any[] = data.elements; | ||||
|         return OsmObject.ParseObjects(elements); | ||||
|     } | ||||
| 
 | ||||
|     public static DownloadAll(neededIds, forceRefresh = true): UIEventSource<OsmObject[]> { | ||||
|  | @ -283,39 +260,34 @@ export abstract class OsmObject { | |||
|         return tags; | ||||
|     } | ||||
| 
 | ||||
|     Download(continuation: ((element: OsmObject, meta: OsmObjectMeta) => void)) { | ||||
|     /** | ||||
|      * Downloads the object, a full download for ways and relations | ||||
|      * @constructor | ||||
|      */ | ||||
|     async Download(): Promise<OsmObject> { | ||||
|         const self = this; | ||||
|         const full = this.type !== "way" ? "" : "/full"; | ||||
|         const url = `${OsmObject.backendURL}api/0.6/${this.type}/${this.id}${full}`; | ||||
|         Utils.downloadJson(url).then(data => { | ||||
| 
 | ||||
|         return await Utils.downloadJson(url).then(data => { | ||||
|                 const element = data.elements.pop(); | ||||
| 
 | ||||
|                 let nodes = [] | ||||
|                 if (self.type === "way" && data.elements.length >= 0) { | ||||
|                     nodes = OsmObject.ParseObjects(data.elements) | ||||
|                 } | ||||
| 
 | ||||
|                 if (self.type === "rellation") { | ||||
|                     throw "We should save some extra data" | ||||
|                 } | ||||
| 
 | ||||
|                 self.LoadData(element) | ||||
|                 self.SaveExtraData(element, nodes); | ||||
| 
 | ||||
|                 const meta = { | ||||
|                     "_last_edit:contributor": element.user, | ||||
|                     "_last_edit:contributor:uid": element.uid, | ||||
|                     "_last_edit:changeset": element.changeset, | ||||
|                     "_last_edit:timestamp": new Date(element.timestamp), | ||||
|                     "_version_number": element.version | ||||
|                 } | ||||
| 
 | ||||
|                 if (OsmObject.backendURL !== OsmObject.defaultBackend) { | ||||
|                     self.tags["_backend"] = OsmObject.backendURL | ||||
|                     meta["_backend"] = OsmObject.backendURL; | ||||
|                 } | ||||
| 
 | ||||
|                 continuation(self, meta); | ||||
|                 return this; | ||||
|             } | ||||
|         ); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -389,18 +361,10 @@ export class OsmNode extends OsmObject { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| export interface OsmObjectMeta { | ||||
|     "_last_edit:contributor": string, | ||||
|     "_last_edit:contributor:uid": number, | ||||
|     "_last_edit:changeset": number, | ||||
|     "_last_edit:timestamp": Date, | ||||
|     "_version_number": number | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class OsmWay extends OsmObject { | ||||
| 
 | ||||
|     nodes: number[]; | ||||
|     // The coordinates of the way, [lat, lon][]
 | ||||
|     coordinates: [number, number][] = [] | ||||
|     lat: number; | ||||
|     lon: number; | ||||
|  | @ -455,12 +419,16 @@ export class OsmWay extends OsmObject { | |||
|     } | ||||
| 
 | ||||
|     public asGeoJson() { | ||||
|         let coordinates : ([number, number][] | [number, number][][]) = this.coordinates.map(c => <[number, number]>c.reverse()); | ||||
|         if(this.isPolygon()){ | ||||
|             coordinates = [coordinates] | ||||
|         } | ||||
|         return { | ||||
|             "type": "Feature", | ||||
|             "properties": this.tags, | ||||
|             "geometry": { | ||||
|                 "type": this.isPolygon() ? "Polygon" : "LineString", | ||||
|                 "coordinates": this.coordinates.map(c => [c[1], c[0]]) | ||||
|                 "coordinates": coordinates | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -511,7 +479,7 @@ ${members}${tags}        </relation> | |||
|         this.members = element.members; | ||||
|     } | ||||
| 
 | ||||
|     asGeoJson() { | ||||
|     asGeoJson(): any { | ||||
|         throw "Not Implemented" | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue