conveyal / r5

Developed to power Conveyal's web-based interface for scenario planning and land-use/transport accessibility analysis, R5 is our routing engine for multimodal (transit/bike/walk/car) networks with a particular focus on public transit
https://conveyal.com/learn
MIT License
287 stars 74 forks source link

R5 fails on shapes with only one point #559

Open abyrd opened 4 years ago

abyrd commented 4 years ago

Using GTFS from http://gtfs.ovapi.nl/ Marco at Movares reports:

Error processing GTFS. Please upload valid GTFS .zip files.
Invalid number of points in LineString (found 1 - must be 0 or >= 2) java.lang.IllegalArgumentException: Invalid number of points in LineString (found 1 - must be 0 or >= 2)
at com.vividsolutions.jts.geom.LineString.init(LineString.java:102)
at com.vividsolutions.jts.geom.LineString.<init>(LineString.java:93)
at com.vividsolutions.jts.geom.GeometryFactory.createLineString(GeometryFactory.java:539)
at com.vividsolutions.jts.geom.GeometryFactory.createLineString(GeometryFactory.java:531)
at com.conveyal.gtfs.model.Shape.<init>(Shape.java:28)
at com.conveyal.gtfs.GTFSFeed.getShape(GTFSFeed.java:386)
at com.conveyal.gtfs.GTFSFeed.getTripGeometry(GTFSFeed.java:692)
at com.conveyal.gtfs.model.Pattern.<init>(Pattern.java:50)
at com.conveyal.gtfs.GTFSFeed.lambda$findPatterns$10(GTFSFeed.java:523)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.conveyal.gtfs.GTFSFeed.findPatterns(GTFSFeed.java:524)
at com.conveyal.gtfs.BaseGTFSCache.put(BaseGTFSCache.java:135)
at com.conveyal.gtfs.BaseGTFSCache.put(BaseGTFSCache.java:118)
at com.conveyal.gtfs.api.ApiMain.registerFeedSource(ApiMain.java:68)
at com.conveyal.taui.controllers.BundleController.lambda$create$1(BundleController.java:139)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

We need to either tolerate this and log an error, or throw an exception containing a clearer description of the problem and a specific shape or trip ID.

It is noteworthy that for analysis work we don't even need the shapes, so it's kind of a shame that bad shape data can halt the import process.

abyrd commented 4 years ago

com.conveyal.gtfs.GTFSFeed#getShape returns null if the Shape has a zero-length shape_dist_traveled array. So if the Shape constructor hits an exception, it could set its fields to have an empty geometry and empty shape_dist_traveled array; alternatively the getShape method could catch exceptions and return null. Either way, more Javadoc should be added to explain error conditions and return values.