101 lines
3.5 KiB
TypeScript
101 lines
3.5 KiB
TypeScript
import { ChangeDescription } from "./ChangeDescription"
|
|
import { OsmCreateAction } from "./OsmChangeAction"
|
|
import { Changes } from "../Changes"
|
|
import { Tag } from "../../Tags/Tag"
|
|
import CreateNewNodeAction from "./CreateNewNodeAction"
|
|
import { And } from "../../Tags/And"
|
|
|
|
export default class CreateNewWayAction extends OsmCreateAction {
|
|
public newElementId: string = undefined
|
|
public newElementIdNumber: number = undefined
|
|
private readonly coordinates: { nodeId?: number; lat: number; lon: number }[]
|
|
private readonly tags: Tag[]
|
|
private readonly _options: {
|
|
theme: string
|
|
}
|
|
|
|
/***
|
|
* Creates a new way to upload to OSM
|
|
* @param tags: the tags to apply to the way
|
|
* @param coordinates: the coordinates. Might have a nodeId, in this case, this node will be used
|
|
* @param options
|
|
*/
|
|
constructor(
|
|
tags: Tag[],
|
|
coordinates: { nodeId?: number; lat: number; lon: number }[],
|
|
options: {
|
|
theme: string
|
|
}
|
|
) {
|
|
super(null, true)
|
|
this.coordinates = []
|
|
|
|
for (const coordinate of coordinates) {
|
|
/* The 'PointReuseAction' is a bit buggy and might generate duplicate ids.
|
|
We filter those here, as the CreateWayWithPointReuseAction delegates the actual creation to here.
|
|
Filtering here also prevents similar bugs in other actions
|
|
*/
|
|
if (
|
|
this.coordinates.length > 0 &&
|
|
coordinate.nodeId !== undefined &&
|
|
this.coordinates[this.coordinates.length - 1].nodeId === coordinate.nodeId
|
|
) {
|
|
// This is a duplicate id
|
|
console.warn(
|
|
"Skipping a node in createWay to avoid a duplicate node:",
|
|
coordinate,
|
|
"\nThe previous coordinates are: ",
|
|
this.coordinates
|
|
)
|
|
continue
|
|
}
|
|
|
|
this.coordinates.push(coordinate)
|
|
}
|
|
|
|
this.tags = tags
|
|
this._options = options
|
|
}
|
|
|
|
public async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
|
|
const newElements: ChangeDescription[] = []
|
|
|
|
const pointIds: number[] = []
|
|
for (const coordinate of this.coordinates) {
|
|
if (coordinate.nodeId !== undefined) {
|
|
pointIds.push(coordinate.nodeId)
|
|
continue
|
|
}
|
|
|
|
const newPoint = new CreateNewNodeAction([], coordinate.lat, coordinate.lon, {
|
|
allowReuseOfPreviouslyCreatedPoints: true,
|
|
changeType: null,
|
|
theme: this._options.theme,
|
|
})
|
|
newElements.push(...(await newPoint.CreateChangeDescriptions(changes)))
|
|
pointIds.push(newPoint.newElementIdNumber)
|
|
}
|
|
|
|
// We have all created (or reused) all the points!
|
|
// Time to create the actual way
|
|
|
|
const id = changes.getNewID()
|
|
this.newElementIdNumber = id
|
|
const newWay = <ChangeDescription>{
|
|
id,
|
|
type: "way",
|
|
meta: {
|
|
theme: this._options.theme,
|
|
changeType: "import",
|
|
},
|
|
tags: new And(this.tags).asChange({}),
|
|
changes: {
|
|
nodes: pointIds,
|
|
coordinates: this.coordinates.map((c) => [c.lon, c.lat]),
|
|
},
|
|
}
|
|
newElements.push(newWay)
|
|
this.newElementId = "way/" + id
|
|
return newElements
|
|
}
|
|
}
|