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 { 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 = { 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 } }