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 |
|
| 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
|
||||||
"""
|
"""
|
||||||
|
@ -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 |
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user