Considering multiple small turns, right after each
other can result in a combined turn angle that is straight instead of turning left and right.
This commit is contained in:
parent
01a2c66472
commit
88c3f4c481
@ -31,6 +31,36 @@ Feature: Simple Turns
|
||||
| f,a | depart,arrive | road,road |
|
||||
| e,a | depart,turn slight right,arrive | turn,road,road |
|
||||
|
||||
Scenario: Turning into splitting road
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
g-b
|
||||
/\
|
||||
/ \
|
||||
c d
|
||||
|\
|
||||
| e
|
||||
|
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| ab | road | primary | no |
|
||||
| bc | road | primary | yes |
|
||||
| fdb | road | primary | yes |
|
||||
| de | turn | primary | no |
|
||||
| bg | left | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route |
|
||||
| f,a | depart,arrive | road,road |
|
||||
| e,a | depart,turn slight right,arrive | turn,road,road |
|
||||
| e,g | depart,turn slight right,turn left,arrive | turn,road,left,left |
|
||||
| f,g | depart,turn left,arrive | road,left,left |
|
||||
| f,c | depart,continue uturn,arrive | road,road,road |
|
||||
|
||||
Scenario: Middle Island
|
||||
Given the node map
|
||||
"""
|
||||
|
@ -1288,3 +1288,90 @@ Feature: Simple Turns
|
||||
| waypoints | route | turns |
|
||||
| a,c | in,through,through | depart,turn left,arrive |
|
||||
|
||||
# http://www.openstreetmap.org/#map=19/52.51556/13.41832
|
||||
Scenario: No Slight Right over Jannowitzbruecke
|
||||
Given the node map
|
||||
"""
|
||||
l m
|
||||
| |
|
||||
f._ | |
|
||||
' g---h.
|
||||
| | '.
|
||||
| | i
|
||||
a_ | |
|
||||
''.b---c
|
||||
| |'d._
|
||||
| | 'e
|
||||
j k
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| ab | Stralauer Str | tertiary | yes |
|
||||
| bcde | Holzmarktstr | secondary | yes |
|
||||
| gf | Stralauer Str | tertiary | yes |
|
||||
| ihg | Holzmarktstr | secondary | yes |
|
||||
| lgbj | Alexanderstr | primary | yes |
|
||||
| kchm | Alexanderstr | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route |
|
||||
| a,e | depart,new name straight,arrive | Stralauer Str,Holzmarktstr,Holzmarktstr |
|
||||
|
||||
Scenario: No Slight Right over Jannowitzbruecke -- less extreme
|
||||
Given the node map
|
||||
"""
|
||||
l m
|
||||
| |
|
||||
f_ | |
|
||||
' 'g h_
|
||||
| | '\_
|
||||
| | i
|
||||
a_ | |
|
||||
'_ b c_
|
||||
| | \_
|
||||
| | e
|
||||
j k
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| ab | Stralauer Str | tertiary | yes |
|
||||
| bce | Holzmarktstr | secondary | yes |
|
||||
| gf | Stralauer Str | tertiary | yes |
|
||||
| ihg | Holzmarktstr | secondary | yes |
|
||||
| lgbj | Alexanderstr | primary | yes |
|
||||
| kchm | Alexanderstr | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route |
|
||||
| a,e | depart,new name straight,arrive | Stralauer Str,Holzmarktstr,Holzmarktstr |
|
||||
|
||||
Scenario: No Slight Right over Jannowitzbruecke
|
||||
Given the node map
|
||||
"""
|
||||
l m
|
||||
| |
|
||||
| |
|
||||
_ _ g h_
|
||||
f' | | '_
|
||||
| | i
|
||||
| |
|
||||
_ _b c__
|
||||
a' | | 'd
|
||||
| |
|
||||
j k
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | oneway |
|
||||
| ab | Stralauer Str | tertiary | yes |
|
||||
| bcd | Holzmarktstr | secondary | yes |
|
||||
| gf | Stralauer Str | tertiary | yes |
|
||||
| ihg | Holzmarktstr | secondary | yes |
|
||||
| lgbj | Alexanderstr | primary | yes |
|
||||
| kchm | Alexanderstr | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route |
|
||||
| a,d | depart,new name straight,arrive | Stralauer Str,Holzmarktstr,Holzmarktstr |
|
||||
|
@ -66,7 +66,7 @@ class IntersectionGenerator
|
||||
Intersection GetConnectedRoads(const NodeID from_node, const EdgeID via_eid) const;
|
||||
|
||||
// check if two indices in an intersection can be seen as a single road in the perceived
|
||||
// intersection representation See below for an example. Utility function for
|
||||
// intersection representation. See below for an example. Utility function for
|
||||
// MergeSegregatedRoads
|
||||
bool CanMerge(const NodeID intersection_node,
|
||||
const Intersection &intersection,
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "engine/guidance/post_processing.hpp"
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
|
||||
@ -567,16 +568,21 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TurnType::Continue == current_step.maneuver.instruction.type ||
|
||||
(TurnType::Suppressed == current_step.maneuver.instruction.type &&
|
||||
current_step.maneuver.instruction.direction_modifier !=
|
||||
DirectionModifier::Straight))
|
||||
steps[step_index].maneuver.instruction.type = TurnType::Turn;
|
||||
const bool continue_or_suppressed =
|
||||
(TurnType::Continue == current_step.maneuver.instruction.type ||
|
||||
(TurnType::Suppressed == current_step.maneuver.instruction.type &&
|
||||
current_step.maneuver.instruction.direction_modifier !=
|
||||
DirectionModifier::Straight));
|
||||
|
||||
else if (TurnType::NewName == current_step.maneuver.instruction.type &&
|
||||
current_step.maneuver.instruction.direction_modifier !=
|
||||
DirectionModifier::Straight &&
|
||||
one_back_step.intersections.front().bearings.size() > 2)
|
||||
const bool turning_name =
|
||||
(TurnType::NewName == current_step.maneuver.instruction.type &&
|
||||
current_step.maneuver.instruction.direction_modifier !=
|
||||
DirectionModifier::Straight &&
|
||||
one_back_step.intersections.front().bearings.size() > 2);
|
||||
|
||||
if (continue_or_suppressed)
|
||||
steps[step_index].maneuver.instruction.type = TurnType::Turn;
|
||||
else if (turning_name)
|
||||
steps[step_index].maneuver.instruction.type = TurnType::Turn;
|
||||
else if (TurnType::UseLane == current_step.maneuver.instruction.type &&
|
||||
current_step.maneuver.instruction.direction_modifier !=
|
||||
@ -584,9 +590,123 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
one_back_step.intersections.front().bearings.size() > 2)
|
||||
steps[step_index].maneuver.instruction.type = TurnType::Turn;
|
||||
|
||||
const auto total_angle = findTotalTurnAngle(steps[one_back_index], current_step);
|
||||
steps[step_index].maneuver.instruction.direction_modifier =
|
||||
getTurnDirection(total_angle);
|
||||
// A new name with a continue/turning suppressed/name requires the adaption of the
|
||||
// direction modifier. The combination of the in-bearing and the out bearing gives the
|
||||
// new modifier for the turn
|
||||
if (continue_or_suppressed || turning_name)
|
||||
{
|
||||
const auto in_bearing = [](const RouteStep &step) {
|
||||
return util::bearing::reverseBearing(
|
||||
step.intersections.front().bearings[step.intersections.front().in]);
|
||||
};
|
||||
const auto out_bearing = [](const RouteStep &step) {
|
||||
return step.intersections.front().bearings[step.intersections.front().out];
|
||||
};
|
||||
|
||||
const auto first_angle =
|
||||
turn_angle(in_bearing(one_back_step), out_bearing(one_back_step));
|
||||
const auto second_angle =
|
||||
turn_angle(in_bearing(current_step), out_bearing(current_step));
|
||||
const auto bearing_turn_angle =
|
||||
turn_angle(in_bearing(one_back_step), out_bearing(current_step));
|
||||
|
||||
// When looking at an intersection, some angles, even though present, feel more like
|
||||
// a straight turn. This happens most often at segregated intersections.
|
||||
// We consider two cases
|
||||
// I) a shift in the road:
|
||||
//
|
||||
// a g h
|
||||
// . | |
|
||||
// b ---- c
|
||||
// | | .
|
||||
// f e d
|
||||
//
|
||||
// Where a-d technicall continues straight, even though the shift models it as a
|
||||
// slight left and a slight right turn.
|
||||
//
|
||||
// II) A curved road
|
||||
//
|
||||
// g h
|
||||
// | |
|
||||
// b ---- c
|
||||
// . | | .
|
||||
// a f e d
|
||||
//
|
||||
// where a-d is a curve passing by an intersection.
|
||||
//
|
||||
// We distinguish this case from other bearings though where the interpretation as
|
||||
// straight would end up disguising turns.
|
||||
|
||||
// check if there is another similar turn next to the turn itself
|
||||
const auto hasSimilarAngle = [&](const std::size_t index,
|
||||
const std::vector<short> &bearings) {
|
||||
return (angularDeviation(bearings[index],
|
||||
bearings[(index + 1) % bearings.size()]) <
|
||||
extractor::guidance::NARROW_TURN_ANGLE) ||
|
||||
(angularDeviation(
|
||||
bearings[index],
|
||||
bearings[(index + bearings.size() - 1) % bearings.size()]) <
|
||||
extractor::guidance::NARROW_TURN_ANGLE);
|
||||
};
|
||||
|
||||
const auto is_shift_or_curve = [&]() -> bool {
|
||||
// since we move an intersection modifier from a slight turn to a straight, we
|
||||
// need to make sure that there is not a similar angle which could prevent this
|
||||
// perception of angles to be true.
|
||||
if (hasSimilarAngle(one_back_step.intersections.front().in,
|
||||
one_back_step.intersections.front().bearings) ||
|
||||
hasSimilarAngle(current_step.intersections.front().out,
|
||||
current_step.intersections.front().bearings))
|
||||
return false;
|
||||
|
||||
// Check if we are on a potential curve, both angles go in the same direction
|
||||
if (angularDeviation(first_angle, second_angle) <
|
||||
extractor::guidance::FUZZY_ANGLE_DIFFERENCE)
|
||||
{
|
||||
// We limit perceptive angles to narrow turns. If the total turn is going to
|
||||
// be not-narrow, we assume it to be more than a simple curve.
|
||||
return angularDeviation(bearing_turn_angle,
|
||||
extractor::guidance::STRAIGHT_ANGLE) <
|
||||
extractor::guidance::NARROW_TURN_ANGLE;
|
||||
}
|
||||
// if one of the angles is a left turn and the other one is a right turn, we
|
||||
// nearly reverse the angle
|
||||
else if ((first_angle > extractor::guidance::STRAIGHT_ANGLE) !=
|
||||
(second_angle > extractor::guidance::STRAIGHT_ANGLE))
|
||||
{
|
||||
// since we are not in a curve, we can check for a shift. If we are going
|
||||
// nearly straight, we call it a shift.
|
||||
return angularDeviation(bearing_turn_angle,
|
||||
extractor::guidance::STRAIGHT_ANGLE) <
|
||||
extractor::guidance::NARROW_TURN_ANGLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}();
|
||||
|
||||
// if the angles continue similar, it looks like we might be in a normal curve
|
||||
if (is_shift_or_curve)
|
||||
steps[step_index].maneuver.instruction.direction_modifier =
|
||||
DirectionModifier::Straight;
|
||||
else
|
||||
steps[step_index].maneuver.instruction.direction_modifier =
|
||||
util::guidance::getTurnDirection(bearing_turn_angle);
|
||||
|
||||
// if the total direction of this turn is now straight, we can keep it suppressed/as
|
||||
// a new name. Else we have to interpret it as a turn.
|
||||
if (!is_shift_or_curve)
|
||||
steps[step_index].maneuver.instruction.type = TurnType::Turn;
|
||||
else
|
||||
steps[step_index].maneuver.instruction.type = TurnType::NewName;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto total_angle = findTotalTurnAngle(steps[one_back_index], current_step);
|
||||
steps[step_index].maneuver.instruction.direction_modifier =
|
||||
getTurnDirection(total_angle);
|
||||
}
|
||||
}
|
||||
|
||||
steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step);
|
||||
|
@ -549,6 +549,15 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
|
||||
for (std::size_t index = 1; index < intersection.size(); ++index)
|
||||
{
|
||||
auto &road = intersection[index];
|
||||
// to find out about the above situation, we need to look at the next intersection (at d in
|
||||
// the example). If the initial road can be merged to the left/right, we are about to adjust
|
||||
// the angle.
|
||||
const auto next_intersection_along_road =
|
||||
GetConnectedRoads(node_at_intersection, road.turn.eid);
|
||||
|
||||
if (next_intersection_along_road.size() <= 1)
|
||||
continue;
|
||||
|
||||
const auto node_at_next_intersection = node_based_graph.GetTarget(road.turn.eid);
|
||||
const util::Coordinate coordinate_at_next_intersection =
|
||||
node_info_list[node_at_next_intersection];
|
||||
@ -569,12 +578,6 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
|
||||
if (range.size() <= 1)
|
||||
continue;
|
||||
|
||||
// to find out about the above situation, we need to look at the next intersection (at d in
|
||||
// the example). If the initial road can be merged to the left/right, we are about to adjust
|
||||
// the angle.
|
||||
const auto next_intersection_along_road =
|
||||
GetConnectedRoads(node_at_intersection, road.turn.eid);
|
||||
|
||||
// check if the u-turn edge at the next intersection could be merged to the left/right. If
|
||||
// this is the case and the road is not far away (see previous distance check), if
|
||||
// influences the perceived angle.
|
||||
|
@ -28,7 +28,7 @@ using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
|
||||
{
|
||||
return !from.IsCompatibleTo(to);
|
||||
return !from.CanCombineWith(to);
|
||||
}
|
||||
|
||||
TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
|
Loading…
Reference in New Issue
Block a user