diff --git a/include/extractor/guidance/coordinate_extractor.hpp b/include/extractor/guidance/coordinate_extractor.hpp index 0a20c884a..f7982882d 100644 --- a/include/extractor/guidance/coordinate_extractor.hpp +++ b/include/extractor/guidance/coordinate_extractor.hpp @@ -49,6 +49,17 @@ class CoordinateExtractor std::vector GetForwardCoordinatesAlongRoad(const NodeID from, const EdgeID turn_edge) const; + // a less precise way to compute coordinates along a route. Due to the heavy interaction of + // graph traversal and turn instructions, we often don't care for high precision. We only want + // to check for available connections in order, or find (with room for error) the straightmost + // turn. This function will offer a bit more error potential but allow for much higher + // performance + OSRM_ATTR_WARN_UNUSED + util::Coordinate GetCoordinateCloseToTurn(const NodeID from_node, + const EdgeID turn_edge, + const bool traversed_in_reverse, + const NodeID to_node) const; + /* When extracting the coordinates, we first extract all coordinates. We don't care about most * of them, though. * diff --git a/include/extractor/guidance/intersection_generator.hpp b/include/extractor/guidance/intersection_generator.hpp index 59b42843d..6deb09f09 100644 --- a/include/extractor/guidance/intersection_generator.hpp +++ b/include/extractor/guidance/intersection_generator.hpp @@ -51,8 +51,14 @@ class IntersectionGenerator // Check for restrictions/barriers and generate a list of valid and invalid turns present at // the node reached from `from_node` via `via_eid`. The resulting candidates have to be analysed // for their actual instructions later on. + // The switch for `use_low_precision_angles` enables a faster mode that will procude less + // accurate coordinates. It should be good enough to check order of turns, find striaghtmost + // turns. Even good enough to do some simple angle verifications. It is mostly available to + // allow for faster graph traversal in the extraction phase. OSRM_ATTR_WARN_UNUSED - Intersection GetConnectedRoads(const NodeID from_node, const EdgeID via_eid) const; + Intersection GetConnectedRoads(const NodeID from_node, + const EdgeID via_eid, + const bool use_low_precision_angles = false) const; private: const util::NodeBasedDynamicGraph &node_based_graph; diff --git a/src/extractor/guidance/coordinate_extractor.cpp b/src/extractor/guidance/coordinate_extractor.cpp index fb9cdc030..c9d341d41 100644 --- a/src/extractor/guidance/coordinate_extractor.cpp +++ b/src/extractor/guidance/coordinate_extractor.cpp @@ -315,6 +315,55 @@ CoordinateExtractor::GetCoordinateAlongRoad(const NodeID intersection_node, .back(); } +util::Coordinate CoordinateExtractor::GetCoordinateCloseToTurn(const NodeID from_node, + const EdgeID turn_edge, + const bool traversed_in_reverse, + const NodeID to_node) const +{ + const auto end_node = traversed_in_reverse ? from_node : to_node; + const auto start_node = traversed_in_reverse ? to_node : from_node; + if (!compressed_geometries.HasEntryForID(turn_edge)) + return node_coordinates[end_node]; + else + { + const auto &geometry = compressed_geometries.GetBucketReference(turn_edge); + + // the compressed edges contain node ids, we transfer them to coordinates accessing the + // node_coordinates array + const auto compressedGeometryToCoordinate = + [this](const CompressedEdgeContainer::OnewayCompressedEdge &compressed_edge) { + return node_coordinates[compressed_edge.node_id]; + }; + + // return the first coordinate that is reasonably far away from the start node + const util::Coordinate start_coordinate = node_coordinates[start_node]; + + // OSM data has a tendency to include repeated nodes with identical coordinates. To skip + // over these, we search for the first coordinate along the path that is at least a meter + // away from the first entry + const auto far_enough_away = [start_coordinate, compressedGeometryToCoordinate]( + const CompressedEdgeContainer::OnewayCompressedEdge &compressed_edge) { + return util::coordinate_calculation::haversineDistance( + compressedGeometryToCoordinate(compressed_edge), start_coordinate) > 1; + }; + + // find the first coordinate, that is at least unequal to the begin of the edge + if (traversed_in_reverse) + { + const auto far_enough = + std::find_if(geometry.rbegin(), geometry.rend(), far_enough_away); + return (far_enough != geometry.rend()) ? compressedGeometryToCoordinate(*far_enough) + : node_coordinates[end_node]; + } + else + { + const auto far_enough = std::find_if(geometry.begin(), geometry.end(), far_enough_away); + return (far_enough != geometry.end()) ? compressedGeometryToCoordinate(*far_enough) + : node_coordinates[end_node]; + } + } +} + std::vector CoordinateExtractor::GetForwardCoordinatesAlongRoad(const NodeID from, const EdgeID turn_edge) const { diff --git a/src/extractor/guidance/intersection_generator.cpp b/src/extractor/guidance/intersection_generator.cpp index ad1d54655..0fb648010 100644 --- a/src/extractor/guidance/intersection_generator.cpp +++ b/src/extractor/guidance/intersection_generator.cpp @@ -20,6 +20,12 @@ namespace extractor { namespace guidance { +namespace +{ +const constexpr bool USE_LOW_PRECISION_MODE = true; +// the inverse of use low precision mode +const constexpr bool USE_HIGH_PRECISION_MODE = !USE_LOW_PRECISION_MODE; +} IntersectionGenerator::IntersectionGenerator( const util::NodeBasedDynamicGraph &node_based_graph, @@ -35,14 +41,14 @@ IntersectionGenerator::IntersectionGenerator( Intersection IntersectionGenerator::operator()(const NodeID from_node, const EdgeID via_eid) const { - return GetConnectedRoads(from_node, via_eid); + return GetConnectedRoads(from_node, via_eid, USE_HIGH_PRECISION_MODE); } // a // | // | // v -// For an intersection from_node --via_edi--> turn_node ----> c +// For an intersection from_node --via_eid--> turn_node ----> c // ^ // | // | @@ -52,7 +58,8 @@ Intersection IntersectionGenerator::operator()(const NodeID from_node, const Edg // but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are // marked as invalid and only needed for intersection classification. Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node, - const EdgeID via_eid) const + const EdgeID via_eid, + const bool use_low_precision_angles) const { Intersection intersection; const NodeID turn_node = node_based_graph.GetTarget(via_eid); @@ -81,6 +88,17 @@ Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node, const auto intersection_lanes = getLaneCountAtIntersection(turn_node, node_based_graph); + const auto extract_coordinate = [&](const NodeID from_node, + const EdgeID via_eid, + const bool traversed_in_reverse, + const NodeID to_node) { + return use_low_precision_angles + ? coordinate_extractor.GetCoordinateCloseToTurn( + from_node, via_eid, traversed_in_reverse, to_node) + : coordinate_extractor.GetCoordinateAlongRoad( + from_node, via_eid, traversed_in_reverse, to_node, intersection_lanes); + }; + for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(turn_node)) { BOOST_ASSERT(onto_edge != SPECIAL_EDGEID); @@ -105,8 +123,7 @@ Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node, // The first coordinate (the origin) can depend on the number of lanes turning onto, // just as the target coordinate can. Here we compute the corrected coordinate for the // incoming edge. - const auto first_coordinate = coordinate_extractor.GetCoordinateAlongRoad( - from_node, via_eid, INVERT, turn_node, intersection_lanes); + const auto first_coordinate = extract_coordinate(from_node, via_eid, INVERT, turn_node); if (from_node == to_node) { @@ -139,8 +156,8 @@ Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node, { // the default distance we lookahead on a road. This distance prevents small mapping // errors to impact the turn angles. - const auto third_coordinate = coordinate_extractor.GetCoordinateAlongRoad( - turn_node, onto_edge, !INVERT, to_node, intersection_lanes); + const auto third_coordinate = + extract_coordinate(turn_node, onto_edge, !INVERT, to_node); angle = util::coordinate_calculation::computeAngle( first_coordinate, turn_coordinate, third_coordinate); @@ -164,12 +181,7 @@ Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node, // will never happen we add an artificial invalid uturn in this case. if (!has_uturn_edge) { - const auto first_coordinate = coordinate_extractor.GetCoordinateAlongRoad( - from_node, - via_eid, - INVERT, - turn_node, - node_based_graph.GetEdgeData(via_eid).road_classification.GetNumberOfLanes()); + const auto first_coordinate = extract_coordinate(from_node, via_eid, INVERT, turn_node); const double bearing = util::coordinate_calculation::bearing(turn_coordinate, first_coordinate); diff --git a/src/extractor/guidance/turn_discovery.cpp b/src/extractor/guidance/turn_discovery.cpp index 2da37e5fc..275a1a8d6 100644 --- a/src/extractor/guidance/turn_discovery.cpp +++ b/src/extractor/guidance/turn_discovery.cpp @@ -12,6 +12,11 @@ namespace guidance namespace lanes { +namespace +{ +const constexpr bool USE_LOW_PRECISION_MODE = true; +} + bool findPreviousIntersection(const NodeID node_v, const EdgeID via_edge, const Intersection intersection, @@ -50,7 +55,8 @@ bool findPreviousIntersection(const NodeID node_v, // (looking at the reverse direction). const auto node_w = node_based_graph.GetTarget(via_edge); const auto u_turn_at_node_w = intersection[0].eid; - const auto node_v_reverse_intersection = intersection_generator(node_w, u_turn_at_node_w); + const auto node_v_reverse_intersection = + intersection_generator.GetConnectedRoads(node_w, u_turn_at_node_w, USE_LOW_PRECISION_MODE); // Continue along the straightmost turn. If there is no straight turn, we cannot find a valid // previous intersection. @@ -64,8 +70,8 @@ bool findPreviousIntersection(const NodeID node_v, return false; const auto node_u = node_based_graph.GetTarget(straightmost_at_v_in_reverse->eid); - const auto node_u_reverse_intersection = - intersection_generator(node_v, straightmost_at_v_in_reverse->eid); + const auto node_u_reverse_intersection = intersection_generator.GetConnectedRoads( + node_v, straightmost_at_v_in_reverse->eid, USE_LOW_PRECISION_MODE); // now check that the u-turn at the given intersection connects to via-edge // The u-turn at the now found intersection should, hopefully, represent the previous edge.