diff --git a/features/guidance/anticipate-lanes.feature b/features/guidance/anticipate-lanes.feature index 02045de5e..cf0a9a16f 100644 --- a/features/guidance/anticipate-lanes.feature +++ b/features/guidance/anticipate-lanes.feature @@ -783,3 +783,38 @@ Feature: Turn Lane Guidance | waypoints | route | turns | lanes | | a,f | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,turn right,arrive | ,left:false left:true none:false none:false,left:false left:true none:false none:false,left:false left:true none:false none:false,left:false left:false right:true, | | a,g | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,turn left,arrive | ,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true right:false, | + + @anticipate + Scenario: Complex lane scenarios scale threshold for triggering Lane Anticipation + Given the node map + """ + a – b – x + | + | + | + | + | + | + | + | + | + | + c + | + e – d – y + """ + # With a grid size of 20m the duration is ~20s but our default threshold for Lane Anticipation is 15s. + # The additional lanes left and right of the turn scale the threshold up so that Lane Anticipation still triggers. + + And the ways + | nodes | turn:lanes:forward | name | + | ab | through\|through\|right\|right | MySt | + | bx | | XSt | + | bc | | MySt | + | cd | left\|right | MySt | + | de | | MySt | + | dy | | YSt | + + When I route I should get + | waypoints | route | turns | lanes | + | a,e | MySt,MySt,MySt,MySt | depart,continue right,turn right,arrive | ,straight:false straight:false right:false right:true,left:false right:true, | diff --git a/src/engine/guidance/lane_processing.cpp b/src/engine/guidance/lane_processing.cpp index 88b2ef3fb..a7b49bf5b 100644 --- a/src/engine/guidance/lane_processing.cpp +++ b/src/engine/guidance/lane_processing.cpp @@ -4,6 +4,7 @@ #include "extractor/guidance/turn_instruction.hpp" #include "engine/guidance/post_processing.hpp" +#include #include #include #include @@ -27,9 +28,26 @@ std::vector anticipateLaneChange(std::vector steps, { // Lane anticipation works on contiguous ranges of quick steps that have lane information const auto is_quick_has_lanes = [&](const RouteStep &step) { - const auto is_quick = step.duration < min_duration_needed_for_lane_change; const auto has_lanes = step.intersections.front().lanes.lanes_in_turn > 0; - return has_lanes && is_quick; + + if (!has_lanes) + return false; + + // The more unused lanes to the left and right of the turn there are, the higher + // the chance the user is driving on one of those and has to cross lanes. + // Scale threshold for these cases to be adaptive to the situation's complexity. + // + // Note: what we could do instead: do Lane Anticipation on all step pairs and then scale + // the threshold based on the lanes we're constraining the user to. Would need a re-write + // since at the moment we first group-by and only then do Lane Anticipation selectively. + // + // We do not have a source-target lane mapping, assume worst case for lanes to cross. + const auto to_cross = std::max(step.NumLanesToTheRight(), step.NumLanesToTheLeft()); + const auto scale = 1 + to_cross; + const auto threshold = scale * min_duration_needed_for_lane_change; + + const auto is_quick = step.duration < threshold; + return is_quick; }; using StepIter = decltype(steps)::iterator;