diff --git a/src/main/java/com/conveyal/r5/streets/EdgeStore.java b/src/main/java/com/conveyal/r5/streets/EdgeStore.java index 0e9e3ed93..7f03d0ab1 100644 --- a/src/main/java/com/conveyal/r5/streets/EdgeStore.java +++ b/src/main/java/com/conveyal/r5/streets/EdgeStore.java @@ -30,6 +30,7 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.Set; @@ -728,6 +729,32 @@ public boolean canTurnFrom(StreetRouter.State s0, StreetRouter.State s1, return true; } + /** + * Cut the packed list of intermediate coordinates in two after specified segment + * @return List with first element int[] of coordinates before end of specified segment, and second element + * int[] of coordinates after end of specified segment. + */ + public ArrayList splitGeometryAfter(int segment) { + // Original packed coordinates of edge + int[] original = geometries.get(pairIndex); + ArrayList geoms = new ArrayList<>(); + geoms.add(Arrays.copyOfRange(original, 0, segment * 2)); // Multiply by 2 because packed array + geoms.add(Arrays.copyOfRange(original, segment * 2, original.length + 1)); + return geoms; + } + + /** + * Set intermediate coordinates directly with packed array + * @param coordinates Packed lists of lat, lon, lat, lon... as fixed-point integers + */ + public void setGeometry (int[] coordinates) { + geometries.set(pairIndex, coordinates); + calculateAngles(); + } + + /** + * Set intermediate coordinates from OSM nodes + */ public void setGeometry (List nodes) { // The same empty int array represents all straight-line edges. if (nodes.size() <= 2) { diff --git a/src/main/java/com/conveyal/r5/streets/Split.java b/src/main/java/com/conveyal/r5/streets/Split.java index b7ad5b570..85307b088 100644 --- a/src/main/java/com/conveyal/r5/streets/Split.java +++ b/src/main/java/com/conveyal/r5/streets/Split.java @@ -156,7 +156,6 @@ public static Split find (double lat, double lon, double searchRadiusMeters, Str // We found an edge. Iterate over its segments again, accumulating distances along its geometry. // The distance calculations involve square roots so are deferred to happen here, only on the selected edge. - // TODO accumulate before/after geoms. Split point can be passed over since it's not an intermediate. // The length is are stored in one-element array to dodge Java's "effectively final" BS. edge.seek(best.edge); best.vertex0 = edge.getFromVertex(); diff --git a/src/main/java/com/conveyal/r5/streets/StreetLayer.java b/src/main/java/com/conveyal/r5/streets/StreetLayer.java index 6e6870f07..09de3da18 100644 --- a/src/main/java/com/conveyal/r5/streets/StreetLayer.java +++ b/src/main/java/com/conveyal/r5/streets/StreetLayer.java @@ -1170,6 +1170,7 @@ public int getOrCreateVertexNear(double lat, double lon, StreetMode streetMode) // The split is somewhere along a street away from an existing intersection vertex. Make a new splitter vertex. int newVertexIndex = vertexStore.addVertexFixed((int) split.fixedLat, (int) split.fixedLon); int oldToVertex = edge.getToVertex(); // Hold a copy of the to vertex index, because it may be modified below. + ArrayList geoms = new ArrayList<>(); if (edge.isMutable()) { // The edge we are going to split is mutable. // We're either building a baseline graph, or modifying an edge created within the same scenario. @@ -1177,9 +1178,8 @@ public int getOrCreateVertexNear(double lat, double lon, StreetMode streetMode) // Its spatial index entry is still valid, since the edge's envelope will only shrink. edge.setLengthMm(split.distance0_mm); edge.setToVertex(newVertexIndex); - // Turn the edge into a straight line. - // FIXME split edges and new edges should have geometries! - edge.setGeometry(Collections.EMPTY_LIST); + geoms = edge.splitGeometryAfter(split.seg); + edge.setGeometry(geoms.get(0)); } else { // The edge we are going to split is immutable, and should be left as-is. // We must be applying a scenario, and this edge is part of the baseline graph shared between threads. @@ -1207,6 +1207,9 @@ public int getOrCreateVertexNear(double lat, double lon, StreetMode streetMode) EdgeStore.Edge newEdge1 = edgeStore.addStreetPair(newVertexIndex, oldToVertex, split.distance1_mm, edge.getOSMID()); // Copy the flags and speeds for both directions, making newEdge1 like the existing edge. newEdge1.copyPairFlagsAndSpeeds(edge); + + if (geoms.size() > 1) newEdge1.setGeometry(geoms.get(1)); + // Insert the new edge into the spatial index if (!edgeStore.isExtendOnlyCopy()) { spatialIndex.insert(newEdge1.getEnvelope(), newEdge1.edgeIndex); diff --git a/src/test/java/com/conveyal/r5/streets/StreetLayerTest.java b/src/test/java/com/conveyal/r5/streets/StreetLayerTest.java index 04c93bd2a..c5af8c3b8 100644 --- a/src/test/java/com/conveyal/r5/streets/StreetLayerTest.java +++ b/src/test/java/com/conveyal/r5/streets/StreetLayerTest.java @@ -122,6 +122,9 @@ public void testSplits() throws Exception { //assertEquals(backwardEdgeName, newBackwardEdge.getName()); //streetLayer.edgeStore.dump(); + + // TODO: check lengths and geometries of curvilinear edges after repeated splitting + } /** Test that simple turn restrictions (no via ways) are read properly, using http://www.openstreetmap.org/relation/5696764 */