Added post process logic to collapse segregated turn instructions (#4925)
* Added post process logic to collapse segregated turn instructions * format updates * Fixed coordinates to reflect reality Updated left turn road name * fixed coordinates to fix test * Skip last step when processing segregated steps * updated segregated turn test * Updated segregated test * Updated test: Segregated Intersection, Cross Belonging to Correct Street - features/guidance/collapse.feature:79 * Fixed all but one for features/guidance/collapse.feature:124 * Fixed Scenario: Partly Segregated Intersection, Two Segregated Roads, Intersection belongs to Second - features/guidance/collapse.feature:219 * Fixed 7 of th 9 failures for Scenario: Partly Segregated Intersection, Two Segregated Roads, Intersection belongs to Second - features/guidance/collapse.feature:219 * Fixed 7 of the 9 failures for Scenario: Segregated Intersection, Cross Belonging to Mixed Streets - Slight Angles (2) - features/guidance/collapse.feature:318 * Fixed Scenario: Segregated Intersection into Slight Turn - features/guidance/collapse.feature:581 * Updated Scenario: U-turn after a traffic light - features/guidance/turn-lanes.feature:1220 * Updated how we combine segregated steps * Added test to Verify end of road left turn across divided roads * Fixed divided highwat tests * Fixed test failure * fixed Scenario: Partitioned turn, Slight Curve - maxspeed - features/guidance/turn-lanes.feature:936 * Fixed Scenario: Partitioned turn, Slight Curve - features/guidance/turn-lanes.feature:961 * Added strategies to combine segrgated intersections * Added setModifier alias for readability * Added strategies to combine segrgated intersections * Format updates * Fixes segregated indentification to not mark `circular` edge as segregated * Added intersection prior to turn so we still call out end of road * updated expectation to be turn instead of continue * Confirmed with @oxidase that the lane information if correct - updated the expectation * Added logic to handle wider straights Fixed tests * Update CHANGELOG.md Added #4925 * Removed TODO * Process straight step prior to wider straight step
This commit is contained in:
@@ -17,21 +17,6 @@ using namespace osrm::guidance;
|
||||
namespace
|
||||
{
|
||||
|
||||
// check bearings for u-turns.
|
||||
// since bearings are wrapped around at 0 (we only support 0,360), we need to do some minor math to
|
||||
// check if bearings `a` and `b` go in opposite directions. In general we accept some minor
|
||||
// deviations for u-turns.
|
||||
bool bearingsAreReversed(const double bearing_in, const double bearing_out)
|
||||
{
|
||||
// Nearly perfectly reversed angles have a difference close to 180 degrees (straight)
|
||||
const double left_turn_angle = [&]() {
|
||||
if (0 <= bearing_out && bearing_out <= bearing_in)
|
||||
return bearing_in - bearing_out;
|
||||
return bearing_in + 360 - bearing_out;
|
||||
}();
|
||||
return util::angularDeviation(left_turn_angle, 180) <= 35;
|
||||
}
|
||||
|
||||
// to collapse steps, we focus on short segments that don't interact with other roads. To collapse
|
||||
// two instructions into one, we need to look at to instrutions immediately after each other.
|
||||
bool noIntermediaryIntersections(const RouteStep &step)
|
||||
|
||||
@@ -221,12 +221,16 @@ void AdjustToCombinedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
if (hasTurnType(step_at_turn_location, TurnType::Suppressed))
|
||||
{
|
||||
if (new_modifier == DirectionModifier::Straight)
|
||||
{
|
||||
setInstructionType(step_at_turn_location, TurnType::NewName);
|
||||
}
|
||||
else
|
||||
{
|
||||
step_at_turn_location.maneuver.instruction.type =
|
||||
haveSameName(step_prior_to_intersection, transfer_from_step)
|
||||
? TurnType::Continue
|
||||
: TurnType::Turn;
|
||||
}
|
||||
}
|
||||
else if (hasTurnType(step_at_turn_location, TurnType::NewName) &&
|
||||
hasTurnType(transfer_from_step, TurnType::Suppressed) &&
|
||||
@@ -285,6 +289,110 @@ void StaggeredTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
: TurnType::NewName;
|
||||
}
|
||||
|
||||
void CombineSegregatedStepsStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
const RouteStep &transfer_from_step) const
|
||||
{
|
||||
// Handle end of road
|
||||
if (hasTurnType(step_at_turn_location, TurnType::EndOfRoad) ||
|
||||
hasTurnType(transfer_from_step, TurnType::EndOfRoad))
|
||||
{
|
||||
setInstructionType(step_at_turn_location, TurnType::EndOfRoad);
|
||||
}
|
||||
}
|
||||
|
||||
SegregatedTurnStrategy::SegregatedTurnStrategy(const RouteStep &step_prior_to_intersection)
|
||||
: step_prior_to_intersection(step_prior_to_intersection)
|
||||
{
|
||||
}
|
||||
|
||||
void SegregatedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
const RouteStep &transfer_from_step) const
|
||||
{
|
||||
// Used to control updating of the modifier based on turn direction
|
||||
bool update_modifier_for_turn_direction = true;
|
||||
|
||||
const auto calculate_turn_angle = [](const RouteStep &entry_step, const RouteStep &exit_step) {
|
||||
return util::bearing::angleBetween(entry_step.maneuver.bearing_before,
|
||||
exit_step.maneuver.bearing_after);
|
||||
};
|
||||
|
||||
// Calculate turn angle and direction for segregated
|
||||
const auto turn_angle = calculate_turn_angle(step_at_turn_location, transfer_from_step);
|
||||
const auto turn_direction = getTurnDirection(turn_angle);
|
||||
|
||||
const auto is_straight_step = [](const RouteStep &step) {
|
||||
return ((hasTurnType(step, TurnType::NewName) || hasTurnType(step, TurnType::Continue) ||
|
||||
hasTurnType(step, TurnType::Suppressed) || hasTurnType(step, TurnType::Turn)) &&
|
||||
(hasModifier(step, DirectionModifier::Straight) ||
|
||||
hasModifier(step, DirectionModifier::SlightLeft) ||
|
||||
hasModifier(step, DirectionModifier::SlightRight)));
|
||||
};
|
||||
|
||||
const auto is_turn_step = [](const RouteStep &step) {
|
||||
return (hasTurnType(step, TurnType::Turn) || hasTurnType(step, TurnType::Continue) ||
|
||||
hasTurnType(step, TurnType::NewName) || hasTurnType(step, TurnType::Suppressed));
|
||||
};
|
||||
|
||||
// Process end of road step
|
||||
if (hasTurnType(step_at_turn_location, TurnType::EndOfRoad) ||
|
||||
hasTurnType(transfer_from_step, TurnType::EndOfRoad))
|
||||
{
|
||||
// Keep end of road
|
||||
setInstructionType(step_at_turn_location, TurnType::EndOfRoad);
|
||||
}
|
||||
// Process fork step at turn
|
||||
else if (hasTurnType(step_at_turn_location, TurnType::Fork))
|
||||
{
|
||||
// Do not update modifier based on turn direction
|
||||
update_modifier_for_turn_direction = false;
|
||||
}
|
||||
// Process straight step
|
||||
else if ((turn_direction == guidance::DirectionModifier::Straight) &&
|
||||
is_straight_step(transfer_from_step))
|
||||
{
|
||||
// Determine if continue or new name
|
||||
setInstructionType(step_at_turn_location,
|
||||
(haveSameName(step_prior_to_intersection, transfer_from_step)
|
||||
? TurnType::Suppressed
|
||||
: TurnType::NewName));
|
||||
}
|
||||
// Process wider straight step
|
||||
else if (isWiderStraight(turn_angle) && hasSingleIntersection(step_at_turn_location) &&
|
||||
hasStraightestTurn(step_at_turn_location) && hasStraightestTurn(transfer_from_step))
|
||||
{
|
||||
// Determine if continue or new name
|
||||
setInstructionType(step_at_turn_location,
|
||||
(haveSameName(step_prior_to_intersection, transfer_from_step)
|
||||
? TurnType::Suppressed
|
||||
: TurnType::NewName));
|
||||
|
||||
// Set modifier to straight
|
||||
setModifier(step_at_turn_location, osrm::guidance::DirectionModifier::Straight);
|
||||
|
||||
// Do not update modifier based on turn direction
|
||||
update_modifier_for_turn_direction = false;
|
||||
}
|
||||
// Process turn step
|
||||
else if ((turn_direction != guidance::DirectionModifier::Straight) &&
|
||||
is_turn_step(transfer_from_step))
|
||||
{
|
||||
// Mark as turn
|
||||
setInstructionType(step_at_turn_location, TurnType::Turn);
|
||||
}
|
||||
// Process the others not covered above by using the transfer step turn type
|
||||
else
|
||||
{
|
||||
// Set type from transfer step
|
||||
setInstructionType(step_at_turn_location, transfer_from_step.maneuver.instruction.type);
|
||||
}
|
||||
|
||||
// Update modifier based on turn direction, if needed
|
||||
if (update_modifier_for_turn_direction)
|
||||
{
|
||||
setModifier(step_at_turn_location, turn_direction);
|
||||
}
|
||||
}
|
||||
|
||||
SetFixedInstructionStrategy::SetFixedInstructionStrategy(const TurnInstruction instruction)
|
||||
: instruction(instruction)
|
||||
{
|
||||
@@ -478,6 +586,85 @@ RouteSteps collapseTurnInstructions(RouteSteps steps)
|
||||
return steps;
|
||||
}
|
||||
|
||||
// OTHER IMPLEMENTATIONS
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
RouteSteps collapseSegregatedTurnInstructions(RouteSteps steps)
|
||||
{
|
||||
// make sure we can safely iterate over all steps (has depart/arrive with TurnType::NoTurn)
|
||||
BOOST_ASSERT(!hasTurnType(steps.front()) && !hasTurnType(steps.back()));
|
||||
BOOST_ASSERT(hasWaypointType(steps.front()) && hasWaypointType(steps.back()));
|
||||
|
||||
if (steps.size() <= 2)
|
||||
return steps;
|
||||
|
||||
auto curr_step = steps.begin() + 1;
|
||||
auto next_step = curr_step + 1;
|
||||
const auto last_step = steps.end() - 1;
|
||||
|
||||
// Loop over steps to collapse the segregated intersections; ignore first and last step
|
||||
while (next_step != last_step)
|
||||
{
|
||||
const auto prev_step = findPreviousTurn(curr_step);
|
||||
|
||||
// if current step and next step are both segregated then combine the steps with no turn
|
||||
// adjustment
|
||||
if (curr_step->is_segregated && next_step->is_segregated)
|
||||
{
|
||||
// Combine segregated steps
|
||||
combineRouteSteps(*curr_step,
|
||||
*next_step,
|
||||
CombineSegregatedStepsStrategy(),
|
||||
TransferSignageStrategy(),
|
||||
TransferLanesStrategy());
|
||||
++next_step;
|
||||
}
|
||||
// else if the current step is segregated and the next step is not then combine with turn
|
||||
// adjustment
|
||||
else if (curr_step->is_segregated && !next_step->is_segregated)
|
||||
{
|
||||
// Determine if u-turn
|
||||
if (bearingsAreReversed(
|
||||
util::bearing::reverse(curr_step->intersections.front()
|
||||
.bearings[curr_step->intersections.front().in]),
|
||||
next_step->intersections.front()
|
||||
.bearings[next_step->intersections.front().out]))
|
||||
{
|
||||
// Collapse segregated u-turn
|
||||
combineRouteSteps(
|
||||
*curr_step,
|
||||
*next_step,
|
||||
SetFixedInstructionStrategy({TurnType::Continue, DirectionModifier::UTurn}),
|
||||
TransferSignageStrategy(),
|
||||
NoModificationStrategy());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Collapse segregated turn
|
||||
combineRouteSteps(*curr_step,
|
||||
*next_step,
|
||||
SegregatedTurnStrategy(*prev_step),
|
||||
TransferSignageStrategy(),
|
||||
NoModificationStrategy());
|
||||
}
|
||||
|
||||
// Segregated step has been removed
|
||||
curr_step->is_segregated = false;
|
||||
++next_step;
|
||||
}
|
||||
// else next step
|
||||
else
|
||||
{
|
||||
curr_step = next_step;
|
||||
++next_step;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up steps
|
||||
steps = removeNoTurnInstructions(std::move(steps));
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
Reference in New Issue
Block a user