diff --git a/features/guidance/driveway.feature b/features/guidance/driveway.feature new file mode 100644 index 000000000..c7e7504eb --- /dev/null +++ b/features/guidance/driveway.feature @@ -0,0 +1,48 @@ +@driveway @guidance +Feature: Driveways intersections + + Background: + Given the profile "car" + Given a grid size of 5 meters + + Scenario: Road with a turn to service road + Given the node map + """ + a + ~. + b----c----d + | + e + """ + + And the ways + | nodes | highway | name | oneway | + | abc | trunk | first | yes | + | cd | trunk | second | yes | + | be | service | parking | yes | + + When I route I should get + | waypoints | route | turns | locations | + | a,d | first,second | depart,arrive | a,d | + + + Scenario: Turn Instead of Ramp + Given the node map + """ + a + ~. + b----c----d + | + e + """ + + And the ways + | nodes | highway | name | oneway | + | ab | trunk | | yes | + | bc | trunk | | yes | + | cd | trunk | second | yes | + | be | service | parking | yes | + + When I route I should get + | waypoints | route | turns | locations | + | a,d | ,second | depart,arrive | a,d | diff --git a/include/extractor/guidance/driveway_handler.hpp b/include/extractor/guidance/driveway_handler.hpp new file mode 100644 index 000000000..78e4f40ee --- /dev/null +++ b/include/extractor/guidance/driveway_handler.hpp @@ -0,0 +1,41 @@ +#ifndef OSRM_EXTRACTOR_GUIDANCE_DRIVEWAY_HANDLER_HPP +#define OSRM_EXTRACTOR_GUIDANCE_DRIVEWAY_HANDLER_HPP + +#include "extractor/guidance/intersection_handler.hpp" + +namespace osrm +{ +namespace extractor +{ +namespace guidance +{ + +// Intersection handlers deal with all issues related to intersections. +// They assign appropriate turn operations to the TurnOperations. +class DrivewayHandler final : public IntersectionHandler +{ + public: + DrivewayHandler(const IntersectionGenerator &intersection_generator, + const util::NodeBasedDynamicGraph &node_based_graph, + const std::vector &coordinates, + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table); + + ~DrivewayHandler() override final = default; + + // check whether the handler can actually handle the intersection + bool canProcess(const NodeID nid, + const EdgeID via_eid, + const Intersection &intersection) const override final; + + // process the intersection + Intersection operator()(const NodeID nid, + const EdgeID via_eid, + Intersection intersection) const override final; +}; + +} // namespace guidance +} // namespace extractor +} // namespace osrm + +#endif /* OSRM_EXTRACTOR_GUIDANCE_DRIVEWAY_HANDLER_HPP */ diff --git a/include/extractor/guidance/intersection_handler.hpp b/include/extractor/guidance/intersection_handler.hpp index fe54c1f5d..e9fb96724 100644 --- a/include/extractor/guidance/intersection_handler.hpp +++ b/include/extractor/guidance/intersection_handler.hpp @@ -114,6 +114,8 @@ class IntersectionHandler // For this scenario returns intersection at `b` and `b`. boost::optional getNextIntersection(const NodeID at, const EdgeID via) const; + + bool isSameName(const EdgeID source_edge_id, const EdgeID target_edge_id) const; }; // Impl. diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp index 96a54e1a4..e1cd80416 100644 --- a/include/extractor/guidance/turn_analysis.hpp +++ b/include/extractor/guidance/turn_analysis.hpp @@ -2,6 +2,7 @@ #define OSRM_EXTRACTOR_TURN_ANALYSIS #include "extractor/compressed_edge_container.hpp" +#include "extractor/guidance/driveway_handler.hpp" #include "extractor/guidance/intersection.hpp" #include "extractor/guidance/intersection_generator.hpp" #include "extractor/guidance/intersection_normalization_operation.hpp" @@ -87,6 +88,7 @@ class TurnAnalysis const TurnHandler turn_handler; const SliproadHandler sliproad_handler; const SuppressModeHandler suppress_mode_handler; + const DrivewayHandler driveway_handler; // Utility function, setting basic turn types. Prepares for normal turn handling. Intersection diff --git a/src/extractor/guidance/driveway_handler.cpp b/src/extractor/guidance/driveway_handler.cpp new file mode 100644 index 000000000..e81257372 --- /dev/null +++ b/src/extractor/guidance/driveway_handler.cpp @@ -0,0 +1,75 @@ +#include "extractor/guidance/driveway_handler.hpp" + +#include "util/assert.hpp" + +using osrm::extractor::guidance::getTurnDirection; +using osrm::util::angularDeviation; + +namespace osrm +{ +namespace extractor +{ +namespace guidance +{ + +DrivewayHandler::DrivewayHandler(const IntersectionGenerator &intersection_generator, + const util::NodeBasedDynamicGraph &node_based_graph, + const std::vector &coordinates, + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table) + : IntersectionHandler(node_based_graph, + coordinates, + name_table, + street_name_suffix_table, + intersection_generator) +{ +} + +// The intersection without major roads needs to pass by service roads (bd, be) +// d +// . +// a--->b--->c +// . +// e +bool DrivewayHandler::canProcess(const NodeID /*nid*/, + const EdgeID /*via_eid*/, + const Intersection &intersection) const +{ + const auto from_eid = intersection.front().eid; + + if (intersection.size() <= 2 || + node_based_graph.GetEdgeData(from_eid).road_classification.IsLowPriorityRoadClass()) + return false; + + auto low_priority_count = + std::count_if(intersection.begin(), intersection.end(), [this](const auto &road) { + return node_based_graph.GetEdgeData(road.eid) + .road_classification.IsLowPriorityRoadClass(); + }); + + // Process intersection if it has two edges with normal priority and one is the entry edge, + // and also has at least one edge with lower priority + return static_cast(low_priority_count) + 2 == intersection.size(); +} + +Intersection DrivewayHandler:: +operator()(const NodeID nid, const EdgeID source_edge_id, Intersection intersection) const +{ + auto road = + std::find_if(intersection.begin() + 1, intersection.end(), [this](const auto &road) { + return !node_based_graph.GetEdgeData(road.eid) + .road_classification.IsLowPriorityRoadClass(); + }); + + (void)nid; + OSRM_ASSERT(road != intersection.end(), coordinates[nid]); + + road->instruction.type = + isSameName(source_edge_id, road->eid) ? TurnType::NoTurn : TurnType::NewName; + + return intersection; +} + +} // namespace guidance +} // namespace extractor +} // namespace osrm diff --git a/src/extractor/guidance/intersection_handler.cpp b/src/extractor/guidance/intersection_handler.cpp index f345d14ae..129b65769 100644 --- a/src/extractor/guidance/intersection_handler.cpp +++ b/src/extractor/guidance/intersection_handler.cpp @@ -436,6 +436,19 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons IntersectionViewAndNode{std::move(intersection), intersection_node}); } +bool IntersectionHandler::isSameName(const EdgeID source_edge_id, const EdgeID target_edge_id) const +{ + const auto &source_edge_data = node_based_graph.GetEdgeData(source_edge_id); + const auto &target_edge_data = node_based_graph.GetEdgeData(target_edge_id); + + return source_edge_data.name_id != EMPTY_NAMEID && // + target_edge_data.name_id != EMPTY_NAMEID && // + !util::guidance::requiresNameAnnounced(source_edge_data.name_id, + target_edge_data.name_id, + name_table, + street_name_suffix_table); // +} + } // namespace guidance } // namespace extractor } // namespace osrm diff --git a/src/extractor/guidance/sliproad_handler.cpp b/src/extractor/guidance/sliproad_handler.cpp index ad5c6076a..7188ee6f6 100644 --- a/src/extractor/guidance/sliproad_handler.cpp +++ b/src/extractor/guidance/sliproad_handler.cpp @@ -473,17 +473,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter // In those cases the obvious non-Sliproad is now obvious and we discard the Fork turn type. if (sliproad_found && main_road.instruction.type == TurnType::Fork) { - const auto &source_edge_data = node_based_graph.GetEdgeData(source_edge_id); - const auto &main_road_data = node_based_graph.GetEdgeData(main_road.eid); - - const auto same_name = source_edge_data.name_id != EMPTY_NAMEID && // - main_road_data.name_id != EMPTY_NAMEID && // - !util::guidance::requiresNameAnnounced(source_edge_data.name_id, - main_road_data.name_id, - name_table, - street_name_suffix_table); // - - if (same_name) + if (isSameName(source_edge_id, main_road.eid)) { if (angularDeviation(main_road.angle, STRAIGHT_ANGLE) < 5) intersection[*obvious].instruction.type = TurnType::Suppressed; @@ -492,7 +482,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter intersection[*obvious].instruction.direction_modifier = getTurnDirection(intersection[*obvious].angle); } - else if (main_road_data.name_id != EMPTY_NAMEID) + else if (node_based_graph.GetEdgeData(main_road.eid).name_id != EMPTY_NAMEID) { intersection[*obvious].instruction.type = TurnType::NewName; intersection[*obvious].instruction.direction_modifier = diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp index 937a40cf3..d74f3b92f 100644 --- a/src/extractor/guidance/turn_analysis.cpp +++ b/src/extractor/guidance/turn_analysis.cpp @@ -68,7 +68,12 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_based_graph, coordinates, name_table, - street_name_suffix_table) + street_name_suffix_table), + driveway_handler(intersection_generator, + node_based_graph, + coordinates, + name_table, + street_name_suffix_table) { } @@ -132,8 +137,14 @@ Intersection TurnAnalysis::AssignTurnTypes(const NodeID node_prior_to_intersecti // set initial defaults for normal turns and modifier based on angle intersection = setTurnTypes(node_prior_to_intersection, entering_via_edge, std::move(intersection)); - if (motorway_handler.canProcess( + if (driveway_handler.canProcess( node_prior_to_intersection, entering_via_edge, intersection)) + { + intersection = driveway_handler( + node_prior_to_intersection, entering_via_edge, std::move(intersection)); + } + else if (motorway_handler.canProcess( + node_prior_to_intersection, entering_via_edge, intersection)) { intersection = motorway_handler( node_prior_to_intersection, entering_via_edge, std::move(intersection));