use of org.opentripplanner.routing.core.TransferTable in project OpenTripPlanner by opentripplanner.
the class Timetable method adjustTimeForTransfer.
/**
* Check transfer table rules. Given the last alight time from the State,
* return the boarding time t0 adjusted for this particular trip's minimum transfer time,
* or -1 if boarding this trip is not allowed.
* FIXME adjustedTime can legitimately be -1! But negative times might as well be zero.
*/
private int adjustTimeForTransfer(State state, Stop currentStop, Trip trip, boolean boarding, ServiceDay serviceDay, int t0) {
if (!state.isEverBoarded()) {
// This is the first boarding not a transfer.
return t0;
}
TransferTable transferTable = state.getOptions().getRoutingContext().transferTable;
int transferTime = transferTable.getTransferTime(state.getPreviousStop(), currentStop, state.getPreviousTrip(), trip, boarding);
// Check whether back edge is TimedTransferEdge
if (state.getBackEdge() instanceof TimedTransferEdge) {
// Transfer must be of type TIMED_TRANSFER
if (transferTime != StopTransfer.TIMED_TRANSFER) {
return -1;
}
}
if (transferTime == StopTransfer.UNKNOWN_TRANSFER) {
// no special rules, just board
return t0;
}
if (transferTime == StopTransfer.FORBIDDEN_TRANSFER) {
// This transfer is forbidden
return -1;
}
// There is a minimum transfer time to make this transfer. Ensure that it is respected.
int minTime = serviceDay.secondsSinceMidnight(state.getLastAlightedTimeSeconds());
if (boarding) {
minTime += transferTime;
if (minTime > t0)
return minTime;
} else {
minTime -= transferTime;
if (minTime < t0)
return minTime;
}
return t0;
}
use of org.opentripplanner.routing.core.TransferTable in project OpenTripPlanner by opentripplanner.
the class TestPatternHopFactory method testTransfers.
public void testTransfers() throws Exception {
TransferTable transferTable = graph.getTransferTable();
// create dummy routes and trips
// In tests we don't patch entities with the feed id, only default agency id is used.
Route fromRoute = new Route();
fromRoute.setId(new AgencyAndId("agency", "1"));
Trip fromTrip = new Trip();
fromTrip.setId(new AgencyAndId("agency", "1.1"));
fromTrip.setRoute(fromRoute);
Route toRoute = new Route();
toRoute.setId(new AgencyAndId("agency", "2"));
Trip toTrip = new Trip();
toTrip.setId(new AgencyAndId("agency", "2.1"));
toTrip.setRoute(toRoute);
Trip toTrip2 = new Trip();
toTrip2.setId(new AgencyAndId("agency", "2.2"));
toTrip2.setRoute(toRoute);
// find stops
Stop stopK = ((TransitStopArrive) graph.getVertex(feedId + ":K_arrive")).getStop();
Stop stopN = ((TransitStopDepart) graph.getVertex(feedId + ":N_depart")).getStop();
Stop stopM = ((TransitStopDepart) graph.getVertex(feedId + ":M_depart")).getStop();
assertTrue(transferTable.hasPreferredTransfers());
assertEquals(StopTransfer.UNKNOWN_TRANSFER, transferTable.getTransferTime(stopN, stopM, fromTrip, toTrip, true));
assertEquals(StopTransfer.FORBIDDEN_TRANSFER, transferTable.getTransferTime(stopK, stopM, fromTrip, toTrip, true));
assertEquals(StopTransfer.PREFERRED_TRANSFER, transferTable.getTransferTime(stopN, stopK, toTrip, toTrip2, true));
assertEquals(StopTransfer.TIMED_TRANSFER, transferTable.getTransferTime(stopN, stopK, fromTrip, toTrip, true));
assertEquals(15, transferTable.getTransferTime(stopN, stopK, fromTrip, toTrip2, true));
TransitStop e_arrive = (TransitStop) graph.getVertex(feedId + ":E");
TransitStop f_depart = (TransitStop) graph.getVertex(feedId + ":F");
Edge edge = new TransferEdge(e_arrive, f_depart, 10000, 10000);
long startTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 18, 0, 50, 0);
Vertex stop_b = graph.getVertex(feedId + ":B_depart");
Vertex stop_g = graph.getVertex(feedId + ":G_arrive");
RoutingRequest options = new RoutingRequest();
options.dateTime = startTime;
options.setRoutingContext(graph, stop_b, stop_g);
ShortestPathTree spt = aStar.getShortestPathTree(options);
GraphPath path = spt.getPath(stop_g, false);
assertNotNull(path);
assertTrue("expected to use much later trip due to min transfer time", path.getEndTime() - startTime > 4.5 * 60 * 60);
/* cleanup */
e_arrive.removeOutgoing(edge);
f_depart.removeIncoming(edge);
}
use of org.opentripplanner.routing.core.TransferTable in project OpenTripPlanner by opentripplanner.
the class TransitBoardAlight method traverse.
/**
* NOTE: We do not need to check the pickup/drop off type. TransitBoardAlight edges are simply
* not created for pick/drop type 1 (no pick/drop).
*
* @param arrivalTimeAtStop TODO: clarify what this is.
*/
public State traverse(State s0, long arrivalTimeAtStop) {
RoutingContext rctx = s0.getContext();
RoutingRequest options = s0.getOptions();
// Forbid taking shortcuts composed of two board-alight edges in a row. Also avoids spurious leg transitions.
if (s0.backEdge instanceof TransitBoardAlight) {
return null;
}
/* If the user requested a wheelchair accessible trip, check whether and this stop is not accessible. */
if (options.wheelchairAccessible && !getPattern().wheelchairAccessible(stopIndex)) {
return null;
}
;
/*
* Determine whether we are going onto or off of transit. Entering and leaving transit is
* not the same thing as boarding and alighting. When arriveBy == true, we are entering
* transit when traversing an alight edge backward.
*/
boolean leavingTransit = (boarding && options.arriveBy) || (!boarding && !options.arriveBy);
/* TODO pull on/off transit out into two functions. */
if (leavingTransit) {
// Perhaps this should be handled by PathParser.
if (s0.getBackEdge() instanceof TransitBoardAlight) {
return null;
}
StateEditor s1 = s0.edit(this);
s1.setTripId(null);
s1.setLastAlightedTimeSeconds(s0.getTimeSeconds());
// Store the stop we are alighting at, for computing stop-to-stop transfer times,
// preferences, and permissions.
// The vertices in the transfer table are stop arrives/departs, not pattern
// arrives/departs, so previousStop is direction-dependent.
s1.setPreviousStop(getStop());
s1.setLastPattern(this.getPattern());
if (boarding) {
int boardingTime = options.getBoardTime(this.getPattern().mode);
if (boardingTime != 0) {
// When traveling backwards the time travels also backwards
s1.incrementTimeInSeconds(boardingTime);
s1.incrementWeight(boardingTime * options.waitReluctance);
}
} else {
int alightTime = options.getAlightTime(this.getPattern().mode);
if (alightTime != 0) {
s1.incrementTimeInSeconds(alightTime);
s1.incrementWeight(alightTime * options.waitReluctance);
// TODO: should we have different cost for alighting and boarding compared to regular waiting?
}
}
/* Determine the wait. */
if (arrivalTimeAtStop > 0) {
// FIXME what is this arrivalTimeAtStop?
int wait = (int) Math.abs(s0.getTimeSeconds() - arrivalTimeAtStop);
s1.incrementTimeInSeconds(wait);
// this should only occur at the beginning
s1.incrementWeight(wait * options.waitAtBeginningFactor);
s1.setInitialWaitTimeSeconds(wait);
// LOG.debug("Initial wait time set to {} in PatternBoard", wait);
}
// so that comparable trip plans result (comparable to non-optimized plans)
if (options.reverseOptimizing)
s1.incrementWeight(options.getBoardCost(s0.getNonTransitMode()));
if (options.reverseOptimizeOnTheFly) {
TripPattern pattern = getPattern();
int thisDeparture = s0.getTripTimes().getDepartureTime(stopIndex);
int numTrips = getPattern().getNumScheduledTrips();
int nextDeparture;
s1.setLastNextArrivalDelta(Integer.MAX_VALUE);
for (int tripIndex = 0; tripIndex < numTrips; tripIndex++) {
Timetable timetable = pattern.getUpdatedTimetable(options, s0.getServiceDay());
nextDeparture = timetable.getTripTimes(tripIndex).getDepartureTime(stopIndex);
if (nextDeparture > thisDeparture) {
s1.setLastNextArrivalDelta(nextDeparture - thisDeparture);
break;
}
}
}
s1.setBackMode(getMode());
return s1.makeState();
} else {
/* Disallow ever re-boarding the same trip pattern. */
if (s0.getLastPattern() == this.getPattern()) {
return null;
}
/* Check this pattern's mode against those allowed in the request. */
if (!options.modes.get(modeMask)) {
return null;
}
/* We assume all trips in a pattern are on the same route. Check if that route is banned. */
if (options.bannedRoutes != null && options.bannedRoutes.matches(getPattern().route)) {
// TODO: remove route checks in/after the trip search
return null;
}
/*
* Find the next boarding/alighting time relative to the current State. Check lists of
* transit serviceIds running yesterday, today, and tomorrow relative to the initial
* state. Choose the closest board/alight time among trips starting yesterday, today, or
* tomorrow. Note that we cannot skip searching on service days that have not started
* yet: Imagine a state at 23:59 Sunday, that should take a bus departing at 00:01
* Monday (and coded on Monday in the GTFS); disallowing Monday's departures would
* produce a strange plan. We also can't break off the search after we find trips today.
* Imagine a trip on a pattern at 25:00 today and another trip on the same pattern at
* 00:30 tommorrow. The 00:30 trip should be taken, but if we stopped the search after
* finding today's 25:00 trip we would never find tomorrow's 00:30 trip.
*/
TripPattern tripPattern = this.getPattern();
int bestWait = -1;
TripTimes bestTripTimes = null;
ServiceDay bestServiceDay = null;
for (ServiceDay sd : rctx.serviceDays) {
/* Find the proper timetable (updated or original) if there is a realtime snapshot. */
Timetable timetable = tripPattern.getUpdatedTimetable(options, sd);
/* Skip this day/timetable if no trip in it could possibly be useful. */
// TODO disabled until frequency representation is stable, and min/max timetable times are set from frequencies
// However, experiments seem to show very little measurable improvement here (due to cache locality?)
// if ( ! timetable.temporallyViable(sd, s0.getTimeSeconds(), bestWait, boarding)) continue;
/* Find the next or prev departure depending on final boolean parameter. */
TripTimes tripTimes = timetable.getNextTrip(s0, sd, stopIndex, boarding);
if (tripTimes != null) {
/* Wait is relative to departures on board and arrivals on alight. */
int wait = boarding ? (int) (sd.time(tripTimes.getDepartureTime(stopIndex)) - s0.getTimeSeconds()) : (int) (s0.getTimeSeconds() - sd.time(tripTimes.getArrivalTime(stopIndex)));
/* A trip was found. The wait should be non-negative. */
if (wait < 0)
LOG.error("Negative wait time when boarding.");
/* Track the soonest departure over all relevant schedules. */
if (bestWait < 0 || wait < bestWait) {
bestWait = wait;
bestServiceDay = sd;
bestTripTimes = tripTimes;
}
}
}
// no appropriate trip was found
if (bestWait < 0)
return null;
Trip trip = bestTripTimes.trip;
// FIXME this should be done WHILE searching for a trip.
if (options.tripIsBanned(trip))
return null;
/* Check if route is preferred by the user. */
long preferences_penalty = options.preferencesPenaltyForRoute(getPattern().route);
/* Compute penalty for non-preferred transfers. */
int transferPenalty = 0;
/* If this is not the first boarding, then we are transferring. */
if (s0.isEverBoarded()) {
TransferTable transferTable = options.getRoutingContext().transferTable;
int transferTime = transferTable.getTransferTime(s0.getPreviousStop(), getStop(), s0.getPreviousTrip(), trip, boarding);
transferPenalty = transferTable.determineTransferPenalty(transferTime, options.nonpreferredTransferPenalty);
}
/* Found a trip to board. Now make the child state. */
StateEditor s1 = s0.edit(this);
s1.setBackMode(getMode());
s1.setServiceDay(bestServiceDay);
// Save the trip times in the State to ensure that router has a consistent view
// and constant-time access to them.
s1.setTripTimes(bestTripTimes);
s1.incrementTimeInSeconds(bestWait);
s1.incrementNumBoardings();
s1.setTripId(trip.getId());
s1.setPreviousTrip(trip);
s1.setZone(getPattern().getZone(stopIndex));
s1.setRoute(trip.getRoute().getId());
double wait_cost = bestWait;
if (!s0.isEverBoarded() && !options.reverseOptimizing) {
wait_cost *= options.waitAtBeginningFactor;
s1.setInitialWaitTimeSeconds(bestWait);
} else {
wait_cost *= options.waitReluctance;
}
s1.incrementWeight(preferences_penalty);
s1.incrementWeight(transferPenalty);
// alight to prevent state domination due to free alights
if (options.reverseOptimizing) {
s1.incrementWeight(wait_cost);
} else {
s1.incrementWeight(wait_cost + options.getBoardCost(s0.getNonTransitMode()));
}
// impacting the possibility of this trip
if (options.reverseOptimizeOnTheFly && !options.reverseOptimizing && s0.isEverBoarded() && s0.getLastNextArrivalDelta() <= bestWait && s0.getLastNextArrivalDelta() > -1) {
// it is re-reversed by optimize, so this still yields a forward tree
State optimized = s1.makeState().optimizeOrReverse(true, true);
if (optimized == null)
LOG.error("Null optimized state. This shouldn't happen.");
return optimized;
}
/* If we didn't return an optimized path, return an unoptimized one. */
return s1.makeState();
}
}
use of org.opentripplanner.routing.core.TransferTable in project OpenTripPlanner by opentripplanner.
the class GTFSPatternHopFactory method loadTransfers.
private void loadTransfers(Graph graph) {
Collection<Transfer> transfers = _dao.getAllTransfers();
TransferTable transferTable = graph.getTransferTable();
for (Transfer sourceTransfer : transfers) {
// we thus expand transfers that use parent stations to all the member stops.
for (Transfer t : expandTransfer(sourceTransfer)) {
Stop fromStop = t.getFromStop();
Stop toStop = t.getToStop();
Route fromRoute = t.getFromRoute();
Route toRoute = t.getToRoute();
Trip fromTrip = t.getFromTrip();
Trip toTrip = t.getToTrip();
Vertex fromVertex = context.stopArriveNodes.get(fromStop);
Vertex toVertex = context.stopDepartNodes.get(toStop);
switch(t.getTransferType()) {
case 1:
// timed (synchronized) transfer
// Handle with edges that bypass the street network.
// from and to vertex here are stop_arrive and stop_depart vertices
// only add edge when it doesn't exist already
boolean hasTimedTransferEdge = false;
for (Edge outgoingEdge : fromVertex.getOutgoing()) {
if (outgoingEdge instanceof TimedTransferEdge) {
if (outgoingEdge.getToVertex() == toVertex) {
hasTimedTransferEdge = true;
break;
}
}
}
if (!hasTimedTransferEdge) {
new TimedTransferEdge(fromVertex, toVertex);
}
// add to transfer table to handle specificity
transferTable.addTransferTime(fromStop, toStop, fromRoute, toRoute, fromTrip, toTrip, StopTransfer.TIMED_TRANSFER);
break;
case 2:
// min transfer time
transferTable.addTransferTime(fromStop, toStop, fromRoute, toRoute, fromTrip, toTrip, t.getMinTransferTime());
break;
case 3:
// forbidden transfer
transferTable.addTransferTime(fromStop, toStop, fromRoute, toRoute, fromTrip, toTrip, StopTransfer.FORBIDDEN_TRANSFER);
break;
case 0:
default:
// preferred transfer
transferTable.addTransferTime(fromStop, toStop, fromRoute, toRoute, fromTrip, toTrip, StopTransfer.PREFERRED_TRANSFER);
break;
}
}
}
}
Aggregations