handle combined turns at segregated roads
This commit is contained in:
parent
3ac061c546
commit
754bc2d274
347
features/guidance/collapse.feature
Normal file
347
features/guidance/collapse.feature
Normal file
@ -0,0 +1,347 @@
|
||||
@routing @guidance @collapsing
|
||||
Feature: Collapse
|
||||
|
||||
Background:
|
||||
Given the profile "car"
|
||||
Given a grid size of 20 meters
|
||||
|
||||
Scenario: Segregated Intersection, Cross Belonging to Single Street
|
||||
Given the node map
|
||||
| | | i | l | | |
|
||||
| | | | | | |
|
||||
| d | | c | b | | a |
|
||||
| e | | f | g | | h |
|
||||
| | | | | | |
|
||||
| | | j | k | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| ab | primary | first | yes |
|
||||
| bc | primary | first | yes |
|
||||
| cd | primary | first | yes |
|
||||
| ef | primary | first | yes |
|
||||
| fg | primary | first | yes |
|
||||
| gh | primary | first | yes |
|
||||
| ic | primary | second | yes |
|
||||
| bl | primary | second | yes |
|
||||
| kg | primary | second | yes |
|
||||
| fj | primary | second | yes |
|
||||
| cf | primary | first | yes |
|
||||
| gb | primary | first | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,l | first,second,second | depart,turn right,arrive |
|
||||
| a,d | first,first | depart,arrive |
|
||||
| a,j | first,second,second | depart,turn left,arrive |
|
||||
| a,h | first,first,first | depart,continue uturn,arrive |
|
||||
| e,j | first,second,second | depart,turn right,arrive |
|
||||
| e,h | first,first | depart,arrive |
|
||||
| e,l | first,second,second | depart,turn left,arrive |
|
||||
| e,d | first,first,first | depart,continue uturn,arrive |
|
||||
| k,h | second,first,first | depart,turn right,arrive |
|
||||
| k,l | second,second | depart,arrive |
|
||||
| k,d | second,first,first | depart,turn left,arrive |
|
||||
| k,j | second,second,second | depart,continue uturn,arrive |
|
||||
| i,d | second,first,first | depart,turn right,arrive |
|
||||
| i,j | second,second | depart,arrive |
|
||||
| i,h | second,first,first | depart,turn left,arrive |
|
||||
| i,l | second,second,second | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Segregated Intersection, Cross Belonging to Correct Street
|
||||
Given the node map
|
||||
| | | i | l | | |
|
||||
| | | | | | |
|
||||
| d | | c | b | | a |
|
||||
| e | | f | g | | h |
|
||||
| | | | | | |
|
||||
| | | j | k | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| ab | primary | first | yes |
|
||||
| bc | primary | first | yes |
|
||||
| cd | primary | first | yes |
|
||||
| ef | primary | first | yes |
|
||||
| fg | primary | first | yes |
|
||||
| gh | primary | first | yes |
|
||||
| ic | primary | second | yes |
|
||||
| bl | primary | second | yes |
|
||||
| kg | primary | second | yes |
|
||||
| fj | primary | second | yes |
|
||||
| cf | primary | second | yes |
|
||||
| gb | primary | second | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,l | first,second,second | depart,turn right,arrive |
|
||||
| a,d | first,first | depart,arrive |
|
||||
| a,j | first,second,second | depart,turn left,arrive |
|
||||
| a,h | first,first,first | depart,continue uturn,arrive |
|
||||
| e,j | first,second,second | depart,turn right,arrive |
|
||||
| e,h | first,first | depart,arrive |
|
||||
| e,l | first,second,second | depart,turn left,arrive |
|
||||
| e,d | first,first,first | depart,continue uturn,arrive |
|
||||
| k,h | second,first,first | depart,turn right,arrive |
|
||||
| k,l | second,second | depart,arrive |
|
||||
| k,d | second,first,first | depart,turn left,arrive |
|
||||
| k,j | second,second,second | depart,continue uturn,arrive |
|
||||
| i,d | second,first,first | depart,turn right,arrive |
|
||||
| i,j | second,second | depart,arrive |
|
||||
| i,h | second,first,first | depart,turn left,arrive |
|
||||
| i,l | second,second,second | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Segregated Intersection, Cross Belonging to Mixed Streets
|
||||
Given the node map
|
||||
| | | i | l | | |
|
||||
| | | | | | |
|
||||
| d | | c | b | | a |
|
||||
| e | | f | g | | h |
|
||||
| | | | | | |
|
||||
| | | j | k | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| ab | primary | first | yes |
|
||||
| bc | primary | second | yes |
|
||||
| cd | primary | first | yes |
|
||||
| ef | primary | first | yes |
|
||||
| fg | primary | first | yes |
|
||||
| gh | primary | first | yes |
|
||||
| ic | primary | second | yes |
|
||||
| bl | primary | second | yes |
|
||||
| kg | primary | second | yes |
|
||||
| fj | primary | second | yes |
|
||||
| cf | primary | second | yes |
|
||||
| gb | primary | first | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,l | first,second,second | depart,turn right,arrive |
|
||||
| a,d | first,first | depart,arrive |
|
||||
| a,j | first,second,second | depart,turn left,arrive |
|
||||
| a,h | first,first,first | depart,continue uturn,arrive |
|
||||
| e,j | first,second,second | depart,turn right,arrive |
|
||||
| e,h | first,first | depart,arrive |
|
||||
| e,l | first,second,second | depart,turn left,arrive |
|
||||
| e,d | first,first,first | depart,continue uturn,arrive |
|
||||
| k,h | second,first,first | depart,turn right,arrive |
|
||||
| k,l | second,second | depart,arrive |
|
||||
| k,d | second,first,first | depart,turn left,arrive |
|
||||
| k,j | second,second,second | depart,continue uturn,arrive |
|
||||
| i,d | second,first,first | depart,turn right,arrive |
|
||||
| i,j | second,second | depart,arrive |
|
||||
| i,h | second,first,first | depart,turn left,arrive |
|
||||
| i,l | second,second,second | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Partly Segregated Intersection, Two Segregated Roads
|
||||
Given the node map
|
||||
| | g | | h | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| c | | b | | a |
|
||||
| d | | e | | f |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | j | | i | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| ab | primary | first | yes |
|
||||
| bc | primary | first | yes |
|
||||
| de | primary | first | yes |
|
||||
| ef | primary | first | yes |
|
||||
| be | primary | first | no |
|
||||
| gbh | primary | second | yes |
|
||||
| iej | primary | second | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,h | first,second,second | depart,turn right,arrive |
|
||||
| a,c | first,first | depart,arrive |
|
||||
| a,j | first,second,second | depart,turn left,arrive |
|
||||
| a,f | first,first,first | depart,continue uturn,arrive |
|
||||
| d,j | first,second,second | depart,turn right,arrive |
|
||||
| d,f | first,first | depart,arrive |
|
||||
| d,h | first,second,second | depart,turn left,arrive |
|
||||
| d,c | first,first,first | depart,continue uturn,arrive |
|
||||
| g,c | second,first,first | depart,turn right,arrive |
|
||||
| g,j | second,second | depart,arrive |
|
||||
| g,f | second,first,first | depart,turn left,arrive |
|
||||
| g,h | second,second,second | depart,continue uturn,arrive |
|
||||
| i,f | second,first,first | depart,turn right,arrive |
|
||||
| i,h | second,second | depart,arrive |
|
||||
| i,c | second,first,first | depart,turn left,arrive |
|
||||
| i,j | second,second,second | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Partly Segregated Intersection, Two Segregated Roads, Intersection belongs to Second
|
||||
Given the node map
|
||||
| | g | | h | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| c | | b | | a |
|
||||
| d | | e | | f |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | j | | i | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| ab | primary | first | yes |
|
||||
| bc | primary | first | yes |
|
||||
| de | primary | first | yes |
|
||||
| ef | primary | first | yes |
|
||||
| be | primary | second | no |
|
||||
| gbh | primary | second | yes |
|
||||
| iej | primary | second | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,h | first,second,second | depart,turn right,arrive |
|
||||
| a,c | first,first | depart,arrive |
|
||||
| a,j | first,second,second | depart,turn left,arrive |
|
||||
| a,f | first,first,first | depart,continue uturn,arrive |
|
||||
| d,j | first,second,second | depart,turn right,arrive |
|
||||
| d,f | first,first | depart,arrive |
|
||||
| d,h | first,second,second | depart,turn left,arrive |
|
||||
| d,c | first,first,first | depart,continue uturn,arrive |
|
||||
| g,c | second,first,first | depart,turn right,arrive |
|
||||
| g,j | second,second | depart,arrive |
|
||||
| g,f | second,first,first | depart,turn left,arrive |
|
||||
| g,h | second,second,second | depart,continue uturn,arrive |
|
||||
| i,f | second,first,first | depart,turn right,arrive |
|
||||
| i,h | second,second | depart,arrive |
|
||||
| i,c | second,first,first | depart,turn left,arrive |
|
||||
| i,j | second,second,second | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Segregated Intersection, Cross Belonging to Mixed Streets - Slight Angles
|
||||
Given the node map
|
||||
| | | i | l | | |
|
||||
| | | | | | a |
|
||||
| | | c | b | | h |
|
||||
| d | | f | g | | |
|
||||
| e | | | | | |
|
||||
| | | j | k | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| ab | primary | first | yes |
|
||||
| bc | primary | second | yes |
|
||||
| cd | primary | first | yes |
|
||||
| ef | primary | first | yes |
|
||||
| fg | primary | first | yes |
|
||||
| gh | primary | first | yes |
|
||||
| ic | primary | second | yes |
|
||||
| bl | primary | second | yes |
|
||||
| kg | primary | second | yes |
|
||||
| fj | primary | second | yes |
|
||||
| cf | primary | second | yes |
|
||||
| gb | primary | first | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,l | first,second,second | depart,turn right,arrive |
|
||||
| a,d | first,first | depart,arrive |
|
||||
| a,j | first,second,second | depart,turn left,arrive |
|
||||
| a,h | first,first,first | depart,continue uturn,arrive |
|
||||
| e,j | first,second,second | depart,turn right,arrive |
|
||||
| e,h | first,first | depart,arrive |
|
||||
| e,l | first,second,second | depart,turn left,arrive |
|
||||
| e,d | first,first,first | depart,continue uturn,arrive |
|
||||
| k,h | second,first,first | depart,turn right,arrive |
|
||||
| k,l | second,second | depart,arrive |
|
||||
| k,d | second,first,first | depart,turn left,arrive |
|
||||
| k,j | second,second,second | depart,continue uturn,arrive |
|
||||
| i,d | second,first,first | depart,turn right,arrive |
|
||||
| i,j | second,second | depart,arrive |
|
||||
| i,h | second,first,first | depart,turn left,arrive |
|
||||
| i,l | second,second,second | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Segregated Intersection, Cross Belonging to Mixed Streets - Slight Angles (2)
|
||||
Given the node map
|
||||
| | | i | l | | |
|
||||
| | | | | | |
|
||||
| | | c | b | | |
|
||||
| d | | f | g | | a |
|
||||
| e | | | | | h |
|
||||
| | | j | k | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| ab | primary | first | yes |
|
||||
| bc | primary | second | yes |
|
||||
| cd | primary | first | yes |
|
||||
| ef | primary | first | yes |
|
||||
| fg | primary | first | yes |
|
||||
| gh | primary | first | yes |
|
||||
| ic | primary | second | yes |
|
||||
| bl | primary | second | yes |
|
||||
| kg | primary | second | yes |
|
||||
| fj | primary | second | yes |
|
||||
| cf | primary | second | yes |
|
||||
| gb | primary | first | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,l | first,second,second | depart,turn right,arrive |
|
||||
| a,d | first,first | depart,arrive |
|
||||
| a,j | first,second,second | depart,turn left,arrive |
|
||||
| a,h | first,first,first | depart,continue uturn,arrive |
|
||||
| e,j | first,second,second | depart,turn right,arrive |
|
||||
| e,h | first,first | depart,arrive |
|
||||
| e,l | first,second,second | depart,turn left,arrive |
|
||||
| e,d | first,first,first | depart,continue uturn,arrive |
|
||||
| k,h | second,first,first | depart,turn right,arrive |
|
||||
| k,l | second,second | depart,arrive |
|
||||
| k,d | second,first,first | depart,turn left,arrive |
|
||||
| k,j | second,second,second | depart,continue uturn,arrive |
|
||||
| i,d | second,first,first | depart,turn right,arrive |
|
||||
| i,j | second,second | depart,arrive |
|
||||
| i,h | second,first,first | depart,turn left,arrive |
|
||||
| i,l | second,second,second | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Entering a segregated road
|
||||
Given the node map
|
||||
| | a | f | | |
|
||||
| | | | | g |
|
||||
| | b | e | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| c | d | | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | primary | first | yes |
|
||||
| def | primary | first | yes |
|
||||
| be | primary | first | no |
|
||||
| ge | primary | second | no |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| d,c | first,first,first | depart,continue uturn,arrive |
|
||||
| a,f | first,first,first | depart,continue uturn,arrive |
|
||||
| a,g | first,second,second | depart,turn left,arrive |
|
||||
| d,g | first,second,second | depart,turn right,arrive |
|
||||
| g,f | second,first,first | depart,turn right,arrive |
|
||||
| g,c | second,first,first | depart,end of road left,arrive |
|
||||
|
||||
|
||||
Scenario: Do not collapse turning roads
|
||||
Given the node map
|
||||
| | | e | | |
|
||||
| | | c | | d |
|
||||
| a | | b | f | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| ab | primary | first |
|
||||
| bc | primary | first |
|
||||
| cd | primary | first |
|
||||
| ce | primary | second |
|
||||
| bf | primary | third |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | first,first,first,first | depart,continue left,continue right,arrive |
|
||||
| a,e | first,second,second | depart,turn left,arrive |
|
||||
| a,f | first,third,third | depart,new name straight,arrive |
|
@ -132,6 +132,7 @@ class RouteAPI : public BaseAPI
|
||||
|
||||
guidance::trimShortSegments(steps, leg_geometry);
|
||||
leg.steps = guidance::postProcess(std::move(steps));
|
||||
leg.steps = guidance::collapseTurns(std::move(leg.steps));
|
||||
leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), leg_geometry,
|
||||
phantoms.source_phantom,
|
||||
phantoms.target_phantom);
|
||||
|
@ -17,6 +17,13 @@ namespace guidance
|
||||
// passed as none-reference to modify in-place and move out again
|
||||
std::vector<RouteStep> postProcess(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.
|
||||
std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps);
|
||||
|
||||
// trim initial/final segment of very short length.
|
||||
// This function uses in/out parameter passing to modify both steps and geometry in place.
|
||||
// We use this method since both steps and geometry are closely coupled logically but
|
||||
@ -30,6 +37,9 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
|
||||
const PhantomNode &source_node,
|
||||
const PhantomNode &target_node);
|
||||
|
||||
//remove steps invalidated by post-processing
|
||||
std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps);
|
||||
|
||||
// postProcess will break the connection between the leg geometry
|
||||
// for which a segment is supposed to represent exactly the coordinates
|
||||
// between routing maneuvers and the route steps itself.
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
@ -56,6 +58,12 @@ inline extractor::guidance::DirectionModifier angleToDirectionModifier(const dou
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
}
|
||||
|
||||
inline double angularDeviation(const double angle, const double from)
|
||||
{
|
||||
const double deviation = std::abs(angle - from);
|
||||
return std::min(360 - deviation, deviation);
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
@ -66,6 +66,13 @@ RouteStep forwardInto(RouteStep destination, const RouteStep &source)
|
||||
return destination;
|
||||
}
|
||||
|
||||
// invalidate a step and set its content to nothing
|
||||
inline void invalidateStep(RouteStep &step)
|
||||
{
|
||||
step = {};
|
||||
step.maneuver.instruction = TurnInstruction::NO_TURN();
|
||||
};
|
||||
|
||||
void fixFinalRoundabout(std::vector<RouteStep> &steps)
|
||||
{
|
||||
for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0;
|
||||
@ -196,8 +203,157 @@ void closeOffRoundabout(const bool on_roundabout,
|
||||
step.maneuver.instruction = TurnInstruction::NO_TURN();
|
||||
}
|
||||
}
|
||||
|
||||
// elongate a step by another. the data is added either at the front, or the back
|
||||
RouteStep elongate(RouteStep step, const RouteStep &by_step)
|
||||
{
|
||||
BOOST_ASSERT(step.mode == by_step.mode);
|
||||
|
||||
step.duration += by_step.duration;
|
||||
step.distance += by_step.distance;
|
||||
|
||||
if (step.geometry_end == by_step.geometry_begin + 1)
|
||||
{
|
||||
step.geometry_end = by_step.geometry_end;
|
||||
|
||||
// if we elongate in the back, we only need to copy the intersections to the beginning.
|
||||
// the bearings remain the same, as the location of the turn doesn't change
|
||||
step.maneuver.intersections.insert(step.maneuver.intersections.end(),
|
||||
by_step.maneuver.intersections.begin(),
|
||||
by_step.maneuver.intersections.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(step.maneuver.waypoint_type == WaypointType::None &&
|
||||
by_step.maneuver.waypoint_type == WaypointType::None);
|
||||
BOOST_ASSERT(by_step.geometry_end == step.geometry_begin + 1);
|
||||
step.geometry_begin = by_step.geometry_begin;
|
||||
|
||||
// elongating in the front changes the location of the maneuver
|
||||
step.maneuver.location = by_step.maneuver.location;
|
||||
step.maneuver.bearing_before = by_step.maneuver.bearing_before;
|
||||
step.maneuver.bearing_after = by_step.maneuver.bearing_after;
|
||||
step.maneuver.instruction = by_step.maneuver.instruction;
|
||||
|
||||
step.maneuver.intersections.insert(step.maneuver.intersections.begin(),
|
||||
by_step.maneuver.intersections.begin(),
|
||||
by_step.maneuver.intersections.end());
|
||||
}
|
||||
return step;
|
||||
}
|
||||
|
||||
// A check whether two instructions can be treated as one. This is only the case for very short
|
||||
// maneuvers that can, in some form, be seen as one. The additional in_step is to find out about
|
||||
// a possible u-turn.
|
||||
inline bool collapsable(const RouteStep &step)
|
||||
{
|
||||
const constexpr double MAX_COLLAPSE_DISTANCE = 25;
|
||||
return step.distance < MAX_COLLAPSE_DISTANCE;
|
||||
};
|
||||
|
||||
void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
const std::size_t two_back_index,
|
||||
const std::size_t one_back_index,
|
||||
const std::size_t step_index)
|
||||
{
|
||||
const auto ¤t_step = steps[step_index];
|
||||
|
||||
const auto &one_back_step = steps[one_back_index];
|
||||
|
||||
const auto bearingsAreReversed = [](const double bearing_in, const double bearing_out) {
|
||||
// Nearly perfectly reversed angles have a difference close to 180 degrees (straight)
|
||||
return angularDeviation(bearing_in, bearing_out) > 170;
|
||||
};
|
||||
|
||||
// Very Short New Name
|
||||
if (TurnType::NewName == one_back_step.maneuver.instruction.type)
|
||||
{
|
||||
if (one_back_step.mode == steps[two_back_index].mode)
|
||||
{
|
||||
steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step);
|
||||
// If the previous instruction asked to continue, the name change will have to
|
||||
// be changed into a turn
|
||||
invalidateStep(steps[one_back_index]);
|
||||
|
||||
if (TurnType::Continue == current_step.maneuver.instruction.type)
|
||||
steps[step_index].maneuver.instruction.type = TurnType::Turn;
|
||||
}
|
||||
}
|
||||
// very short segment after turn
|
||||
else if (TurnType::NewName == current_step.maneuver.instruction.type)
|
||||
{
|
||||
if (one_back_step.mode == current_step.mode)
|
||||
{
|
||||
steps[step_index] = elongate(std::move(steps[step_index]), steps[one_back_index]);
|
||||
invalidateStep(steps[one_back_index]);
|
||||
|
||||
if (TurnType::Continue == current_step.maneuver.instruction.type)
|
||||
{
|
||||
steps[step_index].maneuver.instruction.type = TurnType::Turn;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Potential U-Turn
|
||||
else if (bearingsAreReversed(one_back_step.maneuver.bearing_before,
|
||||
current_step.maneuver.bearing_after))
|
||||
|
||||
{
|
||||
// the simple case is a u-turn that changes directly into the in-name again
|
||||
const bool direct_u_turn = steps[two_back_index].name == current_step.name;
|
||||
|
||||
// however, we might also deal with a dual-collapse scenario in which we have to
|
||||
// additionall collapse a name-change as well
|
||||
const bool continues_with_name_change =
|
||||
(step_index + 1 < steps.size()) &&
|
||||
(TurnType::NewName == steps[step_index + 1].maneuver.instruction.type);
|
||||
const bool u_turn_with_name_change =
|
||||
collapsable(current_step) && continues_with_name_change &&
|
||||
steps[step_index + 1].name == steps[two_back_index].name;
|
||||
|
||||
if (direct_u_turn || u_turn_with_name_change)
|
||||
{
|
||||
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
|
||||
invalidateStep(steps[step_index]);
|
||||
if (u_turn_with_name_change)
|
||||
{
|
||||
steps[one_back_index] =
|
||||
elongate(std::move(steps[one_back_index]), steps[step_index + 1]);
|
||||
invalidateStep(steps[step_index + 1]); // will be skipped due to the
|
||||
// continue statement at the
|
||||
// beginning of this function
|
||||
}
|
||||
|
||||
steps[one_back_index].name = steps[two_back_index].name;
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
DirectionModifier::UTurn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Post processing can invalidate some instructions. For example StayOnRoundabout
|
||||
// is turned into exit counts. These instructions are removed by the following function
|
||||
|
||||
std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps)
|
||||
{
|
||||
// finally clean up the post-processed instructions.
|
||||
// Remove all invalid instructions from the set of instructions.
|
||||
// An instruction is invalid, if its NO_TURN and has WaypointType::None.
|
||||
// Two valid NO_TURNs exist in each leg in the form of Depart/Arrive
|
||||
|
||||
// keep valid instructions
|
||||
const auto not_is_valid = [](const RouteStep &step) {
|
||||
return step.maneuver.instruction == TurnInstruction::NO_TURN() &&
|
||||
step.maneuver.waypoint_type == WaypointType::None;
|
||||
};
|
||||
|
||||
boost::remove_erase_if(steps, not_is_valid);
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
// Every Step Maneuver consists of the information until the turn.
|
||||
// This list contains a set of instructions, called silent, which should
|
||||
// not be part of the final output.
|
||||
@ -287,20 +443,65 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
||||
detail::fixFinalRoundabout(steps);
|
||||
}
|
||||
|
||||
// finally clean up the post-processed instructions.
|
||||
// Remove all invalid instructions from the set of instructions.
|
||||
// An instruction is invalid, if its NO_TURN and has WaypointType::None.
|
||||
// Two valid NO_TURNs exist in each leg in the form of Depart/Arrive
|
||||
return removeNoTurnInstructions(std::move(steps));
|
||||
}
|
||||
|
||||
// keep valid instructions
|
||||
const auto not_is_valid = [](const RouteStep &step) {
|
||||
return step.maneuver.instruction == TurnInstruction::NO_TURN() &&
|
||||
step.maneuver.waypoint_type == WaypointType::None;
|
||||
// Post Processing to collapse unnecessary sets of combined instructions into a single one
|
||||
std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
{
|
||||
// Get the previous non-invalid instruction
|
||||
const auto getPreviousIndex = [&steps](std::size_t index) {
|
||||
BOOST_ASSERT(index > 0);
|
||||
--index;
|
||||
while (index > 0 && steps[index].maneuver.instruction == TurnInstruction::NO_TURN())
|
||||
--index;
|
||||
|
||||
return index;
|
||||
};
|
||||
|
||||
boost::remove_erase_if(steps, not_is_valid);
|
||||
// first and last instructions are waypoints that cannot be collapsed
|
||||
for (std::size_t step_index = 2; step_index < steps.size(); ++step_index)
|
||||
{
|
||||
const auto ¤t_step = steps[step_index];
|
||||
const auto one_back_index = getPreviousIndex(step_index);
|
||||
|
||||
return steps;
|
||||
// cannot collapse the depart instruction
|
||||
if (one_back_index == 0 || current_step.maneuver.instruction == TurnInstruction::NO_TURN())
|
||||
continue;
|
||||
|
||||
const auto &one_back_step = steps[one_back_index];
|
||||
const auto two_back_index = getPreviousIndex(one_back_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.
|
||||
// In these cases, the name change will be suppressed.
|
||||
if (TurnType::NewName == current_step.maneuver.instruction.type &&
|
||||
TurnType::NewName == one_back_step.maneuver.instruction.type)
|
||||
{
|
||||
// valid due to step_index starting at 2
|
||||
const auto &coming_from_name = steps[step_index - 2].name;
|
||||
if (current_step.name == coming_from_name)
|
||||
{
|
||||
if (current_step.mode == one_back_step.mode &&
|
||||
one_back_step.mode == steps[two_back_index].mode)
|
||||
{
|
||||
steps[two_back_index] = detail::elongate(
|
||||
detail::elongate(std::move(steps[two_back_index]), steps[one_back_index]),
|
||||
steps[step_index]);
|
||||
detail::invalidateStep(steps[one_back_index]);
|
||||
detail::invalidateStep(steps[step_index]);
|
||||
}
|
||||
// TODO discuss: we could think about changing the new-name to a pure notification
|
||||
// about mode changes
|
||||
}
|
||||
}
|
||||
else if (detail::collapsable(one_back_step))
|
||||
{
|
||||
// check for one of the multiple collapse scenarios and, if possible, collapse the turn
|
||||
detail::collapseTurnAt(steps, two_back_index, one_back_index, step_index);
|
||||
}
|
||||
}
|
||||
return removeNoTurnInstructions(std::move(steps));
|
||||
}
|
||||
|
||||
void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
||||
|
Loading…
Reference in New Issue
Block a user