From 248ea78b17c9cf3fa11140e32155c06ed82b1aa9 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sun, 18 Jul 2021 21:37:14 +0200 Subject: [PATCH] First working version of split road functionality --- Logic/FeatureSource/ChangeApplicator.ts | 6 +- Logic/FeatureSource/FeaturePipeline.ts | 9 +- Logic/FeatureSource/FilteringFeatureSource.ts | 1 - Logic/Osm/Actions/SplitAction.ts | 97 ++++++++++--------- Logic/Tags/Tag.ts | 7 ++ Models/Constants.ts | 2 +- UI/BigComponents/SimpleAddUI.ts | 7 +- UI/Input/LocationInput.ts | 1 - UI/ShowDataLayer.ts | 15 +-- UI/SpecialVisualizations.ts | 7 +- package.json | 2 +- 11 files changed, 88 insertions(+), 66 deletions(-) diff --git a/Logic/FeatureSource/ChangeApplicator.ts b/Logic/FeatureSource/ChangeApplicator.ts index 5e87d80ff0..9b4f2271dc 100644 --- a/Logic/FeatureSource/ChangeApplicator.ts +++ b/Logic/FeatureSource/ChangeApplicator.ts @@ -34,7 +34,6 @@ export default class ChangeApplicator implements FeatureSource { runningUpdate = true; changes = changes.filter(ch => !seenChanges.has(ch)) changes.forEach(c => seenChanges.add(c)) - console.log("Called back", changes) ChangeApplicator.ApplyChanges(self.features.data, changes, mode) source.features.ping() runningUpdate = false; @@ -67,6 +66,7 @@ export default class ChangeApplicator implements FeatureSource { const now = new Date() function add(feature) { + feature.id = feature.properties.id features.push({ feature: feature, freshness: now @@ -135,9 +135,7 @@ export default class ChangeApplicator implements FeatureSource { for (const change of changesPerId.get(id)) { for (const kv of change.tags ?? []) { // Apply tag changes and ping the consumers - const k = kv.k - let v = kv.v - f.properties[k] = v; + f.properties[kv.k] = kv.v; } // Apply other changes to the object diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index 4e34200a96..a52bcbc8dd 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -43,7 +43,7 @@ export default class FeaturePipeline implements FeatureSource { new FeatureDuplicatorPerLayer(flayers, new RegisteringFeatureSource( new ChangeApplicator( - updater, changes, {generateNewGeometries: true} + updater, changes )) )), layout)); @@ -65,7 +65,12 @@ export default class FeaturePipeline implements FeatureSource { const amendedOsmApiSource = new RememberingSource( new MetaTaggingFeatureSource(allLoadedFeatures, new FeatureDuplicatorPerLayer(flayers, - new RegisteringFeatureSource(new ChangeApplicator(fromOsmApi, changes))))); + new RegisteringFeatureSource(new ChangeApplicator(fromOsmApi, changes, + { + // We lump in the new points here + generateNewGeometries: true + } + ))))); const merged = new FeatureSourceMerger([ diff --git a/Logic/FeatureSource/FilteringFeatureSource.ts b/Logic/FeatureSource/FilteringFeatureSource.ts index 043f2ea3a2..ff8883d070 100644 --- a/Logic/FeatureSource/FilteringFeatureSource.ts +++ b/Logic/FeatureSource/FilteringFeatureSource.ts @@ -76,7 +76,6 @@ export default class FilteringFeatureSource implements FeatureSource { return false; }); - console.log("Filtering layer source: input: ", upstream.features.data?.length, "output:", newFeatures.length) self.features.setData(newFeatures); if (missingLayers.size > 0) { console.error("Some layers were not found: ", Array.from(missingLayers)) diff --git a/Logic/Osm/Actions/SplitAction.ts b/Logic/Osm/Actions/SplitAction.ts index 1e9f94adef..8ee1731e43 100644 --- a/Logic/Osm/Actions/SplitAction.ts +++ b/Logic/Osm/Actions/SplitAction.ts @@ -95,8 +95,8 @@ export default class SplitAction extends OsmChangeAction { changeDescription.push({ type: "node", id: element.originalIndex, - changes:{ - lon: element.lngLat[0], + changes: { + lon: element.lngLat[0], lat: element.lngLat[1] } }) @@ -110,31 +110,34 @@ export default class SplitAction extends OsmChangeAction { if (isOriginal) { // We change the actual element! changeDescription.push({ - type:"way", + type: "way", id: originalElement.id, - changes:{ + changes: { locations: wayPart.map(p => p.lngLat), - nodes: wayPart.map(p => p.originalIndex) + nodes: wayPart.map(p => p.originalIndex) } }) } else { let id = changes.getNewID(); newWayIds.push(id) - + const kv = [] for (const k in originalElement.tags) { - if(!originalElement.tags.hasOwnProperty(k)){ + if (!originalElement.tags.hasOwnProperty(k)) { continue } - kv .push({k: k, v: originalElement.tags[k]}) + if (k.startsWith("_") || k === "id") { + continue; + } + kv.push({k: k, v: originalElement.tags[k]}) } changeDescription.push({ - type:"way", - id:id, + type: "way", + id: id, tags: kv, - changes:{ + changes: { locations: wayPart.map(p => p.lngLat), - nodes: wayPart.map(p => p.originalIndex) + nodes: wayPart.map(p => p.originalIndex) } }) } @@ -148,7 +151,7 @@ export default class SplitAction extends OsmChangeAction { // And we have our objects! // Time to upload - return changeDescription + return changeDescription } /** @@ -176,40 +179,40 @@ export default class SplitAction extends OsmChangeAction { // When this is done, we check that no now point is too close to an already existing point and no very small segments get created - /* for (let i = allPoints.length - 1; i > 0; i--) { - - const point = allPoints[i]; - if (point.properties._original_index !== undefined) { - // This point is already in OSM - we have to keep it! - continue; - } - - if (i != allPoints.length - 1) { - const prevPoint = allPoints[i + 1] - const diff = Math.abs(point.properties.location - prevPoint.properties.location) * 1000 - if (diff <= toleranceInM) { - // To close to the previous point! We delete this point... - allPoints.splice(i, 1) - // ... and mark the previous point as a split point - prevPoint.properties._is_split_point = true - continue; - } - } - - if (i > 0) { - const nextPoint = allPoints[i - 1] - const diff = Math.abs(point.properties.location - nextPoint.properties.location) * 1000 - if (diff <= toleranceInM) { - // To close to the next point! We delete this point... - allPoints.splice(i, 1) - // ... and mark the next point as a split point - nextPoint.properties._is_split_point = true - // noinspection UnnecessaryContinueJS - continue; - } - } - // We don't have to remove this point... - }*/ + /* for (let i = allPoints.length - 1; i > 0; i--) { + + const point = allPoints[i]; + if (point.properties._original_index !== undefined) { + // This point is already in OSM - we have to keep it! + continue; + } + + if (i != allPoints.length - 1) { + const prevPoint = allPoints[i + 1] + const diff = Math.abs(point.properties.location - prevPoint.properties.location) * 1000 + if (diff <= toleranceInM) { + // To close to the previous point! We delete this point... + allPoints.splice(i, 1) + // ... and mark the previous point as a split point + prevPoint.properties._is_split_point = true + continue; + } + } + + if (i > 0) { + const nextPoint = allPoints[i - 1] + const diff = Math.abs(point.properties.location - nextPoint.properties.location) * 1000 + if (diff <= toleranceInM) { + // To close to the next point! We delete this point... + allPoints.splice(i, 1) + // ... and mark the next point as a split point + nextPoint.properties._is_split_point = true + // noinspection UnnecessaryContinueJS + continue; + } + } + // We don't have to remove this point... + }*/ const splitInfo: SplitInfo[] = [] let nextId = -1 diff --git a/Logic/Tags/Tag.ts b/Logic/Tags/Tag.ts index c16833ae58..d252010c9a 100644 --- a/Logic/Tags/Tag.ts +++ b/Logic/Tags/Tag.ts @@ -25,12 +25,19 @@ export class Tag extends TagsFilter { matchesProperties(properties: any): boolean { for (const propertiesKey in properties) { + if(!properties.hasOwnProperty(propertiesKey)){ + continue + } if (this.key === propertiesKey) { const value = properties[propertiesKey]; + if(value === undefined){ + continue + } return value === this.value; } } // The tag was not found + if (this.value === "") { // and it shouldn't be found! return true; diff --git a/Models/Constants.ts b/Models/Constants.ts index 75423405e4..a7218f2bd2 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -2,7 +2,7 @@ import { Utils } from "../Utils"; export default class Constants { - public static vNumber = "0.8.4-rc3"; + public static vNumber = "0.8.5"; // The user journey states thresholds when a new feature gets unlocked public static userJourney = { diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 2205851886..62ea506bbd 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -76,7 +76,12 @@ export default class SimpleAddUI extends Toggle { State.state.changes.applyAction(newElementAction) selectedPreset.setData(undefined) isShown.setData(false) - Hash.hash.setData(newElementAction.newElementId) + State.state.selectedElement.setData(State.state.allElements.ContainingFeatures.get( + newElementAction.newElementId + )) + console.log("Did set selected element to",State.state.allElements.ContainingFeatures.get( + newElementAction.newElementId + )) }, () => { selectedPreset.setData(undefined) }) diff --git a/UI/Input/LocationInput.ts b/UI/Input/LocationInput.ts index d568e4443f..d54af67919 100644 --- a/UI/Input/LocationInput.ts +++ b/UI/Input/LocationInput.ts @@ -42,7 +42,6 @@ export default class LocationInput extends InputElement { } ) map.leafletMap.addCallbackAndRunD(leaflet => { - console.log(leaflet.getBounds(), leaflet.getBounds().pad(0.15)) leaflet.setMaxBounds( leaflet.getBounds().pad(0.15) ) diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index 36fb62efc1..70d7e52036 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -23,7 +23,7 @@ export default class ShowDataLayer { layoutToUse: UIEventSource, enablePopups = true, zoomToFeatures = false, - name?:string) { + name?: string) { this._leafletMap = leafletMap; this._enablePopups = enablePopups; this._features = features; @@ -130,6 +130,7 @@ export default class ShowDataLayer { }) }); } + private postProcessFeature(feature, leafletLayer: L.Layer) { const layer: LayerConfig = this._layerDict[feature._matching_layer_id]; if (layer === undefined) { @@ -157,7 +158,7 @@ export default class ShowDataLayer { leafletLayer.on("popupopen", () => { State.state.selectedElement.setData(feature) - + if (infobox === undefined) { const tags = State.state.allElements.getEventSourceById(feature.properties.id); infobox = new FeatureInfoBox(tags, layer); @@ -172,7 +173,7 @@ export default class ShowDataLayer { infobox.AttachTo(id) - infobox.Activate(); + infobox.Activate(); }); const self = this; State.state.selectedElement.addCallbackAndRunD(selected => { @@ -185,11 +186,13 @@ export default class ShowDataLayer { if (selected.properties.id === feature.properties.id) { // A small sanity check to prevent infinite loops: if (selected.geometry.type === feature.geometry.type // If a feature is rendered both as way and as point, opening one popup might trigger the other to open, which might trigger the one to open again - - && feature.id === feature.properties.id // the feature might have as id 'node/-1' and as 'feature.properties.id' = 'the newly assigned id'. That is no good too - ) { + && feature.id === feature.properties.id // the feature might have as id 'node/-1' and as 'feature.properties.id' = 'the newly assigned id'. That is no good too + ) { leafletLayer.openPopup() } + if(feature.id !== feature.properties.id){ + console.log("Not opening the popup for", feature) + } } }) diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index 1e48649128..8b9475c328 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -55,9 +55,12 @@ export default class SpecialVisualizations { if (!tags.hasOwnProperty(key)) { continue; } - parts.push(key + "=" + tags[key]); + parts.push([key , tags[key] ?? "undefined" ]); } - return parts.join("
") + return new Table( + ["key","value"], + parts + ) })).SetStyle("border: 1px solid black; border-radius: 1em;padding:1em;display:block;") }) }, diff --git a/package.json b/package.json index 6f26034508..57e7b80704 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "main": "index.js", "scripts": { "increase-memory": "export NODE_OPTIONS=--max_old_space_size=4096", - "start": "ts-node scripts/generateLayerOverview.ts --no-fail && npm run increase-memory && parcel *.html UI/** Logic/** assets/*.json assets/generated/* assets/layers/*/*.svg assets/tagRendering/*.json assets/themes/*/*.svg assets/themes/*/*.png vendor/* vendor/*/*", + "start": "ts-node scripts/generateLayerOverview.ts --no-fail && npm run increase-memory && parcel *.html UI/** Logic/** assets/*.json assets/svg/* assets/generated/* assets/layers/*/*.svg assets/tagRendering/*.json assets/themes/*/*.svg assets/themes/*/*.png vendor/* vendor/*/*", "test": "ts-node test/TestAll.ts", "init": "npm ci && npm run generate && npm run generate:editor-layer-index && npm run generate:layouts && npm run clean", "add-weblate-upstream": "git remote add weblate-layers https://hosted.weblate.org/git/mapcomplete/layer-translations/ ; git remote update weblate-layers",