Review updates

This commit is contained in:
Michael Krasnyk 2018-03-01 23:36:32 +01:00
parent 8b52c6c7ac
commit b56a7579a8
4 changed files with 431 additions and 391 deletions

View File

@ -78,9 +78,9 @@ Feature: Simple Turns
| a | c | ab,bc | depart,arrive |
| a | d | ab,bd,bd | depart,turn right,arrive |
#https://www.openstreetmap.org/#map=19/52.50602/13.25468
# this scenario detects obvious correctly, but requires changes in collapsing roads
@todo
#https://www.openstreetmap.org/#map=19/52.50602/13.25468
# this scenario detects obvious correctly, but requires changes in collapsing roads
Scenario: Small offset due to large Intersection
Given the node map
"""
@ -99,12 +99,13 @@ Feature: Simple Turns
| df | residential |
When I route I should get
| from | to | route | turns |
| a | e | abc,bde,bde | depart,turn right,arrive |
| a | f | abc,df,df | depart,turn sharp right,arrive |
| from | to | route | turns |
| a | e | abc,bde,bde,bde | depart,turn right,continue left,arrive |
| a | f | abc,bde,df,df | depart,turn right,turn right,arrive |
# https://www.openstreetmap.org/#map=19/52.49709/13.26620
# https://www.openstreetmap.org/#map=19/52.49458/13.26273
# scenario requires handling in post-processing
@todo
Scenario: Offsets in road
Given a grid size of 3 meters
@ -160,7 +161,6 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=19/52.49198/13.28069
@todo
Scenario: Curved roads at turn
Given the node map
"""
@ -182,12 +182,11 @@ Feature: Simple Turns
| befg | residential | casper | yes |
When I route I should get
| from | to | route | turns |
| a | d | herbert,herbert | depart,arrive |
| a | g | herbert,casper,casper | depart,turn left,arrive |
| from | to | route | turns |
| a | d | herbert,herbert,herbert | depart,continue right,arrive |
| a | g | herbert,casper,casper | depart,turn left,arrive |
# https://www.openstreetmap.org/#map=19/52.49189/13.28431
@todo
Scenario: Turning residential
Given the node map
"""
@ -205,12 +204,11 @@ Feature: Simple Turns
| bd | residential | caspar | yes |
When I route I should get
| from | to | route | turns |
| a | c | bismark,bismark | depart,arrive |
| a | d | bismark,caspar,caspar | depart,turn left,arrive |
| from | to | route | turns |
| a | c | bismark,bismark,bismark | depart,continue right,arrive |
| a | d | bismark,caspar,caspar | depart,turn left,arrive |
# https://www.openstreetmap.org/#map=19/52.48681/13.28547
@todo
Scenario: Slight Loss in Category with turning road
Given the node map
"""
@ -225,7 +223,7 @@ Feature: Simple Turns
| nodes | highway | name |
| ab | tertiary | warm |
| bcd | residential | warm |
| begg | tertiary | paul |
| befg | tertiary | paul |
When I route I should get
| from | to | route | turns |
@ -304,7 +302,6 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=19/37.61256/-122.40371
@todo
Scenario: Turning Road with Offset at Segregated Intersection
Given the node map
"""
@ -327,10 +324,10 @@ Feature: Simple Turns
| icj | primary | camino | yes |
When I route I should get
| from | to | route | turns |
| a | g | park,diego,diego | depart,turn slight left,arrive |
| a | h | park,camino,camino | depart,turn left,arrive |
| a | j | park,camino,camino | depart,turn right,arrive |
| from | to | route | turns |
| a | g | park,diego,diego | depart,turn slight left,arrive |
| a | h | park,diego,camino,camino | depart,turn slight left,turn left,arrive |
| a | j | park,camino,camino | depart,turn right,arrive |
# https://www.openstreetmap.org/#map=19/37.76407/-122.49642
@ -356,6 +353,7 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=19/37.77072/-122.41727
# requires changes in post-processing
@todo
Scenario: Splitting road at traffic island before a turn
Given the node map
@ -390,6 +388,7 @@ Feature: Simple Turns
| e | a | ness,howard,howard | depart,turn slight right,arrive | |
# https://www.openstreetmap.org/#map=19/37.63171/-122.46205
# requires changes in post-processing
@todo
Scenario: Weird combination of turning roads
Given the node map
@ -432,7 +431,6 @@ Feature: Simple Turns
| d | n | depart,turn right,arrive | loop,drive,drive |
# https://www.openstreetmap.org/#map=19/37.26591/-121.84474
@todo
Scenario: Road splitting (unmerged)
Given the node map
"""
@ -456,15 +454,14 @@ Feature: Simple Turns
| hgfe | primary | lane | no |
When I route I should get
| from | to | route | turns |
| a | h | lane,lane | depart,arrive |
| a | i | lane,, | depart,turn right,arrive |
| h | d | lane,lane | depart,arrive |
| h | i | lane,, | depart,turn left,arrive |
| from | to | route | turns |
| a | h | lane,lane | depart,arrive |
| a | i | lane,, | depart,turn sharp right,arrive |
| h | d | lane,lane | depart,arrive |
| h | i | lane,, | depart,turn left,arrive |
# https://www.openstreetmap.org/#map=19/37.85108/-122.27078
@todo
Scenario: Turning Road category
Given the node map
"""
@ -474,9 +471,9 @@ Feature: Simple Turns
f c i
| | `
| j`
| ` | l
|k |.`
| |
| ` |
|k | l
| |.`
g b
| |
| |
@ -493,13 +490,12 @@ Feature: Simple Turns
When I route I should get
| from | to | route | turns |
| e | h | martin,adeline | depart,arrive |
| a | d | adeline,martin,martin | depart,turn slight left, arrive |
| e | h | martin,adeline,adeline | depart,turn straight,arrive |
| a | d | adeline,martin,martin | depart,turn slight left,arrive |
| a | l | adeline,adeline,adeline | depart,continue slight right,arrive |
| i | h | adeline,adeline | depart,arrive |
# https://www.openstreetmap.org/#map=19/37.76471/-122.49639
@todo
Scenario: Turning road
Given the node map
"""
@ -519,13 +515,12 @@ Feature: Simple Turns
| eghbi | secondary | 37 | yes |
When I route I should get
| from | to | route | turns |
| d | i | lincoln,37,37 | depart,turn left,arrive |
| d | f | lincoln,lincoln | depart,arrive |
| from | to | route | turns |
| d | i | lincoln,37,37 | depart,turn slight left,arrive |
| d | f | lincoln,lincoln | depart,arrive |
# https://www.openstreetmap.org/#map=19/37.63541/-122.48343
# https://www.openstreetmap.org/#map=19/52.47752/13.28864
@todo
Scenario: Road Splitting up
Given the node map
"""
@ -536,7 +531,7 @@ Feature: Simple Turns
a - - - - - - - - - b
`
`
`c
` c
"""
@ -551,6 +546,7 @@ Feature: Simple Turns
| a | d | vista,sierra,sierra | depart,turn left,arrive |
# https://www.openstreetmap.org/#map=19/52.45191/13.44113
# check service road handling in `is_similar_turn`
@todo
Scenario: Road Splitting up at a Driveway
Given the node map
@ -578,6 +574,7 @@ Feature: Simple Turns
| a | e | britz,, | depart,turn straight,arrive |
# https://www.openstreetmap.org/#map=20/37.62997/-122.49246
# test is mutually exclusive with features/guidance/fork.feature:27 "Scenario: Don't Fork On Single Road"
@todo
Scenario: Curving road with name-handoff
Given the node map
@ -601,11 +598,11 @@ Feature: Simple Turns
| lkjihd | residential | clare | yes |
When I route I should get
| from | to | route | turns |
| a | g | palm,clare,clare | depart,turn left,arrive |
| g | a | clare,palm,palm | depart,turn right,arrive |
| l | g | clare,clare | depart,arrive |
| l | a | clare,palm,palm | depart,turn left,arrive |
| from | to | route | turns |
| a | g | palm,clare,clare | depart,new name slight left,arrive |
| g | a | clare,palm,palm | depart,turn right,arrive |
| l | g | clare,clare | depart,arrive |
| l | a | clare,palm,palm | depart,turn left,arrive |
# https://www.openstreetmap.org/#map=19/37.84291/-122.23681
Scenario: Two roads turning into the same direction
@ -632,6 +629,9 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=19/37.82815/-122.28733
# the similarity check considers `bc` as non-similar to `bd` due to a name change "mandela"->"horton"
# this behavior is captured by features/guidance/turn.feature:126 "Scenario: Three Way Intersection"
# and is mutually exclusive with the test expectation
@todo
Scenario: Turning Secondary Next to Residential
Given the node map
@ -718,7 +718,6 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=19/37.63866/-122.46677
@todo
Scenario: Slightly offset traffic circle
Given the node map
"""
@ -735,13 +734,14 @@ Feature: Simple Turns
| abcdefghib | residential | road |
When I route I should get
| from | to | route | turns |
| a | e | road,road | depart,arrive |
| i | a | road,road | depart,arrive |
| d | a | road,road | depart,arrive |
| from | to | route | turns |
| a | e | road,road,road | depart,continue right,arrive |
| i | a | road,road,road | depart,continue right,arrive |
| d | a | road,road,road | depart,continue left,arrive |
# https://www.openstreetmap.org/#map=19/37.63829/-122.46345
# scenario geometry must be updated to catch the OSM map
@todo
Scenario: Entering a motorway (curved)
Given the node map
@ -767,7 +767,6 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=18/48.99155/8.43520
@todo
Scenario: Passing a motorway link on a trunk road
Given the node map
"""
@ -784,7 +783,7 @@ Feature: Simple Turns
When I route I should get
| from | to | route | turns |
| a | c | sued,sued | depart,arrive |
| a | d | sued,, | depart,on ramp right,arrive |
| a | d | sued,, | depart,off ramp slight right,arrive |
# https://www.openstreetmap.org/#map=19/48.98900/8.43800
@ -901,6 +900,8 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=19/48.99810/8.46749
# the test case depends on geometry: for `da` route both `no_name_change_to_candidate`
# and `compare_road_deviation_is_distinct` are true so `bc` is considered non-similar
@todo
Scenario: Slight End of Road
Given the node map
@ -952,6 +953,7 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=19/52.56562/13.39109
# the obviousness check depends on geometry at node `c`
@todo
Scenario: Dented Straight
Given the node map
@ -976,7 +978,6 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=17/52.57124/13.39892
@todo
Scenario: Primary road curved turn
Given the node map
"""
@ -996,23 +997,24 @@ Feature: Simple Turns
"""
And the ways
| nodes | highway | name | oneway |
| abc | primary | schoen | yes |
| cdef | primary | grab | yes |
| klm | primary | schoen | yes |
| ghijk | primary | grab | yes |
| cj | secondary_link | mann | yes |
| jo | secondary | mann | yes |
| pk | secondary | mann | yes |
| nodes | highway | name | oneway | lanes |
| abc | primary | schoen | yes | 2 |
| cdef | primary | grab | yes | 1 |
| klm | primary | schoen | yes | 2 |
| ghijk | primary | grab | yes | 1 |
| cj | secondary_link | mann | yes | 1 |
| jo | secondary | mann | yes | 1 |
| pk | secondary | mann | yes | 1 |
When I route I should get
| from | to | route | turns |
| a | f | schoen,grab,grab | depart,turn right,arrive |
| g | m | grab,schoen | depart,arrive |
| a | o | schoen,mann,mann | depart,turn slight left,arrive |
| from | to | route | turns |
| a | f | schoen,grab,grab | depart,turn slight right,arrive |
| g | m | grab,schoen | depart,arrive |
| a | o | schoen,mann,mann | depart,turn straight,arrive |
# https://www.openstreetmap.org/#map=18/52.55374/13.41462
# scenario for internal intersection collapsing
@todo
Scenario: Turn Links as Straights
Given the node map
@ -1047,7 +1049,6 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=19/52.56934/13.40131
@todo
Scenario: Crossing Segregated before a turn
Given the node map
"""
@ -1055,8 +1056,8 @@ Feature: Simple Turns
f - - - e -- ` `
| _-c
a - - -.b -- ` `
. `
g`
. `
g`
"""
And the ways
@ -1069,15 +1070,14 @@ Feature: Simple Turns
| be | secondary_link | no | woll |
When I route I should get
| from | to | route | turns |
| g | c | woll,brei,brei | depart,turn right,arrive |
| g | f | woll,scho,scho | depart,turn sharp left,arrive |
| a | c | scho,brei | depart,arrive |
| d | f | brei,scho | depart,arrive |
| from | to | route | turns |
| g | c | woll,brei,brei | depart,turn slight right,arrive |
| g | f | woll,scho,scho | depart,continue sharp left,arrive |
| a | c | scho,brei | depart,arrive |
| d | f | brei,scho | depart,arrive |
# https://www.openstreetmap.org/#map=19/52.58072/13.42985
@todo
Scenario: Trunk Turning into Motorway
Given the node map
"""
@ -1094,9 +1094,9 @@ Feature: Simple Turns
| bd | trunk_link | | yes |
When I route I should get
| from | to | route | turns |
| a | c | prenz, | depart,arrive |
| a | d | prenz,,, | depart,turn slight right,arrive |
| from | to | route | turns |
| a | c | prenz, | depart,arrive |
| a | d | prenz,, | depart,off ramp slight right,arrive |
# https://www.openstreetmap.org/#map=19/52.57800/13.42900
@ -1118,11 +1118,10 @@ Feature: Simple Turns
When I route I should get
| from | to | route | turns |
| a | c | dame,pase,pase | depart,new name straight,arrive |
| a | c | dame,pase,pase | depart,new name straight,arrive |
| a | e | dame,feuc,feuc | depart,turn slight right,arrive |
# https://www.openstreetmap.org/#map=19/52.48468/13.34532
@todo
Scenario: Forking into Tertiary
Given the node map
"""
@ -1139,8 +1138,8 @@ Feature: Simple Turns
When I route I should get
| from | to | route | turns |
| a | c | kenny,kenny,kenny | depart,fork slight right,arrive |
| a | d | kenny,domi,domi | depart,fork slight left,arrie |
| a | c | kenny,kenny,kenny | depart,continue straight,arrive |
| a | d | kenny,domi,domi | depart,turn slight left,arrive |
# https://www.openstreetmap.org/#map=18/52.56960/13.43815
Scenario: Turn onto classified
@ -1167,7 +1166,6 @@ Feature: Simple Turns
# https://www.openstreetmap.org/#map=18/52.50908/13.27312
@todo
Scenario: Merging onto a different street
Given the node map
"""
@ -1182,9 +1180,9 @@ Feature: Simple Turns
| dbc | primary | theo | yes |
When I route I should get
| from | to | route | turns |
| a | c | masu,theo | depart,arrive |
| d | c | theo,theo | depart,arrive |
| from | to | route | turns | # |
| a | c | masu,theo,theo | depart,turn straight,arrive | theo is a through street |
| d | c | theo,theo | depart,arrive | |
# https://www.openstreetmap.org/#map=18/52.51299/13.28936
Scenario: Lanes override road classes

View File

@ -848,6 +848,7 @@ Feature: Simple Turns
| h,a | Heide,Perle,Perle | depart,turn left,arrive | true:16;true:90 true:195 true:270 true:345;true:90 |
#http://www.openstreetmap.org/#map=19/52.53293/13.32956
# adjusted ways to reflect the case geometry for 2/3/2018
Scenario: Curved Exit from Curved Road
Given the node map
"""
@ -874,16 +875,16 @@ Feature: Simple Turns
And the ways
| nodes | name | oneway | lanes | highway |
| abcd | Siemens | no | 5 | secondary |
| defg | Erna | no | 3 | secondary |
| ab | Siemens | no | 5 | secondary |
| bcdefg | Erna | no | 3 | secondary |
| dhij | Siemens | no | | residential |
When I route I should get
| waypoints | route | turns |
| a,j | Siemens,Siemens,Siemens | depart,continue slight right,arrive |
| a,g | Siemens,Erna | depart,arrive |
| g,j | Erna,Siemens,Siemens | depart,turn left,arrive |
| g,a | Erna,Siemens | depart,arrive |
| waypoints | route | turns |
| a,j | Siemens,Siemens,Siemens | depart,turn slight right,arrive |
| a,g | Siemens,Erna | depart,arrive |
| g,j | Erna,Siemens,Siemens | depart,turn left,arrive |
| g,a | Erna,Siemens | depart,arrive |
#http://www.openstreetmap.org/#map=19/52.51303/13.32170
Scenario: Ernst Reuter Platz

View File

@ -135,23 +135,34 @@ inline bool canBeSeenAsFork(const RoadClassification first, const RoadClassifica
}
// priority groups are road classes that can be categoriesed as somewhat similar
inline std::uint32_t getRoadGroup(const RoadClassification classification)
inline std::uint8_t getRoadGroup(const RoadClassification classification)
{
// a list of dividers (inclusive) specifying the end of a class
const auto constexpr num_dividers = 7;
// dividers point one past the entry we want, so motorways will be pre-primary
const constexpr RoadPriorityClass::Enum dividers[num_dividers] = {
RoadPriorityClass::PRIMARY,
RoadPriorityClass::TERTIARY_LINK,
RoadPriorityClass::ALLEY,
RoadPriorityClass::LINK_ROAD,
RoadPriorityClass::UNCLASSIFIED,
RoadPriorityClass::BIKE_PATH,
RoadPriorityClass::CONNECTIVITY + 1};
const constexpr std::uint8_t groups[RoadPriorityClass::CONNECTIVITY + 1] = {
0, // MOTORWAY
0, // MOTORWAY_LINK
1, // TRUNK
1, // TRUNK_LINK
2, // PRIMARY
2, // PRIMARY_LINK
2, // SECONDARY
2, // SECONDARY_LINK
2, // TERTIARY
2, // TERTIARY_LINK
3, // MAIN_RESIDENTIAL
3, // SIDE_RESIDENTIAL
3, // ALLEY
3, // PARKING
4, // LINK_ROAD
4, // UNCLASSIFIED
5, // BIKE_PATH
6, // FOOT_PATH
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7 // CONNECTIVITY
};
const auto upper =
std::upper_bound(dividers, dividers + num_dividers, classification.GetPriority());
return upper - dividers;
BOOST_ASSERT(groups[RoadPriorityClass::CONNECTIVITY] == 7);
return groups[classification.GetPriority()];
}
// LHS road classification is strictly less than RHS, if it belongs to a lower general category

View File

@ -20,8 +20,6 @@
#include <boost/optional.hpp>
static std::mutex mmm;
namespace osrm
{
namespace guidance
@ -71,6 +69,14 @@ class IntersectionHandler
TurnType::Enum areSameClasses(const EdgeID via_edge, const ConnectedRoad &road) const;
template <typename IntersectionType>
inline bool IsDistinctNarrowTurn(const EdgeID via_edge,
const typename IntersectionType::const_iterator candidate,
const IntersectionType &intersection) const;
template <typename IntersectionType>
inline bool IsDistinctWideTurn(const EdgeID via_edge,
const typename IntersectionType::const_iterator candidate,
const IntersectionType &intersection) const;
template <typename IntersectionType>
inline bool IsDistinctTurn(const EdgeID via_edge,
const typename IntersectionType::const_iterator candidate,
@ -83,14 +89,6 @@ class IntersectionHandler
template <typename IntersectionType> // works with Intersection and IntersectionView
std::size_t findObviousTurn(const EdgeID via_edge, const IntersectionType &intersection) const;
template <typename IntersectionType> // works with Intersection and IntersectionView
std::size_t findObviousTurnOld(const EdgeID via_edge,
const IntersectionType &intersection) const;
template <typename IntersectionType> // works with Intersection and IntersectionView
std::size_t findObviousTurnNew(const EdgeID via_edge,
const IntersectionType &intersection) const;
// Obvious turns can still take multiple forms. This function looks at the turn onto a road
// candidate when coming from a via_edge and determines the best instruction to emit.
// `through_street` indicates if the street turned onto is a through sreet (think mergees and
@ -139,11 +137,48 @@ class IntersectionHandler
bool isSameName(const EdgeID source_edge_id, const EdgeID target_edge_id) const;
};
// Implementation
namespace
{
inline bool roadHasLowerClass(const util::NodeBasedEdgeData &from_data,
const util::NodeBasedEdgeData &to_data,
const util::NodeBasedEdgeData &compare_data)
{
// Check if a road has a strictly lower category
const auto from_classification = from_data.flags.road_classification;
const auto to_classification = to_data.flags.road_classification;
const auto compare_classification = compare_data.flags.road_classification;
const auto from_lanes_number = from_classification.GetNumberOfLanes();
const auto compare_lanes_number = compare_classification.GetNumberOfLanes();
// 1) if the road has strictly less classification than the incoming candidate roads
// and has smaller number of lanes
const auto lanes_number_reduced =
compare_lanes_number > 0 && compare_lanes_number + 1 < from_lanes_number;
if (strictlyLess(compare_classification, from_classification) &&
strictlyLess(compare_classification, to_classification) && lanes_number_reduced)
{
return true;
}
// 2) if a link of the same category
if (isLinkTo(compare_classification, from_classification) &&
isLinkTo(compare_classification, to_classification))
{
return true;
}
return false;
}
}
template <typename IntersectionType> // works with Intersection and IntersectionView
inline bool
IntersectionHandler::IsDistinctTurn(const EdgeID via_edge,
const typename IntersectionType::const_iterator candidate,
const IntersectionType &intersection) const
IntersectionHandler::IsDistinctNarrowTurn(const EdgeID via_edge,
const typename IntersectionType::const_iterator candidate,
const IntersectionType &intersection) const
{
const auto &via_edge_data = node_based_graph.GetEdgeData(via_edge);
const auto &via_edge_annotation =
@ -163,300 +198,293 @@ IntersectionHandler::IsDistinctTurn(const EdgeID via_edge,
return num_lanes(compare_data) > 0 && num_lanes(compare_data) == num_lanes(via_edge_data);
};
auto const lanes_number_reduced = [&](auto const &compare_data) {
// Check if the lanes number is reduced going from the inbound edge to the compare road
return num_lanes(compare_data) > 0 &&
num_lanes(compare_data) + 1 < num_lanes(via_edge_data);
};
// In case of narrow turns, we apply different criteria than for actual turns. In case of a
// narrow turn, having two choices one of which is forbidden is fine. In case of a end of
// the road turn, having two directions and not being allowed to turn onto one of them isn't
// always as clear
auto const road_has_lower_class = [&](auto const &road) {
// Check if a road has a strictly lower category and can be ignored:
// check if the candidate road changes it's name
auto const no_name_change_to_candidate =
!util::guidance::requiresNameAnnounced(via_edge_annotation.name_id,
candidate_annotation.name_id,
name_table,
street_name_suffix_table);
// check if there are other narrow turns are not considered passing a low category or simply
// a link of the same type as the potentially obvious turn
auto const is_similar_turn = [&](auto const &road) {
// 1. Skip the candidate road
if (road.eid == candidate->eid)
{
return false;
}
// 2. For candidates with narrow turns don't consider not allowed entries
if (candidate_deviation < NARROW_TURN_ANGLE && !road.entry_allowed)
{
return false;
}
auto const compare_deviation = util::angularDeviation(road.angle, STRAIGHT_ANGLE);
auto const &compare_data = node_based_graph.GetEdgeData(road.eid);
auto const &compare_annotation =
node_data_container.GetAnnotation(compare_data.annotation_data);
// 1) if the road has strictly less classification than the incoming candidate roads
// and has smaller number of lanes
if (strictlyLess(compare_data.flags.road_classification,
via_edge_data.flags.road_classification) &&
strictlyLess(compare_data.flags.road_classification,
candidate_data.flags.road_classification) &&
lanes_number_reduced(compare_data))
auto const is_lane_fork =
num_lanes(compare_data) > 0 && num_lanes(candidate_data) == num_lanes(compare_data) &&
num_lanes(via_edge_data) == num_lanes(candidate_data) + num_lanes(compare_data) &&
util::angularDeviation(candidate->angle, road.angle) < GROUP_ANGLE;
auto const compare_road_deviation_is_distinct =
compare_deviation > DISTINCTION_RATIO * candidate_deviation &&
std::abs(compare_deviation - candidate_deviation) > FUZZY_ANGLE_DIFFERENCE / 2.;
const auto compare_road_deviation_is_slightly_distinct =
compare_deviation > 0.7 * DISTINCTION_RATIO * candidate_deviation;
// 3. Small side-roads that are marked restricted are not similar to unrestricted roads
if (!via_edge_data.flags.restricted && !candidate_data.flags.restricted &&
compare_data.flags.restricted && compare_road_deviation_is_distinct)
{
return true;
return false;
}
// 2) if a link of the same category
if (isLinkTo(compare_data.flags.road_classification,
via_edge_data.flags.road_classification) &&
isLinkTo(compare_data.flags.road_classification,
candidate_data.flags.road_classification))
// 4. Roundabout exits with larger deviations wrt candidate roads are not similar
if (via_edge_data.flags.roundabout == candidate_data.flags.roundabout &&
via_edge_data.flags.roundabout != compare_data.flags.roundabout &&
candidate_deviation < compare_deviation)
{
return true;
return false;
}
return false;
};
// 5. Similarity check based on name changes
auto const name_changes_to_compare =
util::guidance::requiresNameAnnounced(via_edge_annotation.name_id,
compare_annotation.name_id,
name_table,
street_name_suffix_table);
if (candidate_deviation < GROUP_ANGLE)
{
// In case of narrow turns, we apply different criteria than for actual turns. In case of a
// narrow turn, having two choices one of which is forbidden is fine. In case of a end of
// the road turn, having two directions and not being allowed to turn onto one of them isn't
// always as clear
if ((no_name_change_to_candidate || name_changes_to_compare) && !is_lane_fork &&
compare_road_deviation_is_distinct)
{
return false;
}
// check if the candidate road changes it's name
auto const no_name_change_to_candidate =
!util::guidance::requiresNameAnnounced(via_edge_annotation.name_id,
candidate_annotation.name_id,
// 6. If the road has a continuation on the opposite side of intersection
// it can not be similar to the candidate road
auto const opposing_turn =
intersection.FindClosestBearing(util::bearing::reverse(road.perceived_bearing));
auto const &opposing_data = node_based_graph.GetEdgeData(opposing_turn->eid);
auto const &opposing_annotation =
node_data_container.GetAnnotation(opposing_data.annotation_data);
auto const four_or_more_ways_intersection = intersection.size() >= 4;
auto const no_name_change_to_compare_from_opposing =
!util::guidance::requiresNameAnnounced(opposing_annotation.name_id,
compare_annotation.name_id,
name_table,
street_name_suffix_table);
// check if there are other narrow turns are not considered passing a low category or simply
// a link of the same type as the potentially obvious turn
auto const is_similar_turn = [&](auto const &road) {
const auto opposing_to_compare_angle =
util::angularDeviation(road.angle, opposing_turn->angle);
// 1. Skip the candidate road
if (road.eid == candidate->eid)
auto const opposing_to_compare_road_is_distinct =
no_name_change_to_compare_from_opposing ||
opposing_to_compare_angle > (STRAIGHT_ANGLE - NARROW_TURN_ANGLE);
if (four_or_more_ways_intersection && opposing_to_compare_road_is_distinct &&
compare_road_deviation_is_distinct)
{
return false;
}
if (four_or_more_ways_intersection && no_name_change_to_candidate &&
name_changes_to_compare && compare_road_deviation_is_slightly_distinct &&
no_name_change_to_compare_from_opposing &&
opposing_to_compare_angle > STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE)
{
return false;
}
if (!four_or_more_ways_intersection && no_name_change_to_candidate &&
name_changes_to_compare && compare_road_deviation_is_distinct && !is_lane_fork &&
opposing_to_compare_angle > STRAIGHT_ANGLE - GROUP_ANGLE)
{
return false;
}
// 7. If the inbound road has low priority, consider all distinct roads as non-similar
auto const from_non_main_road_class =
via_edge_data.flags.road_classification.GetPriority() >
extractor::RoadPriorityClass::SECONDARY;
if (from_non_main_road_class && compare_road_deviation_is_distinct)
{
return false;
}
// 8. Consider roads non-similar if the candidate road has the same number
// of lanes and has quite small deviation from straightforward direction
// a=a=a + b=b=b
// ` c-c
if (lanes_number_equal(candidate_data) && candidate_deviation < FUZZY_ANGLE_DIFFERENCE &&
compare_road_deviation_is_distinct)
{
return false;
}
// 9. Priority checks
const auto same_priority_to_candidate =
via_edge_data.flags.road_classification.GetPriority() ==
candidate_data.flags.road_classification.GetPriority();
const auto compare_has_lower_class =
candidate_data.flags.road_classification.GetPriority() <
compare_data.flags.road_classification.GetPriority();
const auto compare_has_higher_class =
candidate_data.flags.road_classification.GetPriority() >
compare_data.flags.road_classification.GetPriority() + 4;
if (same_priority_to_candidate && compare_has_lower_class && no_name_change_to_candidate &&
compare_road_deviation_is_slightly_distinct)
{
return false;
}
if (same_priority_to_candidate && compare_has_higher_class && no_name_change_to_candidate &&
compare_road_deviation_is_slightly_distinct)
{
return false;
}
if (roadHasLowerClass(via_edge_data, candidate_data, compare_data))
{
return false;
}
const auto candidate_road_has_same_priority_group =
via_edge_data.flags.road_classification.GetPriority() ==
candidate_data.flags.road_classification.GetPriority();
const auto compare_road_has_lower_priority_group =
extractor::getRoadGroup(via_edge_data.flags.road_classification) <
extractor::getRoadGroup(compare_data.flags.road_classification);
auto const candidate_and_compare_have_different_names =
util::guidance::requiresNameAnnounced(candidate_annotation.name_id,
compare_annotation.name_id,
name_table,
street_name_suffix_table);
if (candidate_road_has_same_priority_group && compare_road_has_lower_priority_group &&
candidate_and_compare_have_different_names && name_changes_to_compare)
{
return false;
}
if (candidate_road_has_same_priority_group &&
compare_data.flags.road_classification.IsLinkClass())
{
return false;
}
return true;
};
return std::find_if(intersection.begin() + 1, intersection.end(), is_similar_turn) ==
intersection.end();
}
template <typename IntersectionType>
inline bool
IntersectionHandler::IsDistinctWideTurn(const EdgeID via_edge,
const typename IntersectionType::const_iterator candidate,
const IntersectionType &intersection) const
{
const auto &via_edge_data = node_based_graph.GetEdgeData(via_edge);
const auto &candidate_data = node_based_graph.GetEdgeData(candidate->eid);
auto const candidate_deviation = util::angularDeviation(candidate->angle, STRAIGHT_ANGLE);
// Deviation is larger than NARROW_TURN_ANGLE0 here for the candidate
// check if there is any turn, that might look just as obvious, even though it might not
// be allowed. Entry-allowed isn't considered a valid distinction criterion here
auto const is_similar_turn = [&](auto const &road) {
// 1. Skip over our candidate
if (road.eid == candidate->eid)
return false;
// we do not consider roads of far lesser category to be more obvious
const auto &compare_data = node_based_graph.GetEdgeData(road.eid);
const auto compare_deviation = util::angularDeviation(road.angle, STRAIGHT_ANGLE);
const auto is_compare_straight =
getTurnDirection(road.angle) == DirectionModifier::Straight;
// 2. Don't consider similarity if a compare road is non-straight and has lower class
if (!is_compare_straight && roadHasLowerClass(via_edge_data, candidate_data, compare_data))
{
return false;
}
// 3. If the turn is much stronger, we are also fine (note that we do not have to check
// absolutes, since candidate is at least > NARROW_TURN_ANGLE)
auto const compare_road_deviation_is_distinct =
compare_deviation > DISTINCTION_RATIO * candidate_deviation;
if (compare_road_deviation_is_distinct)
{
return false;
}
// 4. If initial and adjusted bearings are quite different then check deviations
// computed in the vicinity of the intersection point based in initial bearings:
// road is not similar to candidate if a road-to-candidate is not a straight direction
// and road has distinctive deviation.
if (util::angularDeviation(intersection[0].initial_bearing,
intersection[0].perceived_bearing) > FUZZY_ANGLE_DIFFERENCE)
{
using osrm::util::bearing::reverse;
using osrm::util::bearing::angleBetween;
using osrm::util::angularDeviation;
const auto via_edge_initial_bearing = reverse(intersection[0].initial_bearing);
const auto candidate_deviation_initial = angularDeviation(
angleBetween(via_edge_initial_bearing, candidate->initial_bearing), STRAIGHT_ANGLE);
const auto road_deviation_initial = angularDeviation(
angleBetween(via_edge_initial_bearing, road.initial_bearing), STRAIGHT_ANGLE);
const auto road_to_candidate_angle =
angleBetween(reverse(road.initial_bearing), candidate->initial_bearing);
const auto is_straight_road_to_candidate =
getTurnDirection(road_to_candidate_angle) == DirectionModifier::Straight;
if (!is_straight_road_to_candidate &&
road_deviation_initial > DISTINCTION_RATIO * candidate_deviation_initial)
{
return false;
}
}
// 2. For candidates with narrow turns don't consider not allowed entries
if (candidate_deviation < NARROW_TURN_ANGLE && !road.entry_allowed)
{
return false;
}
return true;
};
auto const compare_deviation = util::angularDeviation(road.angle, STRAIGHT_ANGLE);
auto const &compare_data = node_based_graph.GetEdgeData(road.eid);
auto const &compare_annotation =
node_data_container.GetAnnotation(compare_data.annotation_data);
return std::find_if(intersection.begin() + 1, intersection.end(), is_similar_turn) ==
intersection.end();
}
auto const compare_road_deviation_is_distinct =
compare_deviation > DISTINCTION_RATIO * candidate_deviation &&
std::abs(compare_deviation - candidate_deviation) > FUZZY_ANGLE_DIFFERENCE / 2.;
template <typename IntersectionType>
inline bool
IntersectionHandler::IsDistinctTurn(const EdgeID via_edge,
const typename IntersectionType::const_iterator candidate,
const IntersectionType &intersection) const
{
auto const candidate_deviation = util::angularDeviation(candidate->angle, STRAIGHT_ANGLE);
const auto compare_road_deviation_is_slightly_distinct =
compare_deviation > 0.7 * DISTINCTION_RATIO * candidate_deviation;
// 3. Small side-roads that are marked restricted are not similar to unrestricted roads
if (!via_edge_data.flags.restricted && !candidate_data.flags.restricted &&
compare_data.flags.restricted && compare_road_deviation_is_distinct)
{
return false;
}
// 4. Roundabout exits with larger deviations wrt candidate roads are not similar
if (via_edge_data.flags.roundabout == candidate_data.flags.roundabout &&
via_edge_data.flags.roundabout != compare_data.flags.roundabout &&
candidate_deviation < compare_deviation)
{
return false;
}
// 5. Similarity check based on name changes
auto const name_changes_to_compare =
util::guidance::requiresNameAnnounced(via_edge_annotation.name_id,
compare_annotation.name_id,
name_table,
street_name_suffix_table);
if ((no_name_change_to_candidate || name_changes_to_compare) &&
compare_road_deviation_is_distinct)
{
return false;
}
// 6. If the road has a continuation on the opposite side of intersection
// it can not be similar to the candidate road
auto const opposing_turn =
intersection.FindClosestBearing(util::bearing::reverse(road.perceived_bearing));
auto const &opposing_data = node_based_graph.GetEdgeData(opposing_turn->eid);
auto const &opposing_annotation =
node_data_container.GetAnnotation(opposing_data.annotation_data);
auto const four_or_more_ways_intersection = intersection.size() >= 4;
auto const no_name_change_to_compare_from_opposing =
!util::guidance::requiresNameAnnounced(opposing_annotation.name_id,
compare_annotation.name_id,
name_table,
street_name_suffix_table);
const auto opposing_to_compare_angle =
util::angularDeviation(road.angle, opposing_turn->angle);
auto const opposing_to_compare_road_is_distinct =
no_name_change_to_compare_from_opposing ||
opposing_to_compare_angle > (STRAIGHT_ANGLE - NARROW_TURN_ANGLE);
if (four_or_more_ways_intersection && opposing_to_compare_road_is_distinct &&
compare_road_deviation_is_distinct)
{
return false;
}
if (four_or_more_ways_intersection && no_name_change_to_candidate &&
name_changes_to_compare && compare_road_deviation_is_slightly_distinct &&
no_name_change_to_compare_from_opposing &&
opposing_to_compare_angle > STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE)
{
return false;
}
if (!four_or_more_ways_intersection && no_name_change_to_candidate &&
name_changes_to_compare && compare_road_deviation_is_distinct &&
opposing_to_compare_angle > STRAIGHT_ANGLE - GROUP_ANGLE)
{
return false;
}
// 7. If the inbound road has low priority, consider all distinct roads as non-similar
auto const from_non_main_road_class =
via_edge_data.flags.road_classification.GetPriority() >
extractor::RoadPriorityClass::SECONDARY;
if (from_non_main_road_class && compare_road_deviation_is_distinct)
{
return false;
}
// 8. Consider roads non-similar if the candidate road has the same number
// of lanes and has quite small deviation from straightforward direction
// a=a=a + b=b=b
// ` c-c
if (lanes_number_equal(candidate_data) &&
candidate_deviation < FUZZY_ANGLE_DIFFERENCE && compare_road_deviation_is_distinct)
{
return false;
}
// 9. Priority checks
const auto same_priority_to_candidate =
via_edge_data.flags.road_classification.GetPriority() ==
candidate_data.flags.road_classification.GetPriority();
const auto compare_has_lower_class =
candidate_data.flags.road_classification.GetPriority() <
compare_data.flags.road_classification.GetPriority();
const auto compare_has_higher_class =
candidate_data.flags.road_classification.GetPriority() >
compare_data.flags.road_classification.GetPriority() + 4;
if (same_priority_to_candidate && compare_has_lower_class &&
no_name_change_to_candidate && compare_road_deviation_is_slightly_distinct)
{
return false;
}
if (same_priority_to_candidate && compare_has_higher_class &&
no_name_change_to_candidate && compare_road_deviation_is_slightly_distinct)
{
return false;
}
if (road_has_lower_class(road))
{
return false;
}
const auto candidate_road_has_same_priority_group =
via_edge_data.flags.road_classification.GetPriority() ==
candidate_data.flags.road_classification.GetPriority();
const auto compare_road_has_lower_priority_group =
extractor::getRoadGroup(via_edge_data.flags.road_classification) <
extractor::getRoadGroup(compare_data.flags.road_classification);
auto const candidate_and_compare_have_different_names =
util::guidance::requiresNameAnnounced(candidate_annotation.name_id,
compare_annotation.name_id,
name_table,
street_name_suffix_table);
if (candidate_road_has_same_priority_group && compare_road_has_lower_priority_group &&
candidate_and_compare_have_different_names)
{
return false;
}
if (candidate_road_has_same_priority_group &&
compare_data.flags.road_classification.IsLinkClass())
{
return false;
}
return true;
};
return std::find_if(intersection.begin() + 1, intersection.end(), is_similar_turn) ==
intersection.end();
}
else
if (candidate_deviation < GROUP_ANGLE)
{
// Deviation is larger than NARROW_TURN_ANGLE0 here for the candidate
// check if there is any turn, that might look just as obvious, even though it might not
// be allowed. Entry-allowed isn't considered a valid distinction criterion here
auto const is_similar_turn = [&](auto const &road) {
// 1. Skip over our candidate
if (road.eid == candidate->eid)
return false;
// we do not consider roads of far lesser category to be more obvious
// const auto &compare_data = node_based_graph.GetEdgeData(road.eid);
const auto compare_deviation = util::angularDeviation(road.angle, STRAIGHT_ANGLE);
const auto is_compare_straight =
getTurnDirection(road.angle) == DirectionModifier::Straight;
// 2. Don't consider similarity if a compare road is non-straight and has lower class
if (!is_compare_straight && road_has_lower_class(road))
{
return false;
}
// 3. If the turn is much stronger, we are also fine (note that we do not have to check
// absolutes, since candidate is at least > NARROW_TURN_ANGLE)
auto const compare_road_deviation_is_distinct =
compare_deviation > DISTINCTION_RATIO * candidate_deviation;
if (compare_road_deviation_is_distinct)
{
return false;
}
// 4. If initial and adjusted bearings are quite different then check deviations
// computed in the vicinity of the intersection point based in initial bearings:
// road is not similar to candidate if a road-to-candidate is not a straight direction
// and road has distinctive deviation.
if (util::angularDeviation(intersection[0].initial_bearing,
intersection[0].perceived_bearing) > FUZZY_ANGLE_DIFFERENCE)
{
using osrm::util::bearing::reverse;
using osrm::util::bearing::angleBetween;
using osrm::util::angularDeviation;
const auto via_edge_initial_bearing = reverse(intersection[0].initial_bearing);
const auto candidate_deviation_initial = angularDeviation(
angleBetween(via_edge_initial_bearing, candidate->initial_bearing),
STRAIGHT_ANGLE);
const auto road_deviation_initial = angularDeviation(
angleBetween(via_edge_initial_bearing, road.initial_bearing), STRAIGHT_ANGLE);
const auto road_to_candidate_angle =
angleBetween(reverse(road.initial_bearing), candidate->initial_bearing);
const auto is_straight_road_to_candidate =
getTurnDirection(road_to_candidate_angle) == DirectionModifier::Straight;
if (!is_straight_road_to_candidate &&
road_deviation_initial > DISTINCTION_RATIO * candidate_deviation_initial)
{
return false;
}
}
return true;
};
return std::find_if(intersection.begin() + 1, intersection.end(), is_similar_turn) ==
intersection.end();
return IsDistinctNarrowTurn(via_edge, candidate, intersection);
}
return IsDistinctWideTurn(via_edge, candidate, intersection);
}
// Impl.
@ -613,14 +641,16 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
}
// Special case handling for roads splitting up, all the same name (exactly the same)
if (intersection.size() == 3 &&
const auto all_roads_have_same_name =
std::all_of(intersection.begin(),
intersection.end(),
[ id = via_edge_annotation.name_id, this ](auto const &road) {
auto const data_id = node_based_graph.GetEdgeData(road.eid).annotation_data;
auto const name_id = node_data_container.GetAnnotation(data_id).name_id;
return (name_id != EMPTY_NAMEID) && (name_id == id);
}) &&
});
if (intersection.size() == 3 && all_roads_have_same_name &&
intersection.countEnterable() == 1 &&
// ensure that we do not lookt at a end of the road turn in a segregated intersection
(util::angularDeviation(intersection[1].angle, 90) > NARROW_TURN_ANGLE ||