Skip to content

Commit

Permalink
fix(splitting): preserve geometry
Browse files Browse the repository at this point in the history
Fixes #511
  • Loading branch information
ansoncfit committed Jun 5, 2019
1 parent 70490cc commit 9e80edb
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 4 deletions.
27 changes: 27 additions & 0 deletions src/main/java/com/conveyal/r5/streets/EdgeStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<int[]> splitGeometryAfter(int segment) {
// Original packed coordinates of edge
int[] original = geometries.get(pairIndex);
ArrayList<int[]> 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<Node> nodes) {
// The same empty int array represents all straight-line edges.
if (nodes.size() <= 2) {
Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/conveyal/r5/streets/Split.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/com/conveyal/r5/streets/StreetLayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -1170,16 +1170,16 @@ 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<int[]> 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.
// Modify the existing bidirectional edge pair to serve as the first segment leading up to the split point.
// 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.
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/test/java/com/conveyal/r5/streets/StreetLayerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit 9e80edb

Please sign in to comment.