use of org.opentripplanner.model.Timetable in project OpenTripPlanner by opentripplanner.
the class GeometryAndBlockProcessor method interline.
/**
* Identify interlined trips (where a physical vehicle continues on to another logical trip)
* and update the TripPatterns accordingly.
*/
private void interline(Collection<TripPattern> tripPatterns, Graph graph) {
/* Record which Pattern each interlined TripTimes belongs to. */
Map<TripTimes, TripPattern> patternForTripTimes = Maps.newHashMap();
/* TripTimes grouped by the block ID and service ID of their trips. Must be a ListMultimap to allow sorting. */
ListMultimap<BlockIdAndServiceId, TripTimes> tripTimesForBlock = ArrayListMultimap.create();
LOG.info("Finding interlining trips based on block IDs.");
for (TripPattern pattern : tripPatterns) {
Timetable timetable = pattern.scheduledTimetable;
/* TODO: Block semantics seem undefined for frequency trips, so skip them? */
for (TripTimes tripTimes : timetable.tripTimes) {
Trip trip = tripTimes.trip;
if (!Strings.isNullOrEmpty(trip.getBlockId())) {
tripTimesForBlock.put(new BlockIdAndServiceId(trip), tripTimes);
// For space efficiency, only record times that are part of a block.
patternForTripTimes.put(tripTimes, pattern);
}
}
}
// Associate pairs of TripPatterns with lists of trips that continue from one pattern to the other.
Multimap<P2<TripPattern>, P2<Trip>> interlines = ArrayListMultimap.create();
// linking them. Has no effect on single-trip blocks.
SERVICE_BLOCK: for (BlockIdAndServiceId block : tripTimesForBlock.keySet()) {
List<TripTimes> blockTripTimes = tripTimesForBlock.get(block);
Collections.sort(blockTripTimes);
TripTimes prev = null;
for (TripTimes curr : blockTripTimes) {
if (prev != null) {
if (prev.getDepartureTime(prev.getNumStops() - 1) > curr.getArrivalTime(0)) {
LOG.error("Trip times within block {} are not increasing on service {} after trip {}.", block.blockId, block.serviceId, prev.trip.getId());
continue SERVICE_BLOCK;
}
TripPattern prevPattern = patternForTripTimes.get(prev);
TripPattern currPattern = patternForTripTimes.get(curr);
Stop fromStop = prevPattern.getStop(prevPattern.getStops().size() - 1);
Stop toStop = currPattern.getStop(0);
double teleportationDistance = SphericalDistanceLibrary.fastDistance(fromStop.getLat(), fromStop.getLon(), toStop.getLat(), toStop.getLon());
if (teleportationDistance > maxInterlineDistance) {
// FIXME Trimet data contains a lot of these -- in their data, two trips sharing a block ID just
// means that they are served by the same vehicle, not that interlining is automatically allowed.
// see #1654
// LOG.error(graph.addBuilderAnnotation(new InterliningTeleport(prev.trip, block.blockId, (int)teleportationDistance)));
// Only skip this particular interline edge; there may be other valid ones in the block.
} else {
interlines.put(new P2<>(prevPattern, currPattern), new P2<>(prev.trip, curr.trip));
}
}
prev = curr;
}
}
// TODO: verify whether we need to be keeping track of patterns at all here, or could just accumulate trip-trip relationships.
for (P2<TripPattern> patterns : interlines.keySet()) {
for (P2<Trip> trips : interlines.get(patterns)) {
graph.interlinedTrips.put(trips.first, trips.second);
}
}
LOG.info("Done finding interlining trips.");
}
use of org.opentripplanner.model.Timetable in project OpenTripPlanner by opentripplanner.
the class IndexAPI method getStoptimesForTrip.
@GET
@Path("/trips/{tripId}/stoptimes")
public List<TripTimeShort> getStoptimesForTrip(@PathParam("tripId") String tripId) {
RoutingService routingService = createRoutingService();
Trip trip = getTrip(routingService, tripId);
TripPattern pattern = getTripPattern(routingService, trip);
// Note, we need the updated timetable not the scheduled one (which contains no real-time updates).
Timetable table = routingService.getTimetableForTripPattern(pattern);
return TripTimeShort.fromTripTimes(table, trip);
}
use of org.opentripplanner.model.Timetable in project OpenTripPlanner by opentripplanner.
the class StopTimesHelper method listTripTimeShortsForPatternAtStop.
private static Queue<TripTimeShort> listTripTimeShortsForPatternAtStop(RoutingService routingService, TimetableSnapshot timetableSnapshot, Stop stop, TripPattern pattern, long startTime, int timeRange, int numberOfDepartures, boolean omitNonPickups, ServiceDate[] serviceDates) {
// The bounded priority Q is used to keep a sorted short list of trip times. We can not
// relay on the trip times to be in order because of real-time updates. This code can
// probably be optimized, and the trip search in the Raptor search does almost the same
// thing. This is no part of a routing request, but is a used frequently in some
// operation like Entur for "departure boards" (apps, widgets, screens on platforms, and
// hotel lobbies). Setting the numberOfDepartures and timeRange to a big number for a
// transit hub could result in a DOS attack, but there are probably other more effective
// ways to do it.
//
// The {@link MinMaxPriorityQueue} is marked beta, but we do not have a god alternative.
MinMaxPriorityQueue<TripTimeShort> pq = MinMaxPriorityQueue.orderedBy(Comparator.comparing((TripTimeShort tts) -> tts.serviceDay + tts.realtimeDeparture)).maximumSize(numberOfDepartures).create();
// Loop through all possible days
for (ServiceDate serviceDate : serviceDates) {
ServiceDay sd = new ServiceDay(routingService.getServiceCodes(), serviceDate, routingService.getCalendarService(), pattern.route.getAgency().getId());
Timetable tt;
if (timetableSnapshot != null) {
tt = timetableSnapshot.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) {
if (omitNonPickups && pattern.stopPattern.pickups[sidx] == StopPattern.PICKDROP_NONE)
continue;
for (TripTimes t : tt.tripTimes) {
if (!sd.serviceRunning(t.serviceCode))
continue;
if (t.getDepartureTime(sidx) != -1 && t.getDepartureTime(sidx) >= secondsSinceMidnight) {
pq.add(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.add(new TripTimeShort(freq.materialize(sidx, departureTime, true), sidx, stop, sd));
departureTime += freq.headway;
i++;
}
}
}
sidx++;
}
}
return pq;
}
use of org.opentripplanner.model.Timetable in project OpenTripPlanner by opentripplanner.
the class StopTimesHelper method stopTimesForStop.
/**
* Get a list of all trips that pass through a stop during a single ServiceDate. Useful when creating complete stop
* timetables for a single day.
*
* @param stop Stop object to perform the search for
* @param serviceDate Return all departures for the specified date
*/
public static List<StopTimesInPattern> stopTimesForStop(RoutingService routingService, Stop stop, ServiceDate serviceDate, boolean omitNonPickups) {
List<StopTimesInPattern> ret = new ArrayList<>();
Collection<TripPattern> patternsForStop = routingService.getPatternsForStop(stop, true);
for (TripPattern pattern : patternsForStop) {
StopTimesInPattern stopTimes = new StopTimesInPattern(pattern);
Timetable tt;
TimetableSnapshot timetableSnapshot = routingService.getTimetableSnapshot();
if (timetableSnapshot != null) {
tt = timetableSnapshot.resolve(pattern, serviceDate);
} else {
tt = pattern.scheduledTimetable;
}
ServiceDay sd = new ServiceDay(routingService.getServiceCodes(), serviceDate, routingService.getCalendarService(), pattern.route.getAgency().getId());
int sidx = 0;
for (Stop currStop : pattern.stopPattern.stops) {
if (currStop == stop) {
if (omitNonPickups && pattern.stopPattern.pickups[sidx] == StopPattern.PICKDROP_NONE)
continue;
for (TripTimes t : tt.tripTimes) {
if (!sd.serviceRunning(t.serviceCode))
continue;
stopTimes.times.add(new TripTimeShort(t, sidx, stop, sd));
}
}
sidx++;
}
ret.add(stopTimes);
}
return ret;
}
use of org.opentripplanner.model.Timetable in project OpenTripPlanner by opentripplanner.
the class TimetableSnapshotSource method cancelPreviouslyAddedTrip.
/**
* Cancel previously added trip from buffer if there is a previously added trip with given trip
* id (without agency id) on service date. This does not remove the modified/added trip from the buffer, it just
* marks it as canceled. This also does not remove the corresponding vertices and edges from the Graph. Any
* TripPattern that was created for the added/modified trip continues to exist, and will be reused if a similar
* added/modified trip message is received with the same route and stop sequence.
*
* @param tripId trip id without agency id
* @param serviceDate service date
* @return true if a previously added trip was cancelled
*/
private boolean cancelPreviouslyAddedTrip(FeedScopedId tripId, final ServiceDate serviceDate) {
boolean success = false;
final TripPattern pattern = buffer.getLastAddedTripPattern(tripId, serviceDate);
if (pattern != null) {
// Cancel trip times for this trip in this pattern
final Timetable timetable = buffer.resolve(pattern, serviceDate);
final int tripIndex = timetable.getTripIndex(tripId);
if (tripIndex == -1) {
LOG.warn("Could not cancel previously added trip {}", tripId);
} else {
final TripTimes newTripTimes = new TripTimes(timetable.getTripTimes(tripIndex));
newTripTimes.cancel();
buffer.update(pattern, newTripTimes, serviceDate);
success = true;
}
}
return success;
}
Aggregations