Skip to content

Commit

Permalink
accept GTFS with pathway stop location_types
Browse files Browse the repository at this point in the history
This is the first step of #803.
It will gracefully ignore pathway nodes and reduce errors, but does not
yet build the routable edges inside the stations.
  • Loading branch information
abyrd committed Apr 15, 2022
1 parent 43068e1 commit f0c81a1
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ static class StopApiResponse extends BaseApiResponse {
}
}
/**
* Return StopApiResponse values for GTFS stops (location_type = 0) in a single feed
* Return StopApiResponse values for GTFS stops (location_type = 0) in a single feed.
* All other location_types (station, entrance, generic node, boarding area) are skipped.
*/
private List<StopApiResponse> getAllStopsForOneFeed(Request req, Response res) {
GTFSFeed feed = getFeedFromRequest(req);
Expand All @@ -160,8 +161,8 @@ private List<StopApiResponse> getAllStopsForOneFeed(Request req, Response res) {
}

/**
* Groups the feedId and stops (location_type = 0; not parent stations, entrances/exits, generic nodes, etc.) for a
* given GTFS feed
* Compound return type for the feedId and stops with location_type = 0 for a given GTFS feed.
* All other location_types (station, entrance, generic node, boarding area) are skipped.
*/
static class FeedGroupStopsApiResponse {
public final String feedId;
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/conveyal/gtfs/GTFSCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ private void buildStopsIndex (String bundleScopedFeedId, STRtree tree) {
final GTFSFeed feed = this.get(bundleScopedFeedId);
LOG.info("{}: indexing {} stops", feed.feedId, feed.stops.size());
for (Stop stop : feed.stops.values()) {
// To match existing GTFS API, include only stop objects that have location_type 0.
// All other location_types (station, entrance, generic node, boarding area) are skipped.
// Missing (NaN) coordinates will confuse the spatial index and cascade hundreds of errors.
if (stop.location_type != 0 || !Double.isFinite(stop.stop_lat) || !Double.isFinite(stop.stop_lon)) {
continue;
}
Envelope stopEnvelope = new Envelope(stop.stop_lon, stop.stop_lon, stop.stop_lat, stop.stop_lat);
Point point = GeometryUtils.geometryFactory.createPoint(new Coordinate(stop.stop_lon, stop.stop_lat));

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/conveyal/gtfs/model/Calendar.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public Loader(GTFSFeed feed, Map<String, Service> services) {

@Override
protected boolean isRequired() {
return true;
// One of calendar or calendar_dates must be present - check in more flexible modular validation later.
return false;
}

@Override
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/conveyal/gtfs/model/CalendarDate.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public Loader(GTFSFeed feed, Map<String, Service> services) {

@Override
protected boolean isRequired() {
// One of calendar or calendar_dates must be present - check in more flexible modular validation later.
return false;
}

Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/conveyal/gtfs/model/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ protected URL getUrlField(String column, boolean required) throws IOException {
return url;
}

/** @return NaN if the number is missing or cannot be parsed. */
protected double getDoubleField(String column, boolean required, double min, double max) throws IOException {
String str = getFieldCheckRequired(column, required);
double val = Double.NaN;
Expand Down
15 changes: 9 additions & 6 deletions src/main/java/com/conveyal/gtfs/model/Stop.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,20 @@ public void loadOneRow() throws IOException {
s.stop_code = getStringField("stop_code", false);
s.stop_name = getStringField("stop_name", true);
s.stop_desc = getStringField("stop_desc", false);
s.stop_lat = getDoubleField("stop_lat", true, -90D, 90D);
s.stop_lon = getDoubleField("stop_lon", true, -180D, 180D);
s.zone_id = getStringField("zone_id", false);
s.stop_url = getUrlField("stop_url", false);
s.location_type = getIntField("location_type", false, 0, 1);
s.parent_station = getStringField("parent_station", false);
s.stop_timezone = getStringField("stop_timezone", false);
s.location_type = getIntField("location_type", false, 0, 4);
// 0...2 are stop, station, and entrance which must have lat and lon. Other nodes do not need coordinates.
boolean coord_required = s.location_type > 2;
s.stop_lat = getDoubleField("stop_lat", coord_required, -90D, 90D);
s.stop_lon = getDoubleField("stop_lon", coord_required, -180D, 180D);
// Required for entrances, generic nodes, and boarding areas. Optional for stops, forbidden for stations.
boolean parent_station_required = s.location_type >= 2;
s.parent_station = getStringField("parent_station", parent_station_required);
s.stop_timezone = getStringField("stop_timezone", parent_station_required);
s.wheelchair_boarding = getStringField("wheelchair_boarding", false);
s.feed_id = feed.feedId;
/* TODO check ref integrity later, this table self-references via parent_station */

feed.stops.put(s.stop_id, s);
}

Expand Down

0 comments on commit f0c81a1

Please sign in to comment.