Skip to content

Commit

Permalink
tolerate routes with no explicit shapes
Browse files Browse the repository at this point in the history
report their quantity as a scenario application info message
  • Loading branch information
abyrd committed Jan 11, 2024
1 parent 3cd6b6c commit fa02518
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 18 deletions.
11 changes: 10 additions & 1 deletion src/main/java/com/conveyal/r5/analyst/scenario/SelectLink.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public class SelectLink extends Modification {

private Map<String, GTFSFeed> feedForUnscopedId;

private int nPatternsWithoutShapes = 0;

@Override
public boolean resolve(TransportNetwork network) {
// Convert the incoming description of the selected link area to a Geometry for computing intersections.
Expand Down Expand Up @@ -87,6 +89,9 @@ public boolean apply(TransportNetwork network) {
String feedId = feedIdForTripPattern(tripPattern);
GTFSFeed feed = feedForUnscopedId.get(feedId);
TransitLayer.addShapeToTripPattern(feed, tripPattern);
if (tripPattern.shape == null) {
nPatternsWithoutShapes += 1;
}
// TransitLayer parameter enables fetching straight lines between stops in case shapes are not present.
List<LineString> hopGeometries = tripPattern.getHopGeometries(network.transitLayer);
TIntArrayList intersectedHops = new TIntArrayList();
Expand All @@ -100,7 +105,11 @@ public boolean apply(TransportNetwork network) {
hopsInTripPattern.put(patternIndex, intersectedHops.toArray());
}
}

if (nPatternsWithoutShapes > 0) {
addInfo( "Out of %d patterns, %d had no shapes and used straight lines.".formatted(
network.transitLayer.tripPatterns.size(), nPatternsWithoutShapes
));
}
// After finding all links (TripPattern hops) in the SelectedLink area, release the GTFSFeeds which don't really
// belong in a Modification. This avoids memory leaks, and protects us from inadvertently relying on or
// modifying those feed objects later.
Expand Down
39 changes: 22 additions & 17 deletions src/main/java/com/conveyal/r5/transit/TransitLayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -439,45 +439,50 @@ public static void addShapeToTripPattern (
TripPattern tripPattern
) {
// First, find an exemplar trip that is representative of the TripPattern.
boolean foundExemplarTrip = false;
Trip trip = null;
Iterable<StopTime> stopTimes = null;
for (TripSchedule tripSchedule : tripPattern.tripSchedules) {
// In constructor, TripSchedule.tripId = String.join(":", trip.feed_id, trip.trip_id);
// In constructor, TripSchedule.tripId is set to String.join(":", trip.feed_id, trip.trip_id).
String[] tripIdParts = tripSchedule.tripId.split(":");
if (!tripIdParts[0].equals(gtfsFeed.feedId)) {
LOG.warn("Feed ID scope of trip ID for TripSchedule in TripPattern does not match supplied GTFS feed.");
continue;
}
String unscopedTripId = tripIdParts[1];
trip = gtfsFeed.trips.get(unscopedTripId);
if (trip == null) {
Trip candidateTrip = gtfsFeed.trips.get(unscopedTripId);
if (candidateTrip == null) {
LOG.warn("Could not find trip for unscoped ID " + unscopedTripId);
continue;
}
if (trip.shape_id == null) {
continue;
if (trip == null || candidateTrip.shape_id != null) {
try {
// FIXME here and below: why did we need interpolated stop times? We are only the positions right?
Iterable<StopTime> candidateStopTimes = gtfsFeed.getInterpolatedStopTimesForTrip(unscopedTripId);
// Iterable<StopTime> candidateStopTimes = gtfsFeed.getOrderedStopTimesForTrip(unscopedTripId);
// All checks succeeded, retain the information from this trip as the exemplar for the pattern.
trip = candidateTrip;
stopTimes = candidateStopTimes;
} catch (GTFSFeed.FirstAndLastStopsDoNotHaveTimes e) {
continue;
}
}
try {
stopTimes = gtfsFeed.getInterpolatedStopTimesForTrip(unscopedTripId);
} catch (GTFSFeed.FirstAndLastStopsDoNotHaveTimes e) {
continue;
if (candidateTrip.shape_id != null) {
// Found exemplar trip with explicit shape, no need to search further.
// Otherwise, we found a suitable trip but its shape will be composed of straight lines.
// Retain it, but continue iterative search for trips in pattern having explicit shapes.
break;
}
// All checks succeeded, record the information from this trip as the exemplar for the pattern.
foundExemplarTrip = true;
break;
}
// Could add a possibly slow check: get each trip, check if exemplarTrip.shapeId equals shape in each trip.
// LOG.warn(String.format("Multiple trips in the same TripPattern have different shapes (e.g. %s and %s)")

if (!foundExemplarTrip) {
LOG.warn("Did not find any exemplar trip with usable Shape and StopTimes for pattern " + tripPattern);
if (trip == null) {
LOG.warn("Did not find any exemplar trip with usable StopTimes for pattern " + tripPattern);
return;
}
// This is assigned outside the loop only to make it final, as required by lambdas below.
final Shape shape = gtfsFeed.getShape(trip.shape_id);
if (shape == null) {
LOG.error("Shape {} for trip {} was missing", trip.shape_id, trip.trip_id);
LOG.debug("Trip {} has no explicit shape, straight lines will be used.", trip.trip_id, trip.shape_id);
return;
}
tripPattern.shape = shape.geometry;
Expand Down

0 comments on commit fa02518

Please sign in to comment.