This commit is contained in:
Pieter Vander Vennet 2022-01-21 03:57:49 +01:00
parent 5182085f35
commit 1e3206120c
6 changed files with 108 additions and 69 deletions

View file

@ -311,7 +311,7 @@ export default class FeaturePipeline {
// Also load points/lines that are newly added. // Also load points/lines that are newly added.
const newGeometry = new NewGeometryFromChangesFeatureSource(state.changes, state.osmConnection._oauth_config.url) const newGeometry = new NewGeometryFromChangesFeatureSource(state.changes, state.allElements, state.osmConnection._oauth_config.url)
newGeometry.features.addCallbackAndRun(geometries => { newGeometry.features.addCallbackAndRun(geometries => {
console.debug("New geometries are:", geometries) console.debug("New geometries are:", geometries)
}) })
@ -323,7 +323,10 @@ export default class FeaturePipeline {
// We don't bother to split them over tiles as it'll contain little features by default, so we simply add them like this // We don't bother to split them over tiles as it'll contain little features by default, so we simply add them like this
perLayerHierarchy.get(perLayer.layer.layerDef.id).registerTile(perLayer) perLayerHierarchy.get(perLayer.layer.layerDef.id).registerTile(perLayer)
// AT last, we always apply the metatags whenever possible // AT last, we always apply the metatags whenever possible
perLayer.features.addCallbackAndRunD(_ => self.onNewDataLoaded(perLayer)) perLayer.features.addCallbackAndRunD(feats => {
console.log("New feature for layer ", perLayer.layer.layerDef.id, ":", feats)
self.onNewDataLoaded(perLayer);
})
}, },
newGeometry, newGeometry,

View file

@ -41,6 +41,7 @@ export default class PerLayerFeatureSourceSplitter {
} }
for (const f of features) { for (const f of features) {
console.log("Classifying ", f.feature)
for (const layer of layers.data) { for (const layer of layers.data) {
if (layer.layerDef.source.osmTags.matchesProperties(f.feature.properties)) { if (layer.layerDef.source.osmTags.matchesProperties(f.feature.properties)) {
// We have found our matching layer! // We have found our matching layer!
@ -50,8 +51,8 @@ export default class PerLayerFeatureSourceSplitter {
break; break;
} }
} }
noLayerFound.push(f)
} }
noLayerFound.push(f)
} }
// At this point, we have our features per layer as a list // At this point, we have our features per layer as a list

View file

@ -63,7 +63,6 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
} }
private update() { private update() {
console.log("FIltering", this.upstream.name)
const self = this; const self = this;
const layer = this.upstream.layer; const layer = this.upstream.layer;
const features: { feature: any; freshness: Date }[] = (this.upstream.features.data ?? []); const features: { feature: any; freshness: Date }[] = (this.upstream.features.data ?? []);

View file

@ -1,8 +1,9 @@
import {Changes} from "../../Osm/Changes"; import {Changes} from "../../Osm/Changes";
import {OsmNode, OsmRelation, OsmWay} from "../../Osm/OsmObject"; import {OsmNode, OsmObject, OsmRelation, OsmWay} from "../../Osm/OsmObject";
import FeatureSource from "../FeatureSource"; import FeatureSource from "../FeatureSource";
import {UIEventSource} from "../../UIEventSource"; import {UIEventSource} from "../../UIEventSource";
import {ChangeDescription} from "../../Osm/Actions/ChangeDescription"; import {ChangeDescription} from "../../Osm/Actions/ChangeDescription";
import {ElementStorage} from "../../ElementStorage";
export class NewGeometryFromChangesFeatureSource implements FeatureSource { export class NewGeometryFromChangesFeatureSource implements FeatureSource {
// This class name truly puts the 'Java' into 'Javascript' // This class name truly puts the 'Java' into 'Javascript'
@ -13,79 +14,115 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
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 = "newFeatures"; public readonly name: string = "newFeatures";
constructor(changes: Changes, backendUrl: string) { constructor(changes: Changes, allElementStorage: ElementStorage, backendUrl: string) {
const seenChanges = new Set<ChangeDescription>(); const seenChanges = new Set<ChangeDescription>();
const features = this.features.data; const features = this.features.data;
const self = this; const self = this;
changes.pendingChanges changes.pendingChanges.addCallbackAndRunD(changes => {
.map(changes => changes.filter(ch => if (changes.length === 0) {
// only new objects allowed return;
ch.id < 0 && }
// The change is an update to the object (e.g. tags or geometry) - not the actual create
ch.changes !== undefined && const now = new Date();
// If tags is undefined, this is probably a new point that is part of a split road let somethingChanged = false;
ch.tags !== undefined &&
// Already handled function add(feature) {
!seenChanges.has(ch))) feature.id = feature.properties.id
.addCallbackAndRunD(changes => { features.push({
if (changes.length === 0) { feature: feature,
return; freshness: now
})
somethingChanged = true;
}
for (const change of changes) {
if (seenChanges.has(change)) {
// Already handled
continue;
}
seenChanges.add(change)
if (change.tags === undefined) {
// If tags is undefined, this is probably a new point that is part of a split road
continue
} }
const now = new Date(); if (change.id > 0) {
// This is an already existing object
function add(feature) { // In _most_ of the cases, this means that this _isn't_ a new object
feature.id = feature.properties.id // However, when a point is snapped to an already existing point, we have to create a representation for this point!
features.push({ // For this, we introspect the change
feature: feature, if (allElementStorage.has(change.id)) {
freshness: now // const currentTags = allElementStorage.getEventSourceById(change.id).data
}) continue;
}
for (const change of changes) {
seenChanges.add(change)
try {
const tags = {}
for (const kv of change.tags) {
tags[kv.k] = kv.v
}
tags["id"] = change.type + "/" + change.id
tags["_backend"] = backendUrl
switch (change.type) {
case "node":
const n = new OsmNode(change.id)
n.tags = tags
n.lat = change.changes["lat"]
n.lon = change.changes["lon"]
const geojson = n.asGeoJson()
add(geojson)
break;
case "way":
const w = new OsmWay(change.id)
w.tags = tags
w.nodes = change.changes["nodes"]
w.coordinates = change.changes["coordinates"].map(coor => [coor[1], coor[0]])
add(w.asGeoJson())
break;
case "relation":
const r = new OsmRelation(change.id)
r.tags = tags
r.members = change.changes["members"]
add(r.asGeoJson())
break;
}
} catch (e) {
console.error("Could not generate a new geometry to render on screen for:", e)
} }
console.debug("Detected a reused point")
// The 'allElementsStore' does _not_ have this point yet, so we have to create it
OsmObject.DownloadObjectAsync(change.type + "/" + change.id).then(feat => {
console.log("Got the reused point:", feat)
for (const kv of change.tags) {
feat.tags[kv.k] = kv.v
}
const geojson= feat.asGeoJson();
allElementStorage.addOrGetElement(geojson)
self.features.data.push({feature: geojson, freshness: new Date()})
self.features.ping()
})
continue
} else if (change.id < 0 && change.changes === undefined) {
// The geometry is not described - not a new point
if (change.id < 0) {
console.error("WARNING: got a new point without geometry!")
}
continue;
} }
try {
const tags = {}
for (const kv of change.tags) {
tags[kv.k] = kv.v
}
tags["id"] = change.type + "/" + change.id
tags["_backend"] = backendUrl
switch (change.type) {
case "node":
const n = new OsmNode(change.id)
n.tags = tags
n.lat = change.changes["lat"]
n.lon = change.changes["lon"]
const geojson = n.asGeoJson()
add(geojson)
break;
case "way":
const w = new OsmWay(change.id)
w.tags = tags
w.nodes = change.changes["nodes"]
w.coordinates = change.changes["coordinates"].map(coor => [coor[1], coor[0]])
add(w.asGeoJson())
break;
case "relation":
const r = new OsmRelation(change.id)
r.tags = tags
r.members = change.changes["members"]
add(r.asGeoJson())
break;
}
} catch (e) {
console.error("Could not generate a new geometry to render on screen for:", e)
}
}
if (somethingChanged) {
self.features.ping() self.features.ping()
}) }
})
} }
} }

View file

@ -153,8 +153,7 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
"mapRendering": [ "mapRendering": [
{ {
"location": [ "location": [
"point", "point"
"centroid"
], ],
"icon": { "icon": {
"render": "circle:white;help:black", "render": "circle:white;help:black",

View file

@ -230,7 +230,7 @@ export default class LayerConfig extends WithContextLoader {
if (this.lineRendering.length === 0 && this.mapRendering.length === 0) { if (this.lineRendering.length === 0 && this.mapRendering.length === 0) {
console.log(json.mapRendering) console.log(json.mapRendering)
throw("The layer " + this.id + " does not have any maprenderings defined and will thus not show up on the map at all. If this is intentional, set maprenderings to 'null' instead of '[]'") throw("The layer " + this.id + " does not have any maprenderings defined and will thus not show up on the map at all. If this is intentional, set maprenderings to 'null' instead of '[]'")
} else if (!hasCenterRendering && this.lineRendering.length === 0) { } else if (!hasCenterRendering && this.lineRendering.length === 0 && !this.source.geojsonSource?.startsWith("https://api.openstreetmap.org/api/0.6/notes.json")) {
throw "The layer " + this.id + " might not render ways. This might result in dropped information" throw "The layer " + this.id + " might not render ways. This might result in dropped information"
} }
} }