protected DirectionalizedEdge(final Edge source) { super(source.getAtlas()); this.source = source; }
/** * @return An {@link Edge} that is reversed to this one if it exists, empty otherwise. */ public Optional<Edge> reversed() { final Edge edge = this.getAtlas().edge(-this.getIdentifier()); if (edge != null) { return Optional.of(edge); } return Optional.empty(); }
/** * @return {@code true} if there is a reverse edge to this one */ public boolean hasReverseEdge() { return this.getAtlas().edge(-this.getIdentifier()) != null; }
/** * Find all possible routes from the start {@link Edge} to the end {@link Edge}, using DFS. * * @param start * The {@link Edge} to start from * @param end * The {@link Edge} to end at * @return all possible {@link Route}s from start to end */ public static Set<Route> allRoutes(final Edge start, final Edge end) { if (start.getAtlas() != end.getAtlas()) { throw new CoreException("Supplied start and end edges must come from the same atlas!"); } if (Iterables.size(start.getAtlas().edges()) > MAXIMUM_ALLOWED_EDGES_FOR_TRAVERSAL) { throw new CoreException( "Atlas has too many edges for an efficient traversal - aborting!"); } final Stack<Edge> path = new Stack<>(); final Set<Long> onPath = new HashSet<>(); final Set<Route> routes = new HashSet<>(); allRoutes(start, end, path, onPath, routes, ALL_EDGES); return routes; }
/** * Find all possible routes from the start {@link Edge} to the end {@link Edge}, using DFS. Only * {@link Edge}s that meet the given filter will be included in the resulting {@link Route}s. * * @param start * The {@link Edge} to start from * @param end * The {@link Edge} to end at * @param filter * The filter to use when including {@link Edge}s that make up the route * @return all possible {@link Route}s from start to end */ public static Set<Route> allRoutes(final Edge start, final Edge end, final Predicate<Edge> filter) { if (start.getAtlas() != end.getAtlas()) { throw new CoreException("Supplied start and end edges must come from the same atlas!"); } if (Iterables.size(start.getAtlas().edges()) > MAXIMUM_ALLOWED_EDGES_FOR_TRAVERSAL) { throw new CoreException( "Atlas has too many edges for an efficient traversal - aborting!"); } final Stack<Edge> path = new Stack<>(); final Set<Long> onPath = new HashSet<>(); final Set<Route> routes = new HashSet<>(); allRoutes(start, end, path, onPath, routes, filter); return routes; }
/** * Find all possible routes from the start {@link Edge} to the end {@link Edge}, using DFS and * return in an order determined by the given {@link Comparator}. * * @param start * The {@link Edge} to start from * @param end * The {@link Edge} to end at * @param comparator * Used to order the found routes * @return all possible {@link Route}s from start to end */ public static Set<Route> allRoutes(final Edge start, final Edge end, final Comparator<Route> comparator) { if (start.getAtlas() != end.getAtlas()) { throw new CoreException("Supplied start and end edges must come from the same atlas!"); } if (Iterables.size(start.getAtlas().edges()) > MAXIMUM_ALLOWED_EDGES_FOR_TRAVERSAL) { throw new CoreException( "Atlas has too many edges for an efficient traversal - aborting!"); } final Stack<Edge> path = new Stack<>(); final Set<Long> onPath = new HashSet<>(); final Set<Route> routes = new TreeSet<>(comparator); allRoutes(start, end, path, onPath, routes, ALL_EDGES); return routes; }
/** * Create a road for given OSM identifier per sub atlas given edge list. Ignore empty roads, * because not all sub atlases will have a road for an OSM way. * * @param osmIdentifier * OSM identifier to used as reference * @param edges * Edge list * @return List of {@link TemporaryRoad}s */ private List<TemporaryRoad> createRoadsPerSubAtlas(final long osmIdentifier, final List<Edge> edges) { final Map<Integer, TemporaryRoad> edgesPerSubAtlas = new HashMap<>(); for (final Atlas subAtlas : this.subAtlases) { edgesPerSubAtlas.put(subAtlas.getIdentifier(), new TemporaryRoad(subAtlas, osmIdentifier)); } for (final Edge edge : edges) { edgesPerSubAtlas.get(edge.getAtlas().getIdentifier()).add(edge); } // Filter out empty roads edgesPerSubAtlas.values().removeIf(road -> road.getMembers().isEmpty()); // Return the rest return new ArrayList<>(edgesPerSubAtlas.values()); }
public void add(final Edge edge) { if (this.route != null) { throw new CoreException("Cannot add new edges when the route has already been created"); } // Skip those, they will be re-constructed if (edge.getIdentifier() < 0) { return; } // Avoiding .equals() is intentional here! if (this.subAtlas != edge.getAtlas()) { throw new CoreException("Cannot add an edge that is not from the right Atlas"); } this.members.add(edge); }
ComplexHighwayAreaHelper(final Edge edge) { this.sourceEdge = edge; buildHighwayAreaBoundary(Route.forEdge(edge)).ifPresent(route -> { this.boundary = route.asPolyLine(); StreamSupport.stream(route.spliterator(), false).map(Edge::getIdentifier) .forEach(this.visitedEdgeIdentifiers::add); this.sourceEdge = edge.getAtlas().edge(this.visitedEdgeIdentifiers.first()); }); if (this.boundary == null) { this.oops = new CoreException("Unable to build boundary for edge {}", edge.getOsmIdentifier()); } }
private boolean hasPerfectMatch(final Edge edge, final Iterable<Edge> otherEdges) { if (this.withGeometryMatching) { final PolyLine source = edge.asPolyLine(); final List<PolyLine> candidates = Iterables.stream(otherEdges).map(Edge::asPolyLine) .collectToList(); final Optional<PolyLineRoute> match = source.costDistanceToOneWay(candidates) .match(Distance.ZERO); if (match.isPresent() && match.get().getCost().isLessThanOrEqualTo(Distance.ZERO)) { // The edge was probably split by way sectioning without changing itself. logger.trace("Edge {} from {} has no equal member but found a match with no cost.", edge, edge.getAtlas().getName()); return true; } } return false; } }
/** * Checks for roads that should not be inside a roundabout. Such roads are car navigable, not a * roundabout, bridge, or tunnel, don't have a layer tag, and have geometry inside the * roundabout. * * @param roundabout * A roundabout as a {@link Route} * @return true if there is a road that is crossing and has geometry enclosed by the roundabout */ private boolean roundaboutEnclosesRoads(final Route roundabout) { final Polygon roundaboutPoly = new Polygon(roundabout.asPolyLine()); return roundabout.start().getAtlas().edgesIntersecting(roundaboutPoly, edge -> HighwayTag.isCarNavigableHighway(edge) && !JunctionTag.isRoundabout(edge) && !this.ignoreBridgeTunnelCrossings(edge) && this.intersectsWithEnclosedGeometry(roundaboutPoly, edge)) .iterator().hasNext(); }
final Atlas atlas = edge.getAtlas(); return Iterables .asList(atlas.edgesIntersecting(edgeBounds,
final Iterable<Edge> edgesInBounds = edge.getAtlas().edgesIntersecting(bounds, Edge::isMasterEdge);
private boolean differentEdges(final Edge baseEdge, final Edge alterEdge) { try { boolean result = false; if (!baseEdge.asPolyLine().equals(alterEdge.asPolyLine())) { result = true; } if (!result && baseEdge.start().getIdentifier() != alterEdge.start().getIdentifier()) { result = true; } if (!result && baseEdge.end().getIdentifier() != alterEdge.end().getIdentifier()) { result = true; } if (result) { // Make sure that there is not way to find a match with the other polylines result = !hasGoodMatch(baseEdge, alterEdge.getAtlas()); } return result; } catch (final Exception e) { throw new CoreException("Unable to compare edges {} and {}", baseEdge, alterEdge, e); } }