Merge pull request #3217 from Project-OSRM/refactor/obviousness
Refactor find obvious turn handling
This commit is contained in:
commit
6d961d4a15
@ -947,6 +947,7 @@ 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
|
||||||
@ -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 |
|
||||||
|
119
features/guidance/low-priority.feature
Normal file
119
features/guidance/low-priority.feature
Normal 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 |
|
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user