All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.transit.raptor.rangeraptor.standard.StdRangeRaptorWorkerState Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
package org.opentripplanner.transit.raptor.rangeraptor.standard;


import java.util.Collection;
import java.util.Iterator;
import org.opentripplanner.transit.raptor.api.path.Path;
import org.opentripplanner.transit.raptor.api.transit.IntIterator;
import org.opentripplanner.transit.raptor.api.transit.RaptorTransfer;
import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
import org.opentripplanner.transit.raptor.api.transit.TransitArrival;
import org.opentripplanner.transit.raptor.rangeraptor.standard.besttimes.BestTimes;
import org.opentripplanner.transit.raptor.rangeraptor.transit.TransitCalculator;
import org.opentripplanner.transit.raptor.util.BitSetIterator;


/**
 * Tracks the state of a standard Range Raptor search, specifically the best arrival times at each transit stop
 * at the end of a particular round, along with associated data to reconstruct paths etc.
 * 

* This is grouped into a separate class (rather than just having the fields in the raptor worker class) because we * want to separate the logic of maintaining stop arrival state and performing the steps of the algorithm. This * also make it possible to have more than one state implementation, which have ben used in the past to test different * memory optimizations. *

* Note that this represents the entire state of the Range Raptor search for all rounds. The {@code stopArrivalsState} * implementation can be swapped to achieve different results. * * @param The TripSchedule type defined by the user of the raptor API. */ public final class StdRangeRaptorWorkerState implements StdWorkerState { /** * The best times to reach each stop, whether via a transfer or via transit directly. * This is the bare minimum to execute the algorithm. */ private final BestTimes bestTimes; /** * Track the stop arrivals to be able to return some kind of result. Depending on the * desired result, different implementation is injected. */ private final StopArrivalsState stopArrivalsState; /** * The list of egress stops, can be used to terminate the search when the stops are reached. */ private final ArrivedAtDestinationCheck arrivedAtDestinationCheck; /** * The calculator is used to calculate transit related times/events like access arrival time. */ private final TransitCalculator calculator; /** * create a BestTimes Range Raptor State for given context. */ public StdRangeRaptorWorkerState( TransitCalculator calculator, BestTimes bestTimes, StopArrivalsState stopArrivalsState, ArrivedAtDestinationCheck arrivedAtDestinationCheck ) { this.calculator = calculator; this.bestTimes = bestTimes; this.stopArrivalsState = stopArrivalsState; this.arrivedAtDestinationCheck = arrivedAtDestinationCheck; } @Override public boolean isNewRoundAvailable() { return bestTimes.isCurrentRoundUpdated(); } @Override public BitSetIterator stopsTouchedByTransitCurrentRound() { return bestTimes.onBoardStopArrivalsReachedCurrentRound(); } @Override public IntIterator stopsTouchedPreviousRound() { return bestTimes.stopsReachedLastRound(); } @Override public boolean isStopReachedInPreviousRound(int stop) { return bestTimes.isStopReachedLastRound(stop); } /** * Return the "best time" found in the previous round. This is used to calculate the board/alight * time in the next round. *

* PLEASE OVERRIDE! *

* The implementation here is not correct - please override if you plan to use any result paths * or "rounds" as "number of transfers". The implementation is OK if the only thing you care * about is the "arrival time". */ @Override public int bestTimePreviousRound(int stop) { // This is a simplification, *bestTimes* might get updated during the current round; // Hence leading to a new boarding from the same stop in the same round. // If we do not count rounds or track paths, this is OK. But be sure to override this // method with the best time from the previous round if you care about number of // transfers and results paths. return stopArrivalsState.bestTimePreviousRound(stop); } @Override public void setAccessToStop(RaptorTransfer accessPath, int departureTime) { final int durationInSeconds = accessPath.durationInSeconds(); final int stop = accessPath.stop(); // The time of arrival at the given stop for the current iteration // (or departure time at the last stop if we search backwards). int arrivalTime = calculator.plusDuration(departureTime, durationInSeconds); if (exceedsTimeLimit(arrivalTime)) { return; } boolean reachedOnBoard = accessPath.stopReachedOnBoard() && newOnBoardBestTime(stop, arrivalTime); boolean bestTime = newOverallBestTime(stop, arrivalTime); if(reachedOnBoard || bestTime) { stopArrivalsState.setAccessTime(arrivalTime, accessPath, bestTime); } else { stopArrivalsState.rejectAccessTime(arrivalTime, accessPath); } } /** * Set the time at a transit stop iff it is optimal. This sets both the bestTime and the transitTime. */ @Override public void transitToStop(int stop, int arrivalTime, int boardStop, int boardTime, T trip) { if (exceedsTimeLimit(arrivalTime)) { return; } if (newOnBoardBestTime(stop, arrivalTime)) { // transitTimes upper bounds bestTimes final boolean newOverallBestTime = newOverallBestTime(stop, arrivalTime); stopArrivalsState.setNewBestTransitTime( stop, arrivalTime, trip, boardStop, boardTime, newOverallBestTime ); } else { stopArrivalsState.rejectNewBestTransitTime(stop, arrivalTime, trip, boardStop, boardTime); } } @Override public TransitArrival previousTransit(int boardStopIndex) { return stopArrivalsState.previousTransit(boardStopIndex); } /** * Set the arrival time at all transit stop if time is optimal for the given list of transfers. */ @Override public void transferToStops(int fromStop, Iterator transfers) { int arrivalTimeTransit = bestTimes.onBoardTime(fromStop); while (transfers.hasNext()) { transferToStop(arrivalTimeTransit, fromStop, transfers.next()); } } @Override public Collection> extractPaths() { return stopArrivalsState.extractPaths(); } private void transferToStop(int arrivalTimeTransit, int fromStop, RaptorTransfer transfer) { // Use the calculator to make sure the calculation is done correct for a normal // forward search and a reverse search. final int arrivalTime = calculator.plusDuration(arrivalTimeTransit, transfer.durationInSeconds()); if (exceedsTimeLimit(arrivalTime)) { return; } final int toStop = transfer.stop(); if (newOverallBestTime(toStop, arrivalTime)) { stopArrivalsState.setNewBestTransferTime(fromStop, arrivalTime, transfer); } else { stopArrivalsState.rejectNewBestTransferTime(fromStop, arrivalTime, transfer); } } @Override public boolean isDestinationReachedInCurrentRound() { return arrivedAtDestinationCheck.arrivedAtDestinationCurrentRound(); } /* private methods */ private boolean newOverallBestTime(int stop, int alightTime) { return bestTimes.updateNewBestTime(stop, alightTime); } private boolean newOnBoardBestTime(int stop, int alightTime) { return bestTimes.updateOnBoardBestTime(stop, alightTime); } private boolean exceedsTimeLimit(int time) { return calculator.exceedsTimeLimit(time); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy