forked from MapComplete/MapComplete
First working version of snapping to already existing ways from the add-UI (still too slow though), partial fix of #436
This commit is contained in:
parent
bf2d634208
commit
0a01561d37
15 changed files with 460 additions and 143 deletions
|
@ -14,7 +14,7 @@ export interface ChangeDescription {
|
|||
lat: number,
|
||||
lon: number
|
||||
} | {
|
||||
// Coordinates are only used for rendering
|
||||
// Coordinates are only used for rendering. They should be lon, lat
|
||||
locations: [number, number][]
|
||||
nodes: number[],
|
||||
} | {
|
||||
|
|
|
@ -3,6 +3,8 @@ import OsmChangeAction from "./OsmChangeAction";
|
|||
import {Changes} from "../Changes";
|
||||
import {ChangeDescription} from "./ChangeDescription";
|
||||
import {And} from "../../Tags/And";
|
||||
import {OsmWay} from "../OsmObject";
|
||||
import {GeoOperations} from "../../GeoOperations";
|
||||
|
||||
export default class CreateNewNodeAction extends OsmChangeAction {
|
||||
|
||||
|
@ -10,13 +12,20 @@ export default class CreateNewNodeAction extends OsmChangeAction {
|
|||
private readonly _lat: number;
|
||||
private readonly _lon: number;
|
||||
|
||||
public newElementId : string = undefined
|
||||
|
||||
constructor(basicTags: Tag[], lat: number, lon: number) {
|
||||
public newElementId: string = undefined
|
||||
private readonly _snapOnto: OsmWay;
|
||||
private readonly _reusePointDistance: number;
|
||||
|
||||
constructor(basicTags: Tag[], lat: number, lon: number, options?: { snapOnto: OsmWay, reusePointWithinMeters?: number }) {
|
||||
super()
|
||||
this._basicTags = basicTags;
|
||||
this._lat = lat;
|
||||
this._lon = lon;
|
||||
if(lat === undefined || lon === undefined){
|
||||
throw "Lat or lon are undefined!"
|
||||
}
|
||||
this._snapOnto = options?.snapOnto;
|
||||
this._reusePointDistance = options.reusePointWithinMeters ?? 1
|
||||
}
|
||||
|
||||
CreateChangeDescriptions(changes: Changes): ChangeDescription[] {
|
||||
|
@ -24,7 +33,7 @@ export default class CreateNewNodeAction extends OsmChangeAction {
|
|||
const properties = {
|
||||
id: "node/" + id
|
||||
}
|
||||
this.newElementId = "node/"+id
|
||||
this.newElementId = "node/" + id
|
||||
for (const kv of this._basicTags) {
|
||||
if (typeof kv.value !== "string") {
|
||||
throw "Invalid value: don't use a regex in a preset"
|
||||
|
@ -32,16 +41,68 @@ export default class CreateNewNodeAction extends OsmChangeAction {
|
|||
properties[kv.key] = kv.value;
|
||||
}
|
||||
|
||||
return [{
|
||||
const newPointChange: ChangeDescription = {
|
||||
tags: new And(this._basicTags).asChange(properties),
|
||||
type: "node",
|
||||
id: id,
|
||||
changes:{
|
||||
changes: {
|
||||
lat: this._lat,
|
||||
lon: this._lon
|
||||
}
|
||||
}]
|
||||
}
|
||||
if (this._snapOnto === undefined) {
|
||||
return [newPointChange]
|
||||
}
|
||||
|
||||
|
||||
// Project the point onto the way
|
||||
|
||||
const geojson = this._snapOnto.asGeoJson()
|
||||
const projected = GeoOperations.nearestPoint(geojson, [this._lon, this._lat])
|
||||
const index = projected.properties.index
|
||||
// We check that it isn't close to an already existing point
|
||||
let reusedPointId = undefined;
|
||||
const prev = <[number, number]>geojson.geometry.coordinates[index]
|
||||
if (GeoOperations.distanceBetween(prev, <[number, number]>projected.geometry.coordinates) * 1000 < this._reusePointDistance) {
|
||||
// We reuse this point instead!
|
||||
reusedPointId = this._snapOnto.nodes[index]
|
||||
}
|
||||
const next = <[number, number]>geojson.geometry.coordinates[index + 1]
|
||||
if (GeoOperations.distanceBetween(next, <[number, number]>projected.geometry.coordinates) * 1000 < this._reusePointDistance) {
|
||||
// We reuse this point instead!
|
||||
reusedPointId = this._snapOnto.nodes[index + 1]
|
||||
}
|
||||
if (reusedPointId !== undefined) {
|
||||
console.log("Reusing an existing point:", reusedPointId)
|
||||
this.newElementId = "node/" + reusedPointId
|
||||
|
||||
return [{
|
||||
tags: new And(this._basicTags).asChange(properties),
|
||||
type: "node",
|
||||
id: reusedPointId
|
||||
}]
|
||||
}
|
||||
|
||||
const locations = [...this._snapOnto.coordinates]
|
||||
locations.forEach(coor => coor.reverse())
|
||||
console.log("Locations are: ", locations)
|
||||
const ids = [...this._snapOnto.nodes]
|
||||
|
||||
locations.splice(index + 1, 0, [this._lon, this._lat])
|
||||
ids.splice(index + 1, 0, id)
|
||||
|
||||
// Allright, we have to insert a new point in the way
|
||||
return [
|
||||
newPointChange,
|
||||
{
|
||||
type:"way",
|
||||
id: this._snapOnto.id,
|
||||
changes: {
|
||||
locations: locations,
|
||||
nodes: ids
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,9 +27,6 @@ export class Changes {
|
|||
private readonly previouslyCreated : OsmObject[] = []
|
||||
|
||||
constructor() {
|
||||
this.isUploading.addCallbackAndRun(uploading => {
|
||||
console.trace("Is uploading changed:", uploading)
|
||||
})
|
||||
}
|
||||
|
||||
private static createChangesetFor(csId: string,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue