Collapse Staggered Intersections.
Staggered intersection are very short zig-zags of only a few meters. They are common in rural and exurban areas, especially in the US. (In addition, these cases could as well be tagging issues) We do not want to announce these short left-rights or right-lefts: * -> b a -> * | or | becomes a -> b a -> * * -> b Here is one example: - https://www.openstreetmap.org/edit#map=20/39.26017/-84.25182 And here are two edge-cases that we don't handle at the moment: - http://www.openstreetmap.org/edit#map=20/38.87900/-76.98519 - http://www.openstreetmap.org/edit#map=19/45.51056/-122.63462 and probably should not handle since the distance in between is quite long (roughly 7-15 meters). For these we want to announce two turns to not confuse the user. Thanks to @1ec5 for raising this issue and @karenzshea for providing additional US examples and cultural insights.
This commit is contained in:
parent
e8ce119972
commit
b1e309b4eb
92
features/guidance/staggered-intersections.feature
Normal file
92
features/guidance/staggered-intersections.feature
Normal file
@ -0,0 +1,92 @@
|
||||
@routing @guidance @staggered-intersections
|
||||
Feature: Staggered Intersections
|
||||
|
||||
Background:
|
||||
Given the profile "car"
|
||||
Given a grid size of 1 meters
|
||||
# Note the one meter grid size: staggered intersections make zig-zags of a couple of meters only
|
||||
|
||||
# https://www.openstreetmap.org/#map=19/39.26022/-84.25144
|
||||
Scenario: Staggered Intersection: Oak St, Cedar Dr
|
||||
Given the node map
|
||||
| | | j | | |
|
||||
| a | b | c | | |
|
||||
| | | d | | |
|
||||
| | | e | f | g |
|
||||
| | | h | | |
|
||||
| | | i | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | residential | Oak St |
|
||||
| efg | residential | Oak St |
|
||||
| jcdehi | residential | Cedar Dr |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | Oak St,Oak St | depart,arrive |
|
||||
| g,a | Oak St,Oak St | depart,arrive |
|
||||
|
||||
Scenario: Staggered Intersection: do not collapse if long segment in between
|
||||
Given the node map
|
||||
| | | j | | |
|
||||
| a | b | c | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | d | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | e | f | g |
|
||||
| | | h | | |
|
||||
| | | i | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | residential | Oak St |
|
||||
| efg | residential | Oak St |
|
||||
| jcdehi | residential | Cedar Dr |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
|
||||
| g,a | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
|
||||
|
||||
Scenario: Staggered Intersection: do not collapse if not left-right or right-left
|
||||
Given the node map
|
||||
| | | j | | |
|
||||
| a | b | c | | |
|
||||
| | | d | | |
|
||||
| g | f | e | | |
|
||||
| | | h | | |
|
||||
| | | i | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | residential | Oak St |
|
||||
| efg | residential | Oak St |
|
||||
| jcdehi | residential | Cedar Dr |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | Oak St,Oak St,Oak St | depart,continue uturn,arrive |
|
||||
| g,a | Oak St,Oak St,Oak St | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Staggered Intersection: do not collapse if the names are not the same
|
||||
Given the node map
|
||||
| | | j | | |
|
||||
| a | b | c | | |
|
||||
| | | d | | |
|
||||
| | | e | f | g |
|
||||
| | | h | | |
|
||||
| | | i | | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | residential | Oak St |
|
||||
| efg | residential | Elm St |
|
||||
| jcdehi | residential | Cedar Dr |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | Oak St,Cedar Dr,Elm St,Elm St | depart,turn right,turn left,arrive |
|
||||
| g,a | Elm St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
|
@ -17,6 +17,7 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
@ -513,6 +514,33 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Staggered intersection are very short zig-zags of a few meters.
|
||||
// We do not want to announce these short left-rights or right-lefts:
|
||||
//
|
||||
// * -> b a -> *
|
||||
// | or | becomes a -> b
|
||||
// a -> * * -> b
|
||||
//
|
||||
bool isStaggeredIntersection(const RouteStep &previous, const RouteStep ¤t)
|
||||
{
|
||||
// Base decision on distance since the zig-zag is a visual clue.
|
||||
const constexpr auto MAX_STAGGERED_DISTANCE = 3; // debatable, but keep short to be on safe side
|
||||
|
||||
using namespace util::guidance;
|
||||
|
||||
const auto left_right = isLeftTurn(previous.maneuver.instruction) && //
|
||||
isRightTurn(current.maneuver.instruction);
|
||||
const auto right_left = isRightTurn(previous.maneuver.instruction) && //
|
||||
isLeftTurn(current.maneuver.instruction);
|
||||
|
||||
// A RouteStep holds distance/duration from the maneuver to the subsequent step.
|
||||
// We are only interested in the distance between the first and the second.
|
||||
const auto is_short = previous.distance < MAX_STAGGERED_DISTANCE;
|
||||
|
||||
return is_short && (left_right || right_left);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Post processing can invalidate some instructions. For example StayOnRoundabout
|
||||
@ -753,12 +781,13 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
// A name oszillation changes from name A shortly to name B and back to A.
|
||||
// In these cases, the name change will be suppressed.
|
||||
else if (one_back_index > 0 && compatible(current_step, one_back_step) &&
|
||||
isCollapsableInstruction(current_step.maneuver.instruction) &&
|
||||
isCollapsableInstruction(one_back_step.maneuver.instruction))
|
||||
((isCollapsableInstruction(current_step.maneuver.instruction) &&
|
||||
isCollapsableInstruction(one_back_step.maneuver.instruction)) ||
|
||||
isStaggeredIntersection(one_back_step, current_step)))
|
||||
{
|
||||
const auto two_back_index = getPreviousIndex(one_back_index);
|
||||
BOOST_ASSERT(two_back_index < steps.size());
|
||||
// valid, since one_back is collapsable:
|
||||
// valid, since one_back is collapsable or a turn and therefore not depart:
|
||||
const auto &coming_from_name = steps[two_back_index].name;
|
||||
if (current_step.name == coming_from_name)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user