-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Part A - Via search, refactor OTP Internal programming API #4156
Comments
During our breakdown of this issue we ran into some questions:
|
You can do as you like. It looks strange, but it is part of a larger refactoring and touches the work I am doing as well, when I am done the RoutingService will be gone.
My thoughts: There are a few domains: REST API, 2 Graph QL APIs, RoutingService(glue on top of Street Model and Transit Model), Street Model (AStar graph), Transit Model (Raptor transit data), AStart, Raptor and so on... Right now the bounderies are not clear . The classes above replaces the
No. But, yes. Keep in mind that the Request classes are DTOs, so putting interfaces on top does not serve a purpose. But, we do not want to duplicate these classes in another form when passing the information down to the different domains, so the trick is to let each model define its own API interfaces and then let the But for now, just keep the existing mapping code, this is a refactoring we will do gradually. |
Here is a revised edition of the model Modelpackage org.opentripplanner.routing.api.request;
interface RoutingService {
RoutingResponse route(RouteRequest request);
RoutingResponse routeVia(RouteViaRequest request, RoutingPreferences preferences);
}
// TODO - Inline RouteRequest, rename RouteRequest
class RoutingRequestAndPreferences { .. }
class RouteRequest {
Instant dateTime = Instant.now();
GenericLocation from;
GenericLocation to;
Duration searchWindow;
PageCursor pageCursor;
boolean timetableView = true;
boolean arriveBy = false;
Locale locale = new Locale("en", "US");
int numItineraries = 50;
// TODO VIA
boolean wheelchairEnabled = false;
// Nested
JourneyRequest journey;
RoutingPreferences preferences; // TODO - this is in RoutingRequestAndPreferences
// TODO VIA - Move this here from SystemPreferences
ItineraryFilterParameters itineraryFilters = ItineraryFilterParameters.createDefault();
// TODO VIA - Move this here from SystemPreferences
DataOverlayParameters dataOverlay;
// Deprecated - not working - TODO VIA Delete these
FeedScopedId startingTransitStopId;
FeedScopedId startingTransitTripId;
// Internal state
// fromEnvelope, toEnvelope (these belong in the Graph context)
};
/**
* User request: from/to time/location; preferences slack/cost/reluctance
*/
class RouteViaRequest {
Instant dateTime = Instant.now();
GenericLocation from;
GenericLocation to;
List<ViaLocation> viaPoints;
// Number of trips must match viaPoints + 1 and is limited to max 5 trips
List<JourneyRequest> viaJourneys;
Duration searchWindow;
PageCursor pageCursor;
// boolean timetableView = true; ONLY SUPPORT true
boolean arriveBy = false;
Locale locale = new Locale("en", "US");
int numItineraries = 50;
}
class JourneyRequest {
// TODO VIA - initial value should be null
TransitRequest transit = null;
StreetRequest access = null;
StreetRequest egress = null;
StreetRequest transfer = null;
StreetRequest direct = null;
// TODO VIA - These parameters control transit and direct search
boolean hasTransit() { return transit != null; }
boolean hasDirect() { return direct != null; }
// TODO VIA - Set transit, access, egress and transfer nonnull
JourneyRequest enableTransit();
// TODO VIA - Set transit, access, egress and transfer nonnull
JourneyRequest enableDirect();
}
/**
* User/trip cost/time/slack/reluctance search config.
*/
class RoutingPreferences {
TransitPreferences transit;
TransferPreferences transfer;
StreetPreferences street;
WalkPreferences walk;
WheelchairPreferences wheelchair;
BikePreferences bike;
CarPreferences car;
VehicleRentalPreferences rental;
ItineraryFilterParameters itineraryFilters = ItineraryFilterParameters.createDefault();
DataOverlayParameters dataOverlay;
SystemPreferences system;
}
class ViaLocation {
GenericLocation point;
boolean passThroughPoint = false;
Duration slack = Duration.ofMinutes(60);
}
class TransitPreferences {
boolean ignoreRealtimeUpdates = false;
boolean includePlannedCancellations = false;
int boardSlack = 0;
Map<TransitMode, Integer> boardSlackForMode = new EnumMap<>(TransitMode.class);
int alightSlack = 0;
Map<TransitMode, Integer> alightSlackForMode = new EnumMap<>(TransitMode.class);
Map<TransitMode, Double> reluctanceForMode = new HashMap<>();
@Deprecated int otherThanPreferredRoutesPenalty = 300;
@Deprecated int useUnpreferredRoutesPenalty = 300;
RaptorOptions raptorOptions = new RaptorOptions();
};
class TransitRequest {
List<AllowedTransitMode> modes = AllowedTransitMode.getAllTransitModes();
List<FeedScopedId> whiteListedAgencies = List.of();
List<FeedScopedId> bannedAgencies = List.of();
List<FeedScopedId> preferredAgencies = List.of();
List<FeedScopedId> unpreferredAgencies = List.of();
RouteMatcher whiteListedRoutes = RouteMatcher.emptyMatcher();
RouteMatcher bannedRoutes = RouteMatcher.emptyMatcher();
RouteMatcher preferredRoutes = RouteMatcher.emptyMatcher();
@Deprecated RouteMatcher unpreferredRoutes = RouteMatcher.emptyMatcher();
Set<FeedScopedId> bannedTrips = Set.of();
DebugRaptor raptorDebugging = new DebugRaptor();
}
class TransferPreferences {
int cost = 0;
int slack = 120;
int nonpreferredCost = 180;
double waitReluctance = 1.0;
double waitAtBeginningFactor = 0.4;
TransferOptimizationParameters optimization = new TransferOptimizationRequest();
Integer maxTransfers = 12;
}
class WalkPreferences {
double speed = 1.33;
double reluctance = 2.0;
// TODO VIA - Move to TransitPreferences: walkBoardCost
int boardCost = 60 * 10;
double stairsReluctance = 2.0;
double stairsTimeFactor = 3.0;
}
// Direct street search
class StreetPreferences {
Duration maxAccessEgressDuration = Duration.ofMinutes(45);
Map<StreetMode, Duration> maxAccessEgressDurationForMode = new HashMap<>();
Duration maxDirectStreetDuration = Duration.ofHours(4);
Map<StreetMode, Duration> maxDirectStreetDurationForMode = new HashMap<>();
double turnReluctance = 1.0;
int elevatorBoardTime = 90;
int elevatorBoardCost = 90;
int elevatorHopTime = 20;
int elevatorHopCost = 20;
String pathComparator = null;
}
class StreetRequest {
Duration maxDuration; // <- Default from StreetPreferences
StreetMode mode = StreetMode.WALK;
// TODO VIA - Move from JourneyRequest
TraverseModeSet traverseModeSet;
// TODO VIA - Move here from JourneyRequest
VehicleRentalRequest vehicleRental;
VehicleParkingRequest vehicleParking;
}
// TODO VIA - Rename WheelchairPreferences
class WheelchairAccessibilityRequest {
// TODO VIA - Move this to request
// boolean enabled
WheelchairAccessibilityFeature trip;
WheelchairAccessibilityFeature stop;
WheelchairAccessibilityFeature elevator;
double inaccessibleStreetReluctance;
double maxSlope;
double slopeExceededReluctance;
double stairsReluctance;
}
class BikePreferences {
BicycleOptimizeType optimizeType = BicycleOptimizeType.SAFE;
double speed = 5;
// TODO VIA - Move to TransitPreferences: bikeBoardCost
int boardCost = 60 * 10;
double walkingSpeed = 1.33;
double walkingReluctance = 5.0;
double reluctance = 2.0;
int switchTime;
int switchCost;
int parkTime = 60;
int parkCost = 120;
double triangleTimeFactor;
double triangleSlopeFactor;
double triangleSafetyFactor;
}
class CarPreferences {
double speed = 40.0;
double reluctance = 2.0;
int parkTime = 60;
int parkCost = 120;
int dropoffTime = 120;
int pickupTime = 60;
int pickupCost = 120;
double decelerationSpeed = 2.9;
double accelerationSpeed = 2.9;
}
class VehicleRentalPreferences {
int pickupTime = 60;
int pickupCost = 120;
int dropoffTime = 30;
int dropoffCost = 30;
double keepingVehicleAtDestinationCost = 0;
}
class VehicleRentalRequest {
Set<RentalVehicleType.FormFactor> allowedFormFactors = new HashSet<>();
Set<String> allowedNetworks = Set.of();
Set<String> bannedNetworks = Set.of();
boolean useAvailabilityInformation = false;
boolean allowKeepingVehicleAtDestination = false;
}
class VehicleParkingRequest {
Set<String> requiredTags = Set.of();
Set<String> bannedTags = Set.of();
boolean useAvailabilityInformation = false;
}
/** System config & debug, available on API for testing purposes */
class SystemPreferences {
Tags tags = Tags.of();
boolean geoidElevation=false;
// The REST API should hold onto this, and pass it to the mapper, no need to include it in the
// request.
// boolean showIntermediateStops=false;
}
class DELETE_THESE {
boolean onlyTransitTrips=false;
boolean disableAlertFiltering=false;
TraverseModeSet streetSubRequestModes = new TraverseModeSet(TraverseMode.WALK); // defaults in constructor overwrite this
FeedScopedId startingTransitStopId;
FeedScopedId startingTransitTripId;
} |
Updated Model: package org.opentripplanner.routing.api.request;
interface RoutingService {
RoutingResponse route(RouteRequest request);
RoutingResponse routeVia(RouteViaRequest request, RoutingPreferences preferences);
}
class RouteRequest {
GenericLocation from;
GenericLocation to;
Instant dateTime = Instant.now();
Duration searchWindow;
PageCursor pageCursor;
boolean timetableView = true;
boolean arriveBy = false;
int numItineraries = 50;
Locale locale = new Locale("en", "US");
RoutingPreferences preferences = new RoutingPreferences();
JourneyRequest journey = new JourneyRequest();
ItineraryFilterParameters itineraryFilters = ItineraryFilterParameters.createDefault();
DataOverlayParameters dataOverlay;
boolean wheelchair = false;
};
/**
* User/trip cost/time/slack/reluctance search config.
*/
class RoutingPreferences {
TransitPreferences transit;
TransferPreferences transfer;
StreetPreferences street;
WalkPreferences walk;
WheelchairAccessibilityPreferences wheelchairAccessibility = WheelchairAccessibilityPreferences.DEFAULT
BikePreferences bike;
CarPreferences car;
VehicleRentalPreferences rental;
SystemPreferences system;
}
class TransitPreferences {
int walkBoardCost = 60 * 10;
int bikeBoardCost = 60 * 10;
int boardSlack = 0;
Map<TransitMode, Integer> boardSlackForMode = new EnumMap<TransitMode, Integer>(TransitMode.class);
int alightSlack = 0;
Map<TransitMode, Integer> alightSlackForMode = new EnumMap<TransitMode, Integer>(TransitMode.class);
Map<TransitMode, Double> reluctanceForMode = new HashMap<>();
int otherThanPreferredRoutesPenalty = 300;
DoubleFunction<Double> unpreferredCost = RequestFunctions.createLinearFunction(0.0,DEFAULT_ROUTE_RELUCTANCE);
boolean ignoreRealtimeUpdates = false;
boolean includePlannedCancellations = false;
RaptorOptions raptorOptions = new RaptorOptions();
};
class TransitRequest {
List<AllowedTransitMode> modes = AllowedTransitMode.getAllTransitModes();
List<FeedScopedId> whiteListedAgencies = List.of();
List<FeedScopedId> bannedAgencies = List.of();
List<FeedScopedId> preferredAgencies = List.of();
List<FeedScopedId> unpreferredAgencies = List.of();
RouteMatcher whiteListedRoutes = RouteMatcher.emptyMatcher();
RouteMatcher bannedRoutes = RouteMatcher.emptyMatcher();
List<FeedScopedId> preferredRoutes = RouteMatcher.emptyMatcher();
List<FeedScopedId> RouteMatcher unpreferredRoutes = RouteMatcher.emptyMatcher();
List<FeedScopedId> bannedTrips = List.of();
DebugRaptor raptorDebugging = new DebugRaptor();
}
class TransferPreferences {
int cost = 0;
int slack = 120;
int nonpreferredCost = 180;
double waitReluctance = 1.0;
double waitAtBeginningFactor = 0.4;
TransferOptimizationParameters optimization = new TransferOptimizationRequest();
Integer maxTransfers = 12;
}
class WalkPreferences {
double speed = 1.33;
double reluctance = 2.0;
double stairsReluctance = 2.0;
double stairsTimeFactor = 3.0;
double safetyFactor = 1.0;
}
// Direct street search
class StreetPreferences {
Duration maxAccessEgressDuration = Duration.ofMinutes(45);
Map<StreetMode, Duration> maxAccessEgressDurationForMode = new HashMap<>();
Duration maxDirectStreetDuration = Duration.ofHours(4);
Map<StreetMode, Duration> maxDirectStreetDurationForMode = new HashMap<>();
double turnReluctance = 1.0;
int elevatorBoardTime = 90;
int elevatorBoardCost = 90;
int elevatorHopTime = 20;
int elevatorHopCost = 20;
}
class WheelchairAccessibilityRequest {
WheelchairAccessibilityFeature trip;
WheelchairAccessibilityFeature stop;
WheelchairAccessibilityFeature elevator;
double inaccessibleStreetReluctance;
double maxSlope;
double slopeExceededReluctance;
double stairsReluctance;
}
record TriangleFactor {
double time;
double slope;
double safety;
}
class BikePreferences {
BicycleOptimizeType optimizeType = BicycleOptimizeType.SAFE;
double speed = 5;
double walkingSpeed = 1.33;
double walkingReluctance = 5.0;
double reluctance = 2.0;
int switchTime;
int switchCost;
int parkTime = 60;
int parkCost = 120;
TriangleFactor triangleFactor;
}
class CarPreferences {
double speed = 40.0;
double reluctance = 2.0;
int parkTime = 60;
int parkCost = 120;
int dropoffTime = 120;
int pickupTime = 60;
int pickupCost = 120;
double decelerationSpeed = 2.9;
double accelerationSpeed = 2.9;
}
class VehicleRentalPreferences {
int pickupTime = 60;
int pickupCost = 120;
int dropoffTime = 30;
int dropoffCost = 30;
double keepingVehicleAtDestinationCost = 0;
}
class VehicleRentalRequest {
Set<String> allowedNetworks = Set.of();
Set<String> bannedNetworks = Set.of();
boolean useAvailabilityInformation = false;
// this is renamed allowKeepingVehicleAtDestination
boolean allowArrivingInRentedVehicleAtDestination = false;
}
class VehicleParkingRequest {
Set<String> requiredTags = Set.of();
Set<String> bannedTags = Set.of();
boolean useAvailabilityInformation = false;
boolean parkAndRide = false
}
/** System config & debug, available on API for testing purposes */
class SystemPreferences {
Tags tags = Tags.of();
boolean geoidElevation=false;
private Duration maxJourneyDuration = Duration.ofHours(24);
}
class JourneyRequest {
// initial value should be null
TransitRequest transit = null;
StreetRequest access = null;
StreetRequest egress = null;
StreetRequest transfer = null;
StreetRequest direct = null;
// These parameters control transit and direct search
boolean hasTransit() { return transit != null; }
boolean hasDirect() { return direct != null; }
// Set transit, access, egress and transfer nonnull
JourneyRequest enableTransit();
// Set transit, access, egress and transfer nonnull
JourneyRequest enableDirect();
}
class StreetRequest {
StreetMode mode = StreetMode.WALK;
TraverseModeSet traverseModeSet;
VehicleRentalRequest vehicleRental;
VehicleParkingRequest vehicleParking;
}
/**
* User request: from/to time/location; preferences slack/cost/reluctance
*/
class RouteViaRequest {
Instant dateTime = Instant.now();
GenericLocation from;
GenericLocation to;
List<ViaLocation> viaPoints;
// Number of trips must match viaPoints + 1 and is limited to max 5 trips
List<JourneyRequest> viaJourneys;
Duration searchWindow;
PageCursor pageCursor;
// boolean timetableView = true; ONLY SUPPORT true
boolean arriveBy = false;
Locale locale = new Locale("en", "US");
int numItineraries = 50;
}
class ViaLocation {
GenericLocation point;
boolean passThroughPoint = false;
Duration slack = Duration.ofMinutes(60);
}
class DELETE_THESE {
boolean onlyTransitTrips=false;
boolean disableAlertFiltering=false;
TraverseModeSet streetSubRequestModes = new TraverseModeSet(TraverseMode.WALK); // defaults in constructor overwrite this
FeedScopedId startingTransitStopId;
FeedScopedId startingTransitTripId;
int otherThanPreferredRoutesPenalty = 300;
int useUnpreferredRoutesPenalty = 300;
String pathComparator;
Set<RentalVehicleType.FormFactor> allowedFormFactors
// The REST API should hold onto this, and pass it to the mapper, no need to include it in the
// request.
boolean showIntermediateStops=false;
private boolean disableAlertFiltering = false;
} |
Request / response outline
We do not want to extend the existing request to support via search, we want to refactor the existing
RoutingRequest
so different parts of it can be reused in the "normal" and "via" request. Note! This do not apply to the http endpoint APIs, because we may want to add via search to be backwards compatible.I am not sure if we need to do the same exercise for the response.
Request Design
Suggested refactoring - I have taken the
RoutingRequest
and divided it into smaller classes. Fields names are updated in some cases where the old field name repeat the context. E.gbikeSpeed
->BikePreferences{ speed }
. I have taken all fields and moved them into separate classes. We can use records for some of these classes to simplify a bit, That is up to the person implementing this.I have moved unused fields into the DELETE_THESE class. These fields should be deleted.
The JavaDoc is not copied into this, but should of cause follow the fields in the refactoring. For records, adde the JavaDoc to the field, and for DTO classes add the JavaDoc to the getter. Avoid using the existing pattern with public fields.
Naming
class.
Model (draft, see updated version below)
Left for later
Apply inversion of control to the request and the routing implementation. The different part of the routing engine should not depend on the Request classes, but define Parameter interfaces witch the Request classes can implement.
The text was updated successfully, but these errors were encountered: