use of org.opentripplanner.routing.spt.GraphPath in project OpenTripPlanner by opentripplanner.
the class GraphPathFinder method joinPaths.
private static GraphPath joinPaths(List<GraphPath> paths) {
State lastState = paths.get(0).states.getLast();
GraphPath newPath = new GraphPath(lastState, false);
Vertex lastVertex = lastState.getVertex();
// With more paths we should allow more transfers
lastState.getOptions().maxTransfers *= paths.size();
for (GraphPath path : paths.subList(1, paths.size())) {
lastState = newPath.states.getLast();
// add a leg-switching state
LegSwitchingEdge legSwitchingEdge = new LegSwitchingEdge(lastVertex, lastVertex);
lastState = legSwitchingEdge.traverse(lastState);
newPath.edges.add(legSwitchingEdge);
newPath.states.add(lastState);
// add the next subpath
for (Edge e : path.edges) {
lastState = e.traverse(lastState);
newPath.edges.add(e);
newPath.states.add(lastState);
}
lastVertex = path.getEndVertex();
}
return newPath;
}
use of org.opentripplanner.routing.spt.GraphPath in project OpenTripPlanner by opentripplanner.
the class GraphPathFinder method getPaths.
/**
* Repeatedly build shortest path trees, retaining the best path to the destination after each try.
* For search N, all trips used in itineraries retained from trips 0..(N-1) are "banned" to create variety.
* The goal direction heuristic is reused between tries, which means the later tries have more information to
* work with (in the case of the more sophisticated bidirectional heuristic, which improves over time).
*/
public List<GraphPath> getPaths(RoutingRequest options) {
RoutingRequest originalReq = options.clone();
if (options == null) {
LOG.error("PathService was passed a null routing request.");
return null;
}
// Reuse one instance of AStar for all N requests, which are carried out sequentially
AStar aStar = new AStar();
if (options.rctx == null) {
options.setRoutingContext(router.graph);
// The special long-distance heuristic should be sufficient to constrain the search to the right area.
}
// If this Router has a GraphVisualizer attached to it, set it as a callback for the AStar search
if (router.graphVisualizer != null) {
aStar.setTraverseVisitor(router.graphVisualizer.traverseVisitor);
// options.disableRemainingWeightHeuristic = true; // DEBUG
}
// Without transit, we'd just just return multiple copies of the same on-street itinerary.
if (!options.modes.isTransit()) {
options.numItineraries = 1;
}
// FORCING the dominance function to weight only
options.dominanceFunction = new DominanceFunction.MinimumWeight();
LOG.debug("rreq={}", options);
// Choose an appropriate heuristic for goal direction.
RemainingWeightHeuristic heuristic;
RemainingWeightHeuristic reversedSearchHeuristic;
if (options.disableRemainingWeightHeuristic) {
heuristic = new TrivialRemainingWeightHeuristic();
reversedSearchHeuristic = new TrivialRemainingWeightHeuristic();
} else if (options.modes.isTransit()) {
// Only use the BiDi heuristic for transit. It is not very useful for on-street modes.
// heuristic = new InterleavedBidirectionalHeuristic(options.rctx.graph);
// Use a simplistic heuristic until BiDi heuristic is improved, see #2153
heuristic = new InterleavedBidirectionalHeuristic();
reversedSearchHeuristic = new InterleavedBidirectionalHeuristic();
} else {
heuristic = new EuclideanRemainingWeightHeuristic();
reversedSearchHeuristic = new EuclideanRemainingWeightHeuristic();
}
options.rctx.remainingWeightHeuristic = heuristic;
/* In RoutingRequest, maxTransfers defaults to 2. Over long distances, we may see
* itineraries with far more transfers. We do not expect transfer limiting to improve
* search times on the LongDistancePathService, so we set it to the maximum we ever expect
* to see. Because people may use either the traditional path services or the
* LongDistancePathService, we do not change the global default but override it here. */
options.maxTransfers = 4;
// Now we always use what used to be called longDistance mode. Non-longDistance mode is no longer supported.
options.longDistance = true;
/* In long distance mode, maxWalk has a different meaning than it used to.
* It's the radius around the origin or destination within which you can walk on the streets.
* If no value is provided, max walk defaults to the largest double-precision float.
* This would cause long distance mode to do unbounded street searches and consider the whole graph walkable. */
if (options.maxWalkDistance == Double.MAX_VALUE)
options.maxWalkDistance = DEFAULT_MAX_WALK;
if (options.maxWalkDistance > CLAMP_MAX_WALK)
options.maxWalkDistance = CLAMP_MAX_WALK;
long searchBeginTime = System.currentTimeMillis();
LOG.debug("BEGIN SEARCH");
List<GraphPath> paths = Lists.newArrayList();
while (paths.size() < options.numItineraries) {
// TODO pull all this timeout logic into a function near org.opentripplanner.util.DateUtils.absoluteTimeout()
int timeoutIndex = paths.size();
if (timeoutIndex >= router.timeouts.length) {
timeoutIndex = router.timeouts.length - 1;
}
double timeout = searchBeginTime + (router.timeouts[timeoutIndex] * 1000);
// Convert from absolute to relative time
timeout -= System.currentTimeMillis();
// Convert milliseconds to seconds
timeout /= 1000;
if (timeout <= 0) {
// Catch the case where advancing to the next (lower) timeout value means the search is timed out
// before it even begins. Passing a negative relative timeout in the SPT call would mean "no timeout".
options.rctx.aborted = true;
break;
}
// Don't dig through the SPT object, just ask the A star algorithm for the states that reached the target.
aStar.getShortestPathTree(options, timeout);
if (options.rctx.aborted) {
// Search timed out or was gracefully aborted for some other reason.
break;
}
List<GraphPath> newPaths = aStar.getPathsToTarget();
if (newPaths.isEmpty()) {
break;
}
// Do a full reversed search to compact the legs
if (options.compactLegsByReversedSearch) {
newPaths = compactLegsByReversedSearch(aStar, originalReq, options, newPaths, timeout, reversedSearchHeuristic);
}
// Find all trips used in this path and ban them for the remaining searches
for (GraphPath path : newPaths) {
// path.dump();
List<AgencyAndId> tripIds = path.getTrips();
for (AgencyAndId tripId : tripIds) {
options.banTrip(tripId);
}
if (tripIds.isEmpty()) {
// This path does not use transit (is entirely on-street). Do not repeatedly find the same one.
options.onlyTransitTrips = true;
}
}
paths.addAll(newPaths.stream().filter(path -> {
double duration = options.useRequestedDateTimeInMaxHours ? options.arriveBy ? options.dateTime - path.getStartTime() : path.getEndTime() - options.dateTime : path.getDuration();
return duration < options.maxHours * 60 * 60;
}).collect(Collectors.toList()));
LOG.debug("we have {} paths", paths.size());
}
LOG.debug("END SEARCH ({} msec)", System.currentTimeMillis() - searchBeginTime);
Collections.sort(paths, new PathComparator(options.arriveBy));
return paths;
}
use of org.opentripplanner.routing.spt.GraphPath in project OpenTripPlanner by opentripplanner.
the class PlannerResource method plan.
// We inject info about the incoming request so we can include the incoming query
// parameters in the outgoing response. This is a TriMet requirement.
// Jersey uses @Context to inject internal types and @InjectParam or @Resource for DI objects.
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML + Q, MediaType.TEXT_XML + Q })
public Response plan(@Context UriInfo uriInfo, @Context Request grizzlyRequest) {
/*
* TODO: add Lang / Locale parameter, and thus get localized content (Messages & more...)
* TODO: from/to inputs should be converted / geocoded / etc... here, and maybe send coords
* or vertex ids to planner (or error back to user)
* TODO: org.opentripplanner.routing.module.PathServiceImpl has COOORD parsing. Abstract that
* out so it's used here too...
*/
// Create response object, containing a copy of all request parameters. Maybe they should be in the debug section of the response.
Response response = new Response(uriInfo);
RoutingRequest request = null;
Router router = null;
List<GraphPath> paths = null;
try {
/* Fill in request fields from query parameters via shared superclass method, catching any errors. */
request = super.buildRequest();
router = otpServer.getRouter(request.routerId);
/* Find some good GraphPaths through the OTP Graph. */
// we could also get a persistent router-scoped GraphPathFinder but there's no setup cost here
GraphPathFinder gpFinder = new GraphPathFinder(router);
paths = gpFinder.graphPathFinderEntryPoint(request);
/* Convert the internal GraphPaths to a TripPlan object that is included in an OTP web service Response. */
TripPlan plan = GraphPathToTripPlanConverter.generatePlan(paths, request);
response.setPlan(plan);
} catch (Exception e) {
PlannerError error = new PlannerError(e);
if (!PlannerError.isPlanningError(e.getClass()))
LOG.warn("Error while planning path: ", e);
response.setError(error);
} finally {
if (request != null) {
if (request.rctx != null) {
response.debugOutput = request.rctx.debugOutput;
}
// TODO verify that this cleanup step is being done on Analyst web services
request.cleanup();
}
}
/* Populate up the elevation metadata */
response.elevationMetadata = new ElevationMetadata();
response.elevationMetadata.ellipsoidToGeoidDifference = router.graph.ellipsoidToGeoidDifference;
response.elevationMetadata.geoidElevation = request.geoidElevation;
/* Log this request if such logging is enabled. */
if (request != null && router != null && router.requestLogger != null) {
StringBuilder sb = new StringBuilder();
String clientIpAddress = grizzlyRequest.getRemoteAddr();
// sb.append(LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME));
sb.append(clientIpAddress);
sb.append(' ');
sb.append(request.arriveBy ? "ARRIVE" : "DEPART");
sb.append(' ');
sb.append(LocalDateTime.ofInstant(Instant.ofEpochSecond(request.dateTime), ZoneId.systemDefault()));
sb.append(' ');
sb.append(request.modes.getAsStr());
sb.append(' ');
sb.append(request.from.lat);
sb.append(' ');
sb.append(request.from.lng);
sb.append(' ');
sb.append(request.to.lat);
sb.append(' ');
sb.append(request.to.lng);
sb.append(' ');
if (paths != null) {
for (GraphPath path : paths) {
sb.append(path.getDuration());
sb.append(' ');
sb.append(path.getTrips().size());
sb.append(' ');
}
}
router.requestLogger.info(sb.toString());
}
return response;
}
use of org.opentripplanner.routing.spt.GraphPath in project OpenTripPlanner by opentripplanner.
the class TestTransfers method testStopToStopTransfer.
public void testStopToStopTransfer() throws Exception {
// Replace the transfer table with an empty table
TransferTable table = new TransferTable();
when(graph.getTransferTable()).thenReturn(table);
// Compute a normal path between two stops
Vertex origin = graph.getVertex(feedId + ":N");
Vertex destination = graph.getVertex(feedId + ":H");
// Set options like time and routing context
RoutingRequest options = new RoutingRequest();
options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 11, 11, 11, 0);
options.setRoutingContext(graph, origin, destination);
// Plan journey
GraphPath path;
List<Trip> trips;
path = planJourney(options);
trips = extractTrips(path);
// Validate result
assertEquals("8.1", trips.get(0).getId().getId());
assertEquals("4.2", trips.get(1).getId().getId());
// Add transfer to table, transfer time was 27600 seconds
Stop stopK = new Stop();
stopK.setId(new AgencyAndId(feedId, "K"));
Stop stopF = new Stop();
stopF.setId(new AgencyAndId(feedId, "F"));
table.addTransferTime(stopK, stopF, null, null, null, null, 27601);
// Plan journey
path = planJourney(options);
trips = extractTrips(path);
// Check whether a later second trip was taken
assertEquals("8.1", trips.get(0).getId().getId());
assertEquals("4.3", trips.get(1).getId().getId());
// Revert the graph, thus using the original transfer table again
reset(graph);
}
use of org.opentripplanner.routing.spt.GraphPath in project OpenTripPlanner by opentripplanner.
the class TestTransfers method testStopToStopTransferInReverse.
public void testStopToStopTransferInReverse() throws Exception {
// Replace the transfer table with an empty table
TransferTable table = new TransferTable();
when(graph.getTransferTable()).thenReturn(table);
// Compute a normal path between two stops
Vertex origin = graph.getVertex(feedId + ":N");
Vertex destination = graph.getVertex(feedId + ":H");
// Set options like time and routing context
RoutingRequest options = new RoutingRequest();
options.setArriveBy(true);
options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 12, 1, 0, 0);
options.setRoutingContext(graph, origin, destination);
// Plan journey
GraphPath path;
List<Trip> trips;
path = planJourney(options, true);
trips = extractTrips(path);
// Validate result
assertEquals("8.1", trips.get(0).getId().getId());
assertEquals("4.2", trips.get(1).getId().getId());
// Add transfer to table, transfer time was 27600 seconds
Stop stopK = new Stop();
stopK.setId(new AgencyAndId(feedId, "K"));
Stop stopF = new Stop();
stopF.setId(new AgencyAndId(feedId, "F"));
table.addTransferTime(stopK, stopF, null, null, null, null, 27601);
// Plan journey
path = planJourney(options, true);
trips = extractTrips(path);
// Check whether a later second trip was taken
assertEquals("8.1", trips.get(0).getId().getId());
assertEquals("4.3", trips.get(1).getId().getId());
// Revert the graph, thus using the original transfer table again
reset(graph);
}
Aggregations