use of org.opentripplanner.routing.core.State in project OpenTripPlanner by opentripplanner.
the class PlainStreetEdgeTest method testTraverseModeSwitchBike.
/**
* Test the traversal of two edges with different traverse modes, with a focus on cycling.
* This test will fail unless the following three conditions are met:
* 1. Turn costs are computed based on the back edge's traverse mode during reverse traversal.
* 2. Turn costs are computed such that bike walking is taken into account correctly.
* 3. User-specified bike speeds are applied correctly during turn cost computation.
*/
@Test
public void testTraverseModeSwitchBike() {
StreetEdge e0 = edge(v0, v1, 50.0, StreetTraversalPermission.PEDESTRIAN);
StreetEdge e1 = edge(v1, v2, 18.4, StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE);
v1.trafficLight = (true);
RoutingRequest forward = proto.clone();
forward.setMode(TraverseMode.BICYCLE);
forward.bikeSpeed = 3.0f;
forward.setRoutingContext(_graph, v0, v2);
State s0 = new State(forward);
State s1 = e0.traverse(s0);
State s2 = e1.traverse(s1);
RoutingRequest reverse = proto.clone();
reverse.setMode(TraverseMode.BICYCLE);
reverse.setArriveBy(true);
reverse.bikeSpeed = 3.0f;
reverse.setRoutingContext(_graph, v0, v2);
State s3 = new State(reverse);
State s4 = e1.traverse(s3);
State s5 = e0.traverse(s4);
assertEquals(73, s2.getElapsedTimeSeconds());
assertEquals(73, s5.getElapsedTimeSeconds());
}
use of org.opentripplanner.routing.core.State in project OpenTripPlanner by opentripplanner.
the class PlainStreetEdgeTest method testTurnRestriction.
@Test
public void testTurnRestriction() {
StreetEdge e0 = edge(v0, v1, 50.0, StreetTraversalPermission.ALL);
StreetEdge e1 = edge(v1, v2, 18.4, StreetTraversalPermission.ALL);
State state = new State(v2, 0, proto.clone());
state.getOptions().setArriveBy(true);
_graph.addTurnRestriction(e1, new TurnRestriction(e1, e0, null, TraverseModeSet.allModes()));
assertNotNull(e0.traverse(e1.traverse(state)));
}
use of org.opentripplanner.routing.core.State in project OpenTripPlanner by opentripplanner.
the class RoundBasedProfileRouter method makeSurfaces.
/**
* analyst mode: propagate to street network
*/
private void makeSurfaces() {
LOG.info("Propagating from transit stops to the street network...");
List<State> lower = Lists.newArrayList();
List<State> upper = Lists.newArrayList();
List<State> avg = Lists.newArrayList();
RoutingRequest rr = new RoutingRequest(TraverseMode.WALK);
rr.batch = (true);
rr.from = new GenericLocation(request.fromLat, request.fromLon);
rr.setRoutingContext(graph);
rr.longDistance = true;
rr.dominanceFunction = new DominanceFunction.EarliestArrival();
rr.setNumItineraries(1);
rr.worstTime = rr.dateTime + CUTOFF_SECONDS;
long startTime = rr.dateTime;
State origin = new State(rr);
// Multi-origin Dijkstra search; preinitialize the queue with states at each transit stop
for (Collection<ProfileState> pss : retainedStates.asMap().values()) {
TransitStop tstop = null;
int lowerBound = Integer.MAX_VALUE;
int upperBound = Integer.MAX_VALUE;
for (ProfileState ps : pss) {
if (tstop == null)
tstop = ps.stop;
if (ps.lowerBound < lowerBound)
lowerBound = ps.lowerBound;
if (ps.upperBound < upperBound)
upperBound = ps.upperBound;
}
if (lowerBound == Integer.MAX_VALUE || upperBound == Integer.MAX_VALUE)
throw new IllegalStateException("Invalid bound!");
lower.add(new State(tstop, null, lowerBound + startTime, startTime, rr));
upper.add(new State(tstop, null, upperBound + startTime, startTime, rr));
// TODO extremely incorrect hack!
avg.add(new State(tstop, null, (upperBound + lowerBound) / 2 + startTime, startTime, rr));
}
// get direct trips as well
lower.add(origin);
upper.add(origin);
avg.add(origin);
// create timesurfaces
timeSurfaceRangeSet = new TimeSurface.RangeSet();
AStar astar = new AStar();
timeSurfaceRangeSet.min = new TimeSurface(astar.getShortestPathTree(rr, 20, null, lower), false);
astar = new AStar();
timeSurfaceRangeSet.max = new TimeSurface(astar.getShortestPathTree(rr, 20, null, upper), false);
astar = new AStar();
timeSurfaceRangeSet.avg = new TimeSurface(astar.getShortestPathTree(rr, 20, null, avg), false);
rr.cleanup();
LOG.info("Done with propagation.");
/* Store the results in a field in the router object. */
}
use of org.opentripplanner.routing.core.State 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.State in project OpenTripPlanner by opentripplanner.
the class AStar method getShortestPathTree.
/**
* Get an SPT, starting from a collection of states
*/
public ShortestPathTree getShortestPathTree(RoutingRequest options, double relTimeoutSeconds, SearchTerminationStrategy terminationStrategy, Collection<State> initialStates) {
ShortestPathTree spt = null;
long abortTime = DateUtils.absoluteTimeout(relTimeoutSeconds);
startSearch(options, terminationStrategy, abortTime, false);
if (runState != null) {
for (State state : initialStates) {
runState.spt.add(state);
// TODO: hardwired for earliest arrival
// TODO: weights are seconds, no?
runState.pq.insert(state, state.getElapsedTimeSeconds());
}
runSearch(abortTime);
spt = runState.spt;
}
return spt;
}
Aggregations