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