use of org.opentripplanner.routing.graph.Edge in project OpenTripPlanner by opentripplanner.
the class SIsochrone method getLinesAndSubEdgesWithinMaxTime.
/**
* Filters all input edges and returns all those as LineString geometries, that have at least one end point within the time limits. If they have
* only one end point inside, then the sub-edge is returned.
*
* @param maxTime the time limit in seconds that defines the size of the walkshed
* @param allConnectingStateEdges all Edges that have been found to connect all states < maxTime
* @param spt the ShortestPathTree generated for the pushpin drop point as origin
* @param angleLimit the angle tolerance to detect roads with u-shapes, i.e. Pi/2 angles, in Radiant.
* @param distanceTolerance in percent (e.g. 1.1 = 110%) for u-shape detection based on distance criteria
* @param hasCar is travel mode by CAR?
* @param performSpeedTest if true applies a test to each edge to check if the edge can be traversed in time. The test can detect u-shaped roads.
* @return
*/
ArrayList<LineString> getLinesAndSubEdgesWithinMaxTime(long maxTime, ArrayList<Edge> allConnectingStateEdges, ShortestPathTree spt, double angleLimit, double distanceTolerance, double userSpeed, boolean hasCar, boolean performSpeedTest) {
LOG.debug("maximal userSpeed set to: " + userSpeed + " m/sec ");
if (hasCar) {
LOG.debug("travel mode is set to CAR, hence the given speed may be adjusted for each edge");
}
ArrayList<LineString> walkShedEdges = new ArrayList<LineString>();
ArrayList<LineString> otherEdges = new ArrayList<LineString>();
ArrayList<LineString> borderEdges = new ArrayList<LineString>();
ArrayList<LineString> uShapes = new ArrayList<LineString>();
int countEdgesOutside = 0;
// -- determination of walkshed edges via edge states
for (Iterator iterator = allConnectingStateEdges.iterator(); iterator.hasNext(); ) {
Edge edge = (Edge) iterator.next();
State sFrom = spt.getState(edge.getFromVertex());
State sTo = spt.getState(edge.getToVertex());
if ((sFrom != null) && (sTo != null)) {
long fromTime = sFrom.getElapsedTimeSeconds();
long toTime = sTo.getElapsedTimeSeconds();
long dt = Math.abs(toTime - fromTime);
Geometry edgeGeom = edge.getGeometry();
if ((edgeGeom != null) && (edgeGeom instanceof LineString)) {
LineString ls = (LineString) edgeGeom;
// detect u-shape roads/crescents - they need to be treated separately
boolean uShapeOrLonger = testForUshape(edge, maxTime, fromTime, toTime, angleLimit, distanceTolerance, userSpeed, hasCar, performSpeedTest);
if (uShapeOrLonger) {
uShapes.add(ls);
}
// evaluate if an edge is completely within the time or only with one end
if ((fromTime < maxTime) && (toTime < maxTime)) {
// a second test if we have a u-shaped road.
if (uShapeOrLonger) {
treatAndAddUshapeWithinTimeLimits(maxTime, userSpeed, walkShedEdges, edge, fromTime, toTime, ls, hasCar);
} else {
walkShedEdges.add(ls);
}
} else // end if:fromTime & toTime < maxTime
{
// create the sub edge
if ((fromTime < maxTime) || (toTime < maxTime)) {
double lineDist = edge.getDistance();
LineString inputLS = ls;
double fraction = 1.0;
if (fromTime < toTime) {
double distanceToWalkInTimeMissing = distanceToMoveInRemainingTime(maxTime, fromTime, dt, userSpeed, edge, hasCar, uShapeOrLonger);
fraction = (double) distanceToWalkInTimeMissing / (double) lineDist;
} else {
// toTime < fromTime : invert the edge direction
inputLS = (LineString) ls.reverse();
double distanceToWalkInTimeMissing = distanceToMoveInRemainingTime(maxTime, toTime, dt, userSpeed, edge, hasCar, uShapeOrLonger);
fraction = (double) distanceToWalkInTimeMissing / (double) lineDist;
}
// get the subedge
LineString subLine = this.getSubLineString(inputLS, fraction);
borderEdges.add(subLine);
} else {
// this edge is completely outside - this should actually not happen
// we will not do anything, just count
countEdgesOutside++;
}
}
// end else: fromTime & toTime < maxTime
} else // end if: edge instance of LineString
{
// edge is not instance of LineString
LOG.debug("edge not instance of LineString");
}
} else // end if(sFrom && sTo != null) start Else
{
// LOG.debug("could not retrieve state for edge-endpoint"); //for a 6min car ride, there can be (too) many of such messages
Geometry edgeGeom = edge.getGeometry();
if ((edgeGeom != null) && (edgeGeom instanceof LineString)) {
otherEdges.add((LineString) edgeGeom);
}
}
// end else: sFrom && sTo != null
}
// end for loop over edges
walkShedEdges.addAll(borderEdges);
this.debugGeoms.addAll(uShapes);
LOG.debug("number of detected u-shapes/crescents: " + uShapes.size());
return walkShedEdges;
}
use of org.opentripplanner.routing.graph.Edge in project OpenTripPlanner by opentripplanner.
the class SimpleStreetSplitter method link.
/**
* Link this vertex into the graph
*/
public boolean link(Vertex vertex, TraverseMode traverseMode, RoutingRequest options) {
// find nearby street edges
// TODO: we used to use an expanding-envelope search, which is more efficient in
// dense areas. but first let's see how inefficient this is. I suspect it's not too
// bad and the gains in simplicity are considerable.
final double radiusDeg = SphericalDistanceLibrary.metersToDegrees(MAX_SEARCH_RADIUS_METERS);
Envelope env = new Envelope(vertex.getCoordinate());
// Perform a simple local equirectangular projection, so distances are expressed in degrees latitude.
final double xscale = Math.cos(vertex.getLat() * Math.PI / 180);
// Expand more in the longitude direction than the latitude direction to account for converging meridians.
env.expandBy(radiusDeg / xscale, radiusDeg);
final double DUPLICATE_WAY_EPSILON_DEGREES = SphericalDistanceLibrary.metersToDegrees(DUPLICATE_WAY_EPSILON_METERS);
final TraverseModeSet traverseModeSet;
if (traverseMode == TraverseMode.BICYCLE) {
traverseModeSet = new TraverseModeSet(traverseMode, TraverseMode.WALK);
} else {
traverseModeSet = new TraverseModeSet(traverseMode);
}
// We sort the list of candidate edges by distance to the stop
// This should remove any issues with things coming out of the spatial index in different orders
// Then we link to everything that is within DUPLICATE_WAY_EPSILON_METERS of of the best distance
// so that we capture back edges and duplicate ways.
List<StreetEdge> candidateEdges = idx.query(env).stream().filter(streetEdge -> streetEdge instanceof StreetEdge).map(edge -> (StreetEdge) edge).filter(edge -> edge.canTraverse(traverseModeSet) && // only link to edges still in the graph.
edge.getToVertex().getIncoming().contains(edge)).collect(Collectors.toList());
// Make a map of distances to all edges.
final TIntDoubleMap distances = new TIntDoubleHashMap();
for (StreetEdge e : candidateEdges) {
distances.put(e.getId(), distance(vertex, e, xscale));
}
// Sort the list.
Collections.sort(candidateEdges, (o1, o2) -> {
double diff = distances.get(o1.getId()) - distances.get(o2.getId());
// A Comparator must return an integer but our distances are doubles.
if (diff < 0)
return -1;
if (diff > 0)
return 1;
return 0;
});
// find the closest candidate edges
if (candidateEdges.isEmpty() || distances.get(candidateEdges.get(0).getId()) > radiusDeg) {
// We only link to stops if we are searching for origin/destination and for that we need transitStopIndex.
if (destructiveSplitting || transitStopIndex == null) {
return false;
}
LOG.debug("No street edge was found for {}", vertex);
// We search for closest stops (since this is only used in origin/destination linking if no edges were found)
// in the same way the closest edges are found.
List<TransitStop> candidateStops = new ArrayList<>();
transitStopIndex.query(env).forEach(candidateStop -> candidateStops.add((TransitStop) candidateStop));
final TIntDoubleMap stopDistances = new TIntDoubleHashMap();
for (TransitStop t : candidateStops) {
stopDistances.put(t.getIndex(), distance(vertex, t, xscale));
}
Collections.sort(candidateStops, (o1, o2) -> {
double diff = stopDistances.get(o1.getIndex()) - stopDistances.get(o2.getIndex());
if (diff < 0) {
return -1;
}
if (diff > 0) {
return 1;
}
return 0;
});
if (candidateStops.isEmpty() || stopDistances.get(candidateStops.get(0).getIndex()) > radiusDeg) {
LOG.debug("Stops aren't close either!");
return false;
} else {
List<TransitStop> bestStops = Lists.newArrayList();
// Add stops until there is a break of epsilon meters.
// we do this to enforce determinism. if there are a lot of stops that are all extremely close to each other,
// we want to be sure that we deterministically link to the same ones every time. Any hard cutoff means things can
// fall just inside or beyond the cutoff depending on floating-point operations.
int i = 0;
do {
bestStops.add(candidateStops.get(i++));
} while (i < candidateStops.size() && stopDistances.get(candidateStops.get(i).getIndex()) - stopDistances.get(candidateStops.get(i - 1).getIndex()) < DUPLICATE_WAY_EPSILON_DEGREES);
for (TransitStop stop : bestStops) {
LOG.debug("Linking vertex to stop: {}", stop.getName());
makeTemporaryEdges((TemporaryStreetLocation) vertex, stop);
}
return true;
}
} else {
// find the best edges
List<StreetEdge> bestEdges = Lists.newArrayList();
// add edges until there is a break of epsilon meters.
// we do this to enforce determinism. if there are a lot of edges that are all extremely close to each other,
// we want to be sure that we deterministically link to the same ones every time. Any hard cutoff means things can
// fall just inside or beyond the cutoff depending on floating-point operations.
int i = 0;
do {
bestEdges.add(candidateEdges.get(i++));
} while (i < candidateEdges.size() && distances.get(candidateEdges.get(i).getId()) - distances.get(candidateEdges.get(i - 1).getId()) < DUPLICATE_WAY_EPSILON_DEGREES);
for (StreetEdge edge : bestEdges) {
link(vertex, edge, xscale, options);
}
// Warn if a linkage was made, but the linkage was suspiciously long.
if (vertex instanceof TransitStop) {
double distanceDegreesLatitude = distances.get(candidateEdges.get(0).getId());
int distanceMeters = (int) SphericalDistanceLibrary.degreesLatitudeToMeters(distanceDegreesLatitude);
if (distanceMeters > WARNING_DISTANCE_METERS) {
// Registering an annotation but not logging because tests produce thousands of these warnings.
graph.addBuilderAnnotation(new StopLinkedTooFar((TransitStop) vertex, distanceMeters));
}
}
return true;
}
}
use of org.opentripplanner.routing.graph.Edge in project OpenTripPlanner by opentripplanner.
the class DirectTransferGenerator method buildGraph.
@Override
public void buildGraph(Graph graph, HashMap<Class<?>, Object> extra) {
/* Initialize graph index which is needed by the nearby stop finder. */
if (graph.index == null) {
graph.index = new GraphIndex(graph);
}
/* The linker will use streets if they are available, or straight-line distance otherwise. */
NearbyStopFinder nearbyStopFinder = new NearbyStopFinder(graph, radiusMeters);
if (nearbyStopFinder.useStreets) {
LOG.info("Creating direct transfer edges between stops using the street network from OSM...");
} else {
LOG.info("Creating direct transfer edges between stops using straight line distance (not streets)...");
}
int nTransfersTotal = 0;
int nLinkableStops = 0;
for (TransitStop ts0 : Iterables.filter(graph.getVertices(), TransitStop.class)) {
/* Skip stops that are entrances to stations or whose entrances are coded separately */
if (!ts0.isStreetLinkable())
continue;
if (++nLinkableStops % 1000 == 0) {
LOG.info("Linked {} stops", nLinkableStops);
}
LOG.debug("Linking stop '{}' {}", ts0.getStop(), ts0);
/* Determine the set of stops that are already reachable via other pathways or transfers */
Set<TransitStop> pathwayDestinations = new HashSet<TransitStop>();
for (Edge e : ts0.getOutgoing()) {
if (e instanceof PathwayEdge || e instanceof SimpleTransfer) {
if (e.getToVertex() instanceof TransitStop) {
TransitStop to = (TransitStop) e.getToVertex();
pathwayDestinations.add(to);
}
}
}
/* Make transfers to each nearby stop that is the closest stop on some trip pattern. */
int n = 0;
for (NearbyStopFinder.StopAtDistance sd : nearbyStopFinder.findNearbyStopsConsideringPatterns(ts0)) {
/* Skip the origin stop, loop transfers are not needed. */
if (sd.tstop == ts0 || pathwayDestinations.contains(sd.tstop))
continue;
new SimpleTransfer(ts0, sd.tstop, sd.dist, sd.geom, sd.edges);
n += 1;
}
LOG.debug("Linked stop {} to {} nearby stops on other patterns.", ts0.getStop(), n);
if (n == 0) {
LOG.debug(graph.addBuilderAnnotation(new StopNotLinkedForTransfers(ts0)));
}
nTransfersTotal += n;
}
LOG.info("Done connecting stops to one another. Created a total of {} transfers from {} stops.", nTransfersTotal, nLinkableStops);
graph.hasDirectTransfers = true;
}
use of org.opentripplanner.routing.graph.Edge in project OpenTripPlanner by opentripplanner.
the class GraphStatisticsModule method buildGraph.
@Override
public void buildGraph(Graph graph, HashMap<Class<?>, Object> extra) {
DiscreteDistribution<ConstantQuantifiable<String>> edgeTypeDistribution = new DiscreteDistribution<ConstantQuantifiable<String>>();
DiscreteDistribution<NumberQuantifiable<Integer>> edgeNameDistribution = new DiscreteDistribution<NumberQuantifiable<Integer>>();
DiscreteDistribution<NumberQuantifiable<Integer>> geomSizeDistribution = new DiscreteDistribution<NumberQuantifiable<Integer>>();
DiscreteDistribution<LogQuantifiable<Double>> geomLenDistribution = new DiscreteDistribution<LogQuantifiable<Double>>();
DiscreteDistribution<ConstantQuantifiable<String>> vertexTypeDistribution = new DiscreteDistribution<ConstantQuantifiable<String>>();
DiscreteDistribution<NumberQuantifiable<Integer>> vertexNameDistribution = new DiscreteDistribution<NumberQuantifiable<Integer>>();
DiscreteDistribution<NumberQuantifiable<Integer>> vertexLabelDistribution = new DiscreteDistribution<NumberQuantifiable<Integer>>();
for (Edge e : graph.getEdges()) {
edgeTypeDistribution.add(new ConstantQuantifiable<String>(e.getClass().toString()));
edgeNameDistribution.add(new NumberQuantifiable<Integer>(e.getName() == null ? 0 : e.getName().length()), e.getName());
if (e.getGeometry() != null) {
LineString geometry = e.getGeometry();
geomSizeDistribution.add(new NumberQuantifiable<Integer>(geometry.getNumPoints()));
double lenMeters = SphericalDistanceLibrary.fastLength(geometry);
geomLenDistribution.add(new LogQuantifiable<Double>(lenMeters, 5.0));
}
}
for (Vertex v : graph.getVertices()) {
vertexTypeDistribution.add(new ConstantQuantifiable<String>(v.getClass().toString()));
vertexNameDistribution.add(new NumberQuantifiable<Integer>(v.getName() == null ? 0 : v.getName().length()), v.getName());
vertexLabelDistribution.add(new NumberQuantifiable<Integer>(v.getLabel().length()), v.getLabel());
}
LOG.info("Geometry size distribution (linear scale, # points):\n" + geomSizeDistribution.toString());
LOG.info("Geometry length distribution (log scale, meters):\n" + geomLenDistribution.toString());
LOG.info("Edge type distribution:\n" + edgeTypeDistribution.toString());
LOG.info("Edge name distribution:\n" + edgeNameDistribution.toString());
LOG.info("Vertex type distribution:\n" + vertexTypeDistribution.toString());
LOG.info("Vertex name distribution:\n" + vertexNameDistribution.toString());
LOG.info("Vertex label distribution:\n" + vertexLabelDistribution.toString());
}
use of org.opentripplanner.routing.graph.Edge in project OpenTripPlanner by opentripplanner.
the class StreetMatcher method match.
@SuppressWarnings("unchecked")
public List<Edge> match(Geometry routeGeometry) {
routeGeometry = removeDuplicatePoints(routeGeometry);
if (routeGeometry == null)
return null;
routeGeometry = DouglasPeuckerSimplifier.simplify(routeGeometry, 0.00001);
// initial state: start midway along a block.
LocationIndexedLine indexedLine = new LocationIndexedLine(routeGeometry);
LinearLocation startIndex = indexedLine.getStartIndex();
Coordinate routeStartCoordinate = startIndex.getCoordinate(routeGeometry);
Envelope envelope = new Envelope(routeStartCoordinate);
double distanceThreshold = DISTANCE_THRESHOLD;
envelope.expandBy(distanceThreshold);
BinHeap<MatchState> states = new BinHeap<MatchState>();
List<Edge> nearbyEdges = index.query(envelope);
while (nearbyEdges.isEmpty()) {
envelope.expandBy(distanceThreshold);
distanceThreshold *= 2;
nearbyEdges = index.query(envelope);
}
// compute initial states
for (Edge initialEdge : nearbyEdges) {
Geometry edgeGeometry = initialEdge.getGeometry();
LocationIndexedLine indexedEdge = new LocationIndexedLine(edgeGeometry);
LinearLocation initialLocation = indexedEdge.project(routeStartCoordinate);
double error = MatchState.distance(initialLocation.getCoordinate(edgeGeometry), routeStartCoordinate);
MidblockMatchState state = new MidblockMatchState(null, routeGeometry, initialEdge, startIndex, initialLocation, error, 0.01);
// make sure all initial states are visited by inserting them at 0
states.insert(state, 0);
}
// search for best-matching path
int seen_count = 0, total = 0;
HashSet<MatchState> seen = new HashSet<MatchState>();
while (!states.empty()) {
double k = states.peek_min_key();
MatchState state = states.extract_min();
if (++total % 50000 == 0) {
log.debug("seen / total: " + seen_count + " / " + total);
}
if (seen.contains(state)) {
++seen_count;
continue;
} else {
if (k != 0) {
// but do not mark states as closed if we start at them
seen.add(state);
}
}
if (state instanceof EndMatchState) {
return toEdgeList(state);
}
for (MatchState next : state.getNextStates()) {
if (seen.contains(next)) {
continue;
}
states.insert(next, next.getTotalError() - next.getDistanceAlongRoute());
}
}
return null;
}
Aggregations