diff --git a/features/guidance/roundabout.feature b/features/guidance/roundabout.feature index e507945f9..079e844bb 100644 --- a/features/guidance/roundabout.feature +++ b/features/guidance/roundabout.feature @@ -222,6 +222,43 @@ Feature: Basic Roundabout | j,f | jkl,def,def | depart,roundabout-exit-2,arrive | | j,c | jkl,abc,abc | depart,roundabout-exit-3,arrive | + Scenario: Mixed Entry and Exit - clockwise order + Given the node map + """ + c a + j b f + k e + l h d + g i + """ + + And the ways + | nodes | junction | oneway | + | abc | | yes | + | def | | yes | + | ghi | | yes | + | jkl | | yes | + | behkb | roundabout | yes | + + When I route I should get + | waypoints | route | turns | + | a,c | abc,abc,abc | depart,roundabout-exit-4,arrive | + | a,l | abc,jkl,jkl | depart,roundabout-exit-3,arrive | + | a,i | abc,ghi,ghi | depart,roundabout-exit-2,arrive | + | a,f | abc,def,def | depart,roundabout-exit-1,arrive | + | d,f | def,def,def | depart,roundabout-exit-4,arrive | + | d,c | def,abc,abc | depart,roundabout-exit-3,arrive | + | d,l | def,jkl,jkl | depart,roundabout-exit-2,arrive | + | d,i | def,ghi,ghi | depart,roundabout-exit-1,arrive | + | g,i | ghi,ghi,ghi | depart,roundabout-exit-4,arrive | + | g,f | ghi,def,def | depart,roundabout-exit-3,arrive | + | g,c | ghi,abc,abc | depart,roundabout-exit-2,arrive | + | g,l | ghi,jkl,jkl | depart,roundabout-exit-1,arrive | + | j,l | jkl,jkl,jkl | depart,roundabout-exit-4,arrive | + | j,i | jkl,ghi,ghi | depart,roundabout-exit-3,arrive | + | j,f | jkl,def,def | depart,roundabout-exit-2,arrive | + | j,c | jkl,abc,abc | depart,roundabout-exit-1,arrive | + Scenario: Mixed Entry and Exit - segregated roads, different names Given the node map """ @@ -707,3 +744,27 @@ Feature: Basic Roundabout When I route I should get | waypoints | route | turns | | a,h | ab,ef,ef,fh,fh | depart,roundabout-exit-4,notification slight right,notification straight,arrive | + + + Scenario: Drive through roundabout + Given the node map + """ + a + b e d f + c + g h + """ + + And the ways + | nodes | junction | oneway | + | abcda | roundabout | yes | + | edf | | | + | gch | | yes | + + When I route I should get + | waypoints | bearings | route | turns | + | e,f | 90 90 | edf,edf,edf | depart,roundabout-exit-1,arrive | + | e,h | 90 135 | edf,gch,gch | depart,roundabout-exit-2,arrive | + | g,f | 45 90 | gch,edf,edf | depart,roundabout-exit-2,arrive | + | g,h | 45 135 | gch,gch,gch | depart,roundabout-exit-1,arrive | + | e,e | 90 270 | edf,edf,edf | depart,roundabout-exit-3,arrive | diff --git a/src/extractor/guidance/roundabout_handler.cpp b/src/extractor/guidance/roundabout_handler.cpp index 6bc590271..167ced0e0 100644 --- a/src/extractor/guidance/roundabout_handler.cpp +++ b/src/extractor/guidance/roundabout_handler.cpp @@ -111,32 +111,57 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, if (in_edge_data.roundabout || in_edge_data.circular) return; - bool past_roundabout_angle = false; - const bool lhs = profile_properties.left_hand_driving; - const int step = lhs ? -1 : 1; - for (std::size_t cnt = 0, idx = lhs ? intersection.size() - 1 : 0; cnt < intersection.size(); - ++cnt, idx += step) + std::cout << "invalidateExitAgainstDirection\n"; + + // Find range in which exits that must be invalidated (shaded areas): + // exit..end exit..end begin..exit for ↺ roundabouts + // ⭦ ⭦ ⭩ ⭦ + // ⭡⭧ ⭡⭩ ▒ ▒⭨⭡ + // ⭡⭦ ⭡⭨▒▒ ▒▒⭡⭨ + // ⭧▒▒⭦ ⭧▒▒▒▒ ▒▒⭧ + // + // begin..exit begin..exit exit..end for ↻ roundabouts + // ⭨▒▒▒ ⭨▒▒ ⭩ ▒▒⭨ + // ⭣⭧▒ ⭣⭩ ▒▒⭣⭧ + // ⭣⭦▒ ⭣⭨ ▒⭧⭣ + // ⭩ ⭦ ⭩ ⭩ + bool roundabout_entry_first = false; + auto invalidate_from = intersection.end(), invalidate_to = intersection.end(); + for (auto road = intersection.begin(); road != intersection.end(); ++road) { - auto &road = intersection[idx]; - const auto &edge_data = node_based_graph.GetEdgeData(road.eid); - // only check actual outgoing edges - if (edge_data.reversed) + const auto &edge_data = node_based_graph.GetEdgeData(road->eid); + if (edge_data.roundabout || edge_data.circular) { - // remember whether we have seen the roundabout in-part - if (edge_data.roundabout || edge_data.circular) - past_roundabout_angle = true; - - continue; + if (edge_data.reversed) + { + if (roundabout_entry_first) + { // invalidate turns in range exit..end + invalidate_from = road + 1; + invalidate_to = intersection.end(); + } + else + { // invalidate turns in range begin..exit + invalidate_from = intersection.begin() + 1; + invalidate_to = road; + } + } + else + { + roundabout_entry_first = true; + } } + } - // Exiting roundabouts at an entry point is technically a data-modelling issue. - // This workaround handles cases in which an exit precedes and entry. The resulting - // u-turn against the roundabout direction is invalidated. - // The sorting of the angles represents a problem for left-sided driving, though. + // Exiting roundabouts at an entry point is technically a data-modelling issue. + // This workaround handles cases in which an exit precedes and entry. The resulting + // u-turn against the roundabout direction is invalidated. + for (; invalidate_from != invalidate_to; ++invalidate_from) + { + const auto &edge_data = node_based_graph.GetEdgeData(invalidate_from->eid); if (!edge_data.roundabout && !edge_data.circular && - node_based_graph.GetTarget(road.eid) != from_nid && past_roundabout_angle) + node_based_graph.GetTarget(invalidate_from->eid) != from_nid) { - road.entry_allowed = false; + invalidate_from->entry_allowed = false; } } }