mapcomplete/Logic/Osm/Actions/CreateNewWayAction.ts
2022-02-22 14:13:41 +01:00

94 lines
No EOL
3.3 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
}
}