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);
|
guidance::trimShortSegments(steps, leg_geometry);
|
||||||
leg.steps = guidance::postProcess(std::move(steps));
|
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,
|
leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), leg_geometry,
|
||||||
phantoms.source_phantom,
|
phantoms.source_phantom,
|
||||||
phantoms.target_phantom);
|
phantoms.target_phantom);
|
||||||
|
@ -17,6 +17,13 @@ namespace guidance
|
|||||||
// passed as none-reference to modify in-place and move out again
|
// passed as none-reference to modify in-place and move out again
|
||||||
std::vector<RouteStep> postProcess(std::vector<RouteStep> steps);
|
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.
|
// trim initial/final segment of very short length.
|
||||||
// This function uses in/out parameter passing to modify both steps and geometry in place.
|
// 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
|
// 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 &source_node,
|
||||||
const PhantomNode &target_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
|
// postProcess will break the connection between the leg geometry
|
||||||
// for which a segment is supposed to represent exactly the coordinates
|
// for which a segment is supposed to represent exactly the coordinates
|
||||||
// between routing maneuvers and the route steps itself.
|
// between routing maneuvers and the route steps itself.
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include "extractor/guidance/turn_instruction.hpp"
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
#include "util/bearing.hpp"
|
#include "util/bearing.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace engine
|
namespace engine
|
||||||
@ -56,6 +58,12 @@ inline extractor::guidance::DirectionModifier angleToDirectionModifier(const dou
|
|||||||
return extractor::guidance::DirectionModifier::Left;
|
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 guidance
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
@ -66,6 +66,13 @@ RouteStep forwardInto(RouteStep destination, const RouteStep &source)
|
|||||||
return destination;
|
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)
|
void fixFinalRoundabout(std::vector<RouteStep> &steps)
|
||||||
{
|
{
|
||||||
for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0;
|
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();
|
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
|
} // 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.
|
// Every Step Maneuver consists of the information until the turn.
|
||||||
// This list contains a set of instructions, called silent, which should
|
// This list contains a set of instructions, called silent, which should
|
||||||
// not be part of the final output.
|
// not be part of the final output.
|
||||||
@ -287,20 +443,65 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
|||||||
detail::fixFinalRoundabout(steps);
|
detail::fixFinalRoundabout(steps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally clean up the post-processed instructions.
|
return removeNoTurnInstructions(std::move(steps));
|
||||||
// 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
|
// Post Processing to collapse unnecessary sets of combined instructions into a single one
|
||||||
const auto not_is_valid = [](const RouteStep &step) {
|
std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||||
return step.maneuver.instruction == TurnInstruction::NO_TURN() &&
|
{
|
||||||
step.maneuver.waypoint_type == WaypointType::None;
|
// 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)
|
void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
||||||
|
Loading…
Reference in New Issue
Block a user