org.opentripplanner.transit.raptor.rangeraptor.standard.configure.StdRangeRaptorConfig Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otp Show documentation
Show all versions of otp Show documentation
The OpenTripPlanner multimodal journey planning system
package org.opentripplanner.transit.raptor.rangeraptor.standard.configure;
import java.util.function.BiFunction;
import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
import org.opentripplanner.transit.raptor.api.view.Heuristics;
import org.opentripplanner.transit.raptor.api.view.Worker;
import org.opentripplanner.transit.raptor.rangeraptor.RoutingStrategy;
import org.opentripplanner.transit.raptor.rangeraptor.WorkerState;
import org.opentripplanner.transit.raptor.rangeraptor.path.DestinationArrivalPaths;
import org.opentripplanner.transit.raptor.rangeraptor.path.configure.PathConfig;
import org.opentripplanner.transit.raptor.rangeraptor.standard.ArrivalTimeRoutingStrategy;
import org.opentripplanner.transit.raptor.rangeraptor.standard.ArrivedAtDestinationCheck;
import org.opentripplanner.transit.raptor.rangeraptor.standard.BestNumberOfTransfers;
import org.opentripplanner.transit.raptor.rangeraptor.standard.MinTravelDurationRoutingStrategy;
import org.opentripplanner.transit.raptor.rangeraptor.standard.StdRangeRaptorWorkerState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.StdWorkerState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.StopArrivalsState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.BestTimes;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.BestTimesOnlyStopArrivalsState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.SimpleArrivedAtDestinationCheck;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.SimpleBestNumberOfTransfers;
import org.opentripplanner.transit.raptor.rangeraptor.standard.debug.DebugStopArrivalsState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.heuristics.HeuristicSearch;
import org.opentripplanner.transit.raptor.rangeraptor.standard.heuristics.HeuristicsAdapter;
import org.opentripplanner.transit.raptor.rangeraptor.standard.stoparrivals.StdStopArrivalsState;
import org.opentripplanner.transit.raptor.rangeraptor.standard.stoparrivals.StopArrivals;
import org.opentripplanner.transit.raptor.rangeraptor.standard.stoparrivals.path.EgressArrivalToPathAdapter;
import org.opentripplanner.transit.raptor.rangeraptor.standard.stoparrivals.view.StopsCursor;
import org.opentripplanner.transit.raptor.rangeraptor.transit.SearchContext;
/**
* The responsibility of this class is to wire different standard range raptor
* worker configurations together based on the context passed into the class.
* There is a factory (create) method for each legal configuration.
*
* @param The TripSchedule type defined by the user of the raptor API.
*/
public class StdRangeRaptorConfig {
private final SearchContext ctx;
private final PathConfig pathConfig;
private BestTimes bestTimes = null;
private StopArrivals arrivals = null;
private ArrivedAtDestinationCheck destinationCheck = null;
private BestNumberOfTransfers bestNumberOfTransfers = null;
public StdRangeRaptorConfig(SearchContext context) {
this.ctx = context;
this.pathConfig = new PathConfig<>(context);
}
/**
* Create a heuristic search using the provided callback to create the worker.
* The callback is necessary because the heuristics MUST be created before the
* worker, if not the heuristic can not be added to the worker lifecycle and fails.
*/
public HeuristicSearch createHeuristicSearch(
BiFunction, RoutingStrategy, Worker> createWorker
) {
StdRangeRaptorWorkerState state = createState();
Heuristics heuristics = createHeuristicsAdapter();
return new HeuristicSearch<>(createWorker.apply(state, createWorkerStrategy(state)), heuristics);
}
public Worker createSearch(
BiFunction, RoutingStrategy, Worker> createWorker
) {
StdRangeRaptorWorkerState state = createState();
return createWorker.apply(state, createWorkerStrategy(state));
}
/* private factory methods */
private StdRangeRaptorWorkerState createState() {
new VerifyRequestIsValid(ctx).verify();
switch (ctx.profile()) {
case STANDARD:
case MIN_TRAVEL_DURATION:
return workerState(stdStopArrivalsState());
case BEST_TIME:
case MIN_TRAVEL_DURATION_BEST_TIME:
return workerState(bestTimeStopArrivalsState());
}
throw new IllegalArgumentException(ctx.profile().toString());
}
private RoutingStrategy createWorkerStrategy(StdWorkerState state) {
switch (ctx.profile()) {
case STANDARD:
case BEST_TIME:
return new ArrivalTimeRoutingStrategy<>(ctx.calculator(), state);
case MIN_TRAVEL_DURATION:
case MIN_TRAVEL_DURATION_BEST_TIME:
return new MinTravelDurationRoutingStrategy<>(ctx.calculator(), state);
}
throw new IllegalArgumentException(ctx.profile().toString());
}
private Heuristics createHeuristicsAdapter() {
assertNotNull(bestNumberOfTransfers);
return new HeuristicsAdapter(
bestTimes(),
this.bestNumberOfTransfers,
ctx.egressPaths(),
ctx.calculator(),
ctx.lifeCycle()
);
}
private StdRangeRaptorWorkerState workerState(StopArrivalsState stopArrivalsState) {
return new StdRangeRaptorWorkerState<>(ctx.calculator(), bestTimes(), stopArrivalsState, destinationCheck());
}
private BestTimesOnlyStopArrivalsState bestTimeStopArrivalsState() {
return new BestTimesOnlyStopArrivalsState<>(bestTimes(), simpleBestNumberOfTransfers());
}
/**
* Return instance if created by heuristics or null if not needed.
*/
private SimpleBestNumberOfTransfers simpleBestNumberOfTransfers() {
SimpleBestNumberOfTransfers value = new SimpleBestNumberOfTransfers(
ctx.nStops(),
ctx.roundProvider()
);
setBestNumberOfTransfers(value);
return value;
}
/**
* Create a Standard Range Raptor state for the given context. If debugging is enabled,
* the stop arrival state is wrapped.
*/
private StopArrivalsState stdStopArrivalsState() {
StdStopArrivalsState state = new StdStopArrivalsState<>(stopArrivals(), destinationArrivalPaths());
return wrapStopArrivalsStateWithDebugger(state);
}
private StopArrivalsState wrapStopArrivalsStateWithDebugger(StopArrivalsState state) {
if (ctx.debugFactory().isDebugStopArrival()) {
return new DebugStopArrivalsState<>(ctx.roundProvider(), ctx.debugFactory(), stopsCursor(), state);
} else {
return state;
}
}
private StopArrivals stopArrivals() {
if (arrivals == null) {
arrivals = new StopArrivals<>(
ctx.nRounds(),
ctx.nStops(),
ctx.roundProvider()
);
setBestNumberOfTransfers(arrivals);
}
return arrivals;
}
private void setBestNumberOfTransfers(BestNumberOfTransfers bestNumberOfTransfers) {
assertSetValueIsNull("bestNumberOfTransfers", this.bestNumberOfTransfers, bestNumberOfTransfers);
this.bestNumberOfTransfers = bestNumberOfTransfers;
}
private StopsCursor stopsCursor() {
// Always create new cursors
return new StopsCursor<>(stopArrivals(), ctx.calculator(), ctx.boardSlackProvider());
}
private DestinationArrivalPaths destinationArrivalPaths() {
DestinationArrivalPaths destinationArrivalPaths = pathConfig.createDestArrivalPaths(false);
// Add egressArrivals to stops and bind them to the destination arrival paths. The
// adapter notify the destination on each new egress stop arrival.
EgressArrivalToPathAdapter pathsAdapter = new EgressArrivalToPathAdapter<>(
destinationArrivalPaths,
ctx.calculator(),
stopsCursor(),
ctx.lifeCycle()
);
// Use the adapter to play the role of the destination arrival check
setDestinationCheck(pathsAdapter);
stopArrivals().setupEgressStopStates(ctx.egressPaths(), pathsAdapter);
return destinationArrivalPaths;
}
private BestTimes bestTimes() {
// Cache best times; request scope
if (bestTimes == null) {
bestTimes = new BestTimes(ctx.nStops(), ctx.calculator(), ctx.lifeCycle());
}
return bestTimes;
}
private ArrivedAtDestinationCheck destinationCheck() {
// Cache best times; request scope
if (destinationCheck == null) {
setDestinationCheck(simpleDestinationCheck());
}
return destinationCheck;
}
private void setDestinationCheck(ArrivedAtDestinationCheck check) {
// Cache best times; request scope
if (destinationCheck != null) {
throw new IllegalStateException(
"ArrivedAtDestinationCheck is alredy initialized: " + destinationCheck.getClass().getSimpleName()
);
}
destinationCheck = check;
}
private SimpleArrivedAtDestinationCheck simpleDestinationCheck() {
return new SimpleArrivedAtDestinationCheck(ctx.egressStops(), bestTimes());
}
private void assertSetValueIsNull(String name, Object setValue, Object newValue) {
if (setValue != null) {
throw new IllegalStateException(
"There is more than one instance of " + name + ": " +
newValue.getClass().getSimpleName() + ", " +
setValue.getClass().getSimpleName()
);
}
}
private void assertNotNull(Object value) {
if(value == null) {
throw new NullPointerException();
}
}
}