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:
Moritz Kobitzsch 2016-08-08 15:46:33 +02:00
parent 01a2c66472
commit 88c3f4c481
6 changed files with 260 additions and 20 deletions

View File

@ -31,6 +31,36 @@ Feature: Simple Turns
| f,a | depart,arrive | road,road | | f,a | depart,arrive | road,road |
| e,a | depart,turn slight right,arrive | turn,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 Scenario: Middle Island
Given the node map Given the node map
""" """

View File

@ -1288,3 +1288,90 @@ Feature: Simple Turns
| waypoints | route | turns | | waypoints | route | turns |
| a,c | in,through,through | depart,turn left,arrive | | 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 |

View File

@ -66,7 +66,7 @@ class IntersectionGenerator
Intersection GetConnectedRoads(const NodeID from_node, const EdgeID via_eid) const; 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 // 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 // MergeSegregatedRoads
bool CanMerge(const NodeID intersection_node, bool CanMerge(const NodeID intersection_node,
const Intersection &intersection, const Intersection &intersection,

View File

@ -1,4 +1,5 @@
#include "engine/guidance/post_processing.hpp" #include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
@ -567,16 +568,21 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
} }
else else
{ {
if (TurnType::Continue == current_step.maneuver.instruction.type || const bool continue_or_suppressed =
(TurnType::Suppressed == current_step.maneuver.instruction.type && (TurnType::Continue == current_step.maneuver.instruction.type ||
current_step.maneuver.instruction.direction_modifier != (TurnType::Suppressed == current_step.maneuver.instruction.type &&
DirectionModifier::Straight)) current_step.maneuver.instruction.direction_modifier !=
steps[step_index].maneuver.instruction.type = TurnType::Turn; DirectionModifier::Straight));
else if (TurnType::NewName == current_step.maneuver.instruction.type && const bool turning_name =
current_step.maneuver.instruction.direction_modifier != (TurnType::NewName == current_step.maneuver.instruction.type &&
DirectionModifier::Straight && current_step.maneuver.instruction.direction_modifier !=
one_back_step.intersections.front().bearings.size() > 2) 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; steps[step_index].maneuver.instruction.type = TurnType::Turn;
else if (TurnType::UseLane == current_step.maneuver.instruction.type && else if (TurnType::UseLane == current_step.maneuver.instruction.type &&
current_step.maneuver.instruction.direction_modifier != current_step.maneuver.instruction.direction_modifier !=
@ -584,9 +590,123 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
one_back_step.intersections.front().bearings.size() > 2) one_back_step.intersections.front().bearings.size() > 2)
steps[step_index].maneuver.instruction.type = TurnType::Turn; steps[step_index].maneuver.instruction.type = TurnType::Turn;
const auto total_angle = findTotalTurnAngle(steps[one_back_index], current_step); // A new name with a continue/turning suppressed/name requires the adaption of the
steps[step_index].maneuver.instruction.direction_modifier = // direction modifier. The combination of the in-bearing and the out bearing gives the
getTurnDirection(total_angle); // 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); steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step);

View File

@ -549,6 +549,15 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
for (std::size_t index = 1; index < intersection.size(); ++index) for (std::size_t index = 1; index < intersection.size(); ++index)
{ {
auto &road = intersection[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 auto node_at_next_intersection = node_based_graph.GetTarget(road.turn.eid);
const util::Coordinate coordinate_at_next_intersection = const util::Coordinate coordinate_at_next_intersection =
node_info_list[node_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) if (range.size() <= 1)
continue; 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 // 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 // this is the case and the road is not far away (see previous distance check), if
// influences the perceived angle. // influences the perceived angle.

View File

@ -28,7 +28,7 @@ using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
bool requiresAnnouncement(const EdgeData &from, const EdgeData &to) bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
{ {
return !from.IsCompatibleTo(to); return !from.CanCombineWith(to);
} }
TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,