package org.opentripplanner.graph_builder.module; import com.conveyal.gtfs.GTFSFeed; import com.conveyal.gtfs.model.*; import org.mapdb.Fun; import org.onebusaway.gtfs.model.AgencyAndId; import org.onebusaway.gtfs.model.Stop; import org.opentripplanner.graph_builder.linking.SimpleStreetSplitter; import org.opentripplanner.graph_builder.model.GtfsBundle; import org.opentripplanner.graph_builder.module.osm.DefaultWayPropertySetSource; import org.opentripplanner.graph_builder.module.osm.OpenStreetMapModule; import org.opentripplanner.openstreetmap.impl.AnyFileBasedOpenStreetMapProviderImpl; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.vertextype.TransitStop; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * Get fake graphs. */ public class FakeGraph { /** frequency of trips generated by addTransit, seconds */ public static final int FREQUENCY = 600; /** Travel time between stops of trips generated by addTransit, seconds */ public static final int TRAVEL_TIME = 500; /** Build a graph in Columbus, OH with no transit */ public static Graph buildGraphNoTransit () throws UnsupportedEncodingException { Graph gg = new Graph(); OpenStreetMapModule loader = new OpenStreetMapModule(); loader.setDefaultWayPropertySetSource(new DefaultWayPropertySetSource()); AnyFileBasedOpenStreetMapProviderImpl provider = new AnyFileBasedOpenStreetMapProviderImpl(); File file = new File( URLDecoder.decode(FakeGraph.class.getResource("columbus.osm.pbf").getFile(), "UTF-8")); provider.setPath(file); loader.setProvider(provider); loader.buildGraph(gg, new HashMap<Class<?>, Object>()); return gg; } /** Add transit (not just stops) to a Columbus graph */ public static void addTransit (Graph gg) throws Exception { // using conveyal GTFS lib to build GTFS so a lot of code does not have to be rewritten later // once we're using the conveyal GTFS lib for everything we ought to be able to do this // without even writing out the GTFS to a file. GTFSFeed feed = new GTFSFeed(); Agency a = createDummyAgency("agency", "Agency", "America/New_York"); feed.agency.put("agency", a); Route r = new Route(); r.route_short_name = "1"; r.route_long_name = "High Street"; r.route_type = 3; r.agency = a; r.route_id = "route"; feed.routes.put(r.route_id, r); Service s = createDummyService(); feed.services.put(s.service_id, s); com.conveyal.gtfs.model.Stop s1 = new com.conveyal.gtfs.model.Stop(); s1.stop_id = s1.stop_name = "s1"; s1.stop_lat = 40.2182; s1.stop_lon = -83.0889; feed.stops.put(s1.stop_id, s1); com.conveyal.gtfs.model.Stop s2 = new com.conveyal.gtfs.model.Stop(); s2.stop_id = s2.stop_name = "s2"; s2.stop_lat = 39.9621; s2.stop_lon = -83.0007; feed.stops.put(s2.stop_id, s2); // make timetabled trips for (int departure = 7 * 3600; departure < 20 * 3600; departure += FREQUENCY) { Trip t = new Trip(); t.trip_id = "trip" + departure; t.service = s; t.route = r; feed.trips.put(t.trip_id, t); StopTime st1 = new StopTime(); st1.trip_id = t.trip_id; st1.arrival_time = departure; st1.departure_time = departure; st1.stop_id = s1.stop_id; st1.stop_sequence = 1; feed.stop_times.put(new Fun.Tuple2(st1.trip_id, st1.stop_sequence), st1); StopTime st2 = new StopTime(); st2.trip_id = t.trip_id; st2.arrival_time = departure + TRAVEL_TIME; st2.departure_time = departure + TRAVEL_TIME; st2.stop_sequence = 2; st2.stop_id = s2.stop_id; feed.stop_times.put(new Fun.Tuple2(st2.trip_id, st2.stop_sequence), st2); } File tempFile = File.createTempFile("gtfs", ".zip"); feed.toFile(tempFile.getAbsolutePath()); // phew. load it into the graph. GtfsModule gtfs = new GtfsModule(Arrays.asList(new GtfsBundle(tempFile))); gtfs.buildGraph(gg, new HashMap<>()); } /** Add many transit lines to a lot of stops */ public static void addTransitMultipleLines (Graph g) throws Exception { // using conveyal GTFS lib to build GTFS so a lot of code does not have to be rewritten later // once we're using the conveyal GTFS lib for everything we ought to be able to do this // without even writing out the GTFS to a file. GTFSFeed feed = new GTFSFeed(); Agency a = createDummyAgency("agency", "Agency", "America/New_York"); feed.agency.put("agency", a); Route r = new Route(); r.route_short_name = "1"; r.route_long_name = "High Street"; r.route_type = 3; r.agency = a; r.route_id = "route"; feed.routes.put(r.route_id, r); Service s = createDummyService(); feed.services.put(s.service_id, s); int stopIdx = 0; while (stopIdx < 10000) { com.conveyal.gtfs.model.Stop s1 = new com.conveyal.gtfs.model.Stop(); s1.stop_id = s1.stop_name = "s" + stopIdx++; s1.stop_lat = 39.9354 + (stopIdx % 100) * 1e-3; s1.stop_lon = -83.0589 + (stopIdx / 100) * 1e-3; feed.stops.put(s1.stop_id, s1); com.conveyal.gtfs.model.Stop s2 = new com.conveyal.gtfs.model.Stop(); s2.stop_id = s2.stop_name = "s" + stopIdx++; s2.stop_lat = 39.9354 + (stopIdx % 100) * 1e-3; s2.stop_lon = -83.0589 + (stopIdx / 100) * 1e-3; feed.stops.put(s2.stop_id, s2); // make timetabled trips int departure = 8 * 3600; Trip t = new Trip(); t.trip_id = "trip" + departure + "_" + stopIdx; t.service = s; t.route = r; feed.trips.put(t.trip_id, t); StopTime st1 = new StopTime(); st1.trip_id = t.trip_id; st1.arrival_time = departure; st1.departure_time = departure; st1.stop_id = s1.stop_id; st1.stop_sequence = 1; feed.stop_times.put(new Fun.Tuple2(st1.trip_id, st1.stop_sequence), st1); StopTime st2 = new StopTime(); st2.trip_id = t.trip_id; st2.arrival_time = departure + 500; st2.departure_time = departure + 500; st2.stop_sequence = 2; st2.stop_id = s2.stop_id; feed.stop_times.put(new Fun.Tuple2(st2.trip_id, st2.stop_sequence), st2); } File tempFile = File.createTempFile("gtfs", ".zip"); feed.toFile(tempFile.getAbsolutePath()); // phew. load it into the graph. GtfsModule gtfs = new GtfsModule(Arrays.asList(new GtfsBundle(tempFile))); gtfs.buildGraph(g, new HashMap<>()); } public static void addPerpendicularRoutes(Graph graph) throws Exception { GTFSFeed feed = new GTFSFeed(); Agency agencyA = createDummyAgency("agencyA", "Agency A", "America/New_York"); feed.agency.put("agencyA", agencyA); Agency agencyB = createDummyAgency("agencyB", "Agency B", "America/New_York"); feed.agency.put("agencyB", agencyB); Service s = createDummyService(); feed.services.put(s.service_id, s); int stopIdX = 0; int stopIdY = 0; for (double lat = 39.9058; lat < 40.0281; lat += 0.005) { stopIdX = 0; for (double lon = -83.1341; lon < -82.8646; lon += 0.005) { com.conveyal.gtfs.model.Stop stop = new com.conveyal.gtfs.model.Stop(); stop.stop_id = stop.stop_name = String.format("s-%d-%d", stopIdX, stopIdY); stop.stop_lat = lat; stop.stop_lon = lon; feed.stops.put(stop.stop_id, stop); stopIdX++; } stopIdY++; } for (int i = 0; i < stopIdY; i++) { Route route = new Route(); route.route_short_name = "hr" + i; route.route_long_name = i + "th Horizontal Street"; route.route_type = Route.BUS; route.agency = agencyA; route.route_id = "horizontalroute" + i; feed.routes.put(route.route_id, route); } for (int i = 0; i < stopIdX; i++) { Route route = new Route(); route.route_short_name = "vr" + i; route.route_long_name = i + "th Vertical Street"; route.route_type = Route.TRAM; route.agency = agencyB; route.route_id = "verticalroute" + i; feed.routes.put(route.route_id, route); } Map<String, Route> routes = feed.routes; com.conveyal.gtfs.model.Stop stop; for (Route route : routes.values()) { int routeId = Integer.parseInt(route.route_short_name.substring(2)); int x, y; boolean isHorizontal = route.route_short_name.startsWith("hr"); for (int departure = 7 * 3600; departure < 20 * 3600; departure += FREQUENCY) { Trip t = new Trip(); t.trip_id = "trip:" + route.route_id + ":" + departure; t.service = s; t.route = route; feed.trips.put(t.trip_id, t); int departureTime = departure; int nrOfStops = (isHorizontal ? stopIdX : stopIdY); for (int stopSequenceNr = 0; stopSequenceNr < nrOfStops; stopSequenceNr++) { x = (isHorizontal ? stopSequenceNr : routeId); y = (isHorizontal ? routeId : stopSequenceNr); stop = feed.stops.get(String.format("s-%d-%d", x, y)); StopTime st1 = new StopTime(); st1.trip_id = t.trip_id; st1.arrival_time = departureTime; st1.departure_time = departureTime; st1.stop_id = stop.stop_id; st1.stop_sequence = stopSequenceNr + 1; feed.stop_times.put(new Fun.Tuple2(st1.trip_id, st1.stop_sequence), st1); //connect last stop to first so graph is fully reachable if (stopSequenceNr == 0) { StopTime stopTime = new StopTime(); stopTime.trip_id = t.trip_id; stopTime.arrival_time = departureTime + nrOfStops * 120 + 30 * 60; stopTime.departure_time = departureTime + nrOfStops * 120 + 30 * 60; stopTime.stop_id = stop.stop_id; stopTime.stop_sequence = stopSequenceNr + 1 + nrOfStops; feed.stop_times.put(new Fun.Tuple2(stopTime.trip_id, stopTime.stop_sequence), stopTime); } departureTime += 120; } } } File tempFile = File.createTempFile("gtfs", ".zip"); feed.toFile(tempFile.getAbsolutePath()); // phew. load it into the graph. GtfsModule gtfs = new GtfsModule(Arrays.asList(new GtfsBundle(tempFile))); gtfs.buildGraph(graph, new HashMap<>()); } private static Service createDummyService() { Service s = new Service("service"); s.calendar = new Calendar(); s.calendar.service = s; s.calendar.monday = s.calendar.tuesday = s.calendar.wednesday = s.calendar.thursday = s.calendar.friday = s.calendar.saturday = s.calendar.sunday = 1; s.calendar.start_date = 19991231; s.calendar.end_date = 21001231; return s; } private static Agency createDummyAgency(String id, String name, String timeZone) { Agency a = new Agency(); a.agency_id = id; a.agency_name = name; a.agency_timezone = timeZone; try { a.agency_url = new URL("http://www.example.com/" + id); } catch (MalformedURLException e) { // This really can't happen assert false; a.agency_url = null; } return a; } /** Add a transit line with multiple patterns to a Columbus graph. Most trips serve stops s1, s2, s3 but some serve only s1, s3 */ public static void addMultiplePatterns (Graph gg) throws Exception { // using conveyal GTFS lib to build GTFS so a lot of code does not have to be rewritten later // once we're using the conveyal GTFS lib for everything we ought to be able to do this // without even writing out the GTFS to a file. GTFSFeed feed = new GTFSFeed(); Agency a = createDummyAgency("agency", "Agency", "America/New_York"); feed.agency.put("agency", a); Route r = new Route(); r.route_short_name = "1"; r.route_long_name = "High Street"; r.route_type = 3; r.agency = a; r.route_id = "route"; feed.routes.put(r.route_id, r); Service s = createDummyService(); feed.services.put(s.service_id, s); com.conveyal.gtfs.model.Stop s1 = new com.conveyal.gtfs.model.Stop(); s1.stop_id = s1.stop_name = "s1"; s1.stop_lat = 40.2182; s1.stop_lon = -83.0889; feed.stops.put(s1.stop_id, s1); com.conveyal.gtfs.model.Stop s2 = new com.conveyal.gtfs.model.Stop(); s2.stop_id = s2.stop_name = "s2"; s2.stop_lat = 39.9621; s2.stop_lon = -83.0007; feed.stops.put(s2.stop_id, s2); com.conveyal.gtfs.model.Stop s3 = new com.conveyal.gtfs.model.Stop(); s3.stop_id = s3.stop_name = "s3"; s3.stop_lat = 39.9510; s3.stop_lon = -83.0007; feed.stops.put(s3.stop_id, s3); // make timetabled trips for (int departure = 7 * 3600, dcount = 0; departure < 20 * 3600; departure += FREQUENCY) { Trip t = new Trip(); t.trip_id = "trip" + departure; t.service = s; t.route = r; feed.trips.put(t.trip_id, t); StopTime st1 = new StopTime(); st1.trip_id = t.trip_id; st1.arrival_time = departure; st1.departure_time = departure; st1.stop_id = s1.stop_id; st1.stop_sequence = 1; feed.stop_times.put(new Fun.Tuple2(st1.trip_id, st1.stop_sequence), st1); // occasionally skip second stop boolean secondStop = dcount++ % 10 != 0; if (secondStop) { StopTime st2 = new StopTime(); st2.trip_id = t.trip_id; st2.arrival_time = departure + TRAVEL_TIME; st2.departure_time = departure + TRAVEL_TIME; st2.stop_sequence = 2; st2.stop_id = s2.stop_id; feed.stop_times.put(new Fun.Tuple2(st2.trip_id, st2.stop_sequence), st2); } StopTime st3 = new StopTime(); st3.trip_id = t.trip_id; st3.arrival_time = departure + (secondStop ? 2 : 1) * TRAVEL_TIME; st3.departure_time = departure + (secondStop ? 2 : 1) * TRAVEL_TIME; st3.stop_sequence = 3; st3.stop_id = s3.stop_id; feed.stop_times.put(new Fun.Tuple2(st3.trip_id, st3.stop_sequence), st3); } File tempFile = File.createTempFile("gtfs", ".zip"); feed.toFile(tempFile.getAbsolutePath()); // phew. load it into the graph. GtfsModule gtfs = new GtfsModule(Arrays.asList(new GtfsBundle(tempFile))); gtfs.buildGraph(gg, new HashMap<>()); } /** Add a regular grid of stops to the graph */ public static void addRegularStopGrid(Graph g) { int count = 0; for (double lat = 39.9058; lat < 40.0281; lat += 0.005) { for (double lon = -83.1341; lon < -82.8646; lon += 0.005) { String id = "" + count++; AgencyAndId aid = new AgencyAndId("TEST", id); Stop stop = new Stop(); stop.setLat(lat); stop.setLon(lon); stop.setName(id); stop.setCode(id); stop.setId(aid); new TransitStop(g, stop); count++; } } } /** add some extra stops to the graph */ public static void addExtraStops (Graph g) { int count = 0; double lon = -83; for (double lat = 40; lat < 40.01; lat += 0.005) { String id = "EXTRA_" + count++; AgencyAndId aid = new AgencyAndId("EXTRA", id); Stop stop = new Stop(); stop.setLat(lat); stop.setLon(lon); stop.setName(id); stop.setCode(id); stop.setId(aid); new TransitStop(g, stop); count++; } // add some duplicate stops lon = -83.1341 + 0.1; for (double lat = 39.9058; lat < 40.0281; lat += 0.005) { String id = "" + count++; AgencyAndId aid = new AgencyAndId("EXTRA", id); Stop stop = new Stop(); stop.setLat(lat); stop.setLon(lon); stop.setName(id); stop.setCode(id); stop.setId(aid); new TransitStop(g, stop); count++; } // add some almost duplicate stops lon = -83.1341 + 0.15; for (double lat = 39.9059; lat < 40.0281; lat += 0.005) { String id = "" + count++; AgencyAndId aid = new AgencyAndId("EXTRA", id); Stop stop = new Stop(); stop.setLat(lat); stop.setLon(lon); stop.setName(id); stop.setCode(id); stop.setId(aid); new TransitStop(g, stop); count++; } } /** Add transit (in both directions) to a Columbus graph */ public static void addTransitBidirectional (Graph gg) throws Exception { // using conveyal GTFS lib to build GTFS so a lot of code does not have to be rewritten later // once we're using the conveyal GTFS lib for everything we ought to be able to do this // without even writing out the GTFS to a file. GTFSFeed feed = new GTFSFeed(); Agency a = createDummyAgency("agency", "Agency", "America/New_York"); feed.agency.put("agency", a); Route r = new Route(); r.route_short_name = "1"; r.route_long_name = "High Street"; r.route_type = 3; r.agency = a; r.route_id = "route"; feed.routes.put(r.route_id, r); Service s = createDummyService(); feed.services.put(s.service_id, s); com.conveyal.gtfs.model.Stop s1 = new com.conveyal.gtfs.model.Stop(); s1.stop_id = s1.stop_name = "s1"; s1.stop_lat = 40.2182; s1.stop_lon = -83.0889; feed.stops.put(s1.stop_id, s1); com.conveyal.gtfs.model.Stop s2 = new com.conveyal.gtfs.model.Stop(); s2.stop_id = s2.stop_name = "s2"; s2.stop_lat = 39.9621; s2.stop_lon = -83.0007; feed.stops.put(s2.stop_id, s2); // make timetabled trips for (int departure = 7 * 3600; departure < 20 * 3600; departure += FREQUENCY) { Trip t = new Trip(); t.trip_id = "trip" + departure; t.service = s; t.route = r; t.direction_id = 0; feed.trips.put(t.trip_id, t); StopTime st1 = new StopTime(); st1.trip_id = t.trip_id; st1.arrival_time = departure; st1.departure_time = departure; st1.stop_id = s1.stop_id; st1.stop_sequence = 1; feed.stop_times.put(new Fun.Tuple2(st1.trip_id, st1.stop_sequence), st1); StopTime st2 = new StopTime(); st2.trip_id = t.trip_id; st2.arrival_time = departure + TRAVEL_TIME; st2.departure_time = departure + TRAVEL_TIME; st2.stop_sequence = 2; st2.stop_id = s2.stop_id; feed.stop_times.put(new Fun.Tuple2(st2.trip_id, st2.stop_sequence), st2); // opposite direction t = new Trip(); t.trip_id = "trip_back" + departure; t.service = s; t.route = r; t.direction_id = 1; feed.trips.put(t.trip_id, t); st1 = new StopTime(); st1.trip_id = t.trip_id; st1.arrival_time = departure; st1.departure_time = departure; st1.stop_id = s2.stop_id; st1.stop_sequence = 1; feed.stop_times.put(new Fun.Tuple2(st1.trip_id, st1.stop_sequence), st1); st2 = new StopTime(); st2.trip_id = t.trip_id; st2.arrival_time = departure + TRAVEL_TIME; st2.departure_time = departure + TRAVEL_TIME; st2.stop_sequence = 2; st2.stop_id = s1.stop_id; feed.stop_times.put(new Fun.Tuple2(st2.trip_id, st2.stop_sequence), st2); } File tempFile = File.createTempFile("gtfs", ".zip"); feed.toFile(tempFile.getAbsolutePath()); // phew. load it into the graph. GtfsModule gtfs = new GtfsModule(Arrays.asList(new GtfsBundle(tempFile))); gtfs.buildGraph(gg, new HashMap<>()); } /** link the stops in the graph */ public static void link (Graph g) { SimpleStreetSplitter linker = new SimpleStreetSplitter(g); linker.link(); } }