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