More cleanup, first somewhat working version of #171

This commit is contained in:
pietervdvn 2021-09-22 16:07:56 +02:00
parent 1f93923820
commit bef684aec7
19 changed files with 439 additions and 135 deletions

View file

@ -230,7 +230,7 @@ export default class GeoLocationHandler extends VariableUiElement {
navigator?.permissions navigator?.permissions
?.query({name: "geolocation"}) ?.query({name: "geolocation"})
?.then(function (status) { ?.then(function (status) {
console.log("Geolocation is already", status); console.log("Geolocation permission is ", status.state);
if (status.state === "granted") { if (status.state === "granted") {
self.StartGeolocating(forceZoom); self.StartGeolocating(forceZoom);
} }
@ -289,7 +289,6 @@ export default class GeoLocationHandler extends VariableUiElement {
private StartGeolocating(zoomToGPS = true) { private StartGeolocating(zoomToGPS = true) {
const self = this; const self = this;
console.log("Starting geolocation");
this._lastUserRequest = zoomToGPS ? new Date() : new Date(0); this._lastUserRequest = zoomToGPS ? new Date() : new Date(0);
if (self._permission.data === "denied") { if (self._permission.data === "denied") {
@ -301,8 +300,6 @@ export default class GeoLocationHandler extends VariableUiElement {
this.MoveToCurrentLoction(16); this.MoveToCurrentLoction(16);
} }
console.log("Searching location using GPS");
if (self._isActive.data) { if (self._isActive.data) {
return; return;
} }

View file

@ -184,8 +184,8 @@ export default class OverpassFeatureSource implements FeatureSource, FeatureSour
return; return;
} }
this.runningQuery.setData(true); this.runningQuery.setData(true);
overpass.queryGeoJson(queryBounds, overpass.queryGeoJson(queryBounds).
function (data, date) { then(([data, date]) => {
self._previousBounds.get(z).push(queryBounds); self._previousBounds.get(z).push(queryBounds);
self.retries.setData(0); self.retries.setData(0);
const features = data.features.map(f => ({feature: f, freshness: date})); const features = data.features.map(f => ({feature: f, freshness: date}));
@ -197,12 +197,12 @@ export default class OverpassFeatureSource implements FeatureSource, FeatureSour
console.error("Got the overpass response, but could not process it: ", e, e.stack) console.error("Got the overpass response, but could not process it: ", e, e.stack)
} }
self.runningQuery.setData(false); self.runningQuery.setData(false);
}, })
function (reason) { .catch((reason) => {
self.retries.data++; self.retries.data++;
self.ForceRefresh(); self.ForceRefresh();
self.timeout.setData(self.retries.data * 5); self.timeout.setData(self.retries.data * 5);
console.error(`QUERY FAILED (retrying in ${5 * self.retries.data} sec) due to ${reason}`); console.error(`QUERY FAILED (retrying in ${5 * self.retries.data} sec) due to`, reason);
self.retries.ping(); self.retries.ping();
self.runningQuery.setData(false); self.runningQuery.setData(false);

View file

@ -8,8 +8,6 @@ export default class TitleHandler {
constructor(state) { constructor(state) {
const currentTitle: UIEventSource<string> = state.selectedElement.map( const currentTitle: UIEventSource<string> = state.selectedElement.map(
selected => { selected => {
console.log("UPdating title")
const layout = state.layoutToUse.data const layout = state.layoutToUse.data
const defaultTitle = Translations.WT(layout?.title)?.txt ?? "MapComplete" const defaultTitle = Translations.WT(layout?.title)?.txt ?? "MapComplete"

View file

@ -21,7 +21,7 @@ import {BBox} from "../GeoOperations";
import {TileHierarchyMerger} from "./TiledFeatureSource/TileHierarchyMerger"; import {TileHierarchyMerger} from "./TiledFeatureSource/TileHierarchyMerger";
import RelationsTracker from "../Osm/RelationsTracker"; import RelationsTracker from "../Osm/RelationsTracker";
import {NewGeometryFromChangesFeatureSource} from "./Sources/NewGeometryFromChangesFeatureSource"; import {NewGeometryFromChangesFeatureSource} from "./Sources/NewGeometryFromChangesFeatureSource";
import ChangeGeometryApplicator from "./ChangeApplicator"; import ChangeGeometryApplicator from "./Sources/ChangeGeometryApplicator";
export default class FeaturePipeline implements FeatureSourceState { export default class FeaturePipeline implements FeatureSourceState {
@ -159,7 +159,6 @@ export default class FeaturePipeline implements FeatureSourceState {
// Whenever fresh data comes in, we need to update the metatagging // Whenever fresh data comes in, we need to update the metatagging
self.newDataLoadedSignal.stabilized(1000).addCallback(src => { self.newDataLoadedSignal.stabilized(1000).addCallback(src => {
console.log("Got an update from ", src.name)
self.updateAllMetaTagging() self.updateAllMetaTagging()
}) })
@ -183,7 +182,6 @@ export default class FeaturePipeline implements FeatureSourceState {
} }
private updateAllMetaTagging() { private updateAllMetaTagging() {
console.log("Updating the meta tagging")
const self = this; const self = this;
this.perLayerHierarchy.forEach(hierarchy => { this.perLayerHierarchy.forEach(hierarchy => {
hierarchy.loadedTiles.forEach(src => { hierarchy.loadedTiles.forEach(src => {

View file

@ -1,15 +1,13 @@
import FeatureSource, {FeatureSourceForLayer, IndexedFeatureSource} from "./FeatureSource";
import {UIEventSource} from "../UIEventSource";
import {Changes} from "../Osm/Changes";
import {ChangeDescription, ChangeDescriptionTools} from "../Osm/Actions/ChangeDescription";
import {Utils} from "../../Utils";
import FilteredLayer from "../../Models/FilteredLayer";
import {OsmNode, OsmRelation, OsmWay} from "../Osm/OsmObject";
/** /**
* Applies geometry changes from 'Changes' onto every feature of a featureSource * Applies geometry changes from 'Changes' onto every feature of a featureSource
*/ */
import {Changes} from "../../Osm/Changes";
import {UIEventSource} from "../../UIEventSource";
import {FeatureSourceForLayer, IndexedFeatureSource} from "../FeatureSource";
import FilteredLayer from "../../../Models/FilteredLayer";
import {ChangeDescription, ChangeDescriptionTools} from "../../Osm/Actions/ChangeDescription";
export default class ChangeGeometryApplicator implements FeatureSourceForLayer { export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]); public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
public readonly name: string; public readonly name: string;
@ -76,6 +74,7 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
// We only apply the last change as that one'll have the latest geometry // We only apply the last change as that one'll have the latest geometry
const change = changesForFeature[changesForFeature.length - 1] const change = changesForFeature[changesForFeature.length - 1]
copy.feature.geometry = ChangeDescriptionTools.getGeojsonGeometry(change) copy.feature.geometry = ChangeDescriptionTools.getGeojsonGeometry(change)
console.log("Applying a geometry change onto ", feature, change, copy)
newFeatures.push(copy) newFeatures.push(copy)
} }
this.features.setData(newFeatures) this.features.setData(newFeatures)

View file

@ -27,7 +27,7 @@ export default class TiledFromLocalStorageSource implements TileHierarchy<Featur
return Number(key.substring(prefix.length)); return Number(key.substring(prefix.length));
}) })
console.log("Avaible datasets in local storage:", indexes) console.log("Layer", layer.layerDef.id, "has following tiles in available in localstorage", indexes.map(i => Utils.tile_from_index(i).join("/")).join(", "))
const zLevels = indexes.map(i => i % 100) const zLevels = indexes.map(i => i % 100)
const indexesSet = new Set(indexes) const indexesSet = new Set(indexes)

View file

@ -15,13 +15,15 @@ export interface RelationSplitInput {
* When a way is split and this way is part of a relation, the relation should be updated too to have the new segment if relevant. * When a way is split and this way is part of a relation, the relation should be updated too to have the new segment if relevant.
*/ */
export default class RelationSplitHandler extends OsmChangeAction { export default class RelationSplitHandler extends OsmChangeAction {
private readonly _input: RelationSplitInput;
constructor(input: RelationSplitInput) { constructor(input: RelationSplitInput) {
super() super()
this._input = input;
} }
async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> { async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
return []; return new InPlaceReplacedmentRTSH(this._input).CreateChangeDescriptions(changes)
} }

View file

@ -15,6 +15,11 @@ export default class SplitAction extends OsmChangeAction {
private readonly wayId: string; private readonly wayId: string;
private readonly _splitPointsCoordinates: [number, number] []// lon, lat private readonly _splitPointsCoordinates: [number, number] []// lon, lat
/**
*
* @param wayId
* @param splitPointCoordinates: lon, lat
*/
constructor(wayId: string, splitPointCoordinates: [number, number][]) { constructor(wayId: string, splitPointCoordinates: [number, number][]) {
super() super()
this.wayId = wayId; this.wayId = wayId;
@ -39,12 +44,11 @@ export default class SplitAction extends OsmChangeAction {
} }
async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> { async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
const self = this;
const originalElement = <OsmWay> await OsmObject.DownloadObjectAsync(this.wayId) const originalElement = <OsmWay> await OsmObject.DownloadObjectAsync(this.wayId)
const originalNodes = originalElement.nodes; const originalNodes = originalElement.nodes;
// First, calculate splitpoints and remove points close to one another // First, calculate splitpoints and remove points close to one another
const splitInfo = self.CalculateSplitCoordinates(originalElement) const splitInfo = this.CalculateSplitCoordinates(originalElement)
// Now we have a list with e.g. // Now we have a list with e.g.
// [ { originalIndex: 0}, {originalIndex: 1, doSplit: true}, {originalIndex: 2}, {originalIndex: undefined, doSplit: true}, {originalIndex: 3}] // [ { originalIndex: 0}, {originalIndex: 1, doSplit: true}, {originalIndex: 2}, {originalIndex: undefined, doSplit: true}, {originalIndex: 3}]
@ -166,8 +170,9 @@ export default class SplitAction extends OsmChangeAction {
private CalculateSplitCoordinates(osmWay: OsmWay, toleranceInM = 5): SplitInfo[] { private CalculateSplitCoordinates(osmWay: OsmWay, toleranceInM = 5): SplitInfo[] {
const wayGeoJson = osmWay.asGeoJson() const wayGeoJson = osmWay.asGeoJson()
// Should be [lon, lat][] // Should be [lon, lat][]
const originalPoints = osmWay.coordinates.map(c => <[number, number]>c.reverse()) const originalPoints : [number, number][] = osmWay.coordinates.map(c => [c[1], c[0]])
const allPoints: { const allPoints: {
// lon, lat
coordinates: [number, number], coordinates: [number, number],
isSplitPoint: boolean, isSplitPoint: boolean,
originalIndex?: number, // Original index originalIndex?: number, // Original index
@ -180,6 +185,7 @@ export default class SplitAction extends OsmChangeAction {
// - `dist`: distance between pt and the closest point, // - `dist`: distance between pt and the closest point,
// `location`: distance along the line between start and the closest point. // `location`: distance along the line between start and the closest point.
let projected = GeoOperations.nearestPoint(wayGeoJson, c) let projected = GeoOperations.nearestPoint(wayGeoJson, c)
// c is lon lat
return ({ return ({
coordinates: c, coordinates: c,
isSplitPoint: true, isSplitPoint: true,
@ -233,8 +239,12 @@ export default class SplitAction extends OsmChangeAction {
if (distToNext > distToPrev) { if (distToNext > distToPrev) {
closest = prevPoint closest = prevPoint
} }
// Ok, we have a closest point! // Ok, we have a closest point!
if(closest.originalIndex === 0 || closest.originalIndex === originalPoints.length){
// We can not split on the first or last points...
continue
}
closest.isSplitPoint = true; closest.isSplitPoint = true;
allPoints.splice(i, 1) allPoints.splice(i, 1)

View file

@ -14,7 +14,7 @@ import {LocalStorageSource} from "../Web/LocalStorageSource";
export class Changes { export class Changes {
private static _nextId = -1; // Newly assigned ID's are negative private _nextId : number = -1; // Newly assigned ID's are negative
public readonly name = "Newly added features" public readonly name = "Newly added features"
/** /**
* All the newly created features as featureSource + all the modified features * All the newly created features as featureSource + all the modified features
@ -30,6 +30,8 @@ export class Changes {
constructor() { constructor() {
// We keep track of all changes just as well // We keep track of all changes just as well
this.allChanges.setData([...this.pendingChanges.data]) this.allChanges.setData([...this.pendingChanges.data])
// If a pending change contains a negative ID, we save that
this._nextId = Math.min(-1, ...this.pendingChanges.data?.map(pch => pch.id) ?? [])
} }
private static createChangesetFor(csId: string, private static createChangesetFor(csId: string,
@ -77,7 +79,7 @@ export class Changes {
* Returns a new ID and updates the value for the next ID * Returns a new ID and updates the value for the next ID
*/ */
public getNewID() { public getNewID() {
return Changes._nextId--; return this._nextId--;
} }
/** /**

View file

@ -63,17 +63,26 @@ export abstract class OsmObject {
if (idN < 0) { if (idN < 0) {
return undefined; return undefined;
} }
switch (type) {
case("node"):
return await new OsmNode(idN).Download();
case("way"):
return await new OsmWay(idN).Download();
case("relation"):
return await new OsmRelation(idN).Download();
default:
throw ("Invalid object type:" + type + id);
const full = !id.startsWith("way") ? "" : "/full";
const url = `${OsmObject.backendURL}api/0.6/${id}${full}`;
const rawData = await Utils.downloadJson(url)
// A full query might contain more then just the requested object (e.g. nodes that are part of a way, where we only want the way)
const parsed = OsmObject.ParseObjects(rawData.elements);
// Lets fetch the object we need
for (const osmObject of parsed) {
if(osmObject.type !== type){
continue;
} }
if(osmObject.id !== idN){
continue
}
// Found the one!
return osmObject
}
throw "PANIC: requested object is not part of the response"
} }
@ -205,6 +214,7 @@ export abstract class OsmObject {
private static ParseObjects(elements: any[]): OsmObject[] { private static ParseObjects(elements: any[]): OsmObject[] {
const objects: OsmObject[] = []; const objects: OsmObject[] = [];
const allNodes: Map<number, OsmNode> = new Map<number, OsmNode>() const allNodes: Map<number, OsmNode> = new Map<number, OsmNode>()
for (const element of elements) { for (const element of elements) {
const type = element.type; const type = element.type;
const idN = element.id; const idN = element.id;
@ -226,6 +236,11 @@ export abstract class OsmObject {
osmObject.SaveExtraData(element, []) osmObject.SaveExtraData(element, [])
break; break;
} }
if (osmObject !== undefined && OsmObject.backendURL !== OsmObject.defaultBackend) {
osmObject.tags["_backend"] = OsmObject.backendURL
}
osmObject?.LoadData(element) osmObject?.LoadData(element)
objects.push(osmObject) objects.push(osmObject)
} }
@ -237,7 +252,7 @@ export abstract class OsmObject {
public abstract asGeoJson(): any; public abstract asGeoJson(): any;
abstract SaveExtraData(element: any, allElements: any[]); abstract SaveExtraData(element: any, allElements: OsmObject[]);
/** /**
* Generates the changeset-XML for tags * Generates the changeset-XML for tags
@ -260,37 +275,6 @@ export abstract class OsmObject {
return tags; return tags;
} }
/**
* 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}`;
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);
if (OsmObject.backendURL !== OsmObject.defaultBackend) {
self.tags["_backend"] = OsmObject.backendURL
}
return this;
}
);
}
abstract ChangesetXML(changesetId: string): string; abstract ChangesetXML(changesetId: string): string;
protected VersionXML() { protected VersionXML() {
@ -363,7 +347,7 @@ export class OsmNode extends OsmObject {
export class OsmWay extends OsmObject { export class OsmWay extends OsmObject {
nodes: number[]; nodes: number[] = [];
// The coordinates of the way, [lat, lon][] // The coordinates of the way, [lat, lon][]
coordinates: [number, number][] = [] coordinates: [number, number][] = []
lat: number; lat: number;
@ -400,6 +384,10 @@ export class OsmWay extends OsmObject {
nodeDict.set(node.id, node) nodeDict.set(node.id, node)
} }
if (element.nodes === undefined) {
console.log("PANIC")
}
for (const nodeId of element.nodes) { for (const nodeId of element.nodes) {
const node = nodeDict.get(nodeId) const node = nodeDict.get(nodeId)
if (node === undefined) { if (node === undefined) {
@ -419,7 +407,7 @@ export class OsmWay extends OsmObject {
} }
public asGeoJson() { public asGeoJson() {
let coordinates : ([number, number][] | [number, number][][]) = this.coordinates.map(c => <[number, number]>c.reverse()); let coordinates: ([number, number][] | [number, number][][]) = this.coordinates.map(c => [c[1], c[0]]);
if (this.isPolygon()) { if (this.isPolygon()) {
coordinates = [coordinates] coordinates = [coordinates]
} }

View file

@ -145,14 +145,14 @@ export class OsmPreferences {
private SetPreference(k: string, v: string) { private SetPreference(k: string, v: string) {
if (!this.userDetails.data.loggedIn) { if (!this.userDetails.data.loggedIn) {
console.log(`Not saving preference ${k}: user not logged in`); console.debug(`Not saving preference ${k}: user not logged in`);
return; return;
} }
if (this.preferences.data[k] === v) { if (this.preferences.data[k] === v) {
return; return;
} }
console.log("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15)); console.debug("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15));
if (v === undefined || v === "") { if (v === undefined || v === "") {
this.auth.xhr({ this.auth.xhr({
@ -161,10 +161,10 @@ export class OsmPreferences {
options: {header: {'Content-Type': 'text/plain'}}, options: {header: {'Content-Type': 'text/plain'}},
}, function (error) { }, function (error) {
if (error) { if (error) {
console.log("Could not remove preference", error); console.warn("Could not remove preference", error);
return; return;
} }
console.log("Preference ", k, "removed!"); console.debug("Preference ", k, "removed!");
}); });
return; return;

View file

@ -31,7 +31,7 @@ export class Overpass {
this._relationTracker = relationTracker this._relationTracker = relationTracker
} }
queryGeoJson(bounds: Bounds, continuation: ((any, date: Date) => void), onFail: ((reason) => void)): void { public async queryGeoJson(bounds: Bounds): Promise<[any, Date]> {
let query = this.buildQuery("[bbox:" + bounds.south + "," + bounds.west + "," + bounds.north + "," + bounds.east + "]") let query = this.buildQuery("[bbox:" + bounds.south + "," + bounds.west + "," + bounds.north + "," + bounds.east + "]")
@ -40,24 +40,18 @@ export class Overpass {
query = Overpass.testUrl; query = Overpass.testUrl;
} }
const self = this; const self = this;
Utils.downloadJson(query) const json = await Utils.downloadJson(query)
.then(json => {
if (json.elements === [] && ((json.remarks ?? json.remark).indexOf("runtime error") >= 0)) { if (json.elements === [] && ((json.remarks ?? json.remark).indexOf("runtime error") >= 0)) {
console.log("Timeout or other runtime error"); console.log("Timeout or other runtime error");
onFail("Runtime error (timeout)") throw("Runtime error (timeout)")
return;
} }
self._relationTracker.RegisterRelations(json) self._relationTracker.RegisterRelations(json)
// @ts-ignore // @ts-ignore
const geojson = OsmToGeoJson.default(json); const geojson = OsmToGeoJson.default(json);
const osmTime = new Date(json.osm3s.timestamp_osm_base); const osmTime = new Date(json.osm3s.timestamp_osm_base);
return [geojson, osmTime];
continuation(geojson, osmTime);
}).catch(e => {
onFail(e);
})
} }
buildQuery(bbox: string): string { buildQuery(bbox: string): string {

View file

@ -100,7 +100,7 @@ export interface LayoutConfigJson {
* However, users tend to pan and zoom a lot. It is pretty annoying if every single pan means a reloading of the data. * However, users tend to pan and zoom a lot. It is pretty annoying if every single pan means a reloading of the data.
* For this, the bounds are widened in order to make a small pan still within bounds of the loaded data. * For this, the bounds are widened in order to make a small pan still within bounds of the loaded data.
* *
* IF widenfactor is 0, this feature is disabled. A recommended value is between 0.5 and 0.01 (the latter for very dense queries) * IF widenfactor is 1, this feature is disabled. A recommended value is between 1 and 3
*/ */
widenFactor?: number; widenFactor?: number;

View file

@ -87,7 +87,7 @@ export default class LayoutConfig {
this.startZoom = json.startZoom; this.startZoom = json.startZoom;
this.startLat = json.startLat; this.startLat = json.startLat;
this.startLon = json.startLon; this.startLon = json.startLon;
this.widenFactor = json.widenFactor ?? 0.05; this.widenFactor = json.widenFactor ?? 1.5;
this.roamingRenderings = (json.roamingRenderings ?? []).map((tr, i) => { this.roamingRenderings = (json.roamingRenderings ?? []).map((tr, i) => {
if (typeof tr === "string") { if (typeof tr === "string") {
if (SharedTagRenderings.SharedTagRendering.get(tr) !== undefined) { if (SharedTagRenderings.SharedTagRendering.get(tr) !== undefined) {

View file

@ -356,18 +356,30 @@ export class Utils {
return result; return result;
} }
private static injectedDownloads = {}
public static injectJsonDownloadForTests(url: string, data) {
Utils.injectedDownloads[url] = data
}
public static downloadJson(url: string): Promise<any> { public static downloadJson(url: string): Promise<any> {
const injected = Utils.injectedDownloads[url]
if (injected !== undefined) {
console.log("Using injected resource for test for URL", url)
return new Promise((resolve, _) => resolve(injected))
}
if (this.externalDownloadFunction !== undefined) { if (this.externalDownloadFunction !== undefined) {
return this.externalDownloadFunction(url) return this.externalDownloadFunction(url)
} }
return new Promise( return new Promise((resolve, reject) => {
(resolve, reject) => {
try {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.onload = () => { xhr.onload = () => {
if (xhr.status == 200) { if (xhr.status == 200) {
try { try {
console.log("Got a response! Parsing now...")
resolve(JSON.parse(xhr.response)) resolve(JSON.parse(xhr.response))
} catch (e) { } catch (e) {
reject("Not a valid json: " + xhr.response) reject("Not a valid json: " + xhr.response)
@ -379,12 +391,8 @@ export class Utils {
xhr.open('GET', url); xhr.open('GET', url);
xhr.setRequestHeader("accept", "application/json") xhr.setRequestHeader("accept", "application/json")
xhr.send(); xhr.send();
} catch (e) {
reject(e)
}
} }
) )
} }
/** /**

View file

@ -34,7 +34,7 @@
"startZoom": 14, "startZoom": 14,
"startLon": 3.2228, "startLon": 3.2228,
"maintainer": "MapComplete", "maintainer": "MapComplete",
"widenfactor": 0.01, "widenfactor": 2,
"roamingRenderings": [ "roamingRenderings": [
{ {
"question": { "question": {

View file

@ -3,6 +3,7 @@ import {InPlaceReplacedmentRTSH} from "../Logic/Osm/Actions/RelationSplitHandler
import {OsmObject, OsmRelation} from "../Logic/Osm/OsmObject"; import {OsmObject, OsmRelation} from "../Logic/Osm/OsmObject";
import {Changes} from "../Logic/Osm/Changes"; import {Changes} from "../Logic/Osm/Changes";
import {equal} from "assert"; import {equal} from "assert";
import {Utils} from "../Utils";
export default class RelationSplitHandlerSpec extends T { export default class RelationSplitHandlerSpec extends T {
@ -58,6 +59,28 @@ export default class RelationSplitHandlerSpec extends T {
} }
constructor() { constructor() {
Utils.injectJsonDownloadForTests(
"https://www.openstreetmap.org/api/0.6/node/1124134958/ways",
{"version":"0.6","generator":"CGImap 0.8.5 (2937646 spike-07.openstreetmap.org)","copyright":"OpenStreetMap and contributors","attribution":"http://www.openstreetmap.org/copyright","license":"http://opendatacommons.org/licenses/odbl/1-0/","elements":[{"type":"way","id":97038428,"timestamp":"2019-06-19T12:26:24Z","version":6,"changeset":71399984,"user":"Pieter Vander Vennet","uid":3818858,"nodes":[1124134958,323729212,323729351,2542460408,187073405],"tags":{"highway":"residential","name":"Brugs-Kerkhofstraat","sett:pattern":"arc","surface":"sett"}},{"type":"way","id":97038434,"timestamp":"2019-06-19T12:26:24Z","version":5,"changeset":71399984,"user":"Pieter Vander Vennet","uid":3818858,"nodes":[1124134958,1124135024,187058607],"tags":{"bicycle":"use_sidepath","highway":"residential","name":"Kerkhofblommenstraat","sett:pattern":"arc","surface":"sett"}},{"type":"way","id":97038435,"timestamp":"2017-12-21T21:41:08Z","version":4,"changeset":54826837,"user":"Jakka","uid":2403313,"nodes":[1124134958,2576628889,1124135035,5298371485,5298371495],"tags":{"bicycle":"use_sidepath","highway":"residential","name":"Kerkhofblommenstraat"}},{"type":"way","id":251446313,"timestamp":"2019-01-07T19:22:47Z","version":4,"changeset":66106872,"user":"M!dgard","uid":763799,"nodes":[1124134958,5243143198,4555715455],"tags":{"foot":"yes","highway":"service"}}]}
)
Utils.injectJsonDownloadForTests(
"https://www.openstreetmap.org/api/0.6/relation/9572808",
{"version":"0.6","generator":"CGImap 0.8.5 (3128319 spike-07.openstreetmap.org)","copyright":"OpenStreetMap and contributors","attribution":"http://www.openstreetmap.org/copyright","license":"http://opendatacommons.org/licenses/odbl/1-0/","elements":[{"type":"relation","id":9572808,"timestamp":"2021-08-12T12:44:06Z","version":11,"changeset":109573204,"user":"A67-A67","uid":553736,"members":[{"type":"way","ref":173662702,"role":""},{"type":"way","ref":467606230,"role":""},{"type":"way","ref":126267167,"role":""},{"type":"way","ref":301897426,"role":""},{"type":"way","ref":687866206,"role":""},{"type":"way","ref":295132739,"role":""},{"type":"way","ref":690497698,"role":""},{"type":"way","ref":627893684,"role":""},{"type":"way","ref":295132741,"role":""},{"type":"way","ref":301903120,"role":""},{"type":"way","ref":672541156,"role":""},{"type":"way","ref":126264330,"role":""},{"type":"way","ref":280440853,"role":""},{"type":"way","ref":838499667,"role":""},{"type":"way","ref":838499663,"role":""},{"type":"way","ref":690497623,"role":""},{"type":"way","ref":301902946,"role":""},{"type":"way","ref":280460715,"role":""},{"type":"way","ref":972534369,"role":""},{"type":"way","ref":695680702,"role":""},{"type":"way","ref":690497860,"role":""},{"type":"way","ref":295410363,"role":""},{"type":"way","ref":823864063,"role":""},{"type":"way","ref":663172088,"role":""},{"type":"way","ref":659950322,"role":""},{"type":"way","ref":659950323,"role":""},{"type":"way","ref":230180094,"role":""},{"type":"way","ref":690497912,"role":""},{"type":"way","ref":39588765,"role":""}],"tags":{"distance":"13 km","name":"Abdijenroute","network":"lcn","old_name":"Spoorlijn 58","operator":"Toerisme West-Vlaanderen","railway":"abandoned","route":"bicycle","type":"route","wikipedia":"nl:Spoorlijn 58"}}]}
)
Utils.injectJsonDownloadForTests(
"https://www.openstreetmap.org/api/0.6/way/687866206/full",
{"version":"0.6","generator":"CGImap 0.8.5 (2601512 spike-07.openstreetmap.org)","copyright":"OpenStreetMap and contributors","attribution":"http://www.openstreetmap.org/copyright","license":"http://opendatacommons.org/licenses/odbl/1-0/","elements":[{"type":"node","id":5273988959,"lat":51.1811406,"lon":3.2427712,"timestamp":"2021-07-29T21:14:53Z","version":6,"changeset":108847202,"user":"kaart_fietser","uid":11022240,"tags":{"network:type":"node_network","rwn_ref":"32"}},{"type":"node","id":6448669326,"lat":51.1811346,"lon":3.242891,"timestamp":"2019-05-04T22:44:12Z","version":1,"changeset":69891295,"user":"Pieter Vander Vennet","uid":3818858,"tags":{"barrier":"bollard"}},{"type":"way","id":687866206,"timestamp":"2019-05-06T20:52:20Z","version":2,"changeset":69951497,"user":"noelbov","uid":8054928,"nodes":[6448669326,5273988959],"tags":{"highway":"cycleway","name":"Abdijenroute","railway":"abandoned","surface":"asphalt"}}]}
)
Utils.injectJsonDownloadForTests(
"https://www.openstreetmap.org/api/0.6/way/690497698/full" ,
{"version":"0.6","generator":"CGImap 0.8.5 (3023311 spike-07.openstreetmap.org)","copyright":"OpenStreetMap and contributors","attribution":"http://www.openstreetmap.org/copyright","license":"http://opendatacommons.org/licenses/odbl/1-0/","elements":[{"type":"node","id":170497152,"lat":51.1832353,"lon":3.2498759,"timestamp":"2018-04-24T00:29:37Z","version":7,"changeset":58357376,"user":"Pieter Vander Vennet","uid":3818858},{"type":"node","id":2988218625,"lat":51.1835053,"lon":3.2503067,"timestamp":"2018-09-24T21:48:46Z","version":2,"changeset":62895918,"user":"A67-A67","uid":553736},{"type":"node","id":5273988967,"lat":51.182659,"lon":3.249004,"timestamp":"2017-12-09T18:40:21Z","version":1,"changeset":54493533,"user":"CacherB","uid":1999108},{"type":"way","id":690497698,"timestamp":"2021-07-29T21:14:53Z","version":3,"changeset":108847202,"user":"kaart_fietser","uid":11022240,"nodes":[2988218625,170497152,5273988967],"tags":{"highway":"cycleway","lit":"no","name":"Abdijenroute","oneway":"no","railway":"abandoned","surface":"compacted"}}]}
)
super("relationsplithandler", [ super("relationsplithandler", [
["split 295132739", ["split 295132739",
() => RelationSplitHandlerSpec.split().then(_ => console.log("OK"))] () => RelationSplitHandlerSpec.split().then(_ => console.log("OK"))]

274
test/SplitAction.spec.ts Normal file

File diff suppressed because one or more lines are too long

View file

@ -8,7 +8,8 @@ import OsmObjectSpec from "./OsmObject.spec";
import ScriptUtils from "../scripts/ScriptUtils"; import ScriptUtils from "../scripts/ScriptUtils";
import UnitsSpec from "./Units.spec"; import UnitsSpec from "./Units.spec";
import RelationSplitHandlerSpec from "./RelationSplitHandler.spec"; import RelationSplitHandlerSpec from "./RelationSplitHandler.spec";
import SplitActionSpec from "./SplitAction.spec";
import {Utils} from "../Utils";
ScriptUtils.fixUtils() ScriptUtils.fixUtils()
@ -21,9 +22,19 @@ const allTests = [
new ThemeSpec(), new ThemeSpec(),
new UtilsSpec(), new UtilsSpec(),
new UnitsSpec(), new UnitsSpec(),
new RelationSplitHandlerSpec() new RelationSplitHandlerSpec(),
new SplitActionSpec()
] ]
Utils.externalDownloadFunction = async (url) => {
console.error("Fetching ", url, "blocked in tests, use Utils.injectJsonDownloadForTests")
const data = await ScriptUtils.DownloadJSON(url)
console.log("\n\n ----------- \nBLOCKED DATA\n Utils.injectJsonDownloadForTests(\n" +
" ", JSON.stringify(url),", \n",
" ", JSON.stringify(data), "\n )\n------------------\n\n")
throw "Detected internet access for URL " + url + ", please inject it with Utils.injectJsonDownloadForTests"
}
let args = [...process.argv] let args = [...process.argv]
args.splice(0, 2) args.splice(0, 2)
args = args.map(a => a.toLowerCase()) args = args.map(a => a.toLowerCase())
@ -40,9 +51,9 @@ if(testsToRun.length == 0){
for (let i = 0; i < testsToRun.length; i++) { for (let i = 0; i < testsToRun.length; i++) {
const test = testsToRun[i]; const test = testsToRun[i];
ScriptUtils.erasableLog(" Running test", i, "/", allTests.length) console.log(" Running test", i, "/", allTests.length, test.name)
allFailures.push(...(test.Run() ?? [])) allFailures.push(...(test.Run() ?? []))
console.log("OK!")
} }
if (allFailures.length > 0) { if (allFailures.length > 0) {
for (const failure of allFailures) { for (const failure of allFailures) {
@ -50,4 +61,4 @@ if (allFailures.length > 0) {
} }
throw "Some test failed" throw "Some test failed"
} }
console.log("All tests successful: ", allTests.map(t => t.name).join(", ")) console.log("All tests successful: ", testsToRun.map(t => t.name).join(", "))