MapComplete/src/Logic/Osm/Actions/CreateNewNodeAction.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

132 lines
4.3 KiB
TypeScript
Raw Normal View History

import { Tag } from "../../Tags/Tag"
2022-01-18 18:52:42 +01:00
import { OsmCreateAction } from "./OsmChangeAction"
import { Changes } from "../Changes"
import { ChangeDescription } from "./ChangeDescription"
import { And } from "../../Tags/And"
import { OsmWay } from "../OsmObject"
import { GeoOperations } from "../../GeoOperations"
import InsertPointIntoWayAction from "./InsertPointIntoWayAction"
export default class CreateNewNodeAction extends OsmCreateAction {
/**
* Maps previously created points onto their assigned ID, to reuse the point if uplaoded
* "lat,lon" --> id
*/
private static readonly previouslyCreatedPoints = new Map<string, number>()
public newElementId: string = undefined
public newElementIdNumber: number = undefined
private readonly _basicTags: Tag[]
private readonly _lat: number
private readonly _lon: number
private readonly _snapOnto: OsmWay
private readonly _reusePointDistance: number
2022-10-27 01:50:41 +02:00
private readonly meta: {
changeType: "create" | "import"
theme: string
specialMotivation?: string
}
private readonly _reusePreviouslyCreatedPoint: boolean
2022-09-08 21:40:48 +02:00
constructor(
basicTags: Tag[],
lat: number,
lon: number,
options: {
allowReuseOfPreviouslyCreatedPoints?: boolean
snapOnto?: OsmWay
reusePointWithinMeters?: number
2022-01-25 00:48:05 +01:00
theme: string
changeType: "create" | "import" | null
specialMotivation?: string
},
) {
2022-01-26 21:40:38 +01:00
super(null, basicTags !== undefined && basicTags.length > 0)
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
this._reusePreviouslyCreatedPoint =
options?.allowReuseOfPreviouslyCreatedPoints ?? basicTags.length === 0
this.meta = {
theme: options.theme,
2022-01-25 00:48:05 +01:00
changeType: options.changeType,
specialMotivation: options.specialMotivation,
}
}
async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
if (this._reusePreviouslyCreatedPoint) {
const key = this._lat + "," + this._lon
const prev = CreateNewNodeAction.previouslyCreatedPoints
if (prev.has(key)) {
this.newElementIdNumber = prev.get(key)
this.newElementId = "node/" + this.newElementIdNumber
return []
}
}
const id = changes.getNewID()
const properties = {
id: "node/" + id,
}
this.setElementId(id)
for (const kv of this._basicTags) {
if (typeof kv.value !== "string") {
throw (
"Invalid value: don't use non-string value in a preset. The tag " +
kv.key +
"=" +
kv.value +
" is not a string, the value is a " +
typeof kv.value
2022-09-08 21:40:48 +02:00
)
}
properties[kv.key] = kv.value
}
const newPointChange: ChangeDescription = {
tags: new And(this._basicTags).asChange(properties),
type: "node",
id: id,
changes: {
lat: this._lat,
lon: this._lon,
},
meta: this.meta,
}
if (this._snapOnto?.coordinates === undefined) {
return [newPointChange]
}
const change = new InsertPointIntoWayAction(
this._lat,
this._lon,
id,
this._snapOnto,
{
reusePointWithinMeters: this._reusePointDistance,
allowReuseOfPreviouslyCreatedPoints: this._reusePreviouslyCreatedPoint,
},
).prepareChangeDescription()
2022-09-08 21:40:48 +02:00
return [
newPointChange,
{ ...change, meta: this.meta },
]
}
private setElementId(id: number) {
this.newElementIdNumber = id
2021-11-07 16:34:51 +01:00
this.newElementId = "node/" + id
if (!this._reusePreviouslyCreatedPoint) {
return
}
const key = this._lat + "," + this._lon
CreateNewNodeAction.previouslyCreatedPoints.set(key, id)
}
}