forked from MapComplete/MapComplete
Further experimentation
This commit is contained in:
parent
9c6822a1ac
commit
bfb16874b1
7 changed files with 284 additions and 87 deletions
|
@ -92,7 +92,7 @@ export default class FeaturePipeline {
|
|||
if (location?.zoom === undefined) {
|
||||
return false;
|
||||
}
|
||||
let minzoom = Math.min(...state.layoutToUse.layers.map(layer => layer.minzoom ?? 18));
|
||||
let minzoom = Math.min(...state.filteredLayers.data.map(layer => layer.layerDef.minzoom ?? 18));
|
||||
return location.zoom >= minzoom;
|
||||
}
|
||||
);
|
||||
|
@ -312,7 +312,7 @@ export default class FeaturePipeline {
|
|||
|
||||
|
||||
// Whenever fresh data comes in, we need to update the metatagging
|
||||
self.newDataLoadedSignal.stabilized(250).addCallback(src => {
|
||||
self.newDataLoadedSignal.stabilized(250).addCallback(_ => {
|
||||
self.updateAllMetaTagging()
|
||||
})
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import FeatureSource, {FeatureSourceForLayer, Tiled} from "../FeatureSource";
|
|||
import {OsmNode, OsmObject, OsmWay} from "../../Osm/OsmObject";
|
||||
import SimpleFeatureSource from "../Sources/SimpleFeatureSource";
|
||||
import FilteredLayer from "../../../Models/FilteredLayer";
|
||||
import {UIEventSource} from "../../UIEventSource";
|
||||
|
||||
|
||||
export default class FullNodeDatabaseSource implements TileHierarchy<FeatureSource & Tiled> {
|
||||
|
@ -10,6 +11,7 @@ export default class FullNodeDatabaseSource implements TileHierarchy<FeatureSour
|
|||
private readonly onTileLoaded: (tile: (Tiled & FeatureSourceForLayer)) => void;
|
||||
private readonly layer: FilteredLayer
|
||||
private readonly nodeByIds = new Map<number, OsmNode>();
|
||||
private readonly parentWays = new Map<number, UIEventSource<OsmWay[]>>()
|
||||
|
||||
constructor(
|
||||
layer: FilteredLayer,
|
||||
|
@ -35,7 +37,6 @@ export default class FullNodeDatabaseSource implements TileHierarchy<FeatureSour
|
|||
this.nodeByIds.set(osmNode.id, osmNode)
|
||||
}
|
||||
|
||||
const parentWaysByNodeId = new Map<number, OsmWay[]>()
|
||||
for (const osmObj of allObjects) {
|
||||
if (osmObj.type !== "way") {
|
||||
continue
|
||||
|
@ -43,16 +44,20 @@ export default class FullNodeDatabaseSource implements TileHierarchy<FeatureSour
|
|||
const osmWay = <OsmWay>osmObj;
|
||||
for (const nodeId of osmWay.nodes) {
|
||||
|
||||
if (!parentWaysByNodeId.has(nodeId)) {
|
||||
parentWaysByNodeId.set(nodeId, [])
|
||||
if (!this.parentWays.has(nodeId)) {
|
||||
const src = new UIEventSource<OsmWay[]>([])
|
||||
this.parentWays.set(nodeId,src)
|
||||
src.addCallback(parentWays => {
|
||||
const tgs = nodesById.get(nodeId).tags
|
||||
tgs ["parent_ways"] = JSON.stringify(parentWays.map(w => w.tags))
|
||||
tgs["parent_way_ids"] = JSON.stringify(parentWays.map(w => w.id))
|
||||
})
|
||||
}
|
||||
parentWaysByNodeId.get(nodeId).push(osmWay)
|
||||
const src = this.parentWays.get(nodeId)
|
||||
src.data.push(osmWay)
|
||||
src.ping();
|
||||
}
|
||||
}
|
||||
parentWaysByNodeId.forEach((allWays, nodeId) => {
|
||||
nodesById.get(nodeId).tags["parent_ways"] = JSON.stringify(allWays.map(w => w.tags))
|
||||
nodesById.get(nodeId).tags["parent_way_ids"] = JSON.stringify(allWays.map(w => w.id))
|
||||
})
|
||||
const now = new Date()
|
||||
const asGeojsonFeatures = Array.from(nodesById.values()).map(osmNode => ({
|
||||
feature: osmNode.asGeoJson(), freshness: now
|
||||
|
@ -71,10 +76,18 @@ export default class FullNodeDatabaseSource implements TileHierarchy<FeatureSour
|
|||
* @param id
|
||||
* @constructor
|
||||
*/
|
||||
public GetNode(id: number) : OsmNode {
|
||||
public GetNode(id: number): OsmNode {
|
||||
return this.nodeByIds.get(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parent way list
|
||||
* @param nodeId
|
||||
* @constructor
|
||||
*/
|
||||
public GetParentWays(nodeId: number): UIEventSource<OsmWay[]> {
|
||||
return this.parentWays.get(nodeId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -216,16 +216,16 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
|||
throw "PANIC: replaceGeometryAction needs the FullNodeDatabase, which is undefined. This should be initialized by having the 'type_node'-layer enabled in your theme. (NB: the replacebutton has type_node as dependency)"
|
||||
}
|
||||
for (const nodeId of detachedNodeIds) {
|
||||
const osmNode = nodeDb.GetNode(nodeId)
|
||||
const parentWayIds: number[] = JSON.parse(osmNode.tags["parent_way_ids"])
|
||||
const index = parentWayIds.indexOf(osmWay.id)
|
||||
const parentWays = nodeDb.GetParentWays(nodeId)
|
||||
const index = parentWays.data.map(w => w.id).indexOf(osmWay.id)
|
||||
if(index < 0){
|
||||
console.error("ReplaceGeometryAction is trying to detach node "+nodeId+", but it isn't listed as being part of way "+osmWay.id)
|
||||
continue;
|
||||
}
|
||||
parentWayIds.splice(index, 1)
|
||||
osmNode.tags["parent_way_ids"] = JSON.stringify(parentWayIds)
|
||||
if(parentWayIds.length == 0){
|
||||
// We detachted this node - so we unregister
|
||||
parentWays.data.splice(index, 1)
|
||||
parentWays.ping();
|
||||
if(parentWays.data.length == 0){
|
||||
// This point has no other ways anymore - lets clean it!
|
||||
console.log("Removing node "+nodeId, "as it isn't needed anymore by any way")
|
||||
|
||||
|
@ -254,7 +254,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
|||
* This method contains the main logic for this module, as it decides which node gets moved where.
|
||||
*
|
||||
*/
|
||||
private async GetClosestIds(): Promise<{
|
||||
public async GetClosestIds(): Promise<{
|
||||
|
||||
// A list of the same length as targetCoordinates, containing which OSM-point to move. If undefined, a new point will be created
|
||||
closestIds: number[],
|
||||
|
@ -282,11 +282,33 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
|||
const allNodes = parsed.filter(o => o.type === "node")
|
||||
|
||||
/**
|
||||
* For every already existing OSM-point, we calculate the distance to every target point
|
||||
* For every already existing OSM-point, we calculate:
|
||||
*
|
||||
* - the distance to every target point.
|
||||
* - Wether this node has (other) parent ways, which might restrict movement
|
||||
* - Wether this node has tags set
|
||||
*
|
||||
* Having tags and/or being connected to another way indicate that there is some _relation_ with objects in the neighbourhood.
|
||||
*
|
||||
* The Replace-geometry action should try its best to honour these. Some 'wiggling' is allowed (e.g. moving an entrance a bit), but these relations should not be broken.l
|
||||
*/
|
||||
|
||||
const distances = new Map<number /* osmId*/, number[] /* target coordinate index --> distance (or undefined if a duplicate)*/>();
|
||||
const distances = new Map<number /* osmId*/,
|
||||
/** target coordinate index --> distance (or undefined if a duplicate)*/
|
||||
number[]>();
|
||||
for (const node of allNodes) {
|
||||
const nodesWithAllParents = this.state.featurePipeline.fullNodeDatabase
|
||||
if (nodesWithAllParents === undefined) {
|
||||
throw "PANIC: replaceGeometryAction needs the FullNodeDatabase, which is undefined. This should be initialized by having the 'type_node'-layer enabled in your theme. (NB: the replacebutton has type_node as dependency)"
|
||||
}
|
||||
|
||||
let parentWayIds = nodesWithAllParents.GetParentWays(node.id)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const nodeDistances = this.targetCoordinates.map(_ => undefined)
|
||||
for (let i = 0; i < this.targetCoordinates.length; i++) {
|
||||
if (this.identicalTo[i] !== undefined) {
|
||||
|
@ -299,17 +321,18 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
|||
distances.set(node.id, nodeDistances)
|
||||
}
|
||||
|
||||
const closestIds = this.targetCoordinates.map(_ => undefined)
|
||||
const unusedIds = []
|
||||
{
|
||||
/**
|
||||
* Then, we search the node that has to move the least distance and add this as mapping.
|
||||
* We do this until no points are left
|
||||
*/
|
||||
let candidate: number;
|
||||
let moveDistance: number;
|
||||
const closestIds = this.targetCoordinates.map(_ => undefined)
|
||||
/**
|
||||
* The list of nodes that are _not_ used anymore, typically if there are less targetCoordinates then source coordinates
|
||||
*/
|
||||
const unusedIds = []
|
||||
do {
|
||||
candidate = undefined;
|
||||
moveDistance = Infinity;
|
||||
|
@ -353,7 +376,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
|||
}
|
||||
}
|
||||
} while (candidate !== undefined)
|
||||
|
||||
}
|
||||
|
||||
// If there are still unused values in 'distances', they are definitively unused
|
||||
distances.forEach((_, nodeId) => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as mangrove from 'mangrove-reviews'
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import {Review} from "./Review";
|
||||
import {Utils} from "../../Utils";
|
||||
|
||||
export class MangroveIdentity {
|
||||
public keypair: any = undefined;
|
||||
|
@ -23,7 +24,7 @@ export class MangroveIdentity {
|
|||
})
|
||||
})
|
||||
try {
|
||||
if ((mangroveIdentity.data ?? "") === "") {
|
||||
if (!Utils.runningFromConsole && (mangroveIdentity.data ?? "") === "") {
|
||||
this.CreateIdentity();
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue