use of org.opentripplanner.graph_builder.issues.StopLinkedTooFar in project OpenTripPlanner by opentripplanner.
the class SimpleStreetSplitter method linkToStreetEdges.
public boolean linkToStreetEdges(Vertex vertex, TraverseMode traverseMode, RoutingRequest options, int radiusMeters) {
final double radiusDeg = SphericalDistanceLibrary.metersToDegrees(radiusMeters);
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 = new TraverseModeSet(traverseMode);
if (traverseMode == TraverseMode.BICYCLE) {
traverseModeSet.setWalk(true);
}
// Scope block to avoid confusing edge-related local variables with stop-related variables below.
{
// Perform several transformations at once on the edges returned by the index.
// Only consider street edges traversable by the given mode and still present in the graph.
// Calculate a distance to each of those edges, and keep only the ones within the search radius.
List<DistanceTo<StreetEdge>> candidateEdges = idx.query(env).stream().filter(StreetEdge.class::isInstance).map(StreetEdge.class::cast).filter(e -> e.canTraverse(traverseModeSet) && edgeReachableFromGraph(e)).map(e -> new DistanceTo<>(e, distance(vertex, e, xscale))).filter(ead -> ead.distanceDegreesLat < radiusDeg).collect(Collectors.toList());
// being non-deterministic.
if (!candidateEdges.isEmpty()) {
// There is at least one appropriate edge within range.
double closestDistance = candidateEdges.stream().mapToDouble(ce -> ce.distanceDegreesLat).min().getAsDouble();
candidateEdges.stream().filter(ce -> ce.distanceDegreesLat <= closestDistance + DUPLICATE_WAY_EPSILON_DEGREES).forEach(ce -> link(vertex, ce.item, xscale, options));
// Warn if a linkage was made for a transit stop, but the linkage was suspiciously long.
if (vertex instanceof TransitStopVertex) {
int distanceMeters = (int) SphericalDistanceLibrary.degreesLatitudeToMeters(closestDistance);
if (distanceMeters > WARNING_DISTANCE_METERS) {
issueStore.add(new StopLinkedTooFar((TransitStopVertex) vertex, distanceMeters));
}
}
return true;
}
}
if (radiusMeters >= MAX_SEARCH_RADIUS_METERS) {
// 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 {}, checking transit stop vertices.", vertex);
List<TransitStopVertex> transitStopVertices = transitStopIndex.query(env);
List<DistanceTo<TransitStopVertex>> candidateStops = transitStopVertices.stream().map(tsv -> new DistanceTo<>(tsv, distance(vertex, tsv, xscale))).filter(dts -> dts.distanceDegreesLat <= radiusDeg).collect(Collectors.toList());
if (candidateStops.isEmpty()) {
LOG.debug("No stops nearby.");
return false;
}
// There is at least one stop within range.
double closestDistance = candidateStops.stream().mapToDouble(c -> c.distanceDegreesLat).min().getAsDouble();
candidateStops.stream().filter(dts -> dts.distanceDegreesLat <= closestDistance + DUPLICATE_WAY_EPSILON_DEGREES).map(dts -> dts.item).forEach(sv -> {
LOG.debug("Linking vertex to stop: {}", sv.getName());
makeTemporaryEdges((TemporaryStreetLocation) vertex, sv);
});
return true;
}
return false;
}
Aggregations