From 591048f46df4031f73a51bb35fb341b88f27a314 Mon Sep 17 00:00:00 2001 From: Andrew Byrd Date: Fri, 5 Apr 2024 19:14:53 +0900 Subject: [PATCH] CropGTFS: remove taxi modes and transfers also added polygon for Stockholm, Sweden --- src/main/java/com/conveyal/gtfs/CropGTFS.java | 67 +++++++++++++++---- .../java/com/conveyal/gtfs/Geometries.java | 4 ++ .../com/conveyal/r5/transit/TransitLayer.java | 2 +- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/conveyal/gtfs/CropGTFS.java b/src/main/java/com/conveyal/gtfs/CropGTFS.java index 999d5f34a..e3856f0c9 100644 --- a/src/main/java/com/conveyal/gtfs/CropGTFS.java +++ b/src/main/java/com/conveyal/gtfs/CropGTFS.java @@ -1,5 +1,6 @@ package com.conveyal.gtfs; +import com.conveyal.gtfs.model.Route; import com.conveyal.gtfs.model.Stop; import com.conveyal.gtfs.model.StopTime; import com.conveyal.gtfs.model.Transfer; @@ -18,23 +19,20 @@ import java.util.Set; /** - * Remove all stops outside the bounding box, - * then remove all stop_times outside the bounding box, - * recording all trips with two or more stop_times inside the bounding box. - * Then remove all trips with no stoptimes or one single stoptime, - * then remove all transfers whose stops have been removed. - * - * Note that this does not crop the GTFS shapes, only the stops and stoptimes. - * Therefore in some tools like Transport Analyst, the data set will appear to extend beyond the bounding box - * because the entire shapes are drawn. + * Remove all stops outside the bounding box, then remove all stop_times outside the bounding box, recording all + * trips with two or more stop_times inside the bounding box. Then remove all trips with no stoptimes or one single + * stoptime, and remove all transfers whose stops have been removed. + * Also removes all routes with route_types that we don't support (TPEG >= 1500). + * Note that this does not crop the GTFS shapes, only the stops and stoptimes. Therefore, in tools like the R5 web UI, + * the data set will appear to extend beyond the bounding box because the entire shapes are drawn. */ public class CropGTFS { // Logger is not super useful because as a library, gtfs-lib has no logger implementation defined by default. private static final Logger LOG = LoggerFactory.getLogger(CropGTFS.class); - private static final String inputFile = "/Users/abyrd/test-est/gtfs_fr-cha_pourOAD.zip"; - private static final String outputFile = ""; //"/Users/abyrd/geodata/nl/NL-2016-08-23-noplatforms-noshapes.gtfs.zip"; + private static final String inputFile = "/Users/abyrd/data/stockholm/sweden.gtfs.zip"; + private static final String outputFile = "/Users/abyrd/data/stockholm/stockholm-filtered.gtfs.zip"; // Replace all stops with their parent stations to simplify trip patterns. private static final boolean MERGE_STATIONS = true; @@ -42,6 +40,12 @@ public class CropGTFS { // Remove all shapes from the GTFS to make it simpler to render in a web UI private static final boolean REMOVE_SHAPES = true; + // Remove all routes with taxi and car modes, as well as trips and stoptimes that reference them transitively. + private static final boolean REMOVE_UNSUPPORTED_MODES = true; + + // Remove all transfers before writing out. + private static final boolean REMOVE_TRANSFERS = true; + public static void main (String[] args) { GTFSFeed feed = GTFSFeed.writableTempFileFromGtfs(inputFile); @@ -52,7 +56,43 @@ public static void main (String[] args) { Set retainedTripIds = new HashSet<>(); // The geometry within which we will keep all stops - Geometry bounds = Geometries.getNetherlandsWithoutTexel(); + Geometry bounds = Geometries.getStockholm(); + + if (REMOVE_UNSUPPORTED_MODES) { + System.out.println("Removing routes with unsupported route_type (mode of transport)..."); + Set routeIdsRemoved = new HashSet<>(); + for (Iterator routeIterator = feed.routes.values().iterator(); routeIterator.hasNext(); ) { + Route route = routeIterator.next(); + if (route.route_type >= 1500) { + routeIterator.remove(); + routeIdsRemoved.add(route.route_id); + } + } + Set tripIdsRemoved = new HashSet<>(); + for (Iterator tripIterator = feed.trips.values().iterator(); tripIterator.hasNext(); ) { + Trip trip = tripIterator.next(); + if (routeIdsRemoved.contains(trip.route_id)) { + tripIterator.remove(); + tripIdsRemoved.add(trip.trip_id); + } + } + int nStopTimesRemoved = 0; + for (Iterator it = feed.stop_times.values().iterator(); it.hasNext(); ) { + StopTime st = it.next(); + if (tripIdsRemoved.contains(st.trip_id)) { + it.remove(); + nStopTimesRemoved += 1; + } + } + System.out.println("Number of routes removed: " + routeIdsRemoved.size()); + System.out.println("Number of trips removed: " + tripIdsRemoved.size()); + System.out.println("Number of stop_times removed: " + nStopTimesRemoved); + } + + if (REMOVE_TRANSFERS) { + feed.transfers.clear(); + System.out.println("Removed all transfers."); + } System.out.println("Removing stops outside bounding box..."); Map stopIdReplacements = new HashMap<>(); // Used when collapsing stops into stations. @@ -75,6 +115,7 @@ public static void main (String[] args) { } if (MERGE_STATIONS) { + int nUpdated = 0; System.out.println("Replacing stop_ids in stop_times with those of their parent stations..."); for (Fun.Tuple2 key : feed.stop_times.keySet()) { StopTime stopTime = feed.stop_times.get(key); @@ -83,8 +124,10 @@ public static void main (String[] args) { // Entry.setValue is an unsupported operation in MapDB, just re-put the StopTime. stopTime.stop_id = replacementStopId; feed.stop_times.put(key, stopTime); + nUpdated += 1; } } + System.out.println("Number of stop_times updated: " + nUpdated); } if (REMOVE_SHAPES) { diff --git a/src/main/java/com/conveyal/gtfs/Geometries.java b/src/main/java/com/conveyal/gtfs/Geometries.java index a981b3e9b..e13f41384 100644 --- a/src/main/java/com/conveyal/gtfs/Geometries.java +++ b/src/main/java/com/conveyal/gtfs/Geometries.java @@ -508,4 +508,8 @@ public static Geometry getZuidHolland() { return geometryFactory.toGeometry(new Envelope(4.002074, 4.98848, 51.696796, 52.278661)); } + public static Geometry getStockholm() { + // return geometryFactory.toGeometry(new Envelope(16.96617,19.42143, 58.59599,60.49487)); + return geometryFactory.toGeometry(new Envelope(17.21558,19.23706,58.79098,60.17157)); + } } diff --git a/src/main/java/com/conveyal/r5/transit/TransitLayer.java b/src/main/java/com/conveyal/r5/transit/TransitLayer.java index f978d5a5e..2466d922a 100644 --- a/src/main/java/com/conveyal/r5/transit/TransitLayer.java +++ b/src/main/java/com/conveyal/r5/transit/TransitLayer.java @@ -697,7 +697,7 @@ public static TransitModes getTransitModes(int routeType) { return TransitModes.FERRY; } else if (routeType >= 1300 && routeType < 1400) { //Telecabin Service return TransitModes.GONDOLA; - } else if (routeType >= 1400 && routeType < 1500) { //Funicalar Service + } else if (routeType >= 1400 && routeType < 1500) { //Funicular Service return TransitModes.FUNICULAR; } else if (routeType >= 1500 && routeType < 1600) { //Taxi Service throw new IllegalArgumentException("Taxi route_type code not supported: " + routeType);