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:
@@ -13,13 +13,19 @@ namespace engine
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Multiple possible reasons can result in unnecessary/confusing instructions
|
||||
// Collapsing such turns into a single turn instruction, we give a clearer
|
||||
// set of instructions that is not cluttered by unnecessary turns/name changes.
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<RouteStep> collapseTurnInstructions(std::vector<RouteStep> steps);
|
||||
|
||||
// Multiple possible reasons can result in unnecessary/confusing instructions
|
||||
// A prime example would be a segregated intersection. Turning around at this
|
||||
// intersection would result in two instructions to turn left.
|
||||
// Collapsing such turns into a single turn instruction, we give a clearer
|
||||
// set of instructionst that is not cluttered by unnecessary turns/name changes.
|
||||
// set of instructions that is not cluttered by unnecessary turns/name changes.
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<RouteStep> collapseTurnInstructions(std::vector<RouteStep> steps);
|
||||
std::vector<RouteStep> collapseSegregatedTurnInstructions(std::vector<RouteStep> steps);
|
||||
|
||||
// A combined turn is a set of two instructions that actually form a single turn, as far as we
|
||||
// perceive it. A u-turn consisting of two left turns is one such example. But there are also lots
|
||||
@@ -93,6 +99,22 @@ struct StaggeredTurnStrategy : CombineStrategy
|
||||
const RouteStep &step_prior_to_intersection;
|
||||
};
|
||||
|
||||
// Handling of consecutive segregated steps
|
||||
struct CombineSegregatedStepsStrategy : CombineStrategy
|
||||
{
|
||||
void operator()(RouteStep &step_at_turn_location, const RouteStep &transfer_from_step) const;
|
||||
};
|
||||
|
||||
// Handling of segregated intersections
|
||||
struct SegregatedTurnStrategy : CombineStrategy
|
||||
{
|
||||
SegregatedTurnStrategy(const RouteStep &step_prior_to_intersection);
|
||||
|
||||
void operator()(RouteStep &step_at_turn_location, const RouteStep &transfer_from_step) const;
|
||||
|
||||
const RouteStep &step_prior_to_intersection;
|
||||
};
|
||||
|
||||
// Signage Strategies
|
||||
|
||||
// Transfer the signage from the next step onto this step
|
||||
|
||||
@@ -23,6 +23,7 @@ const constexpr std::size_t MIN_END_OF_ROAD_INTERSECTIONS = std::size_t{2};
|
||||
const constexpr double MAX_COLLAPSE_DISTANCE = 30.0;
|
||||
// a bit larger than 100 to avoid oscillation in tests
|
||||
const constexpr double NAME_SEGMENT_CUTOFF_LENGTH = 105.0;
|
||||
const double constexpr STRAIGHT_ANGLE = 180.;
|
||||
|
||||
// check if a step is completely without turn type
|
||||
inline bool hasTurnType(const RouteStep &step)
|
||||
@@ -104,6 +105,12 @@ inline void setInstructionType(RouteStep &step, const osrm::guidance::TurnType::
|
||||
step.maneuver.instruction.type = type;
|
||||
}
|
||||
|
||||
// alias for readability
|
||||
inline void setModifier(RouteStep &step, const osrm::guidance::DirectionModifier::Enum modifier)
|
||||
{
|
||||
step.maneuver.instruction.direction_modifier = modifier;
|
||||
}
|
||||
|
||||
// alias for readability
|
||||
inline bool haveSameMode(const RouteStep &lhs, const RouteStep &rhs)
|
||||
{
|
||||
@@ -215,6 +222,86 @@ inline double totalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_
|
||||
return total_angle;
|
||||
}
|
||||
|
||||
// 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.
|
||||
inline 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;
|
||||
}
|
||||
|
||||
// Returns true if the specified step has only one intersection
|
||||
inline bool hasSingleIntersection(const RouteStep &step)
|
||||
{
|
||||
return (step.intersections.size() == 1);
|
||||
}
|
||||
|
||||
// Returns true if the specified angle is a wider straight turn
|
||||
inline bool isWiderStraight(const double angle) { return (angle >= 125 && angle <= 235); }
|
||||
|
||||
// Returns the straightest intersecting edge turn for the specified step
|
||||
inline double getStraightestIntersectingEdgeTurn(const RouteStep &step)
|
||||
{
|
||||
const auto &intersection = step.intersections.front();
|
||||
const double bearing_in = util::bearing::reverse(intersection.bearings[intersection.in]);
|
||||
double staightest_turn = 360.;
|
||||
double staightest_delta = 360.;
|
||||
|
||||
for (std::size_t i = 0; i < intersection.bearings.size(); ++i)
|
||||
{
|
||||
// Skip the in, out, and non-traversable edges
|
||||
if ((i == intersection.in) || (i == intersection.out) || !intersection.entry.at(i))
|
||||
continue;
|
||||
|
||||
double intersecting_turn =
|
||||
util::bearing::angleBetween(bearing_in, intersection.bearings.at(i));
|
||||
double straight_delta = util::angularDeviation(intersecting_turn, STRAIGHT_ANGLE);
|
||||
|
||||
if (straight_delta < staightest_delta)
|
||||
{
|
||||
staightest_delta = straight_delta;
|
||||
staightest_turn = intersecting_turn;
|
||||
}
|
||||
}
|
||||
return staightest_turn;
|
||||
}
|
||||
|
||||
// Returns true if the specified step has the straightest turn as compared to
|
||||
// the intersecting edges
|
||||
inline bool hasStraightestTurn(const RouteStep &step)
|
||||
{
|
||||
const auto &intersection = step.intersections.front();
|
||||
const double path_turn =
|
||||
util::bearing::angleBetween(util::bearing::reverse(intersection.bearings[intersection.in]),
|
||||
intersection.bearings[intersection.out]);
|
||||
|
||||
// Path turn must be a wider straight
|
||||
if (isWiderStraight(path_turn))
|
||||
{
|
||||
const double straightest_intersecting_turn = getStraightestIntersectingEdgeTurn(step);
|
||||
const double path_straight_delta = util::angularDeviation(path_turn, STRAIGHT_ANGLE);
|
||||
const double intersecting_straight_delta =
|
||||
util::angularDeviation(straightest_intersecting_turn, STRAIGHT_ANGLE);
|
||||
const double path_intersecting_delta =
|
||||
util::angularDeviation(path_turn, straightest_intersecting_turn);
|
||||
|
||||
// Add some fuzz - the delta between the path and intersecting turn must be greater
|
||||
// than 10 in order to consider using the intersecting turn as the straightest
|
||||
return ((path_intersecting_delta > 10.)
|
||||
? (path_straight_delta <= intersecting_straight_delta)
|
||||
: true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} /* namespace guidance */
|
||||
} /* namespace engine */
|
||||
} /* namespace osrm */
|
||||
|
||||
Reference in New Issue
Block a user