forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			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
 | 
						|
    }
 | 
						|
}
 |