diff --git a/Logic/FeatureSource/FeatureSourceMerger.ts b/Logic/FeatureSource/FeatureSourceMerger.ts index e9901d1f5b..26d9ce4986 100644 --- a/Logic/FeatureSource/FeatureSourceMerger.ts +++ b/Logic/FeatureSource/FeatureSourceMerger.ts @@ -1,6 +1,10 @@ import FeatureSource from "./FeatureSource"; import {UIEventSource} from "../UIEventSource"; +/** + * Merges features from different featureSources + * Uses the freshest feature available in the case multiple sources offer data with the same identifier + */ export default class FeatureSourceMerger implements FeatureSource { public features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]); diff --git a/Logic/Osm/Actions/Action.ts b/Logic/Osm/Actions/Action.ts index e69de29bb2..c09e20cb8f 100644 --- a/Logic/Osm/Actions/Action.ts +++ b/Logic/Osm/Actions/Action.ts @@ -0,0 +1,7 @@ +/** + * An action is a change to the OSM-database + * It will generate some new/modified/deleted objects, which are all bundled by the 'changes'-object + */ +export default interface Action { + +} \ No newline at end of file diff --git a/Logic/Osm/Changes.ts b/Logic/Osm/Changes.ts index d26dec6a62..0d5a05a875 100644 --- a/Logic/Osm/Changes.ts +++ b/Logic/Osm/Changes.ts @@ -1,4 +1,4 @@ -import {OsmNode, OsmObject, OsmWay} from "./OsmObject"; +import {OsmNode, OsmObject} from "./OsmObject"; import State from "../../State"; import {Utils} from "../../Utils"; import {UIEventSource} from "../UIEventSource"; @@ -121,7 +121,7 @@ export class Changes implements FeatureSource{ } } - const changes = this.createTagChangeList(basicTags, properties, id); + const changes = Changes.createTagChangeList(basicTags, properties, id); console.log("New feature added and pinged") this.features.data.push({feature:geojson, freshness: new Date()}); @@ -133,44 +133,8 @@ export class Changes implements FeatureSource{ return geojson; } - /** - * Creates a new road with given tags that consist of the points corresponding to given nodeIDs - * @param basicTags The tags to add to the road - * @param nodeIDs IDs of nodes of which the road consists. Those nodes must already exist in osm or already be added to the changeset. - * @param coordinates The coordinates correspoinding to the nodeID at the same index. Each coordinate is a [lon, lat] point - * @return geojson A geojson representation of the created road - */ - public createRoad(basicTags: Tag[], nodeIDs, coordinates) { - const osmWay = new OsmWay(this.getNewID()); - const id = "way/" + osmWay.id; - osmWay.nodes = nodeIDs; - const properties = {id: id}; - - const geojson = { - "type": "Feature", - "properties": properties, - "id": id, - "geometry": { - "type": "LineString", - "coordinates": coordinates - } - } - - const changes = this.createTagChangeList(basicTags, properties, id); - - console.log("New feature added and pinged") - this.features.data.push({feature:geojson, freshness: new Date()}); - this.features.ping(); - - State.state.allElements.addOrGetElement(geojson).ping(); - - this.uploadAll([osmWay], changes); - return geojson; - } - - - private createTagChangeList(basicTags: Tag[], properties: { id: string }, id: string) { + private static createTagChangeList(basicTags: Tag[], properties: { id: string }, id: string) { // The basictags are COPIED, the id is included in the properties // The tags are not yet written into the OsmObject, but this is applied onto a const changes = []; @@ -229,46 +193,46 @@ export class Changes implements FeatureSource{ State.state.osmConnection.UploadChangeset( State.state.layoutToUse.data, State.state.allElements, - function (csId) { - - let modifications = ""; - for (const element of changedElements) { - if (!element.changed) { - continue; - } - modifications += element.ChangesetXML(csId) + "\n"; - } - - - let creations = ""; - for (const newElement of newElements) { - creations += newElement.ChangesetXML(csId); - } - - - let changes = ``; - - if (creations.length > 0) { - changes += - "" + - creations + - ""; - } - - if (modifications.length > 0) { - changes += - "\n" + - modifications + - "\n"; - } - - changes += ""; - - return changes; - }); + (csId) => Changes.createChangesetFor(csId,changedElements, newElements ) + ); }; + public static createChangesetFor(csId: string, changedElements: OsmObject[], newElements: OsmObject[]): string { + + let modifications = ""; + for (const element of changedElements) { + modifications += element.ChangesetXML(csId) + "\n"; + } + + + let creations = ""; + for (const newElement of newElements) { + creations += newElement.ChangesetXML(csId); + } + + + let changes = ``; + + if (creations.length > 0) { + changes += + "\n\n" + + creations + + ""; + } + + if (modifications.length > 0) { + changes += + "\n\n" + + modifications + + "\n"; + } + + changes += ""; + + return changes; + } + private uploadAll( newElements: OsmObject[], pending: { elementId: string; key: string; value: string }[] @@ -293,13 +257,4 @@ export class Changes implements FeatureSource{ }) } - - /** - * Changes the nodes of road with given id to the given nodes - * @param roadID The ID of the road to update - * @param newNodes The node id's the road consists of (should already be added to the changeset or in osm) - */ - public updateRoadCoordinates(roadID: string, newNodes: number[]) { - // TODO - } } \ No newline at end of file diff --git a/Logic/Osm/CreateNewNodeAction.ts b/Logic/Osm/CreateNewNodeAction.ts index e69de29bb2..c0d9efba1f 100644 --- a/Logic/Osm/CreateNewNodeAction.ts +++ b/Logic/Osm/CreateNewNodeAction.ts @@ -0,0 +1,3 @@ +export default class CreateNewNodeAction { + +} \ No newline at end of file diff --git a/Logic/Osm/OsmObject.ts b/Logic/Osm/OsmObject.ts index 2fe1ef50bf..2a2af0d507 100644 --- a/Logic/Osm/OsmObject.ts +++ b/Logic/Osm/OsmObject.ts @@ -60,6 +60,8 @@ export abstract class OsmObject { case("relation"): new OsmRelation(idN).Download(newContinuation); break; + default: + throw "Invalid road type:" + type; } return src; @@ -150,7 +152,7 @@ export abstract class OsmObject { const minlat = bounds[1][0] const maxlat = bounds[0][0]; const url = `${OsmObject.backendURL}api/0.6/map.json?bbox=${minlon},${minlat},${maxlon},${maxlat}` - Utils.downloadJson(url).then( data => { + Utils.downloadJson(url).then(data => { const elements: any[] = data.elements; const objects = OsmObject.ParseObjects(elements) callback(objects); @@ -354,9 +356,9 @@ export class OsmNode extends OsmObject { ChangesetXML(changesetId: string): string { let tags = this.TagsXML(); - return ' \n' + + return ' \n' + tags + - ' \n'; + ' \n'; } SaveExtraData(element) { @@ -401,7 +403,6 @@ export class OsmWay extends OsmObject { constructor(id) { super("way", id); - } centerpoint(): [number, number] { @@ -418,7 +419,7 @@ export class OsmWay extends OsmObject { return ' \n' + nds + tags + - ' \n'; + ' \n'; } SaveExtraData(element, allNodes: OsmNode[]) { diff --git a/Logic/Osm/RelationSplitlHandler.ts b/Logic/Osm/RelationSplitlHandler.ts index e69de29bb2..7657e094fe 100644 --- a/Logic/Osm/RelationSplitlHandler.ts +++ b/Logic/Osm/RelationSplitlHandler.ts @@ -0,0 +1,11 @@ +/** + * The logic to handle relations after a way within + */ +export default class RelationSplitlHandler { + + constructor() { + + } + + +} \ No newline at end of file diff --git a/Logic/Osm/SplitAction.ts b/Logic/Osm/SplitAction.ts index 4405fd1994..6153f2bad9 100644 --- a/Logic/Osm/SplitAction.ts +++ b/Logic/Osm/SplitAction.ts @@ -1,162 +1,222 @@ -import {UIEventSource} from "../UIEventSource"; -import {OsmNode, OsmObject, OsmWay} from "./OsmObject"; -import State from "../../State"; -import {distance} from "@turf/turf"; +import {OsmNode, OsmObject, OsmRelation, OsmWay} from "./OsmObject"; import {GeoOperations} from "../GeoOperations"; +import State from "../../State"; +import {UIEventSource} from "../UIEventSource"; import {Changes} from "./Changes"; -/** - * Splits a road in different segments, each splitted at one of the given points (or a point on the road close to it) - * @param roadID The id of the road you want to split - * @param points The points on the road where you want the split to occur (geojson point list) - */ -export async function splitRoad(roadID, points) { - if (points.length != 1) { - // TODO: more than one point - console.log(points) - window.alert("Warning, currently only tested on one point, you selected " + points.length + " points") - } - - let road = State.state.allElements.ContainingFeatures.get(roadID); - - /** - * Compares two points based on the starting point of the road, can be used in sort function - * @param point1 [lon, lat] point - * @param point2 [lon, lat] point - */ - function comparePointDistance(point1, point2) { - let distFromStart1 = GeoOperations.nearestPoint(road, point1).properties.location; - let distFromStart2 = GeoOperations.nearestPoint(road, point2).properties.location; - return distFromStart1 - distFromStart2; // Sort requires a number to return instead of a bool - } - - /** - * Eliminates split points close (<4m) to existing points on the road, so you can split on these points instead - * @param road The road geojson object - * @param points The points on the road where you want the split to occur (geojson point list) - * @return realSplitPoints List containing all new locations where you should split - */ - function getSplitPoints(road, points) { - // Copy the list - let roadPoints = [...road.geometry.coordinates]; - - // Get the coordinates of all geojson points - let splitPointsCoordinates = points.map((point) => point.geometry.coordinates); - - roadPoints.push(...splitPointsCoordinates); - - // Sort all points on the road based on the distance from the start - roadPoints.sort(comparePointDistance) - - // Remove points close to existing points on road - let realSplitPoints = [...splitPointsCoordinates]; - for (let index = roadPoints.length - 1; index > 0; index--) { - // Iterate backwards to prevent problems when removing elements - let dist = distance(roadPoints[index - 1], roadPoints[index], {units: "kilometers"}); - // Remove all cutpoints closer than 4m to their previous point - if ((dist < 0.004) && (splitPointsCoordinates.includes(roadPoints[index]))) { - console.log("Removed a splitpoint, using a closer point to the road instead") - realSplitPoints.splice(index, 1) - realSplitPoints.push(roadPoints[index - 1]) - } - } - return realSplitPoints; - } - - let realSplitPoints = getSplitPoints(road, points); - - // Create a sorted list containing all points - let allPoints = [...road.geometry.coordinates]; - allPoints.push(...realSplitPoints); - allPoints.sort(comparePointDistance); - - // The changeset that will contain the operations to split the road - let changes = new Changes(); - - // Download the data of the current road from Osm to get the ID's of the coordinates - let osmRoad: UIEventSource = OsmObject.DownloadObject(roadID); - - // TODO: Remove delay, use a callback on odmRoad instead and execute all code below in callback function - function delay(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - await delay(3000); - - // Dict to quickly convert a coordinate to a nodeID - let coordToIDMap = {}; - - /** - * Converts a coordinate to a string, so it's hashable (e.g. for using it in a dict) - * @param coord [lon, lat] point - */ - function getCoordKey(coord: [number, number]) { - return coord[0] + "," + coord[1]; - } - - osmRoad.data.coordinates.forEach((coord, i) => coordToIDMap[getCoordKey([coord[1], coord[0]])] = osmRoad.data.nodes[i]); - - let currentRoadPoints: number[] = []; - let currentRoadCoordinates: [number, number][] = [] - - /** - * Given a coordinate, check whether there is already a node in osm created (on the road or cutpoints) or create - * such point if it doesn't exist yet and return the id of this coordinate - * @param coord [lon, lat] point - * @return pointID The ID of the existing/created node on given coordinates - */ - function getOrCreateNodeID(coord) { - console.log(coordToIDMap) - let poinID = coordToIDMap[getCoordKey(coord)]; - if (poinID == undefined) { - console.log(getCoordKey(coord) + " not in map") - // TODO: Check if lat, lon is correct - let newNode = changes.createElement([], coord[1], coord[0]); - - coordToIDMap[coord] = newNode.id; - poinID = newNode.id; - - console.log("New point created "); - } - return poinID; - } - - /** - * Creates a new road in OSM, while copying the tags from osmRoad and using currentRoadPoints as points - * @param currentRoadPoints List of id's of nodes the road should exist of - * @param osmRoad The road to copy the tags from - */ - function createNewRoadSegment(currentRoadPoints, osmRoad) { - changes.createRoad(osmRoad.data.tags, currentRoadPoints, currentRoadCoordinates); - } - - for (let coord of allPoints) { - console.log("Handling coord") - let pointID = getOrCreateNodeID(coord); - currentRoadPoints.push(pointID); - currentRoadCoordinates.push(coord); - if (realSplitPoints.includes(coord)) { - console.log("Handling split") - // Should split here - // currentRoadPoints contains a list containing all points for this road segment - createNewRoadSegment(currentRoadPoints, osmRoad); - - // Cleanup for next split - currentRoadPoints = [pointID]; - currentRoadCoordinates = [coord]; - console.log("Splitting here...") - } - } - - // Update the road to contain only the points of the last segment - // changes.updateRoadCoordinates(roadID, currentRoadPoints); - - // push the applied changes - changes.flushChanges(); - - return; +interface SplitInfo { + originalIndex?: number, // or negative for new elements + lngLat: [number, number], + doSplit: boolean } +export default class SplitAction { + private readonly roadObject: any; -// TODO: Vlakbij bestaand punt geklikt? Bestaand punt hergebruiken -// Nieuw wegobject aanmaken, en oude hergebruiken voor andere helft van de weg -// TODO: CHeck if relation exist to the road -> Delete them when splitted, because they might be outdated after the split + /*** + * + * @param roadObject: the geojson of the road object. Properties.id must be the corresponding OSM-id + */ + constructor(roadObject: any) { + this.roadObject = roadObject; + } + + private static SegmentSplitInfo(splitInfo: SplitInfo[]): SplitInfo[][] { + const wayParts = [] + let currentPart = [] + for (const splitInfoElement of splitInfo) { + currentPart.push(splitInfoElement) + + if (splitInfoElement.doSplit) { + // We have to do a split! + // We add the current index to the currentParts, flush it and add it again + wayParts.push(currentPart) + currentPart = [splitInfoElement] + } + } + wayParts.push(currentPart) + return wayParts + } + + public DoSplit(splitPoints: any[]) { + // We mark the new split points with a new id + for (const splitPoint of splitPoints) { + splitPoint.properties["_is_split_point"] = true + } + + + const self = this; + const id = this.roadObject.properties.id + const osmWay = >OsmObject.DownloadObject(id) + const partOf = OsmObject.DownloadReferencingRelations(id) + osmWay.map(originalElement => { + + if(originalElement === undefined || partOf === undefined){ + return; + } + + const changes = State.state?.changes ?? new Changes(); + // First, calculate splitpoints and remove points close to one another + const splitInfo = self.CalculateSplitCoordinates(splitPoints) + // Now we have a list with e.g. + // [ { originalIndex: 0}, {originalIndex: 1, doSplit: true}, {originalIndex: 2}, {originalIndex: undefined, doSplit: true}, {originalIndex: 3}] + + // Lets change 'originalIndex' to the actual node id first: + for (const element of splitInfo) { + if (element.originalIndex >= 0) { + element.originalIndex = originalElement.nodes[element.originalIndex] + } else { + element.originalIndex = changes.getNewID(); + } + } + + // Next up is creating actual parts from this + const wayParts = SplitAction.SegmentSplitInfo(splitInfo); + + // Allright! At this point, we have our new ways! + // Which one is the longest of them (and can keep the id)? + + let longest = undefined; + for (const wayPart of wayParts) { + if (longest === undefined) { + longest = wayPart; + continue + } + if (wayPart.length > longest.length) { + longest = wayPart + } + } + + const newOsmObjects: OsmObject[] = [] + const modifiedObjects: OsmObject[] = [] + // Let's create the new points as needed + for (const element of splitInfo) { + if (element.originalIndex >= 0) { + continue; + } + const node = new OsmNode(element.originalIndex) + node.lon = element.lngLat[0] + node.lat = element.lngLat[1] + newOsmObjects.push(node) + } + + const newWayIds: number[] = [] + // Lets create OsmWays based on them + for (const wayPart of wayParts) { + + let isOriginal = wayPart === longest + if(isOriginal){ + // We change the actual element! + originalElement.nodes = wayPart.map(p => p.originalIndex); + originalElement.changed = true; + modifiedObjects.push(originalElement) + }else{ + let id = changes.getNewID(); + const way = new OsmWay(id) + way.tags = originalElement.tags; + way.nodes = wayPart.map(p => p.originalIndex); + way.changed = true; + newOsmObjects.push(way) + newWayIds.push(way.id) + } + + } + + // At last, we still have to check that we aren't part of a relation... + // At least, the order of the ways is identical, so we can keep the same roles + + modifiedObjects.push(...SplitAction.UpdateRelations(partOf.data, newWayIds, originalElement)) + // And we have our objects! + // Time to upload + + console.log(Changes.createChangesetFor("123", modifiedObjects, newOsmObjects)) + }, [partOf]) + } + + private static UpdateRelations(data: OsmRelation[], newWayIds: number[], originalElement: OsmWay):OsmRelation[]{ + // TODO + return [] + } + + /** + * Calculates the actual points to split + * If another point is closer then ~5m, we reuse that point + */ + private CalculateSplitCoordinates( + splitPoints: any[], + toleranceInM = 5): SplitInfo[] { + + const allPoints = [...splitPoints]; + // We have a bunch of coordinates here: [ [lat, lon], [lat, lon], ...] ... + const originalPoints: [number, number][] = this.roadObject.geometry.coordinates + // We project them onto the line (which should yield pretty much the same point + for (let i = 0; i < originalPoints.length; i++) { + let originalPoint = originalPoints[i]; + let projected = GeoOperations.nearestPoint(this.roadObject, originalPoint) + projected.properties["_is_split_point"] = false + projected.properties["_original_index"] = i + allPoints.push(projected) + } + // At this point, we have a list of both the split point and the old points, with some properties to discriminate between them + // We sort this list so that the new points are at the same location + allPoints.sort((a, b) => a.properties.location - b.properties.location) + + // When this is done, we check that no now point is too close to an already existing point and no very small segments get created + + for (let i = allPoints.length - 1; i > 0; i--) { + + const point = allPoints[i]; + if (point.properties._original_index !== undefined) { + // This point is already in OSM - we have to keep it! + continue; + } + + if (i != allPoints.length - 1) { + const prevPoint = allPoints[i + 1] + const diff = Math.abs(point.properties.location - prevPoint.properties.location) * 1000 + if (diff <= toleranceInM) { + // To close to the previous point! We delete this point... + allPoints.splice(i, 1) + // ... and mark the previous point as a split point + prevPoint.properties._is_split_point = true + continue; + } + } + + if (i > 0) { + const nextPoint = allPoints[i - 1] + const diff = Math.abs(point.properties.location - nextPoint.properties.location) * 1000 + if (diff <= toleranceInM) { + // To close to the next point! We delete this point... + allPoints.splice(i, 1) + // ... and mark the next point as a split point + nextPoint.properties._is_split_point = true + // noinspection UnnecessaryContinueJS + continue; + } + } + // We don't have to remove this point... + } + + const splitInfo: SplitInfo[] = [] + let nextId = -1 + + for (const p of allPoints) { + let index = p.properties._original_index + if (index === undefined) { + index = nextId; + nextId--; + } + const splitInfoElement = { + originalIndex: index, + lngLat: p.geometry.coordinates, + doSplit: p.properties._is_split_point + } + splitInfo.push(splitInfoElement) + } + + return splitInfo + } + + +} diff --git a/UI/Popup/SplitRoadWizard.ts b/UI/Popup/SplitRoadWizard.ts index 8aed42a7ec..c9cd65e567 100644 --- a/UI/Popup/SplitRoadWizard.ts +++ b/UI/Popup/SplitRoadWizard.ts @@ -7,13 +7,15 @@ import State from "../../State"; import ShowDataLayer from "../ShowDataLayer"; import {GeoOperations} from "../../Logic/GeoOperations"; import {LeafletMouseEvent} from "leaflet"; -import LayerConfig from "../../Customizations/JSON/LayerConfig"; import Combine from "../Base/Combine"; import {Button} from "../Base/Button"; import Translations from "../i18n/Translations"; -import {splitRoad} from "../../Logic/Osm/SplitAction"; +import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; +import SplitAction from "../../Logic/Osm/SplitAction"; export default class SplitRoadWizard extends Toggle { + private static splitLayout = new UIEventSource(SplitRoadWizard.GetSplitLayout()) + /** * A UI Element used for splitting roads * @@ -23,25 +25,25 @@ export default class SplitRoadWizard extends Toggle { const t = Translations.t.split; - // Contains the points on the road that are selected to split on - const splitPositions = new UIEventSource([]); + // Contains the points on the road that are selected to split on - contains geojson points with extra properties such as 'location' with the distance along the linestring + const splitPoints = new UIEventSource<{feature: any, freshness: Date}[]>([]); // Toggle variable between show split button and map - const splitClicked = new UIEventSource(true); // todo: -> false + const splitClicked = new UIEventSource(false); // Minimap on which you can select the points to be splitted const miniMap = new Minimap({background: State.state.backgroundLayer}); miniMap.SetStyle("width: 100%; height: 50rem;"); // Define how a cut is displayed on the map - const layoutConfigJson = {id: "splitpositions", source: {osmTags: "_cutposition=yes"}, icon: "./assets/svg/plus.svg"} - State.state.layoutToUse.data.layers.push(new LayerConfig(layoutConfigJson,undefined,"Split Road Wizard")) // Load the road with given id on the minimap const roadElement = State.state.allElements.ContainingFeatures.get(id) + const splitAction = new SplitAction(roadElement) const roadEventSource = new UIEventSource([{feature: roadElement, freshness: new Date()}]); // Datalayer displaying the road and the cut points (if any) - const dataLayer = new ShowDataLayer(roadEventSource, miniMap.leafletMap, State.state.layoutToUse, false, true); + new ShowDataLayer(roadEventSource, miniMap.leafletMap, State.state.layoutToUse, false, true); + new ShowDataLayer(splitPoints, miniMap.leafletMap, SplitRoadWizard.splitLayout, false, false) /** * Handles a click on the overleaf map. @@ -54,17 +56,14 @@ export default class SplitRoadWizard extends Toggle { // Update point properties to let it match the layer pointOnRoad.properties._cutposition = "yes"; - pointOnRoad._matching_layer_id = "splitpositions"; - - // Add it to the list of all points and notify observers - splitPositions.data.push(pointOnRoad); - splitPositions.ping(); + pointOnRoad["_matching_layer_id"] = "splitpositions"; // let the state remember the point, to be able to retrieve it later by id State.state.allElements.addOrGetElement(pointOnRoad); - - roadEventSource.data.push({feature: pointOnRoad, freshness: new Date()}); // show the point on the data layer - roadEventSource.ping(); // not updated using .setData, so manually ping observers + + // Add it to the list of all points and notify observers + splitPoints.data.push({feature: pointOnRoad, freshness: new Date()}); // show the point on the data layer + splitPoints.ping(); // not updated using .setData, so manually ping observers } // When clicked, pass clicked location coordinates to onMapClick function @@ -88,19 +87,16 @@ export default class SplitRoadWizard extends Toggle { State.state.osmConnection.isLoggedIn) // Save button - const saveButton = new Button("Split here", () => splitRoad(id, splitPositions.data)); + const saveButton = new Button("Split here", () => splitAction.DoSplit(splitPoints.data)); saveButton.SetClass("block btn btn-primary"); const disabledSaveButton = new Button("Split here", undefined); disabledSaveButton.SetClass("block btn btn-disabled"); // Only show the save button if there are split points defined - const saveToggle = new Toggle(disabledSaveButton, saveButton, splitPositions.map((data) => data.length === 0)) + const saveToggle = new Toggle(disabledSaveButton, saveButton, splitPoints.map((data) => data.length === 0)) const cancelButton = new Button("Cancel", () => { splitClicked.setData(false); - - splitPositions.setData([]); - // Only keep showing the road, the cutpoints must be removed from the map - roadEventSource.setData([roadEventSource.data[0]]) + splitPoints.setData([]); }); cancelButton.SetClass("block btn btn-secondary"); @@ -111,4 +107,21 @@ export default class SplitRoadWizard extends Toggle { super(mapView, splitToggle, splitClicked); } + + private static GetSplitLayout(): LayoutConfig { + return new LayoutConfig({ + maintainer: "mapcomplete", + language: [], + startLon: 0, + startLat: 0, + description: undefined, + icon: "", startZoom: 0, + title: "Split locations", + version: "", + + id: "splitpositions", + layers: [{id: "splitpositions", source: {osmTags: "_cutposition=yes"}, icon: "./assets/svg/plus.svg"}] + }, true, "split road wizard layout") + + } } \ No newline at end of file diff --git a/test.ts b/test.ts index 3357bf6455..9b632dbe69 100644 --- a/test.ts +++ b/test.ts @@ -1,6 +1,5 @@ -import SplitRoadWizard from "./UI/Popup/SplitRoadWizard"; -import State from "./State"; -import {AllKnownLayouts} from "./Customizations/AllKnownLayouts"; +import SplitAction from "./Logic/Osm/SplitAction"; +import {GeoOperations} from "./Logic/GeoOperations"; const way = { "type": "Feature", @@ -47,7 +46,31 @@ const way = { } } -State.state = new State(AllKnownLayouts.allKnownLayouts.get("fietsstraten")); +let splitPoint = { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + 4.490211009979248, + 51.2041509326002 + ] + } +} + + +let splitClose = { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + 4.489563927054405, + 51.2047546593862 + ] + } +} +// State.state = new State(AllKnownLayouts.allKnownLayouts.get("fietsstraten")); // add road to state -State.state.allElements.addOrGetElement(way); -new SplitRoadWizard("way/23583625").AttachTo("maindiv") \ No newline at end of file +// State.state.allElements.addOrGetElement(way); +new SplitAction(way).DoSplit([splitPoint, splitClose].map(p => GeoOperations.nearestPoint(way,<[number, number]> p.geometry.coordinates))) \ No newline at end of file