use of org.opentripplanner.routing.algorithm.AStar in project OpenTripPlanner by opentripplanner.
the class SampleGridRenderer method getSampleGrid.
/**
* @param spgRequest
* @param sptRequest
* @return
*/
public ZSampleGrid<WTWD> getSampleGrid(SampleGridRequest spgRequest, RoutingRequest sptRequest) {
final double offRoadDistanceMeters = spgRequest.offRoadDistanceMeters;
// m/s, off-road walk speed
final double offRoadWalkSpeedMps = 1.00;
// 1. Compute the Shortest Path Tree.
long t0 = System.currentTimeMillis();
long tOvershot = (long) (2 * offRoadDistanceMeters / offRoadWalkSpeedMps);
sptRequest.worstTime = (sptRequest.dateTime + (sptRequest.arriveBy ? -spgRequest.maxTimeSec - tOvershot : spgRequest.maxTimeSec + tOvershot));
sptRequest.batch = (true);
sptRequest.setRoutingContext(graph);
// TODO swap in different state dominance logic (earliest arrival, pareto, etc.)
final ShortestPathTree spt = new AStar().getShortestPathTree(sptRequest);
// 3. Create a sample grid based on the SPT.
long t1 = System.currentTimeMillis();
Coordinate coordinateOrigin = spgRequest.coordinateOrigin;
if (coordinateOrigin == null)
coordinateOrigin = sptRequest.from.getCoordinate();
final double gridSizeMeters = spgRequest.precisionMeters;
final double cosLat = FastMath.cos(toRadians(coordinateOrigin.y));
double dY = Math.toDegrees(gridSizeMeters / SphericalDistanceLibrary.RADIUS_OF_EARTH_IN_M);
double dX = dY / cosLat;
SparseMatrixZSampleGrid<WTWD> sampleGrid = new SparseMatrixZSampleGrid<WTWD>(16, spt.getVertexCount(), dX, dY, coordinateOrigin);
sampleSPT(spt, sampleGrid, gridSizeMeters, offRoadDistanceMeters, offRoadWalkSpeedMps, sptRequest.getMaxWalkDistance(), spgRequest.maxTimeSec, cosLat);
sptRequest.cleanup();
long t2 = System.currentTimeMillis();
LOG.info("Computed SPT in {}msec, {}msec for sampling ({} msec total)", (int) (t1 - t0), (int) (t2 - t1), (int) (t2 - t0));
return sampleGrid;
}
use of org.opentripplanner.routing.algorithm.AStar 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.algorithm.AStar in project OpenTripPlanner by opentripplanner.
the class SIsochrone method getIsochrone.
/**
* Calculates walksheds for a given location, based on time given to walk and the walk speed.
*
* Depending on the value for the "output" parameter (i.e. "POINTS", "SHED" or "EDGES"), a
* different type of GeoJSON geometry is returned. If a SHED is requested, then a ConcaveHull
* of the EDGES/roads is returned. If that fails, a ConvexHull will be returned.
* <p>
* The ConcaveHull parameter is set to 0.005 degrees. The offroad walkspeed is assumed to be
* 0.83333 m/sec (= 3km/h) until a road is hit.
* <p>
* Note that the set of EDGES/roads returned as well as POINTS returned may contain duplicates.
* If POINTS are requested, then not the end-points are returned at which the max time is
* reached, but instead all the graph nodes/crossings that are within the time limits.
* <p>
* In case there is no road near by within the given time, then a circle for the walktime limit
* is created and returned for the SHED parameter. Otherwise the edge with the direction
* towards the closest road. Note that the circle is calculated in Euclidian 2D coordinates,
* and distortions towards an ellipse will appear if it is transformed/projected to the user location.
* <p>
* An example request may look like this:
* localhost:8080/otp-rest-servlet/ws/iso?layers=traveltime&styles=mask&batch=true&fromPlace=51.040193121307176
* %2C-114.04471635818481&toPlace
* =51.09098935%2C-113.95179705&time=2012-06-06T08%3A00%3A00&mode=WALK&maxWalkDistance=10000&walkSpeed=1.38&walkTime=10.7&output=EDGES
* Though the first parameters (i) layer, (ii) styles and (iii) batch could be discarded.
*
* @param walkmins Maximum number of minutes to walk.
* @param output Can be set to "POINTS", "SHED" or "EDGES" to return different types of GeoJSON
* geometry. SHED returns a ConcaveHull or ConvexHull of the edges/roads. POINTS returns
* all graph nodes that are within the time limit.
* @return a JSON document containing geometries (either points, lineStrings or a polygon).
* @throws Exception
* @author sstein---geo.uzh.ch
*/
@GET
@Produces({ MediaType.APPLICATION_JSON })
public String getIsochrone(@QueryParam("walkTime") @DefaultValue("15") double walkmins, @QueryParam("output") @DefaultValue("POINTS") String output) throws Exception {
this.debugGeoms = new ArrayList();
this.tooFastTraversedEdgeGeoms = new ArrayList();
RoutingRequest sptRequestA = buildRequest();
String from = sptRequestA.from.toString();
int pos = 1;
float lat = 0;
float lon = 0;
for (String s : from.split(",")) {
if (s.isEmpty()) {
// no location
Response.status(Status.BAD_REQUEST).entity("no position").build();
return null;
}
try {
float num = Float.parseFloat(s);
if (pos == 1) {
lat = num;
}
if (pos == 2) {
lon = num;
}
} catch (Exception e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Could not parse position string to number. Require numerical lat & long coords.").build());
}
pos++;
}
GeometryFactory gf = new GeometryFactory();
Coordinate dropPoint = new Coordinate(lon, lat);
int walkInMin = (int) Math.floor(walkmins);
double walkInSec = walkmins * 60;
LOG.debug("given travel time: " + walkInMin + " mins + " + (walkInSec - (60 * walkInMin)) + " sec");
// graph dynamically by 1.3 * min -> this should save processing time
if (walkInMin < 30) {
sptRequestA.worstTime = sptRequestA.dateTime + (30 * 60);
} else {
sptRequestA.worstTime = sptRequestA.dateTime + Math.round(walkInMin * 1.3 * 60);
}
// set the switch-time for shed/area calculation, i.e. to decide if the hull is calculated based on points or on edges
TraverseModeSet modes = sptRequestA.modes;
LOG.debug("mode(s): " + modes);
if (modes.contains(TraverseMode.TRANSIT)) {
// 20min (use 20min for transit, since buses may not come all the time)
shedCalcMethodSwitchTimeInSec = 60 * 20;
} else if (modes.contains(TraverseMode.CAR)) {
// 10min
shedCalcMethodSwitchTimeInSec = 60 * 10;
} else if (modes.contains(TraverseMode.BICYCLE)) {
// 10min
shedCalcMethodSwitchTimeInSec = 60 * 10;
} else {
// 20min
shedCalcMethodSwitchTimeInSec = 60 * 20;
}
// set the maxUserSpeed, which is used later to check for u-type streets/crescents when calculating sub-edges;
// Note, that the car speed depends on the edge itself, so this value may be replaced later
this.usesCar = false;
int numberOfModes = modes.getModes().size();
if (numberOfModes == 1) {
if (modes.getWalk()) {
this.maxUserSpeed = sptRequestA.walkSpeed;
} else if (modes.getBicycle()) {
this.maxUserSpeed = sptRequestA.bikeSpeed;
} else if (modes.getCar()) {
this.maxUserSpeed = sptRequestA.carSpeed;
this.usesCar = true;
}
} else {
// for all other cases (multiple-modes)
// sstein: I thought I may set it to 36.111 m/sec = 130 km/h,
// but maybe it is better to assume walk speed for transit, i.e. treat it like if the
// person gets off the bus on the last crossing and walks the "last mile".
this.maxUserSpeed = sptRequestA.walkSpeed;
}
if (doSpeedTest) {
LOG.debug("performing angle and speed based test to detect u-shapes");
} else {
LOG.debug("performing only angle based test to detect u-shapes");
}
// TODO: OTP prefers to snap to car-roads/ways, which is not so nice, when walking,
// and a footpath is closer by. So far there is no option to switch that off
Router router = otpServer.getRouter(routerId);
// create the ShortestPathTree
try {
sptRequestA.setRoutingContext(router.graph);
} catch (Exception e) {
// if we get an exception here, and in particular a VertexNotFoundException,
// then it is likely that we chose a (transit) mode without having that (transit) modes data
LOG.debug("cannot set RoutingContext: " + e.toString());
LOG.debug("cannot set RoutingContext: setting mode=WALK");
// fall back to walk mode
sptRequestA.setMode(TraverseMode.WALK);
sptRequestA.setRoutingContext(router.graph);
}
ShortestPathTree sptA = new AStar().getShortestPathTree(sptRequestA);
StreetLocation origin = (StreetLocation) sptRequestA.rctx.fromVertex;
// remove inserted points
sptRequestA.cleanup();
// create a LineString for display
Coordinate[] pathToStreetCoords = new Coordinate[2];
pathToStreetCoords[0] = dropPoint;
pathToStreetCoords[1] = origin.getCoordinate();
LineString pathToStreet = gf.createLineString(pathToStreetCoords);
// get distance between origin and drop point for time correction
double distanceToRoad = SphericalDistanceLibrary.distance(origin.getY(), origin.getX(), dropPoint.y, dropPoint.x);
long offRoadTimeCorrection = (long) (distanceToRoad / this.offRoadWalkspeed);
//
// --- filter the states ---
//
Set<Coordinate> visitedCoords = new HashSet<Coordinate>();
ArrayList<Edge> allConnectingEdges = new ArrayList<Edge>();
Coordinate[] coords = null;
long maxTime = (long) walkInSec - offRoadTimeCorrection;
// if the initial walk is already to long, there is no need to parse...
if (maxTime <= 0) {
noRoadNearBy = true;
long timeToWalk = (long) walkInSec;
long timeBetweenStates = offRoadTimeCorrection;
long timeMissing = timeToWalk;
double fraction = (double) timeMissing / (double) timeBetweenStates;
pathToStreet = getSubLineString(pathToStreet, fraction);
LOG.debug("no street found within giving travel time (for off-road walkspeed: {} m/sec)", this.offRoadWalkspeed);
} else {
noRoadNearBy = false;
Map<ReversibleLineStringWrapper, Edge> connectingEdgesMap = Maps.newHashMap();
for (State state : sptA.getAllStates()) {
long et = state.getElapsedTimeSeconds();
if (et <= maxTime) {
// 250 points away (while 145 were finally displayed)
if (visitedCoords.contains(state.getVertex().getCoordinate())) {
continue;
} else {
visitedCoords.add(state.getVertex().getCoordinate());
}
// -- get all Edges needed later for the edge representation
// and to calculate an edge-based walkshed
// Note, it can happen that we get a null geometry here, e.g. for hop-edges!
Collection<Edge> vertexEdgesIn = state.getVertex().getIncoming();
for (Iterator<Edge> iterator = vertexEdgesIn.iterator(); iterator.hasNext(); ) {
Edge edge = (Edge) iterator.next();
Geometry edgeGeom = edge.getGeometry();
if (edgeGeom != null) {
// make sure we get only real edges
if (edgeGeom instanceof LineString) {
// allConnectingEdges.add(edge); // instead of this, use a map now, so we don't have similar edge many times
connectingEdgesMap.put(new ReversibleLineStringWrapper((LineString) edgeGeom), edge);
}
}
}
Collection<Edge> vertexEdgesOut = state.getVertex().getOutgoing();
for (Iterator<Edge> iterator = vertexEdgesOut.iterator(); iterator.hasNext(); ) {
Edge edge = (Edge) iterator.next();
Geometry edgeGeom = edge.getGeometry();
if (edgeGeom != null) {
if (edgeGeom instanceof LineString) {
// allConnectingEdges.add(edge); // instead of this, use a map now, so we don't similar edge many times
connectingEdgesMap.put(new ReversibleLineStringWrapper((LineString) edgeGeom), edge);
}
}
}
}
// end : if(et < maxTime)
}
// --
// points from list to array, for later
coords = new Coordinate[visitedCoords.size()];
int i = 0;
for (Coordinate c : visitedCoords) coords[i++] = c;
// connection edges from Map to List
allConnectingEdges.clear();
for (Edge tedge : connectingEdgesMap.values()) allConnectingEdges.add(tedge);
}
StringWriter sw = new StringWriter();
GeometryJSON geometryJSON = new GeometryJSON();
//
try {
if (output.equals(SIsochrone.RESULT_TYPE_POINTS)) {
// and return those points
if (noRoadNearBy) {
Geometry circleShape = createCirle(dropPoint, pathToStreet);
coords = circleShape.getCoordinates();
}
// -- the states/nodes with time elapsed <= X min.
LOG.debug("write multipoint geom with {} points", coords.length);
geometryJSON.write(gf.createMultiPoint(coords), sw);
LOG.debug("done");
} else if (output.equals(SIsochrone.RESULT_TYPE_SHED)) {
Geometry[] geomsArray = null;
// in case there was no road we create a circle
if (noRoadNearBy) {
Geometry circleShape = createCirle(dropPoint, pathToStreet);
geometryJSON.write(circleShape, sw);
} else {
if (maxTime > shedCalcMethodSwitchTimeInSec) {
// eg., walkshed > 20 min
// -- create a point-based walkshed
// less exact and should be used for large walksheds with many edges
LOG.debug("create point-based shed (not from edges)");
geomsArray = new Geometry[coords.length];
for (int j = 0; j < geomsArray.length; j++) {
geomsArray[j] = gf.createPoint(coords[j]);
}
} else {
// -- create an edge-based walkshed
// it is more exact and should be used for short walks
LOG.debug("create edge-based shed (not from points)");
Map<ReversibleLineStringWrapper, LineString> walkShedEdges = Maps.newHashMap();
// add the walk from the pushpin to closest street point
walkShedEdges.put(new ReversibleLineStringWrapper(pathToStreet), pathToStreet);
// get the edges and edge parts within time limits
ArrayList<LineString> withinTimeEdges = this.getLinesAndSubEdgesWithinMaxTime(maxTime, allConnectingEdges, sptA, angleLimitForUShapeDetection, distanceToleranceForUShapeDetection, maxUserSpeed, usesCar, doSpeedTest);
for (LineString ls : withinTimeEdges) {
walkShedEdges.put(new ReversibleLineStringWrapper(ls), ls);
}
geomsArray = new Geometry[walkShedEdges.size()];
int k = 0;
for (LineString ls : walkShedEdges.values()) geomsArray[k++] = ls;
}
// end if-else: maxTime condition
GeometryCollection gc = gf.createGeometryCollection(geomsArray);
// create the concave hull, but in case it fails we just return the convex hull
Geometry outputHull = null;
LOG.debug("create concave hull from {} geoms with edge length limit of about {} m (distance on meridian)", geomsArray.length, concaveHullAlpha * 111132);
// (see wikipedia: http://en.wikipedia.org/wiki/Latitude#The_length_of_a_degree_of_latitude)
try {
ConcaveHull hull = new ConcaveHull(gc, concaveHullAlpha);
outputHull = hull.getConcaveHull();
} catch (Exception e) {
outputHull = gc.convexHull();
LOG.debug("Could not generate ConcaveHull for WalkShed, using ConvexHull instead.");
}
LOG.debug("write shed geom");
geometryJSON.write(outputHull, sw);
LOG.debug("done");
}
} else if (output.equals(SIsochrone.RESULT_TYPE_EDGES)) {
// in case there was no road we return only the suggested path to the street
if (noRoadNearBy) {
geometryJSON.write(pathToStreet, sw);
} else {
// -- if we would use only the edges from the paths to the origin we will miss
// some edges that will be never on the shortest path (e.g. loops/crescents).
// However, we can retrieve all edges by checking the times for each
// edge end-point
Map<ReversibleLineStringWrapper, LineString> walkShedEdges = Maps.newHashMap();
// add the walk from the pushpin to closest street point
walkShedEdges.put(new ReversibleLineStringWrapper(pathToStreet), pathToStreet);
// get the edges and edge parts within time limits
ArrayList<LineString> withinTimeEdges = this.getLinesAndSubEdgesWithinMaxTime(maxTime, allConnectingEdges, sptA, angleLimitForUShapeDetection, distanceToleranceForUShapeDetection, maxUserSpeed, usesCar, doSpeedTest);
for (LineString ls : withinTimeEdges) {
walkShedEdges.put(new ReversibleLineStringWrapper(ls), ls);
}
Geometry mls = null;
LineString[] edges = new LineString[walkShedEdges.size()];
int k = 0;
for (LineString ls : walkShedEdges.values()) edges[k++] = ls;
LOG.debug("create multilinestring from {} geoms", edges.length);
mls = gf.createMultiLineString(edges);
LOG.debug("write geom");
geometryJSON.write(mls, sw);
LOG.debug("done");
}
} else if (output.equals("DEBUGEDGES")) {
// -- for debugging, i.e. display of detected u-shapes/crescents
ArrayList<LineString> withinTimeEdges = this.getLinesAndSubEdgesWithinMaxTime(maxTime, allConnectingEdges, sptA, angleLimitForUShapeDetection, distanceToleranceForUShapeDetection, maxUserSpeed, usesCar, doSpeedTest);
if (this.showTooFastEdgesAsDebugGeomsANDnotUShapes) {
LOG.debug("displaying edges that are traversed too fast");
this.debugGeoms = this.tooFastTraversedEdgeGeoms;
} else {
LOG.debug("displaying detected u-shaped roads/crescents");
}
LineString[] edges = new LineString[this.debugGeoms.size()];
int k = 0;
for (Iterator iterator = debugGeoms.iterator(); iterator.hasNext(); ) {
LineString ls = (LineString) iterator.next();
edges[k] = ls;
k++;
}
Geometry mls = gf.createMultiLineString(edges);
LOG.debug("write debug geom");
geometryJSON.write(mls, sw);
LOG.debug("done");
}
} catch (Exception e) {
LOG.error("Exception creating isochrone", e);
}
return sw.toString();
}
use of org.opentripplanner.routing.algorithm.AStar in project OpenTripPlanner by opentripplanner.
the class RepeatedRaptorProfileRouter method findInitialStops.
/**
* Find all transit stops accessible by streets around the origin, leaving behind a shortest path tree of the
* reachable area in the field preTransitSpt.
*
* @param data the raptor data table to use. If this is null (i.e. there is no transit) range is extended,
* and we don't care if we actually find any stops, we just want the tree of on-street distances.
*/
@VisibleForTesting
public TIntIntMap findInitialStops(boolean dest, RaptorWorkerData data) {
LOG.info("Finding initial stops");
double lat = dest ? request.toLat : request.fromLat;
double lon = dest ? request.toLon : request.fromLon;
QualifiedModeSet modes = dest ? request.egressModes : request.accessModes;
RoutingRequest rr = new RoutingRequest(modes);
rr.batch = true;
rr.from = new GenericLocation(lat, lon);
// rr.walkSpeed = request.walkSpeed;
rr.to = rr.from;
rr.setRoutingContext(graph);
rr.dateTime = request.date.toDateMidnight(DateTimeZone.forTimeZone(graph.getTimeZone())).getMillis() / 1000 + request.fromTime;
rr.walkSpeed = request.walkSpeed;
rr.bikeSpeed = request.bikeSpeed;
if (data == null) {
// Non-transit mode. Search out to the full 120 minutes.
// Should really use directModes.
rr.worstTime = rr.dateTime + RaptorWorker.MAX_DURATION;
rr.dominanceFunction = new DominanceFunction.EarliestArrival();
} else {
// Transit mode, limit pre-transit travel.
if (rr.modes.contains(TraverseMode.BICYCLE)) {
rr.dominanceFunction = new DominanceFunction.EarliestArrival();
rr.worstTime = rr.dateTime + request.maxBikeTime * 60;
} else {
// We use walk-distance limiting and a least-walk dominance function in order to be consistent with egress walking
// which is implemented this way because walk times can change when walk speed changes. Also, walk times are floating
// point and can change slightly when streets are split. Street lengths are internally fixed-point ints, which do not
// suffer from roundoff. Great care is taken when splitting to preserve sums.
// When cycling, this is not an issue; we already have an explicitly asymmetrical search (cycling at the origin, walking at the destination),
// so we need not preserve symmetry.
// We use the max walk time for the search at the origin, but we clamp it to MAX_WALK_METERS so that we don;t
// have every transit stop in the state as an initial transit stop if someone sets max walk time to four days,
// and so that symmetry is preserved.
// FIXME kind of arbitrary
rr.maxWalkDistance = Math.min(request.maxWalkTime * 60 * request.walkSpeed, GraphIndex.MAX_WALK_METERS);
rr.softWalkLimiting = false;
rr.dominanceFunction = new DominanceFunction.LeastWalk();
}
}
rr.numItineraries = 1;
rr.longDistance = true;
AStar aStar = new AStar();
preTransitSpt = aStar.getShortestPathTree(rr, 5);
// otherwise return null and leave preTransitSpt around for later use.
if (data != null) {
TIntIntMap accessTimes = data.findStopsNear(preTransitSpt, graph, rr.modes.contains(TraverseMode.BICYCLE), request.walkSpeed);
LOG.info("Found {} transit stops", accessTimes.size());
return accessTimes;
} else {
return null;
}
}
use of org.opentripplanner.routing.algorithm.AStar in project OpenTripPlanner by opentripplanner.
the class RoundBasedProfileRouter method makeSurfaces.
/**
* analyst mode: propagate to street network
*/
private void makeSurfaces() {
LOG.info("Propagating from transit stops to the street network...");
List<State> lower = Lists.newArrayList();
List<State> upper = Lists.newArrayList();
List<State> avg = Lists.newArrayList();
RoutingRequest rr = new RoutingRequest(TraverseMode.WALK);
rr.batch = (true);
rr.from = new GenericLocation(request.fromLat, request.fromLon);
rr.setRoutingContext(graph);
rr.longDistance = true;
rr.dominanceFunction = new DominanceFunction.EarliestArrival();
rr.setNumItineraries(1);
rr.worstTime = rr.dateTime + CUTOFF_SECONDS;
long startTime = rr.dateTime;
State origin = new State(rr);
// Multi-origin Dijkstra search; preinitialize the queue with states at each transit stop
for (Collection<ProfileState> pss : retainedStates.asMap().values()) {
TransitStop tstop = null;
int lowerBound = Integer.MAX_VALUE;
int upperBound = Integer.MAX_VALUE;
for (ProfileState ps : pss) {
if (tstop == null)
tstop = ps.stop;
if (ps.lowerBound < lowerBound)
lowerBound = ps.lowerBound;
if (ps.upperBound < upperBound)
upperBound = ps.upperBound;
}
if (lowerBound == Integer.MAX_VALUE || upperBound == Integer.MAX_VALUE)
throw new IllegalStateException("Invalid bound!");
lower.add(new State(tstop, null, lowerBound + startTime, startTime, rr));
upper.add(new State(tstop, null, upperBound + startTime, startTime, rr));
// TODO extremely incorrect hack!
avg.add(new State(tstop, null, (upperBound + lowerBound) / 2 + startTime, startTime, rr));
}
// get direct trips as well
lower.add(origin);
upper.add(origin);
avg.add(origin);
// create timesurfaces
timeSurfaceRangeSet = new TimeSurface.RangeSet();
AStar astar = new AStar();
timeSurfaceRangeSet.min = new TimeSurface(astar.getShortestPathTree(rr, 20, null, lower), false);
astar = new AStar();
timeSurfaceRangeSet.max = new TimeSurface(astar.getShortestPathTree(rr, 20, null, upper), false);
astar = new AStar();
timeSurfaceRangeSet.avg = new TimeSurface(astar.getShortestPathTree(rr, 20, null, avg), false);
rr.cleanup();
LOG.info("Done with propagation.");
/* Store the results in a field in the router object. */
}
Aggregations