forked from MapComplete/MapComplete
		
	Fix #596
This commit is contained in:
		
							parent
							
								
									5182085f35
								
							
						
					
					
						commit
						1e3206120c
					
				
					 6 changed files with 108 additions and 69 deletions
				
			
		|  | @ -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, | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
|  | @ -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 ?? []); | ||||||
|  |  | ||||||
|  | @ -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() | ||||||
|             }) |             } | ||||||
|  |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue