/** * Fetch upcoming vehicle arrivals at a stop. This is a rather convoluted process because all of * the departure search functions currently assume the existence of a State and a routing context. * It would be nice to have another function that gives all departures within a time window at a * stop, being careful to get a mix of all patterns passing through that stop. In fact, such a * function could replace the current boarding logic if we want to allow boarding more than one * trip on the same route at once (return more than one state). The current implementation is a * sketch and does not adequately */ public Collection<StopTimesInPattern> stopTimesForStop(Stop stop) { List<StopTimesInPattern> ret = Lists.newArrayList(); RoutingRequest req = new RoutingRequest(); req.setRoutingContext(graph, (Vertex) null, (Vertex) null); State state = new State(req); for (TripPattern pattern : patternsForStop.get(stop)) { StopTimesInPattern times = new StopTimesInPattern(pattern); // Should actually be getUpdatedTimetable Timetable table = pattern.scheduledTimetable; // A Stop may occur more than once in a pattern, so iterate over all Stops. int sidx = 0; for (Stop currStop : table.pattern.stopPattern.stops) { if (currStop != stop) continue; for (ServiceDay sd : req.rctx.serviceDays) { TripTimes tt = table.getNextTrip(state, sd, sidx, true); if (tt != null) { times.times.add(new TripTimeShort(tt, sidx, stop)); } } sidx++; } if (!times.times.isEmpty()) ret.add(times); } return ret; }
/** * Fetch upcoming vehicle departures from a stop. It goes though all patterns passing the stop for * the previous, current and next service date. It uses a priority queue to keep track of the next * departures. The queue is shared between all dates, as services from the previous service date * can visit the stop later than the current service date's services. This happens eg. with * sleeper trains. * * <p>TODO: Add frequency based trips * * @param stop Stop object to perform the search for * @param startTime Start time for the search. Seconds from UNIX epoch * @param timeRange Searches forward for timeRange seconds from startTime * @param numberOfDepartures Number of departures to fetch per pattern * @return */ public List<StopTimesInPattern> stopTimesForStop( Stop stop, long startTime, int timeRange, int numberOfDepartures) { if (startTime == 0) { startTime = System.currentTimeMillis() / 1000; } List<StopTimesInPattern> ret = new ArrayList<>(); TimetableSnapshot snapshot = null; if (graph.timetableSnapshotSource != null) { snapshot = graph.timetableSnapshotSource.getTimetableSnapshot(); } ServiceDate[] serviceDates = { new ServiceDate().previous(), new ServiceDate(), new ServiceDate().next() }; for (TripPattern pattern : patternsForStop.get(stop)) { // Use the Lucene PriorityQueue, which has a fixed size PriorityQueue<TripTimeShort> pq = new PriorityQueue<TripTimeShort>(numberOfDepartures) { @Override protected boolean lessThan(TripTimeShort tripTimeShort, TripTimeShort t1) { // Calculate exact timestamp return (tripTimeShort.serviceDay + tripTimeShort.realtimeDeparture) > (t1.serviceDay + t1.realtimeDeparture); } }; // Loop through all possible days for (ServiceDate serviceDate : serviceDates) { ServiceDay sd = new ServiceDay(graph, serviceDate, calendarService, pattern.route.getAgency().getId()); Timetable tt; if (snapshot != null) { tt = snapshot.resolve(pattern, serviceDate); } else { tt = pattern.scheduledTimetable; } if (!tt.temporallyViable(sd, startTime, timeRange, true)) continue; int secondsSinceMidnight = sd.secondsSinceMidnight(startTime); int sidx = 0; for (Stop currStop : pattern.stopPattern.stops) { if (currStop == stop) { for (TripTimes t : tt.tripTimes) { if (!sd.serviceRunning(t.serviceCode)) continue; if (t.getDepartureTime(sidx) != -1 && t.getDepartureTime(sidx) >= secondsSinceMidnight) { pq.insertWithOverflow(new TripTimeShort(t, sidx, stop, sd)); } } // TODO: This needs to be adapted after #1647 is merged for (FrequencyEntry freq : tt.frequencyEntries) { if (!sd.serviceRunning(freq.tripTimes.serviceCode)) continue; int departureTime = freq.nextDepartureTime(sidx, secondsSinceMidnight); if (departureTime == -1) continue; int lastDeparture = freq.endTime + freq.tripTimes.getArrivalTime(sidx) - freq.tripTimes.getDepartureTime(0); int i = 0; while (departureTime <= lastDeparture && i < numberOfDepartures) { pq.insertWithOverflow( new TripTimeShort(freq.materialize(sidx, departureTime, true), sidx, stop, sd)); departureTime += freq.headway; i++; } } } sidx++; } } if (pq.size() != 0) { StopTimesInPattern stopTimes = new StopTimesInPattern(pattern); while (pq.size() != 0) { stopTimes.times.add(0, pq.pop()); } ret.add(stopTimes); } } return ret; }