Merge pull request #3324 from Project-OSRM/constrain-staggering

Constrain staggered intersection detection by mode change and intermediary intersections
This commit is contained in:
Karen Shea
2016-11-30 07:35:17 -05:00
committed by GitHub
3 changed files with 218 additions and 17 deletions
+34 -17
View File
@@ -1,6 +1,6 @@
#include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/post_processing.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/guidance/assemble_steps.hpp"
@@ -443,7 +443,7 @@ std::size_t getPreviousIndex(std::size_t index, const std::vector<RouteStep> &st
--index;
return index;
};
}
void collapseUTurn(std::vector<RouteStep> &steps,
const std::size_t two_back_index,
@@ -528,32 +528,31 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
// check if the actual turn we wan't to announce is delayed. This situation describes a turn
// that is expressed by two turns,
const auto isDelayedTurn = [](const RouteStep &openining_turn,
const RouteStep &finishing_turn) {
const auto isDelayedTurn = [](const RouteStep &opening_turn, const RouteStep &finishing_turn) {
// only possible if both are compatible
if (!compatible(openining_turn, finishing_turn))
if (!compatible(opening_turn, finishing_turn))
return false;
else
{
const auto is_short_and_collapsable =
openining_turn.distance <= MAX_COLLAPSE_DISTANCE &&
opening_turn.distance <= MAX_COLLAPSE_DISTANCE &&
isCollapsableInstruction(finishing_turn.maneuver.instruction);
const auto without_choice = choiceless(finishing_turn, openining_turn);
const auto without_choice = choiceless(finishing_turn, opening_turn);
const auto is_not_too_long_and_choiceless =
openining_turn.distance <= 2 * MAX_COLLAPSE_DISTANCE && without_choice;
opening_turn.distance <= 2 * MAX_COLLAPSE_DISTANCE && without_choice;
// for ramps we allow longer stretches, since they are often on some major brides/large
// roads. A combined distance of of 4 intersections would be to long for a normal
// collapse. In case of a ramp though, we also account for situations that have the ramp
// tagged late
const auto is_delayed_turn_onto_a_ramp =
openining_turn.distance <= 4 * MAX_COLLAPSE_DISTANCE && without_choice &&
opening_turn.distance <= 4 * MAX_COLLAPSE_DISTANCE && without_choice &&
util::guidance::hasRampType(finishing_turn.maneuver.instruction);
return !util::guidance::hasRampType(openining_turn.maneuver.instruction) &&
return !util::guidance::hasRampType(opening_turn.maneuver.instruction) &&
(is_short_and_collapsable || is_not_too_long_and_choiceless ||
isLinkroad(openining_turn) || is_delayed_turn_onto_a_ramp);
isLinkroad(opening_turn) || is_delayed_turn_onto_a_ramp);
}
};
@@ -816,13 +815,17 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
// | or | becomes a -> b
// a -> * * -> b
//
bool isStaggeredIntersection(const RouteStep &previous, const RouteStep &current)
bool isStaggeredIntersection(const std::vector<RouteStep> &steps,
const std::size_t &current_index,
const std::size_t &previous_index)
{
const RouteStep previous = steps[previous_index];
const RouteStep current = steps[current_index];
// don't touch roundabouts
if (entersRoundabout(previous.maneuver.instruction) ||
entersRoundabout(current.maneuver.instruction))
return false;
// Base decision on distance since the zig-zag is a visual clue.
// If adjusted, make sure to check validity of the is_right/is_left classification below
const constexpr auto MAX_STAGGERED_DISTANCE = 3; // debatable, but keep short to be on safe side
@@ -853,7 +856,21 @@ bool isStaggeredIntersection(const RouteStep &previous, const RouteStep &current
// We are only interested in the distance between the first and the second.
const auto is_short = previous.distance < MAX_STAGGERED_DISTANCE;
return is_short && (left_right || right_left);
auto intermediary_mode_change = false;
if (current_index > 1)
{
const auto &two_back_index = getPreviousIndex(previous_index, steps);
const auto two_back_step = steps[two_back_index];
intermediary_mode_change =
two_back_step.mode == current.mode && previous.mode != current.mode;
}
// previous step maneuver intersections should be length 1 to indicate that
// there are no intersections between the two potentially collapsible turns
const auto no_intermediary_intersections = previous.intersections.size() == 1;
return is_short && (left_right || right_left) && !intermediary_mode_change &&
no_intermediary_intersections;
}
} // namespace
@@ -1162,13 +1179,13 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
invalidateStep(steps[index]);
}
}
// If we look at two consecutive name changes, we can check for a name oszillation.
// A name oszillation changes from name A shortly to name B and back to A.
// If we look at two consecutive name changes, we can check for a name oscillation.
// A name oscillation changes from name A shortly to name B and back to A.
// In these cases, the name change will be suppressed.
else if (one_back_index > 0 && compatible(current_step, one_back_step) &&
((isCollapsableInstruction(current_step.maneuver.instruction) &&
isCollapsableInstruction(one_back_step.maneuver.instruction)) ||
isStaggeredIntersection(one_back_step, current_step)))
isStaggeredIntersection(steps, step_index, one_back_index)))
{
const auto two_back_index = getPreviousIndex(one_back_index, steps);
BOOST_ASSERT(two_back_index < steps.size());