Merge pull request #3217 from Project-OSRM/refactor/obviousness

Refactor find obvious turn handling
This commit is contained in:
Karen Shea 2016-11-21 14:50:44 -05:00 committed by GitHub
commit 6d961d4a15
4 changed files with 313 additions and 160 deletions

View File

@ -947,11 +947,12 @@ Feature: Collapse
#http://www.openstreetmap.org/#map=19/52.48778/13.30024 #http://www.openstreetmap.org/#map=19/52.48778/13.30024
Scenario: Hohenzollerdammbrücke Scenario: Hohenzollerdammbrücke
Given a grid size of 10 meters
Given the node map Given the node map
""" """
q s q s
p o p o
.. . . .. ..
. . . . . . . .
j - i - - - h - - - g - f j - i - - - h - - - g - f
> k < > l < > k < > l <
@ -1013,13 +1014,13 @@ Feature: Collapse
| restriction | ph | hi | h | no_right_turn | | restriction | ph | hi | h | no_right_turn |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns | locations |
| a,e | hohe,hohe | depart,arrive | | a,e | hohe,hohe | depart,arrive | a,e |
| a,s | hohe,a100,a100 | depart,on ramp left,arrive | | a,s | hohe,a100,a100 | depart,on ramp left,arrive | a,b,s |
| a,t | hohe,a100,a100 | depart,on ramp right,arrive | | a,t | hohe,a100,a100 | depart,on ramp right,arrive | a,b,t |
| a,j | | | | a,j | | | |
| f,j | hohe,hohe | depart,arrive | | f,j | hohe,hohe | depart,arrive | f,j |
| a,t | hohe,a100,a100 | depart,on ramp right,arrive | | a,t | hohe,a100,a100 | depart,on ramp right,arrive | a,b,t |
| f,e | | | | f,e | | | |
| q,j | a100,hohe,hohe | depart,turn right,arrive | | q,j | a100,hohe,hohe | depart,turn right,arrive | q,p,j |
| q,e | a100,a100,hohe | depart,continue left,arrive | | q,e | a100,hohebruecke,hohe | depart,turn left,arrive | q,p,e |

View File

@ -0,0 +1,119 @@
@routing @guidance
Feature: Exceptions for routing onto low-priority roads
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Straight onto low-priority: same name
Given the node map
"""
c
a b d
e
"""
And the ways
| nodes | highway | name |
| abd | residential | road |
| eb | service | service |
| bc | service | service |
When I route I should get
| waypoints | route | turns |
| c,e | service,service | depart,arrive |
| e,c | service,service | depart,arrive |
Scenario: Straight onto low-priority: onto and from unnamed
Given the node map
"""
c
a b d
e
"""
And the ways
| nodes | highway | name |
| abd | residential | road |
| eb | service | |
| bc | service | |
When I route I should get
| waypoints | route | turns |
| e,c | , | depart,arrive |
| c,e | , | depart,arrive |
Scenario: Straight onto low-priority: unnamed
Given the node map
"""
c
a b d
e
"""
And the ways
| nodes | highway | name |
| abd | residential | road |
| eb | service | service |
| bc | service | |
When I route I should get
| waypoints | route | turns |
| e,c | service, | depart,arrive |
| c,e | ,service,service | depart,turn straight,arrive |
Scenario: Straight onto low-priority
Given the node map
"""
a b c
"""
And the ways
| nodes | highway | name |
| ab | residential | road |
| bc | service | service |
When I route I should get
| waypoints | route | turns |
| a,c | road,service,service | depart,new name straight,arrive |
Scenario: Straight onto low-priority, with driveway
Given the node map
"""
f
a b c
"""
And the ways
| nodes | highway | name |
| ab | residential | road |
| bc | service | road |
| bf | driveway | |
When I route I should get
| waypoints | route | turns |
| a,c | road,road | depart,arrive |
Scenario: Straight onto low-priority, with driveway
Given the node map
"""
f
a b c
"""
And the ways
| nodes | highway | name |
| ab | residential | road |
| bc | service | |
| bf | driveway | |
When I route I should get
| waypoints | route | turns |
| a,c | road, | depart,arrive |
| c,a | ,road,road | depart,new name straight,arrive |

View File

@ -165,6 +165,7 @@ inline bool obviousByRoadClass(const RoadClassification in_classification,
const RoadClassification obvious_candidate, const RoadClassification obvious_candidate,
const RoadClassification compare_candidate) const RoadClassification compare_candidate)
{ {
// lower numbers are of higher priority
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() < const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
compare_candidate.GetPriority(); compare_candidate.GetPriority();

View File

@ -1,5 +1,5 @@
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
@ -383,186 +383,210 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
if (intersection.size() == 2) if (intersection.size() == 2)
return 1; return 1;
// at least three roads const EdgeData &in_way_data = node_based_graph.GetEdgeData(via_edge);
std::size_t best = 0;
double best_deviation = 180;
// the strategy for picking the most obvious turn involves deciding between
// an overall best candidate and a best candidate that shares the same name
// as the in road, i.e. a continue road
std::size_t best_option = 0;
double best_option_deviation = 180;
std::size_t best_continue = 0; std::size_t best_continue = 0;
double best_continue_deviation = 180; double best_continue_deviation = 180;
const EdgeData &in_data = node_based_graph.GetEdgeData(via_edge); /* helper functions */
const auto in_classification = in_data.road_classification; const auto IsContinueRoad = [&](const EdgeData &way_data) {
return !util::guidance::requiresNameAnnounced(
in_way_data.name_id, way_data.name_id, name_table, street_name_suffix_table);
};
auto sameOrHigherPriority = [&in_way_data](const auto &way_data) {
return way_data.road_classification.GetPriority() <=
in_way_data.road_classification.GetPriority();
};
auto IsLowPriority = [](const auto &way_data) {
return way_data.road_classification.IsLowPriorityRoadClass();
};
// These two Compare functions are used for sifting out best option and continue
// candidates by evaluating all the ways in an intersection by what they share
// with the in way. Ideal candidates are of similar road class with the in way
// and are require relatively straight turns.
const auto RoadCompare = [&](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
const auto lhs_deviation = angularDeviation(lhs.angle, STRAIGHT_ANGLE);
const auto rhs_deviation = angularDeviation(rhs.angle, STRAIGHT_ANGLE);
for (std::size_t i = 1; i < intersection.size(); ++i) const bool rhs_same_classification =
rhs_data.road_classification == in_way_data.road_classification;
const bool lhs_same_classification =
lhs_data.road_classification == in_way_data.road_classification;
const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_data);
const bool rhs_low_priority = IsLowPriority(rhs_data);
const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_data);
const bool lhs_low_priority = IsLowPriority(lhs_data);
auto left_tie = std::tie(lhs.entry_allowed,
lhs_same_or_higher_priority,
rhs_low_priority,
rhs_deviation,
lhs_same_classification);
auto right_tie = std::tie(rhs.entry_allowed,
rhs_same_or_higher_priority,
lhs_low_priority,
lhs_deviation,
rhs_same_classification);
return left_tie > right_tie;
};
const auto RoadCompareSameName = [&](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
const auto lhs_continues = IsContinueRoad(lhs_data);
const auto rhs_continues = IsContinueRoad(rhs_data);
const auto left_tie = std::tie(lhs.entry_allowed, lhs_continues);
const auto right_tie = std::tie(rhs.entry_allowed, rhs_continues);
return left_tie > right_tie || (left_tie == right_tie && RoadCompare(lhs, rhs));
};
auto best_option_it = std::min_element(begin(intersection), end(intersection), RoadCompare);
// min element should only return end() when vector is empty
BOOST_ASSERT(best_option_it != end(intersection));
best_option = std::distance(begin(intersection), best_option_it);
best_option_deviation = angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
const auto &best_option_data = node_based_graph.GetEdgeData(intersection[best_option].eid);
// Unless the in way is also low priority, it is generally undesirable to
// indicate that a low priority road is obvious
if (IsLowPriority(best_option_data) &&
best_option_data.road_classification != in_way_data.road_classification)
{ {
const double deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE); best_option = 0;
if (!intersection[i].entry_allowed) best_option_deviation = 180;
continue;
const auto out_data = node_based_graph.GetEdgeData(intersection[i].eid);
const auto continue_class =
node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification;
const auto same_name = !util::guidance::requiresNameAnnounced(
in_data.name_id, out_data.name_id, name_table, street_name_suffix_table);
if (same_name && (best_continue == 0 || (continue_class.GetPriority() >
out_data.road_classification.GetPriority() &&
in_classification != continue_class) ||
(deviation < best_continue_deviation &&
out_data.road_classification == continue_class) ||
(continue_class != in_classification &&
out_data.road_classification == continue_class)))
{
best_continue_deviation = deviation;
best_continue = i;
} }
const auto current_best_class = // double check if the way with the lowest deviation from straight is still be better choice
node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification; const auto straightest = intersection.findClosestTurn(STRAIGHT_ANGLE);
if (straightest != best_option_it)
// don't prefer low priority classes
if (best != 0 && out_data.road_classification.IsLowPriorityRoadClass() &&
!current_best_class.IsLowPriorityRoadClass())
continue;
const bool is_better_choice_by_priority =
best == 0 || obviousByRoadClass(in_data.road_classification,
out_data.road_classification,
current_best_class);
const bool other_is_better_choice_by_priority =
best != 0 && obviousByRoadClass(in_data.road_classification,
current_best_class,
out_data.road_classification);
if ((!other_is_better_choice_by_priority && deviation < best_deviation) ||
is_better_choice_by_priority)
{ {
best_deviation = deviation; const EdgeData &straightest_data = node_based_graph.GetEdgeData(straightest->eid);
best = i; double straightest_data_deviation = angularDeviation(straightest->angle, STRAIGHT_ANGLE);
const auto deviation_diff =
std::abs(best_option_deviation - straightest_data_deviation) > FUZZY_ANGLE_DIFFERENCE;
const auto not_ramp_class = !straightest_data.road_classification.IsRampClass();
const auto not_link_class = !straightest_data.road_classification.IsLinkClass();
if (deviation_diff && !IsLowPriority(straightest_data) && not_ramp_class && not_link_class &&
!IsContinueRoad(best_option_data))
{
best_option = std::distance(begin(intersection), straightest);
best_option_deviation =
angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
} }
} }
// We don't consider empty names a valid continue feature. This distinguishes between missing // No non-low priority roads? Declare no obvious turn
// names and actual continuing roads. if (best_option == 0)
if (in_data.name_id == EMPTY_NAMEID)
best_continue = 0;
if (best == 0)
return 0; return 0;
const std::pair<std::int64_t, std::int64_t> num_continue_names = [&]() { auto best_continue_it =
std::int64_t count = 0, count_valid = 0; std::min_element(begin(intersection), end(intersection), RoadCompareSameName);
if (in_data.name_id != EMPTY_NAMEID) const auto best_continue_data = node_based_graph.GetEdgeData(best_continue_it->eid);
if (IsContinueRoad(best_continue_data) || (in_way_data.name_id == EMPTY_NAMEID && best_continue_data.name_id == EMPTY_NAMEID))
{ {
for (std::size_t i = 1; i < intersection.size(); ++i) best_continue = std::distance(begin(intersection), best_continue_it);
{ best_continue_deviation =
const auto &road = intersection[i]; angularDeviation(intersection[best_continue].angle, STRAIGHT_ANGLE);
const auto &road_data = node_based_graph.GetEdgeData(road.eid);
const auto same_name = !util::guidance::requiresNameAnnounced(
in_data.name_id, road_data.name_id, name_table, street_name_suffix_table);
if (same_name)
{
++count;
if (road.entry_allowed)
++count_valid;
} }
}
}
return std::make_pair(count, count_valid);
}();
if (0 != best_continue && best != best_continue && // if the best angle is going straight but the road is turning, declare no obvious turn
angularDeviation(intersection[best].angle, STRAIGHT_ANGLE) < if (0 != best_continue && best_option != best_continue &&
MAXIMAL_ALLOWED_NO_TURN_DEVIATION && best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification == node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification ==
node_based_graph.GetEdgeData(intersection[best].eid).road_classification) best_option_data.road_classification)
{ {
// if the best angle is going straight but the road is turning, we don't name anything
// obvious
return 0; return 0;
} }
// get a count of number of ways from that intersection that qualify to have
// continue instruction because they share a name with the approaching way
const std::int64_t continue_count =
count_if(++begin(intersection), end(intersection), [&](const ConnectedRoad &way) {
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid));
});
const std::int64_t continue_count_valid =
count_if(++begin(intersection), end(intersection), [&](const ConnectedRoad &way) {
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid)) && way.entry_allowed;
});
// checks if continue candidates are sharp turns
const bool all_continues_are_narrow = [&]() { const bool all_continues_are_narrow = [&]() {
if (in_data.name_id == EMPTY_NAMEID)
return false;
return std::count_if( return std::count_if(
intersection.begin() + 1, intersection.end(), [&](const ConnectedRoad &road) { begin(intersection), end(intersection), [&](const ConnectedRoad &road) {
const auto &road_data = node_based_graph.GetEdgeData(road.eid); const EdgeData &road_data = node_based_graph.GetEdgeData(road.eid);
const auto same_name = const double &road_angle = angularDeviation(road.angle, STRAIGHT_ANGLE);
!util::guidance::requiresNameAnnounced(in_data.name_id, return IsContinueRoad(road_data) && (road_angle < NARROW_TURN_ANGLE);
road_data.name_id, }) == continue_count;
name_table,
street_name_suffix_table);
return same_name &&
angularDeviation(road.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
}) == num_continue_names.first;
}(); }();
// has no obvious continued road // return true if the best_option candidate is more promising than the best_continue candidate
const auto &best_data = node_based_graph.GetEdgeData(intersection[best].eid); // otherwise return false, the best_continue candidate is more promising
const auto best_over_best_continue = [&]() {
const auto check_non_continue = [&]() {
// no continue road exists // no continue road exists
if (best_continue == 0) if (best_continue == 0)
return true; return true;
// we have multiple continues and not all are narrow (treat all the same) // we have multiple continues and not all are narrow. This suggests that
if (!all_continues_are_narrow && // the continue candidates are ambiguous
(num_continue_names.first >= 2 && intersection.size() >= 4)) if (!all_continues_are_narrow && (continue_count >= 2 && intersection.size() >= 4))
return true; return true;
// if the best continue is not narrow and we also have at least 2 possible choices, the // if the best continue is not narrow and we also have at least 2 possible choices, the
// intersection size does not matter anymore // intersection size does not matter anymore
if (num_continue_names.second >= 2 && best_continue_deviation >= 2 * NARROW_TURN_ANGLE) if (continue_count_valid >= 2 && best_continue_deviation >= 2 * NARROW_TURN_ANGLE)
return true; return true;
// continue data now most certainly exists // continue data now most certainly exists
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid); const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
if (obviousByRoadClass(in_data.road_classification, // best_continue is obvious by road class
if (obviousByRoadClass(in_way_data.road_classification,
continue_data.road_classification, continue_data.road_classification,
best_data.road_classification)) best_option_data.road_classification))
return false; return false;
if (obviousByRoadClass(in_data.road_classification, // best_option is obvious by road class
best_data.road_classification, if (obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
continue_data.road_classification)) continue_data.road_classification))
return true; return true;
// the best deviation is very straight and not a ramp // the best_option deviation is very straight and not a ramp
if (best_deviation < best_continue_deviation && best_deviation < FUZZY_ANGLE_DIFFERENCE && if (best_option_deviation < best_continue_deviation &&
!best_data.road_classification.IsRampClass()) best_option_deviation < FUZZY_ANGLE_DIFFERENCE &&
!best_option_data.road_classification.IsRampClass())
return true; return true;
// the continue road is of a lower priority, while the road continues on the same priority // the continue road is of a lower priority, while the road continues on the same priority
// with a better angle // with a better angle
if (best_deviation < best_continue_deviation && if (best_option_deviation < best_continue_deviation &&
in_data.road_classification == best_data.road_classification && in_way_data.road_classification == best_option_data.road_classification &&
continue_data.road_classification.GetPriority() > continue_data.road_classification.GetPriority() >
best_data.road_classification.GetPriority()) best_option_data.road_classification.GetPriority())
return true; return true;
return false; return false;
}(); }();
if (check_non_continue) if (best_over_best_continue)
{ {
// Find left/right deviation // Find left/right deviation
// skipping over service roads // skipping over service roads
const std::size_t left_index = [&]() { const std::size_t left_index = [&]() {
const auto index_candidate = (best + 1) % intersection.size(); const auto index_candidate = (best_option + 1) % intersection.size();
if (index_candidate == 0) if (index_candidate == 0)
return index_candidate; return index_candidate;
const auto &candidate_data = const auto &candidate_data =
node_based_graph.GetEdgeData(intersection[index_candidate].eid); node_based_graph.GetEdgeData(intersection[index_candidate].eid);
if (obviousByRoadClass(in_data.road_classification, if (obviousByRoadClass(in_way_data.road_classification,
best_data.road_classification, best_option_data.road_classification,
candidate_data.road_classification)) candidate_data.road_classification))
return (index_candidate + 1) % intersection.size(); return (index_candidate + 1) % intersection.size();
else else
@ -570,14 +594,14 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
}(); }();
const auto right_index = [&]() { const auto right_index = [&]() {
BOOST_ASSERT(best > 0); BOOST_ASSERT(best_option > 0);
const auto index_candidate = best - 1; const auto index_candidate = best_option - 1;
if (index_candidate == 0) if (index_candidate == 0)
return index_candidate; return index_candidate;
const auto candidate_data = const auto candidate_data =
node_based_graph.GetEdgeData(intersection[index_candidate].eid); node_based_graph.GetEdgeData(intersection[index_candidate].eid);
if (obviousByRoadClass(in_data.road_classification, if (obviousByRoadClass(in_way_data.road_classification,
best_data.road_classification, best_option_data.road_classification,
candidate_data.road_classification)) candidate_data.road_classification))
return index_candidate - 1; return index_candidate - 1;
else else
@ -589,28 +613,32 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
const double right_deviation = const double right_deviation =
angularDeviation(intersection[right_index].angle, STRAIGHT_ANGLE); angularDeviation(intersection[right_index].angle, STRAIGHT_ANGLE);
if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION && // return best_option candidate if it is nearly straight and distinct from the nearest other
// out
// way
if (best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE) std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
return best; return best_option;
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid); const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid);
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid); const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid);
const bool obvious_to_left = const bool obvious_to_left =
left_index == 0 || obviousByRoadClass(in_data.road_classification, left_index == 0 || obviousByRoadClass(in_way_data.road_classification,
best_data.road_classification, best_option_data.road_classification,
left_data.road_classification); left_data.road_classification);
const bool obvious_to_right = const bool obvious_to_right =
right_index == 0 || obviousByRoadClass(in_data.road_classification, right_index == 0 || obviousByRoadClass(in_way_data.road_classification,
best_data.road_classification, best_option_data.road_classification,
right_data.road_classification); right_data.road_classification);
// if the best turn isn't narrow, but there is a nearly straight turn, we don't consider the // if the best_option turn isn't narrow, but there is a nearly straight turn, we don't
// consider the
// turn obvious // turn obvious
const auto check_narrow = [&intersection, best_deviation](const std::size_t index) { const auto check_narrow = [&intersection, best_option_deviation](const std::size_t index) {
return angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) <= return angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) <=
FUZZY_ANGLE_DIFFERENCE && FUZZY_ANGLE_DIFFERENCE &&
(best_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed); (best_option_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed);
}; };
// other narrow turns? // other narrow turns?
@ -620,20 +648,23 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
if (check_narrow(left_index) && !obvious_to_left) if (check_narrow(left_index) && !obvious_to_left)
return 0; return 0;
// check if a turn is distinct enough // checks if a given way in the intersection is distinct enough from the best_option
// candidate
const auto isDistinct = [&](const std::size_t index, const double deviation) { const auto isDistinct = [&](const std::size_t index, const double deviation) {
/* /*
If the neighbor is not possible to enter, we allow for a lower If the neighbor is not possible to enter, we allow for a lower
distinction rate. If the road category is smaller, its also adjusted. Only distinction rate. If the road category is smaller, its also adjusted. Only
roads of the same priority require the full distinction ratio. roads of the same priority require the full distinction ratio.
*/ */
const auto &best_option_data =
node_based_graph.GetEdgeData(intersection[best_option].eid);
const auto adjusted_distinction_ratio = [&]() { const auto adjusted_distinction_ratio = [&]() {
// not allowed competitors are easily distinct // not allowed competitors are easily distinct
if (!intersection[index].entry_allowed) if (!intersection[index].entry_allowed)
return 0.7 * DISTINCTION_RATIO; return 0.7 * DISTINCTION_RATIO;
// a bit less obvious are road classes // a bit less obvious are road classes
else if (in_data.road_classification == best_data.road_classification && else if (in_way_data.road_classification == best_option_data.road_classification &&
best_data.road_classification.GetPriority() < best_option_data.road_classification.GetPriority() <
node_based_graph.GetEdgeData(intersection[index].eid) node_based_graph.GetEdgeData(intersection[index].eid)
.road_classification.GetPriority()) .road_classification.GetPriority())
return 0.8 * DISTINCTION_RATIO; return 0.8 * DISTINCTION_RATIO;
@ -641,7 +672,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
else else
return DISTINCTION_RATIO; return DISTINCTION_RATIO;
}(); }();
return index == 0 || deviation / best_deviation >= adjusted_distinction_ratio || return index == 0 || deviation / best_option_deviation >= adjusted_distinction_ratio ||
(deviation <= NARROW_TURN_ANGLE && !intersection[index].entry_allowed); (deviation <= NARROW_TURN_ANGLE && !intersection[index].entry_allowed);
}; };
@ -649,25 +680,24 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
const bool distinct_to_right = isDistinct(right_index, right_deviation); const bool distinct_to_right = isDistinct(right_index, right_deviation);
// Well distinct turn that is nearly straight // Well distinct turn that is nearly straight
if ((distinct_to_left || obvious_to_left) && (distinct_to_right || obvious_to_right)) if ((distinct_to_left || obvious_to_left) && (distinct_to_right || obvious_to_right))
return best; return best_option;
} }
else else
{ {
const double deviation =
angularDeviation(intersection[best_continue].angle, STRAIGHT_ANGLE);
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid); const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
if (std::abs(deviation) < 1) if (std::abs(best_continue_deviation) < 1)
return best_continue; return best_continue;
// check if any other similar best continues exist // check if any other similar best continues exist
for (std::size_t i = 1; i < intersection.size(); ++i) std::size_t i, last = intersection.size();
for (i = 1; i < last; ++i)
{ {
if (i == best_continue || !intersection[i].entry_allowed) if (i == best_continue || !intersection[i].entry_allowed)
continue; continue;
const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid); const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid);
const bool is_obvious_by_road_class = const bool is_obvious_by_road_class =
obviousByRoadClass(in_data.road_classification, obviousByRoadClass(in_way_data.road_classification,
continue_data.road_classification, continue_data.road_classification,
turn_data.road_classification); turn_data.road_classification);
@ -677,7 +707,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
continue; continue;
// continuation could be grouped with a straight turn and the turning road is a ramp // continuation could be grouped with a straight turn and the turning road is a ramp
if (turn_data.road_classification.IsRampClass() && deviation < GROUP_ANGLE) if (turn_data.road_classification.IsRampClass() &&
best_continue_deviation < GROUP_ANGLE &&
!continue_data.road_classification.IsRampClass())
continue; continue;
// perfectly straight turns prevent obviousness // perfectly straight turns prevent obviousness
@ -685,9 +717,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
if (turn_deviation < FUZZY_ANGLE_DIFFERENCE) if (turn_deviation < FUZZY_ANGLE_DIFFERENCE)
return 0; return 0;
const auto deviation_ratio = turn_deviation / deviation; const auto deviation_ratio = turn_deviation / best_continue_deviation;
// in comparison to normal devitions, a continue road can offer a smaller distinction // in comparison to normal deviations, a continue road can offer a smaller distinction
// ratio. Other roads close to the turn angle are not as obvious, if one road continues. // ratio. Other roads close to the turn angle are not as obvious, if one road continues.
if (deviation_ratio < DISTINCTION_RATIO / 1.5) if (deviation_ratio < DISTINCTION_RATIO / 1.5)
return 0; return 0;