Search in sources :

Example 11 with TripPattern

use of org.opentripplanner.routing.edgetype.TripPattern in project OpenTripPlanner by opentripplanner.

the class TimetableSnapshotSourceTest method testHandleDelayedTrip.

@Test
public void testHandleDelayedTrip() {
    final AgencyAndId tripId = new AgencyAndId(feedId, "1.1");
    final AgencyAndId tripId2 = new AgencyAndId(feedId, "1.2");
    final Trip trip = graph.index.tripForId.get(tripId);
    final TripPattern pattern = graph.index.patternForTrip.get(trip);
    final int tripIndex = pattern.scheduledTimetable.getTripIndex(tripId);
    final int tripIndex2 = pattern.scheduledTimetable.getTripIndex(tripId2);
    final TripDescriptor.Builder tripDescriptorBuilder = TripDescriptor.newBuilder();
    tripDescriptorBuilder.setTripId("1.1");
    tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED);
    final TripUpdate.Builder tripUpdateBuilder = TripUpdate.newBuilder();
    tripUpdateBuilder.setTrip(tripDescriptorBuilder);
    final StopTimeUpdate.Builder stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder();
    stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED);
    stopTimeUpdateBuilder.setStopSequence(2);
    final StopTimeEvent.Builder arrivalBuilder = stopTimeUpdateBuilder.getArrivalBuilder();
    final StopTimeEvent.Builder departureBuilder = stopTimeUpdateBuilder.getDepartureBuilder();
    arrivalBuilder.setDelay(1);
    departureBuilder.setDelay(1);
    final TripUpdate tripUpdate = tripUpdateBuilder.build();
    updater.applyTripUpdates(graph, fullDataset, Arrays.asList(tripUpdate), feedId);
    final TimetableSnapshot snapshot = updater.getTimetableSnapshot();
    final Timetable forToday = snapshot.resolve(pattern, serviceDate);
    final Timetable schedule = snapshot.resolve(pattern, null);
    assertNotSame(forToday, schedule);
    assertNotSame(forToday.getTripTimes(tripIndex), schedule.getTripTimes(tripIndex));
    assertSame(forToday.getTripTimes(tripIndex2), schedule.getTripTimes(tripIndex2));
    assertEquals(1, forToday.getTripTimes(tripIndex).getArrivalDelay(1));
    assertEquals(1, forToday.getTripTimes(tripIndex).getDepartureDelay(1));
    assertEquals(RealTimeState.SCHEDULED, schedule.getTripTimes(tripIndex).getRealTimeState());
    assertEquals(RealTimeState.UPDATED, forToday.getTripTimes(tripIndex).getRealTimeState());
    assertEquals(RealTimeState.SCHEDULED, schedule.getTripTimes(tripIndex2).getRealTimeState());
    assertEquals(RealTimeState.SCHEDULED, forToday.getTripTimes(tripIndex2).getRealTimeState());
}
Also used : Timetable(org.opentripplanner.routing.edgetype.Timetable) TripUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate) TimetableSnapshot(org.opentripplanner.routing.edgetype.TimetableSnapshot) TripPattern(org.opentripplanner.routing.edgetype.TripPattern) StopTimeEvent(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent) TripDescriptor(com.google.transit.realtime.GtfsRealtime.TripDescriptor) StopTimeUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate) Test(org.junit.Test)

Example 12 with TripPattern

use of org.opentripplanner.routing.edgetype.TripPattern in project OpenTripPlanner by opentripplanner.

the class TimetableSnapshotSourceTest method testPurgeExpiredData.

@Test
public void testPurgeExpiredData() throws InvalidProtocolBufferException {
    final AgencyAndId tripId = new AgencyAndId(feedId, "1.1");
    // Just to be safe...
    final ServiceDate previously = serviceDate.previous().previous();
    final Trip trip = graph.index.tripForId.get(tripId);
    final TripPattern pattern = graph.index.patternForTrip.get(trip);
    updater.maxSnapshotFrequency = (0);
    updater.purgeExpiredData = (false);
    updater.applyTripUpdates(graph, fullDataset, Arrays.asList(TripUpdate.parseFrom(cancellation)), feedId);
    final TimetableSnapshot snapshotA = updater.getTimetableSnapshot();
    updater.purgeExpiredData = (true);
    final TripDescriptor.Builder tripDescriptorBuilder = TripDescriptor.newBuilder();
    tripDescriptorBuilder.setTripId("1.1");
    tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.CANCELED);
    tripDescriptorBuilder.setStartDate(previously.getAsString());
    final TripUpdate.Builder tripUpdateBuilder = TripUpdate.newBuilder();
    tripUpdateBuilder.setTrip(tripDescriptorBuilder);
    final TripUpdate tripUpdate = tripUpdateBuilder.build();
    updater.applyTripUpdates(graph, fullDataset, Arrays.asList(tripUpdate), feedId);
    final TimetableSnapshot snapshotB = updater.getTimetableSnapshot();
    assertNotSame(snapshotA, snapshotB);
    assertSame(snapshotA.resolve(pattern, null), snapshotB.resolve(pattern, null));
    assertSame(snapshotA.resolve(pattern, serviceDate), snapshotB.resolve(pattern, serviceDate));
    assertNotSame(snapshotA.resolve(pattern, null), snapshotA.resolve(pattern, serviceDate));
    assertSame(snapshotB.resolve(pattern, null), snapshotB.resolve(pattern, previously));
}
Also used : ServiceDate(org.onebusaway.gtfs.model.calendar.ServiceDate) TripUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate) TripDescriptor(com.google.transit.realtime.GtfsRealtime.TripDescriptor) TimetableSnapshot(org.opentripplanner.routing.edgetype.TimetableSnapshot) TripPattern(org.opentripplanner.routing.edgetype.TripPattern) Test(org.junit.Test)

Example 13 with TripPattern

use of org.opentripplanner.routing.edgetype.TripPattern in project OpenTripPlanner by opentripplanner.

the class OnBoardDepartServiceImplTest method testOnBoardAtStation.

@Test
public final void testOnBoardAtStation() {
    TransitStop station0 = mock(TransitStop.class);
    TransitStop station1 = mock(TransitStop.class);
    TransitStop station2 = mock(TransitStop.class);
    PatternDepartVertex depart = mock(PatternDepartVertex.class);
    PatternArriveVertex dwell = mock(PatternArriveVertex.class);
    PatternArriveVertex arrive = mock(PatternArriveVertex.class);
    Graph graph = mock(Graph.class);
    RoutingRequest routingRequest = mock(RoutingRequest.class);
    ServiceDay serviceDay = mock(ServiceDay.class);
    // You're probably not supposed to do this to mocks (access their fields directly)
    // But I know of no other way to do this since the mock object has only action-free stub methods.
    routingRequest.modes = new TraverseModeSet("WALK,TRANSIT");
    when(graph.getTimeZone()).thenReturn(TimeZone.getTimeZone("GMT"));
    ArrayList<Edge> hops = new ArrayList<Edge>(2);
    RoutingContext routingContext = new RoutingContext(routingRequest, graph, null, arrive);
    Agency agency = new Agency();
    AgencyAndId agencyAndId = new AgencyAndId("Agency", "ID");
    Route route = new Route();
    ArrayList<StopTime> stopTimes = new ArrayList<StopTime>(2);
    StopTime stopDepartTime = new StopTime();
    StopTime stopDwellTime = new StopTime();
    StopTime stopArriveTime = new StopTime();
    Stop stopDepart = new Stop();
    Stop stopDwell = new Stop();
    Stop stopArrive = new Stop();
    Trip trip = new Trip();
    routingContext.serviceDays = new ArrayList<ServiceDay>(Collections.singletonList(serviceDay));
    agency.setId(agencyAndId.getAgencyId());
    route.setId(agencyAndId);
    route.setAgency(agency);
    stopDepart.setId(new AgencyAndId("Station", "0"));
    stopDwell.setId(new AgencyAndId("Station", "1"));
    stopArrive.setId(new AgencyAndId("Station", "2"));
    stopDepartTime.setStop(stopDepart);
    stopDepartTime.setDepartureTime(0);
    stopDwellTime.setArrivalTime(20);
    stopDwellTime.setStop(stopDwell);
    stopDwellTime.setDepartureTime(40);
    stopArriveTime.setArrivalTime(60);
    stopArriveTime.setStop(stopArrive);
    stopTimes.add(stopDepartTime);
    stopTimes.add(stopDwellTime);
    stopTimes.add(stopArriveTime);
    trip.setId(agencyAndId);
    trip.setRoute(route);
    TripTimes tripTimes = new TripTimes(trip, stopTimes, new Deduplicator());
    StopPattern stopPattern = new StopPattern(stopTimes);
    TripPattern tripPattern = new TripPattern(route, stopPattern);
    TripPattern.generateUniqueIds(Arrays.asList(tripPattern));
    when(depart.getTripPattern()).thenReturn(tripPattern);
    when(dwell.getTripPattern()).thenReturn(tripPattern);
    PatternHop patternHop0 = new PatternHop(depart, dwell, stopDepart, stopDwell, 0);
    PatternHop patternHop1 = new PatternHop(dwell, arrive, stopDwell, stopArrive, 1);
    hops.add(patternHop0);
    hops.add(patternHop1);
    when(graph.getEdges()).thenReturn(hops);
    when(depart.getCoordinate()).thenReturn(new Coordinate(0, 0));
    when(dwell.getCoordinate()).thenReturn(new Coordinate(0, 0));
    when(arrive.getCoordinate()).thenReturn(new Coordinate(0, 0));
    routingRequest.from = new GenericLocation();
    routingRequest.startingTransitTripId = agencyAndId;
    when(graph.getVertex("Station_0")).thenReturn(station0);
    when(graph.getVertex("Station_1")).thenReturn(station1);
    when(graph.getVertex("Station_2")).thenReturn(station2);
    tripPattern.add(tripTimes);
    graph.index = new GraphIndex(graph);
    when(serviceDay.secondsSinceMidnight(anyInt())).thenReturn(0);
    assertEquals(station0, onBoardDepartServiceImpl.setupDepartOnBoard(routingContext));
    when(serviceDay.secondsSinceMidnight(anyInt())).thenReturn(20);
    assertEquals(station1, onBoardDepartServiceImpl.setupDepartOnBoard(routingContext));
    when(serviceDay.secondsSinceMidnight(anyInt())).thenReturn(30);
    assertEquals(station1, onBoardDepartServiceImpl.setupDepartOnBoard(routingContext));
    when(serviceDay.secondsSinceMidnight(anyInt())).thenReturn(40);
    assertEquals(station1, onBoardDepartServiceImpl.setupDepartOnBoard(routingContext));
    when(serviceDay.secondsSinceMidnight(anyInt())).thenReturn(60);
    assertEquals(station2, onBoardDepartServiceImpl.setupDepartOnBoard(routingContext));
}
Also used : TransitStop(org.opentripplanner.routing.vertextype.TransitStop) ServiceDay(org.opentripplanner.routing.core.ServiceDay) AgencyAndId(org.onebusaway.gtfs.model.AgencyAndId) TransitStop(org.opentripplanner.routing.vertextype.TransitStop) Stop(org.onebusaway.gtfs.model.Stop) ArrayList(java.util.ArrayList) Deduplicator(org.opentripplanner.routing.trippattern.Deduplicator) RoutingContext(org.opentripplanner.routing.core.RoutingContext) GraphIndex(org.opentripplanner.routing.graph.GraphIndex) PatternDepartVertex(org.opentripplanner.routing.vertextype.PatternDepartVertex) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) GenericLocation(org.opentripplanner.common.model.GenericLocation) RoutingRequest(org.opentripplanner.routing.core.RoutingRequest) Route(org.onebusaway.gtfs.model.Route) StopTime(org.onebusaway.gtfs.model.StopTime) StopPattern(org.opentripplanner.model.StopPattern) Trip(org.onebusaway.gtfs.model.Trip) Agency(org.onebusaway.gtfs.model.Agency) TraverseModeSet(org.opentripplanner.routing.core.TraverseModeSet) TripPattern(org.opentripplanner.routing.edgetype.TripPattern) Graph(org.opentripplanner.routing.graph.Graph) Coordinate(com.vividsolutions.jts.geom.Coordinate) PatternHop(org.opentripplanner.routing.edgetype.PatternHop) PatternArriveVertex(org.opentripplanner.routing.vertextype.PatternArriveVertex) Edge(org.opentripplanner.routing.graph.Edge) Test(org.junit.Test)

Example 14 with TripPattern

use of org.opentripplanner.routing.edgetype.TripPattern in project OpenTripPlanner by opentripplanner.

the class OnBoardDepartServiceImplTest method testOnBoardDepartureAtArrivalTime.

@Test
public final void testOnBoardDepartureAtArrivalTime() {
    Coordinate[] coordinates = new Coordinate[2];
    coordinates[0] = new Coordinate(0.0, 0.0);
    coordinates[1] = new Coordinate(0.0, 1.0);
    TransitStop station0 = mock(TransitStop.class);
    TransitStop station1 = mock(TransitStop.class);
    PatternDepartVertex depart = mock(PatternDepartVertex.class);
    PatternArriveVertex arrive = mock(PatternArriveVertex.class);
    Graph graph = mock(Graph.class);
    RoutingRequest routingRequest = mock(RoutingRequest.class);
    ServiceDay serviceDay = mock(ServiceDay.class);
    // You're probably not supposed to do this to mocks (access their fields directly)
    // But I know of no other way to do this since the mock object has only action-free stub methods.
    routingRequest.modes = new TraverseModeSet("WALK,TRANSIT");
    when(graph.getTimeZone()).thenReturn(TimeZone.getTimeZone("GMT"));
    when(station0.getX()).thenReturn(coordinates[0].x);
    when(station0.getY()).thenReturn(coordinates[0].y);
    when(station1.getX()).thenReturn(coordinates[1].x);
    when(station1.getY()).thenReturn(coordinates[1].y);
    RoutingContext routingContext = new RoutingContext(routingRequest, graph, null, arrive);
    AgencyAndId agencyAndId = new AgencyAndId("Agency", "ID");
    Agency agency = new Agency();
    Route route = new Route();
    ArrayList<StopTime> stopTimes = new ArrayList<StopTime>(2);
    StopTime stopDepartTime = new StopTime();
    StopTime stopArriveTime = new StopTime();
    Stop stopDepart = new Stop();
    Stop stopArrive = new Stop();
    Trip trip = new Trip();
    routingContext.serviceDays = new ArrayList<ServiceDay>(Collections.singletonList(serviceDay));
    agency.setId(agencyAndId.getAgencyId());
    route.setId(agencyAndId);
    route.setAgency(agency);
    stopDepart.setId(new AgencyAndId("Station", "0"));
    stopArrive.setId(new AgencyAndId("Station", "1"));
    stopDepartTime.setStop(stopDepart);
    stopDepartTime.setDepartureTime(0);
    stopArriveTime.setArrivalTime(10);
    stopArriveTime.setStop(stopArrive);
    stopTimes.add(stopDepartTime);
    stopTimes.add(stopArriveTime);
    trip.setId(agencyAndId);
    trip.setRoute(route);
    TripTimes tripTimes = new TripTimes(trip, stopTimes, new Deduplicator());
    StopPattern stopPattern = new StopPattern(stopTimes);
    TripPattern tripPattern = new TripPattern(route, stopPattern);
    TripPattern.generateUniqueIds(Arrays.asList(tripPattern));
    when(depart.getTripPattern()).thenReturn(tripPattern);
    PatternHop patternHop = new PatternHop(depart, arrive, stopDepart, stopArrive, 0);
    when(graph.getEdges()).thenReturn(Collections.<Edge>singletonList(patternHop));
    when(depart.getCoordinate()).thenReturn(new Coordinate(0, 0));
    when(arrive.getCoordinate()).thenReturn(new Coordinate(0, 0));
    routingRequest.from = new GenericLocation();
    routingRequest.startingTransitTripId = agencyAndId;
    when(serviceDay.secondsSinceMidnight(anyInt())).thenReturn(10);
    when(graph.getVertex("Station_0")).thenReturn(station0);
    when(graph.getVertex("Station_1")).thenReturn(station1);
    tripPattern.add(tripTimes);
    graph.index = new GraphIndex(graph);
    Vertex vertex = onBoardDepartServiceImpl.setupDepartOnBoard(routingContext);
    assertEquals(coordinates[1].x, vertex.getX(), 0.0);
    assertEquals(coordinates[1].y, vertex.getY(), 0.0);
}
Also used : Vertex(org.opentripplanner.routing.graph.Vertex) PatternDepartVertex(org.opentripplanner.routing.vertextype.PatternDepartVertex) PatternArriveVertex(org.opentripplanner.routing.vertextype.PatternArriveVertex) TransitStop(org.opentripplanner.routing.vertextype.TransitStop) ServiceDay(org.opentripplanner.routing.core.ServiceDay) AgencyAndId(org.onebusaway.gtfs.model.AgencyAndId) TransitStop(org.opentripplanner.routing.vertextype.TransitStop) Stop(org.onebusaway.gtfs.model.Stop) ArrayList(java.util.ArrayList) Deduplicator(org.opentripplanner.routing.trippattern.Deduplicator) RoutingContext(org.opentripplanner.routing.core.RoutingContext) GraphIndex(org.opentripplanner.routing.graph.GraphIndex) PatternDepartVertex(org.opentripplanner.routing.vertextype.PatternDepartVertex) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) GenericLocation(org.opentripplanner.common.model.GenericLocation) RoutingRequest(org.opentripplanner.routing.core.RoutingRequest) Route(org.onebusaway.gtfs.model.Route) StopTime(org.onebusaway.gtfs.model.StopTime) StopPattern(org.opentripplanner.model.StopPattern) Trip(org.onebusaway.gtfs.model.Trip) Agency(org.onebusaway.gtfs.model.Agency) TraverseModeSet(org.opentripplanner.routing.core.TraverseModeSet) TripPattern(org.opentripplanner.routing.edgetype.TripPattern) Graph(org.opentripplanner.routing.graph.Graph) Coordinate(com.vividsolutions.jts.geom.Coordinate) PatternHop(org.opentripplanner.routing.edgetype.PatternHop) PatternArriveVertex(org.opentripplanner.routing.vertextype.PatternArriveVertex) Test(org.junit.Test)

Example 15 with TripPattern

use of org.opentripplanner.routing.edgetype.TripPattern in project OpenTripPlanner by opentripplanner.

the class ProfileRouter method route.

/* Maybe don't even try to accumulate stats and weights on the fly, just enumerate options. */
/* TODO Or actually use a priority queue based on the min time. */
public ProfileResponse route() {
    // Lazy-initialize stop clusters (threadsafe method)
    graph.index.clusterStopsAsNeeded();
    // Lazy-initialize profile transfers (before setting timeouts, since this is slow)
    if (graph.index.transfersFromStopCluster == null) {
        synchronized (graph.index) {
            // we don't initialize it again.
            if (graph.index.transfersFromStopCluster == null) {
                graph.index.initializeProfileTransfers();
            }
        }
    }
    LOG.info("access modes: {}", request.accessModes);
    LOG.info("egress modes: {}", request.egressModes);
    LOG.info("direct modes: {}", request.directModes);
    // Establish search timeouts
    long searchBeginTime = System.currentTimeMillis();
    long abortTime = searchBeginTime + TIMEOUT * 1000;
    // TimeWindow could constructed in the caller, which does have access to the graph index.
    this.window = new TimeWindow(request.fromTime, request.toTime, graph.index.servicesRunning(request.date));
    LOG.info("Finding access/egress paths.");
    // Look for stops that are within a given time threshold of the origin and destination
    // Find the closest stop on each pattern near the origin and destination
    // TODO consider that some stops may be closer by one mode than another
    // and that some stops may be accessible by one mode but not another
    fromStopPaths = findClosestStops(false);
    fromStops = findClosestPatterns(fromStopPaths);
    if (!request.analyst) {
        toStopPaths = findClosestStops(true);
        toStops = findClosestPatterns(toStopPaths);
        // Also look for options connecting origin to destination with no transit.
        for (QualifiedMode qmode : request.directModes.qModes) {
            LOG.info("Finding non-transit path for mode {}", qmode);
            findDirectOption(qmode);
        }
    }
    LOG.info("Done finding access/egress paths.");
    // printStopsForPatterns("from", fromStops);
    // printStopsForPatterns("to", toStops);
    /* Enqueue an unfinished PatternRide for each pattern near the origin, grouped by Stop into unfinished Rides. */
    // One ride per stop cluster
    Map<StopCluster, Ride> initialRides = Maps.newHashMap();
    /* This Multimap will contain multiple entries for the same pattern if it can be reached by multiple modes. */
    for (TripPattern pattern : fromStops.keySet()) {
        if (!request.transitModes.contains(pattern.mode)) {
            // FIXME do not even store these patterns when performing access/egress searches
            continue;
        }
        Collection<StopAtDistance> sds = fromStops.get(pattern);
        for (StopAtDistance sd : sds) {
            /* Fetch or construct a new Ride beginning at this stop cluster. */
            Ride ride = initialRides.get(sd.stopCluster);
            if (ride == null) {
                // null previous ride because this is the first ride
                ride = new Ride(sd.stopCluster, null);
                // empty stats, times for each access mode will be merged in
                ride.accessStats = new Stats();
                // higher than any value that will be merged in
                ride.accessStats.min = Integer.MAX_VALUE;
                // TODO verify correctness and uses
                ride.accessDist = (int) sd.state.getWalkDistance();
                initialRides.put(sd.stopCluster, ride);
            }
            /* Record the access time for this mode in the stats. */
            ride.accessStats.merge(sd.etime);
            /* Loop over stop clusters in case stop cluster appears more than once in the pattern. */
            STOP_INDEX: for (int i = 0; i < pattern.getStops().size(); ++i) {
                if (sd.stopCluster == graph.index.stopClusterForStop.get(pattern.getStops().get(i))) {
                    PatternRide newPatternRide = new PatternRide(pattern, i);
                    // TODO this would be a !contains() call if PatternRides had semantic equality
                    for (PatternRide existingPatternRide : ride.patternRides) {
                        if (existingPatternRide.pattern == newPatternRide.pattern && existingPatternRide.fromIndex == newPatternRide.fromIndex) {
                            continue STOP_INDEX;
                        }
                    }
                    ride.patternRides.add(newPatternRide);
                }
            }
        }
    }
    for (Ride ride : initialRides.values()) {
        // logRide(ride);
        queue.insert(ride, 0);
    }
    /* Explore incomplete rides as long as there are any in the queue. */
    while (!queue.empty()) {
        /* Get the minimum-time unfinished ride off the queue. */
        Ride ride = queue.extract_min();
        // TODO should we check whether ride.previous != null (it is an initial ride)?
        if (dominated(ride, ride.from))
            continue;
        // Maybe when ride is complete, then find transfers here, but that makes for more queue operations.
        if (ride.to != null)
            throw new AssertionError("Ride should be unfinished.");
        /* Track finished Rides by their destination StopCluster, so we can add PatternRides to them. */
        Map<StopCluster, Ride> rides = Maps.newHashMap();
        /* Complete partial PatternRides (with only a pattern and a beginning stop) which were enqueued in this
             * partial ride. This is done by scanning through the Pattern, creating rides to all downstream stops. */
        PR: for (PatternRide pr : ride.patternRides) {
            // LOG.info(" {}", pr);
            List<Stop> stops = pr.pattern.getStops();
            for (int s = pr.fromIndex + 1; s < stops.size(); ++s) {
                StopCluster cluster = graph.index.stopClusterForStop.get(stops.get(s));
                /* Originally we only extended rides to destination stops considered useful in the search, i.e.
                     * those that had transfers leading out of them or were known to be near the destination.
                     * However, analyst needs to know the times we can reach every stop, and pruning is more effective
                     * if we know when rides pass through all stops.*/
                PatternRide pr2 = pr.extendToIndex(s, window);
                // PatternRide may be empty because there are no trips in time window.
                if (pr2 == null)
                    continue PR;
                // LOG.info("   {}", pr2);
                // Get or create the completed Ride to this destination stop.
                Ride ride2 = rides.get(cluster);
                if (ride2 == null) {
                    ride2 = ride.extendTo(cluster);
                    rides.put(cluster, ride2);
                }
                // Add the completed PatternRide to the completed Ride.
                ride2.patternRides.add(pr2);
            }
        }
        /* Build new downstream Rides by transferring from patterns in current Rides. */
        // Create a map of incomplete rides (start but no end point) after transfers, one for each stop.
        Map<StopCluster, Ride> xferRides = Maps.newHashMap();
        for (Ride r1 : rides.values()) {
            r1.calcStats(window, request.walkSpeed);
            if (r1.waitStats == null) {
                // This is a sign of a questionable algorithm, since we eliminate the ride rather late.
                continue;
            } else {
                r1.recomputeBounds();
            }
            /* Retain this ride if it is not dominated by some existing ride at the same location. */
            if (dominated(r1, r1.to))
                continue;
            retainedRides.put(r1.to, r1);
            /* We have a new, non-dominated, completed ride. Find transfers out of this new ride, respecting the transfer limit. */
            int nRides = r1.pathLength;
            if (nRides >= MAX_RIDES)
                continue;
            boolean penultimateRide = (nRides == MAX_RIDES - 1);
            // TODO benchmark, this is so not efficient
            for (ProfileTransfer tr : graph.index.transfersFromStopCluster.get(r1.to)) {
                if (!request.transitModes.contains(tr.tp2.mode))
                    continue;
                if (r1.containsPattern(tr.tp1)) {
                    // Prune loopy or repetitive paths.
                    if (r1.pathContainsRoute(tr.tp2.route))
                        continue;
                    if (tr.sc1 != tr.sc2 && r1.pathContainsStop(tr.sc2))
                        continue;
                    // only transfer to patterns that pass near the destination.
                    if (!request.analyst && penultimateRide && !toStops.containsKey(tr.tp2))
                        continue;
                    // Scan through stops looking for transfer target: stop might appear more than once in a pattern.
                    TARGET_STOP: for (int i = 0; i < tr.tp2.getStops().size(); ++i) {
                        StopCluster cluster = graph.index.stopClusterForStop.get(tr.tp2.getStops().get(i));
                        if (cluster == tr.sc2) {
                            // Save transfer result in an unfinished ride for later exploration.
                            Ride r2 = xferRides.get(tr.sc2);
                            if (r2 == null) {
                                r2 = new Ride(tr.sc2, r1);
                                r2.accessDist = tr.distance;
                                r2.accessStats = new Stats((int) (tr.distance / request.walkSpeed));
                                r2.recomputeBounds();
                                xferRides.put(tr.sc2, r2);
                            }
                            for (PatternRide pr : r2.patternRides) {
                                // TODO refactor with equals function and contains().
                                if (pr.pattern == tr.tp2 && pr.fromIndex == i)
                                    continue TARGET_STOP;
                            }
                            r2.patternRides.add(new PatternRide(tr.tp2, i));
                        }
                    }
                }
            }
        }
        /* Enqueue new incomplete Rides resulting from transfers if they are not dominated at their from-cluster. */
        for (Ride r : xferRides.values()) {
            if (!dominated(r, r.from)) {
                // This ride is unfinished, use the previous ride's travel time lower bound as the p-queue key.
                // Note that we are not adding these transfer results to the retained rides, just enqueuing them.
                queue.insert(r, r.dlb);
            }
        }
        if (System.currentTimeMillis() > abortTime)
            throw new RuntimeException("TIMEOUT");
    }
    LOG.info("Profile routing request finished in {} sec.", (System.currentTimeMillis() - searchBeginTime) / 1000.0);
    if (request.analyst) {
        makeSurfaces();
        return null;
    }
    /* In non-analyst (point-to-point) mode, determine which rides are good ways to reach the destination. */
    /* A fake stop cluster to allow applying generic domination logic at the final destination. */
    final StopCluster DESTINATION = new StopCluster("The Destination", "The Destination");
    for (StopCluster cluster : toStopPaths.keySet()) {
        // TODO shared logic for making access/egress stats
        Stats egressStats = new Stats();
        egressStats.min = Integer.MAX_VALUE;
        for (StopAtDistance sd : toStopPaths.get(cluster)) {
            egressStats.merge(sd.etime);
        }
        for (Ride ride : retainedRides.get(cluster)) {
            // Construct a new unfinished ride, representing "transferring" from the final stop to the destination
            Ride rideAtDestination = new Ride(DESTINATION, ride);
            rideAtDestination.accessStats = egressStats;
            rideAtDestination.recomputeBounds();
            if (!dominated(rideAtDestination, DESTINATION)) {
                retainedRides.put(DESTINATION, rideAtDestination);
            }
        }
    }
    LOG.info("{} nondominated rides reach the destination.", retainedRides.get(DESTINATION).size());
    /* Non-analyst: Build the list of Options by following the back-pointers in Rides. */
    List<Option> options = Lists.newArrayList();
    for (Ride ride : retainedRides.get(DESTINATION)) {
        // slice off the final unfinished ride that only contains the egress stats
        // TODO actually use this ride in preparing the response
        ride = ride.previous;
        // All PatternRides in a Ride end at the same stop.
        Collection<StopAtDistance> accessPaths = fromStopPaths.get(ride.getAccessStopCluster());
        Collection<StopAtDistance> egressPaths = toStopPaths.get(ride.getEgressStopCluster());
        Option option = new Option(ride, accessPaths, egressPaths);
        if (!option.hasEmptyRides())
            options.add(option);
    }
    /* Include the direct (no-transit) biking, driving, and walking options. */
    options.add(new Option(null, directPaths, null));
    return new ProfileResponse(options, request.orderBy, request.limit);
}
Also used : TripPattern(org.opentripplanner.routing.edgetype.TripPattern) List(java.util.List) QualifiedMode(org.opentripplanner.api.parameter.QualifiedMode)

Aggregations

TripPattern (org.opentripplanner.routing.edgetype.TripPattern)53 Stop (org.onebusaway.gtfs.model.Stop)23 TransitStop (org.opentripplanner.routing.vertextype.TransitStop)23 Trip (org.onebusaway.gtfs.model.Trip)20 AgencyAndId (org.onebusaway.gtfs.model.AgencyAndId)19 TripTimes (org.opentripplanner.routing.trippattern.TripTimes)19 Test (org.junit.Test)14 Route (org.onebusaway.gtfs.model.Route)14 Timetable (org.opentripplanner.routing.edgetype.Timetable)11 ArrayList (java.util.ArrayList)10 GET (javax.ws.rs.GET)10 Path (javax.ws.rs.Path)10 Edge (org.opentripplanner.routing.graph.Edge)9 StopTime (org.onebusaway.gtfs.model.StopTime)8 StopPattern (org.opentripplanner.model.StopPattern)8 TimetableSnapshot (org.opentripplanner.routing.edgetype.TimetableSnapshot)8 Graph (org.opentripplanner.routing.graph.Graph)8 Agency (org.onebusaway.gtfs.model.Agency)7 ServiceDay (org.opentripplanner.routing.core.ServiceDay)7 FrequencyEntry (org.opentripplanner.routing.trippattern.FrequencyEntry)7