Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private static ViaLocation mapViaLocation(Map<String, Object> via) {
visit.getGraphQLLabel(),
visit.getGraphQLMinimumWaitTime(),
mapStopLocationIds(visit.getGraphQLStopLocationIds()),
mapCoordinate(visit.getGraphQLCoordinate()).map(List::of).orElse(List.of())
mapCoordinate(visit.getGraphQLCoordinate()).orElse(null)
);
} else {
throw new IllegalArgumentException("ViaLocation must define either pass-through or visit.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ private List<FeedScopedId> mapStopLocationIds(Map<String, Object> map) {
return c == null ? List.of() : idMapper.parseList(c);
}

private static List<WgsCoordinate> mapCoordinate(Map<String, Object> map) {
return CoordinateInputType.mapToWgsCoordinate(ViaLocationInputType.FIELD_COORDINATE, map)
.map(List::of)
.orElseGet(List::of);
@Nullable
private static WgsCoordinate mapCoordinate(Map<String, Object> map) {
return CoordinateInputType.mapToWgsCoordinate(
ViaLocationInputType.FIELD_COORDINATE,
map
).orElse(null);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.opentripplanner.routing.algorithm.raptoradapter.router.FilterTransitWhenDirectModeIsEmpty;
import org.opentripplanner.routing.algorithm.raptoradapter.router.TransitRouter;
import org.opentripplanner.routing.algorithm.raptoradapter.router.street.DirectFlexRouter;
import org.opentripplanner.routing.algorithm.raptoradapter.router.street.DirectStreetRouter;
import org.opentripplanner.routing.algorithm.raptoradapter.router.street.DirectStreetRouterFactory;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.routing.api.request.StreetMode;
import org.opentripplanner.routing.api.request.request.StreetRequest;
Expand Down Expand Up @@ -221,14 +221,6 @@ private Duration searchWindowUsed() {
}

private RoutingResult routeDirectStreet() {
// TODO: Add support for via search to the direct-street search and remove this.
// The direct search is used to prune away silly transit results and it
// would be nice to also support via as a feature in the direct-street
// search.
if (request.isViaSearch()) {
return RoutingResult.empty();
}

// If no direct mode is set, then we set one.
// See {@link FilterTransitWhenDirectModeIsEmpty}
var emptyDirectModeHandler = new FilterTransitWhenDirectModeIsEmpty(
Expand All @@ -243,8 +235,9 @@ private RoutingResult routeDirectStreet() {

debugTimingAggregator.startedDirectStreetRouter();
try {
var directStreetRouter = DirectStreetRouterFactory.create(request);
return RoutingResult.ok(
DirectStreetRouter.route(serverContext, directBuilder.buildRequest(), linkingContext()),
directStreetRouter.route(serverContext, directBuilder.buildRequest(), linkingContext()),
emptyDirectModeHandler.removeWalkAllTheWayResults()
);
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ private StreetLeg generateLeg(List<State> states, WalkStep previousStep) {
// link to the user so we remove it here
.filter(e -> !(e.backEdge instanceof BoardingLocationToStopLink))
.map(State::getBackEdge)
.filter(Objects::nonNull)
.toList();

State firstState = states.get(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.opentripplanner.routing.algorithm.raptoradapter.router.street;

import java.util.Collections;
import java.util.List;
import org.opentripplanner.astar.model.GraphPath;
import org.opentripplanner.framework.application.OTPRequestTimeoutException;
import org.opentripplanner.framework.geometry.SphericalDistanceLibrary;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.routing.algorithm.mapping.GraphPathToItineraryMapper;
import org.opentripplanner.routing.algorithm.mapping.ItinerariesHelper;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.routing.api.request.StreetMode;
import org.opentripplanner.routing.error.PathNotFoundException;
import org.opentripplanner.routing.impl.GraphPathFinder;
import org.opentripplanner.routing.linking.LinkingContext;
import org.opentripplanner.standalone.api.OtpServerRequestContext;
import org.opentripplanner.street.model.edge.Edge;
import org.opentripplanner.street.model.vertex.Vertex;
import org.opentripplanner.street.search.state.State;

/**
* Generates "direct" street routes, i.e. those that do not use transit and are on the street
* network for the entire itinerary. Doesn't support via locations or flex.
*/
public class DefaultDirectStreetRouter implements DirectStreetRouter {

public List<Itinerary> route(
OtpServerRequestContext serverContext,
RouteRequest request,
LinkingContext linkingContext
) {
if (request.journey().direct().mode() == StreetMode.NOT_SET) {
return Collections.emptyList();
}
OTPRequestTimeoutException.checkForTimeout();
try {
var maxCarSpeed = serverContext.streetLimitationParametersService().maxCarSpeed();
if (!straightLineDistanceIsWithinLimit(request, maxCarSpeed, linkingContext)) {
return Collections.emptyList();
}

// we could also get a persistent router-scoped GraphPathFinder but there's no setup cost here
GraphPathFinder gpFinder = new GraphPathFinder(
serverContext.traverseVisitor(),
serverContext.listExtensionRequestContexts(request),
maxCarSpeed
);
List<GraphPath<State, Edge, Vertex>> paths = gpFinder.graphPathFinderEntryPoint(
request,
linkingContext
);

// Convert the internal GraphPaths to itineraries
final GraphPathToItineraryMapper graphPathToItineraryMapper = new GraphPathToItineraryMapper(
serverContext.transitService()::getRegularStop,
serverContext.transitService().getTimeZone(),
serverContext.graph().streetNotesService,
serverContext.graph().ellipsoidToGeoidDifference
);
List<Itinerary> response = graphPathToItineraryMapper.mapItineraries(paths);
response = ItinerariesHelper.decorateItinerariesWithRequestData(
response,
request.journey().wheelchair(),
request.preferences().wheelchair()
);
return response;
} catch (PathNotFoundException e) {
return Collections.emptyList();
}
}

private static boolean straightLineDistanceIsWithinLimit(
RouteRequest request,
float maxCarSpeed,
LinkingContext linkingContext
) {
// TODO This currently only calculates the distances between the first fromVertex
// and the first toVertex
double distance = SphericalDistanceLibrary.distance(
linkingContext.findVertices(request.from()).iterator().next().getCoordinate(),
linkingContext.findVertices(request.to()).iterator().next().getCoordinate()
);
return distance < request.getMaximumDirectDistance(maxCarSpeed);
}
}
Original file line number Diff line number Diff line change
@@ -1,114 +1,19 @@
package org.opentripplanner.routing.algorithm.raptoradapter.router.street;

import java.util.Collections;
import java.util.List;
import org.opentripplanner.astar.model.GraphPath;
import org.opentripplanner.framework.application.OTPRequestTimeoutException;
import org.opentripplanner.framework.geometry.SphericalDistanceLibrary;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.routing.algorithm.mapping.GraphPathToItineraryMapper;
import org.opentripplanner.routing.algorithm.mapping.ItinerariesHelper;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.routing.api.request.StreetMode;
import org.opentripplanner.routing.error.PathNotFoundException;
import org.opentripplanner.routing.impl.GraphPathFinder;
import org.opentripplanner.routing.linking.LinkingContext;
import org.opentripplanner.standalone.api.OtpServerRequestContext;
import org.opentripplanner.street.model.edge.Edge;
import org.opentripplanner.street.model.vertex.Vertex;
import org.opentripplanner.street.search.state.State;

/**
* Generates "direct" street routes, i.e. those that do not use transit and are on the street
* network for the entire itinerary.
*
* @see DirectFlexRouter
* network for the entire itinerary. For flex routing, use {@link DirectFlexRouter}.
*/
public class DirectStreetRouter {

public static List<Itinerary> route(
public interface DirectStreetRouter {
List<Itinerary> route(
OtpServerRequestContext serverContext,
RouteRequest request,
LinkingContext linkingContext
) {
if (request.journey().direct().mode() == StreetMode.NOT_SET) {
return Collections.emptyList();
}
OTPRequestTimeoutException.checkForTimeout();
try {
var maxCarSpeed = serverContext.streetLimitationParametersService().maxCarSpeed();
if (!straightLineDistanceIsWithinLimit(request, maxCarSpeed, linkingContext)) {
return Collections.emptyList();
}

// we could also get a persistent router-scoped GraphPathFinder but there's no setup cost here
GraphPathFinder gpFinder = new GraphPathFinder(
serverContext.traverseVisitor(),
serverContext.listExtensionRequestContexts(request),
maxCarSpeed
);
List<GraphPath<State, Edge, Vertex>> paths = gpFinder.graphPathFinderEntryPoint(
request,
linkingContext
);

// Convert the internal GraphPaths to itineraries
final GraphPathToItineraryMapper graphPathToItineraryMapper = new GraphPathToItineraryMapper(
serverContext.transitService()::getRegularStop,
serverContext.transitService().getTimeZone(),
serverContext.graph().streetNotesService,
serverContext.graph().ellipsoidToGeoidDifference
);
List<Itinerary> response = graphPathToItineraryMapper.mapItineraries(paths);
response = ItinerariesHelper.decorateItinerariesWithRequestData(
response,
request.journey().wheelchair(),
request.preferences().wheelchair()
);
return response;
} catch (PathNotFoundException e) {
return Collections.emptyList();
}
}

private static boolean straightLineDistanceIsWithinLimit(
RouteRequest request,
float maxCarSpeed,
LinkingContext linkingContext
) {
// TODO This currently only calculates the distances between the first fromVertex
// and the first toVertex
double distance = SphericalDistanceLibrary.distance(
linkingContext.findVertices(request.from()).iterator().next().getCoordinate(),
linkingContext.findVertices(request.to()).iterator().next().getCoordinate()
);
return distance < calculateDistanceMaxLimit(request, maxCarSpeed);
}

/**
* Calculates the maximum distance in meters based on the maxDirectStreetDuration and the
* fastest mode available. This assumes that it is not possible to exceed the speed defined in the
* RouteRequest.
*/
private static double calculateDistanceMaxLimit(RouteRequest request, float maxCarSpeed) {
var preferences = request.preferences();
double distanceLimit;
StreetMode mode = request.journey().direct().mode();

double durationLimit = preferences.street().maxDirectDuration().valueOf(mode).toSeconds();

if (mode.includesDriving()) {
distanceLimit = durationLimit * maxCarSpeed;
} else if (mode.includesBiking()) {
distanceLimit = durationLimit * preferences.bike().speed();
} else if (mode.includesScooter()) {
distanceLimit = durationLimit * preferences.scooter().speed();
} else if (mode.includesWalking()) {
distanceLimit = durationLimit * preferences.walk().speed();
} else {
throw new IllegalStateException("Could not set max limit for StreetMode");
}

return distanceLimit;
}
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.opentripplanner.routing.algorithm.raptoradapter.router.street;

import org.opentripplanner.routing.api.request.RouteRequest;

/**
* This factory encapsulates the logic for deciding which direct street router to use.
*/
public class DirectStreetRouterFactory {

/**
* @return {@link DefaultDirectStreetRouter} if there are no via locations, otherwise
* {@link ViaDirectStreetRouter}.
*/
public static DirectStreetRouter create(RouteRequest request) {
return request.isViaSearch() ? new ViaDirectStreetRouter() : new DefaultDirectStreetRouter();
}
}
Loading
Loading