From 7c0057b8571768cecd75dc3c88f27ac4128fc902 Mon Sep 17 00:00:00 2001 From: Andrew Byrd Date: Wed, 26 Jun 2019 18:29:57 +0800 Subject: [PATCH] fix(shapefile): extend shapes before performing noding Previously, it was noding before extending roads, because the intent was to detect and extend only dead-end segments after a first pass of noding. No reasonable way was found to detect post-noding dead ends, so instead we're extending every shape by a few meters before noding. This makes the network significantly more complex but it works. --- .../conveyal/r5/shapefile/ShapefileMain.java | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/conveyal/r5/shapefile/ShapefileMain.java b/src/main/java/com/conveyal/r5/shapefile/ShapefileMain.java index 69b7ab747..de263e378 100644 --- a/src/main/java/com/conveyal/r5/shapefile/ShapefileMain.java +++ b/src/main/java/com/conveyal/r5/shapefile/ShapefileMain.java @@ -89,7 +89,8 @@ private void run () throws Throwable { // Load base network. LTS attributes are: LTSV2 LTSDV2 MVILTS MVIVLTS LTS_ACC loadShapefileIntoSegmentStrings("/Users/abyrd/geodata/bogota/ltsnets/Red_LTS_DPr.shp", "LTSDV1"); - // Create nodes where SegmentStrings cross, project into WGS84 and convert to OSM data. + extendSegmentStrings(); + performIndexNodingWithPrecision(); osm.writeToFile("output.osm.pbf"); @@ -139,32 +140,19 @@ private void loadShapefileIntoSegmentStrings (String filename, String ltsAttribu * Use the code provided by JTS for "noding", i.e. creating shared nodes at each place where shapes cross each other. */ private void performIndexNodingWithPrecision () { + PrecisionModel fixedPM = new PrecisionModel(1); LineIntersector li = new RobustLineIntersector(); li.setPrecisionModel(fixedPM); Noder noder = new MCIndexNoder(new IntersectionAdder(li)); - // Noder noder = new MCIndexNoder(new IntersectionAdder(new RobustLineIntersector())); - // Noder noder = new IteratedNoder(new PrecisionModel()); - // This call should modify the segment strings in place, inserting new nodes. - noder.computeNodes(allSegmentStrings); - - // Overwrite the existing allSegmentStrings with freshly created SegmentStrings. - allSegmentStrings = extendSegmentStrings(noder.getNodedSubstrings()); - - // Create a new intersector and noder for good measure, and re-run the operation with extended SegmentStrings. - // noder = new MCIndexNoder(new IntersectionAdder(new RobustLineIntersector())); - li = new RobustLineIntersector(); - li.setPrecisionModel(fixedPM); - noder = new MCIndexNoder(new IntersectionAdder(li)); // noder = new IteratedNoder(new PrecisionModel()); noder.computeNodes(allSegmentStrings); + // NB: based on experience, you must call getNodedSubstrings to splice the nodes into the coordinate list. - // The segments are not modified in place. + // The input SegmentStrings are not fully modified in place. allSegmentStrings = (List) (noder.getNodedSubstrings()); for (NodedSegmentString segmentString : allSegmentStrings) { - // The following gets only the nodes (intersections with other SegmentStrings) not the intermediate coords: - // SegmentNodeList segmentNodeList = segmentString.getNodeList(); TLongList nodesInWay = new TLongArrayList(); for (Coordinate sourceCoordinate : segmentString.getCoordinates()) { // Perform rounding in source CRS which is should be in isotropic meters. @@ -192,10 +180,10 @@ private void performIndexNodingWithPrecision () { * Detection of dead ends via node-coordinate comparison seems to fail, so currently extending all shapes at both ends. * This is overkill but should work. It seems like the endpoints of every SegmentString are considered nodes. */ - private static List extendSegmentStrings (Collection inputSegmentStrings) { - final double DIST_TO_EXTEND = 5; // source CRS units, usually meters. + private void extendSegmentStrings () { + final double DIST_TO_EXTEND = 4; // source CRS units, usually meters. List outputSegmentStrings = new ArrayList<>(); - for (NodedSegmentString segmentString : inputSegmentStrings) { + for (NodedSegmentString segmentString : allSegmentStrings) { Coordinate [] coordinates = segmentString.getCoordinates(); // Remove repeated coordinates in the incoming geometries. // Repeated geometries lead to zero lengths, which lead to division by zero, yielding NaN coordinates which @@ -231,7 +219,8 @@ private static List extendSegmentStrings (Collection