forked from MapComplete/MapComplete
		
	First working version of split road functionality
This commit is contained in:
		
							parent
							
								
									61f2ebf9ba
								
							
						
					
					
						commit
						248ea78b17
					
				
					 11 changed files with 88 additions and 66 deletions
				
			
		|  | @ -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
 | ||||
|  |  | |||
|  | @ -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([ | ||||
|  |  | |||
|  | @ -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)) | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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) | ||||
|                         }) | ||||
|  |  | |||
|  | @ -42,7 +42,6 @@ export default class LocationInput extends InputElement<Loc> { | |||
|             } | ||||
|         ) | ||||
|         map.leafletMap.addCallbackAndRunD(leaflet => { | ||||
|             console.log(leaflet.getBounds(), leaflet.getBounds().pad(0.15)) | ||||
|             leaflet.setMaxBounds( | ||||
|                 leaflet.getBounds().pad(0.15) | ||||
|             ) | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ export default class ShowDataLayer { | |||
|                 layoutToUse: UIEventSource<LayoutConfig>, | ||||
|                 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) | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
|         }) | ||||
|  |  | |||
|  | @ -55,9 +55,12 @@ export default class SpecialVisualizations { | |||
|                             if (!tags.hasOwnProperty(key)) { | ||||
|                                 continue; | ||||
|                             } | ||||
|                             parts.push(key + "=" + tags[key]); | ||||
|                             parts.push([key , tags[key] ?? "<b>undefined</b>" ]); | ||||
|                         } | ||||
|                         return parts.join("<br/>") | ||||
|                         return new Table( | ||||
|                             ["key","value"], | ||||
|                             parts | ||||
|                         ) | ||||
|                     })).SetStyle("border: 1px solid black; border-radius: 1em;padding:1em;display:block;") | ||||
|                 }) | ||||
|             }, | ||||
|  |  | |||
|  | @ -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", | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue