fix detection of forks in present of oneways

This commit is contained in:
Moritz Kobitzsch 2016-10-04 18:36:39 +02:00
parent dbd108df8c
commit 66f2cc5184
4 changed files with 103 additions and 49 deletions

View File

@ -22,6 +22,37 @@ Feature: Fork Instructions
| a,c | ab,bc,bc | depart,fork slight left,arrive | | a,c | ab,bc,bc | depart,fork slight left,arrive |
| a,d | ab,bd,bd | depart,fork slight right,arrive | | a,d | ab,bd,bd | depart,fork slight right,arrive |
Scenario: Don't Fork On Single Road
Given the node map
| | | | | c |
| a | | b | | |
| | | | | d |
And the ways
| nodes | highway | oneway |
| ab | primary | no |
| cb | primary | yes |
| bd | primary | yes |
When I route I should get
| waypoints | route | turns |
| a,d | ab,bd,bd | depart,new name slight right,arrive |
Scenario: Don't Fork On Single Road
Given the node map
| | | | | | | c |
| a | | b | | d | | |
And the ways
| nodes | highway | oneway | name |
| ab | primary | no | road |
| cb | primary | yes | road |
| bd | primary | yes | turn |
When I route I should get
| waypoints | route | turns |
| a,d | road,turn,turn | depart,new name straight,arrive |
Scenario: Do not fork on link type Scenario: Do not fork on link type
Given the node map Given the node map
| | | | | c | | | | | | c |

View File

@ -133,6 +133,22 @@ Feature: Simple Turns
| d,c | db,cb,cb | depart,turn right,arrive | | d,c | db,cb,cb | depart,turn right,arrive |
| d,a | db,ab,ab | depart,new name straight,arrive | | d,a | db,ab,ab | depart,new name straight,arrive |
Scenario: Three Way Intersection - Meeting Oneways
Given the node map
| | c | |
| a | b | d |
And the ways
| nodes | highway | oneway |
| ab | primary | yes |
| bc | primary | yes |
| db | primary | yes |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,turn left,arrive |
| d,c | db,bc,bc | depart,turn right,arrive |
Scenario: Three Way Intersection on Through Street Scenario: Three Way Intersection on Through Street
Given the node map Given the node map
| | d | | | | d | |

View File

@ -1,5 +1,5 @@
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection_handler.hpp" #include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
@ -534,26 +534,48 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
best_data.road_classification, best_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
// turn obvious
const auto check_narrow = [&intersection, best_deviation](const std::size_t index) {
return angularDeviation(intersection[index].turn.angle, STRAIGHT_ANGLE) <=
FUZZY_ANGLE_DIFFERENCE &&
(best_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed);
};
// other narrow turns? // other narrow turns?
if (angularDeviation(intersection[right_index].turn.angle, STRAIGHT_ANGLE) <= if (check_narrow(right_index) && !obvious_to_right)
FUZZY_ANGLE_DIFFERENCE &&
!obvious_to_right)
return 0; return 0;
if (angularDeviation(intersection[left_index].turn.angle, STRAIGHT_ANGLE) <= if (check_narrow(left_index) && !obvious_to_left)
FUZZY_ANGLE_DIFFERENCE &&
!obvious_to_left)
return 0; return 0;
const bool distinct_to_left = // check if a turn is distinct enough
left_deviation / best_deviation >= DISTINCTION_RATIO || const auto isDistinct = [&](const std::size_t index, const double deviation) {
(left_deviation > best_deviation && /*
(!intersection[left_index].entry_allowed && in_data.distance > 30)); If the neighbor is not possible to enter, we allow for a lower
const bool distinct_to_right = distinction rate. If the road category is smaller, its also adjusted. Only
right_deviation / best_deviation >= DISTINCTION_RATIO || roads of the same priority require the full distinction ratio.
(right_deviation > best_deviation && */
(!intersection[right_index].entry_allowed && in_data.distance > 30)); const auto adjusted_distinction_ratio = [&]() {
// not allowed competitors are easily distinct
if (!intersection[index].entry_allowed)
return 0.7 * DISTINCTION_RATIO;
// a bit less obvious are road classes
else if (in_data.road_classification == best_data.road_classification &&
best_data.road_classification.GetPriority() <
node_based_graph.GetEdgeData(intersection[index].turn.eid)
.road_classification.GetPriority())
return 0.8 * DISTINCTION_RATIO;
// if road classes are the same, we use the full ratio
else
return DISTINCTION_RATIO;
}();
return index == 0 || deviation / best_deviation >= adjusted_distinction_ratio ||
(deviation <= NARROW_TURN_ANGLE && !intersection[index].entry_allowed);
};
const bool distinct_to_left = isDistinct(left_index, left_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;

View File

@ -1,7 +1,7 @@
#include "extractor/guidance/turn_handler.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection_scenario_three_way.hpp" #include "extractor/guidance/intersection_scenario_three_way.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_handler.hpp"
#include "util/guidance/toolkit.hpp" #include "util/guidance/toolkit.hpp"
@ -207,18 +207,6 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
} }
} }
// check whether there is a turn of the same name
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
const bool has_same_name_turn = [&]() {
for (std::size_t i = 1; i < intersection.size(); ++i)
{
if (node_based_graph.GetEdgeData(intersection[i].turn.eid).name_id == in_data.name_id)
return true;
}
return false;
}();
// check whether the obvious choice is actually a through street // check whether the obvious choice is actually a through street
if (obvious_index != 0) if (obvious_index != 0)
{ {
@ -227,26 +215,6 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
via_edge, via_edge,
isThroughStreet(obvious_index, intersection), isThroughStreet(obvious_index, intersection),
intersection[obvious_index]); intersection[obvious_index]);
if (has_same_name_turn &&
node_based_graph.GetEdgeData(intersection[obvious_index].turn.eid).name_id !=
in_data.name_id &&
intersection[obvious_index].turn.instruction.type == TurnType::NewName)
{
// this is a special case that is necessary to correctly handle obvious turns on
// continuing streets. Right now osrm does not know about right of way. If a street
// turns to the left just like:
//
// a
// a
// aaaaaaa b b
//
// And another road exits here, we don't want to call it a new name, even though the
// turn is obvious and does not require steering. To correctly handle these situations
// in turn collapsing, we use the turn + straight combination here
intersection[obvious_index].turn.instruction.type = TurnType::Turn;
intersection[obvious_index].turn.instruction.direction_modifier =
DirectionModifier::Straight;
}
// assign left/right turns // assign left/right turns
intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1); intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
@ -553,9 +521,26 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const EdgeID via_edge,
return true; return true;
}(); }();
// check if all entries in the fork range allow entry
const bool only_valid_entries = [&]() {
BOOST_ASSERT(right <= left && left < intersection.size());
// one past the end of the fork range
const auto end_itr = intersection.begin() + left + 1;
const auto has_entry_forbidden = [](const ConnectedRoad &road) {
return !road.entry_allowed;
};
const auto first_disallowed_entry =
std::find_if(intersection.begin() + right, end_itr, has_entry_forbidden);
// if no entry was found that forbids entry, the intersection entries are all valid.
return first_disallowed_entry == end_itr;
}();
// TODO check whether 2*NARROW_TURN is too large // TODO check whether 2*NARROW_TURN is too large
if (valid_indices && separated_at_left_side && separated_at_right_side && if (valid_indices && separated_at_left_side && separated_at_right_side &&
not_more_than_three && !has_obvious && has_compatible_classes) not_more_than_three && !has_obvious && has_compatible_classes && only_valid_entries)
return std::make_pair(right, left); return std::make_pair(right, left);
} }
return std::make_pair(std::size_t{0}, std::size_t{0}); return std::make_pair(std::size_t{0}, std::size_t{0});