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:
Duane Gearhart
2018-03-30 07:43:56 -04:00
committed by GitHub
parent 0d9f18fe1f
commit 8a63ad9b4b
11 changed files with 449 additions and 121 deletions
@@ -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)
+187
View File
@@ -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