
org.opentripplanner.raptor.api.request.SearchParams Maven / Gradle / Ivy
Show all versions of otp Show documentation
package org.opentripplanner.raptor.api.request;
import static org.opentripplanner.raptor.api.request.RaptorRequest.assertProperty;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import org.opentripplanner.framework.tostring.ToStringBuilder;
import org.opentripplanner.raptor.api.model.RaptorAccessEgress;
import org.opentripplanner.raptor.api.model.RaptorConstants;
import org.opentripplanner.raptor.api.model.RaptorTransfer;
/**
* The responsibility of this class is to encapsulate a Range Raptor travel request search
* parameters.
*/
public class SearchParams {
private final int earliestDepartureTime;
private final int latestArrivalTime;
private final int searchWindowInSeconds;
private final boolean preferLateArrival;
private final int numberOfAdditionalTransfers;
private final int maxNumberOfTransfers;
private final boolean timetable;
private final boolean constrainedTransfers;
private final Collection accessPaths;
private final Collection egressPaths;
/**
* Default values are defined in the default constructor.
*/
private SearchParams() {
earliestDepartureTime = RaptorConstants.TIME_NOT_SET;
latestArrivalTime = RaptorConstants.TIME_NOT_SET;
searchWindowInSeconds = RaptorConstants.NOT_SET;
preferLateArrival = false;
numberOfAdditionalTransfers = 5;
maxNumberOfTransfers = RaptorConstants.NOT_SET;
timetable = false;
constrainedTransfers = false;
accessPaths = List.of();
egressPaths = List.of();
}
SearchParams(SearchParamsBuilder> builder) {
this.earliestDepartureTime = builder.earliestDepartureTime();
this.latestArrivalTime = builder.latestArrivalTime();
this.searchWindowInSeconds = builder.searchWindowInSeconds();
this.preferLateArrival = builder.preferLateArrival();
this.numberOfAdditionalTransfers = builder.numberOfAdditionalTransfers();
this.maxNumberOfTransfers = builder.maxNumberOfTransfers();
this.timetable = builder.timetable();
this.constrainedTransfers = builder.constrainedTransfers();
this.accessPaths = List.copyOf(builder.accessPaths());
this.egressPaths = List.copyOf(builder.egressPaths());
}
/**
* The earliest a journey can depart from the origin. The unit is seconds since midnight.
* Inclusive.
*
* In the case of a 'depart after' search this is a required. In the case of a 'arrive by' search
* this is optional, but it will improve performance if it is set.
*/
public int earliestDepartureTime() {
return earliestDepartureTime;
}
public boolean isEarliestDepartureTimeSet() {
return earliestDepartureTime != RaptorConstants.TIME_NOT_SET;
}
/**
* The latest a journey may arrive at the destination. The unit is seconds since midnight.
* Exclusive.
*
* In the case of a 'arrive by' search this is a required. In the case of a 'depart after' search
* this is optional, but it will improve performance if it is set.
*/
public int latestArrivalTime() {
return latestArrivalTime;
}
public boolean isLatestArrivalTimeSet() {
return latestArrivalTime != RaptorConstants.TIME_NOT_SET;
}
/**
* The time window used to search. The unit is seconds.
*
* For a *depart-by-search*, this is added to the 'earliestDepartureTime' to find the
* 'latestDepartureTime'.
*
* For an *arrive-by-search* this is used to calculate the 'earliestArrivalTime'. The algorithm
* will find all optimal travels within the given time window.
*
* Set the search window to 0 (zero) to run 1 iteration.
*
* Required. Must be a positive integer or 0(zero).
*/
public int searchWindowInSeconds() {
return searchWindowInSeconds;
}
public boolean isSearchWindowSet() {
return searchWindowInSeconds != RaptorConstants.NOT_SET;
}
public boolean searchOneIterationOnly() {
return searchWindowInSeconds == 0;
}
/**
* Keep the latest departures arriving before the given latest-arrival-time(LAT). LAT is required
* if this parameter is set. This parameter is not allowed if the {@link #timetable} is
* enabled.
*
* TODO - Reactor, we should use an Enum value instead of this and 'timetable':
* - timePreference : enum TimePreference{ TIMETABLE, DEPART_AFTER, ARRIVE_BY }
* - PS! There are some corner cases here. E.g. DEPART_AFTER must work when
* edt=null & lat!=null - same for ARRIVE_BY.
*/
public boolean preferLateArrival() {
return preferLateArrival;
}
/**
* RangeRaptor is designed to search until the destination is reached and then {@code
* numberOfAdditionalTransfers} more rounds.
*
* The default value is 5.
*/
public int numberOfAdditionalTransfers() {
return numberOfAdditionalTransfers;
}
/**
* This is an absolute limit to the number of transfers. The preferred way to limit the transfers
* is to use the {@link #numberOfAdditionalTransfers()}.
*
* The default is to use the limit in the tuning parameters {@link RaptorTuningParameters#maxNumberOfTransfers()}.
*/
public int maxNumberOfTransfers() {
return maxNumberOfTransfers;
}
public boolean isMaxNumberOfTransfersSet() {
return maxNumberOfTransfers != RaptorConstants.NOT_SET;
}
/**
* The timetable flag allow a Journey to be included in the result if it departs from the origin
* AFTER another Journey, even if the first departure have lower cost, number of transfers, and
* shorter travel time. For two Journeys that depart at the same time only the best one will be
* included (both if they are mutually dominating each other).
*
* Setting this parameter to "TRUE" will increase the number of paths returned. The performance
* impact is small since the check only affect the pareto check at the destination.
*
* The default value is FALSE.
*/
public boolean timetable() {
return timetable;
}
/**
* If requested, constrained transfers(guaranteed, stay-seated ..) are used during routing, if
* not they are ignored. Some profiles do not support constrained transfers, for these profiles
* constrained transfers are NOT used - the 'constrainedTransfers' flag is ignored. Constrained
* transfers are supported for all profiles returning paths.
*/
public boolean constrainedTransfers() {
return constrainedTransfers;
}
/**
* List of access paths from the origin to all transit stops using the street network.
*
* Required, at least one access path must exist.
*/
public Collection accessPaths() {
return accessPaths;
}
/**
* List of all possible egress paths to reach the destination using the street network.
*
* NOTE! The {@link RaptorTransfer#stop()} is the stop where the egress path start, NOT the
* destination - think of it as a reversed path.
*
* Required, at least one egress path must exist.
*/
public Collection egressPaths() {
return egressPaths;
}
/**
* Get the maximum duration of any access or egress path in seconds.
*/
public int accessEgressMaxDurationSeconds() {
return Math.max(
accessPaths.stream().mapToInt(RaptorAccessEgress::durationInSeconds).max().orElse(0),
egressPaths.stream().mapToInt(RaptorAccessEgress::durationInSeconds).max().orElse(0)
);
}
@Override
public int hashCode() {
return Objects.hash(
earliestDepartureTime,
latestArrivalTime,
searchWindowInSeconds,
preferLateArrival,
numberOfAdditionalTransfers,
accessPaths,
egressPaths
);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SearchParams that = (SearchParams) o;
return (
earliestDepartureTime == that.earliestDepartureTime &&
latestArrivalTime == that.latestArrivalTime &&
searchWindowInSeconds == that.searchWindowInSeconds &&
preferLateArrival == that.preferLateArrival &&
numberOfAdditionalTransfers == that.numberOfAdditionalTransfers &&
accessPaths.equals(that.accessPaths) &&
egressPaths.equals(that.egressPaths)
);
}
@Override
public String toString() {
var dft = defaults();
return ToStringBuilder
.of(SearchParams.class)
.addServiceTime("earliestDepartureTime", earliestDepartureTime, dft.earliestDepartureTime)
.addServiceTime("latestArrivalTime", latestArrivalTime, dft.latestArrivalTime)
.addDurationSec("searchWindow", searchWindowInSeconds, dft.searchWindowInSeconds)
.addBoolIfTrue("departAsLateAsPossible", preferLateArrival)
.addNum(
"numberOfAdditionalTransfers",
numberOfAdditionalTransfers,
dft.numberOfAdditionalTransfers
)
.addCollection("accessPaths", accessPaths, 5, RaptorAccessEgress::defaultToString)
.addCollection("egressPaths", egressPaths, 5, RaptorAccessEgress::defaultToString)
.toString();
}
static SearchParams defaults() {
return new SearchParams();
}
/* private methods */
void verify() {
assertProperty(
isEarliestDepartureTimeSet() || isLatestArrivalTimeSet(),
"'earliestDepartureTime' or 'latestArrivalTime' is required."
);
assertProperty(!accessPaths.isEmpty(), "At least one 'accessPath' is required.");
assertProperty(!egressPaths.isEmpty(), "At least one 'egressPath' is required.");
assertProperty(
!(preferLateArrival && !isLatestArrivalTimeSet()),
"The 'latestArrivalTime' is required when 'departAsLateAsPossible' is set."
);
assertProperty(
!(preferLateArrival && timetable),
"The 'departAsLateAsPossible' is not allowed together with 'timetableEnabled'."
);
}
}