improve slipway handling to allow multiple styles of turn lanes / turn roads

This commit is contained in:
Moritz Kobitzsch 2016-06-08 14:55:59 +02:00 committed by Patrick Niklaus
parent e9a0beb4e8
commit 2b5355edca
No known key found for this signature in database
GPG Key ID: E426891B5F978B1B
7 changed files with 260 additions and 55 deletions

View File

@ -528,3 +528,103 @@ Feature: Collapse
| waypoints | turns | route | | waypoints | turns | route |
| a,d | depart,continue right,end of road right,arrive | road,road,road,road | | a,d | depart,continue right,end of road right,arrive | road,road,road,road |
| d,a | depart,continue left,end of road left,arrive | road,road,road,road | | d,a | depart,continue left,end of road left,arrive | road,road,road,road |
Scenario: Forking before a turn
Given the node map
| | | | g | |
| | | | | |
| | | | c | |
| a | | b | d | e |
| | | | | |
| | | | f | |
And the ways
| nodes | name | oneway | highway |
| ab | road | yes | primary |
| bd | road | yes | primary |
| bc | road | yes | primary |
| de | road | yes | primary |
| fdcg | cross | no | secondary |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bd | fdcg | d | no_left_turn |
| restriction | bc | fdcg | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road | depart,arrive |
Scenario: Forking before a turn (narrow)
Given the node map
| | | | g | |
| | | | | |
| | | | c | |
| a | b | | d | e |
| | | | | |
| | | | f | |
And the ways
| nodes | name | oneway | highway |
| ab | road | yes | primary |
| bd | road | yes | primary |
| bc | road | yes | primary |
| de | road | yes | primary |
| fdcg | cross | no | secondary |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bd | fdcg | d | no_left_turn |
| restriction | bc | fdcg | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road | depart,arrive |
Scenario: Forking before a turn (forky)
Given the node map
| | | | g | | |
| | | | | | |
| | | | c | | |
| a | b | | | | |
| | | | | d | |
| | | | | f | e |
And the ways
| nodes | name | oneway | highway |
| ab | road | yes | primary |
| bd | road | yes | primary |
| bc | road | yes | primary |
| de | road | yes | primary |
| fdcg | cross | no | secondary |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bd | fdcg | d | no_left_turn |
| restriction | bc | fdcg | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road,road | depart,continue slight right,arrive |
Scenario: On-Off on Highway
Given the node map
| f | | | |
| a | b | c | d |
| | | | e |
And the ways
| nodes | name | highway | oneway |
| abcd | Hwy | motorway | yes |
| fb | on | motorway_link | yes |
| ce | off | motorway_link | yes |
When I route I should get
| waypoints | route | turns |
| a,d | Hwy,Hwy | depart,arrive |
| f,d | on,Hwy,Hwy | depart,merge slight right,arrive |
| f,e | on,Hwy,off,off | depart,merge slight right,off ramp right,arrive |
| a,e | Hwy,off,off | depart,off ramp right,arrive |

View File

@ -805,3 +805,31 @@ Feature: Simple Turns
| a,d | abc,bd,bd | depart,turn sharp right,arrive | | a,d | abc,bd,bd | depart,turn sharp right,arrive |
| a,e | abc,be,be | depart,turn right,arrive | | a,e | abc,be,be | depart,turn right,arrive |
| a,f | abc,bf,bf | depart,turn slight right,arrive | | a,f | abc,bf,bf | depart,turn slight right,arrive |
Scenario: Turn Lane on Splitting up Road
Given the node map
| | | | | | | | | | | | | | | |
| g | | | | f | | | | | | | | | | |
| | | | | | | | | | | | | | | |
| | | | | | h | | | e | | | c | | | d |
| a | | | b | | | | | | | | | | | |
| | | | i | | | | | | | | | | | |
And the ways
| nodes | highway | oneway | name |
| ab | secondary | yes | road |
| be | secondary | yes | road |
| ecd | secondary | no | road |
| efg | secondary | yes | road |
| ehb | secondary_link | yes | road |
| bi | tertiary | no | cross |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | ehb | be | b | no_left_turn |
When I route I should get
| waypoints | route | turns |
| a,d | road,road | depart,arrive |
| d,i | road,cross,cross | depart,turn left,arrive |
| d,g | road,road | depart,arrive |

View File

@ -85,31 +85,31 @@ Feature: Bearing parameter
| f | | | e | | | d | | f | | | e | | | d |
And the ways And the ways
| nodes | oneway | | nodes | oneway | name |
| ia | yes | | ia | yes | ia |
| jb | yes | | jb | yes | jb |
| kc | yes | | kc | yes | kc |
| ld | yes | | ld | yes | ld |
| me | yes | | me | yes | me |
| nf | yes | | nf | yes | nf |
| og | yes | | og | yes | og |
| ph | yes | | ph | yes | ph |
| ab | yes | | ab | yes | ring |
| bc | yes | | bc | yes | ring |
| cd | yes | | cd | yes | ring |
| de | yes | | de | yes | ring |
| ef | yes | | ef | yes | ring |
| fg | yes | | fg | yes | ring |
| gh | yes | | gh | yes | ring |
| ha | yes | | ha | yes | ring |
When I route I should get When I route I should get
| from | to | bearings | route | bearing | | from | to | bearings | route | bearing |
| 0 | q | 0 90 | ia,ab,bc,cd,de,ef,fg,gh,ha,ha | 0->0,0->90,90->180,180->180,180->270,270->270,270->0,0->0,0->90,90->0 | | 0 | q | 0 90 | ia,ring,ring,ring,ring,ring | 0->0,0->90,180->270,270->0,0->90,90->0 |
| 0 | a | 45 90 | jb,bc,cd,de,ef,fg,gh,ha,ha | 0->45,45->180,180->180,180->270,270->270,270->0,0->0,0->90,90->0 | | 0 | a | 45 90 | jb,ring,ring,ring,ring,ring | 0->45,45->180,180->270,270->0,0->90,90->0 |
| 0 | q | 90 90 | kc,cd,de,ef,fg,gh,ha,ha | 0->90,90->180,180->270,270->270,270->0,0->0,0->90,90->0 | | 0 | q | 90 90 | kc,ring,ring,ring,ring | 0->90,90->180,270->0,0->90,90->0 |
| 0 | a | 135 90 | ld,de,ef,fg,gh,ha,ha | 0->135,135->270,270->270,270->0,0->0,0->90,90->0 | | 0 | a | 135 90 | ld,ring,ring,ring,ring | 0->135,135->270,270->0,0->90,90->0 |
| 0 | a | 180 90 | me,ef,fg,gh,ha,ha | 0->180,180->270,270->0,0->0,0->90,90->0 | | 0 | a | 180 90 | me,ring,ring,ring | 0->180,180->270,0->90,90->0 |
| 0 | a | 225 90 | nf,fg,gh,ha,ha | 0->225,225->0,0->0,0->90,90->0 | | 0 | a | 225 90 | nf,ring,ring,ring | 0->225,225->0,0->90,90->0 |
| 0 | a | 270 90 | og,gh,ha,ha | 0->270,270->0,0->90,90->0 | | 0 | a | 270 90 | og,ring,ring | 0->270,270->0,90->0 |
| 0 | a | 315 90 | ph,ha,ha | 0->315,315->90,90->0 | | 0 | a | 315 90 | ph,ring,ring | 0->315,315->90,90->0 |

View File

@ -33,6 +33,16 @@ namespace
{ {
const constexpr double MAX_COLLAPSE_DISTANCE = 25; const constexpr double MAX_COLLAPSE_DISTANCE = 25;
inline bool choiceless(const RouteStep &step, const RouteStep &previous)
{
// if the next turn is choiceless, we consider longer turn roads collapsable than usually
// accepted. We might need to improve this to find out whether we merge onto a through-street.
return previous.distance < 3 * MAX_COLLAPSE_DISTANCE &&
1 >= std::count(step.intersections.front().entry.begin(),
step.intersections.front().entry.end(),
true);
}
// List of types that can be collapsed, if all other restrictions pass // List of types that can be collapsed, if all other restrictions pass
bool isCollapsableInstruction(const TurnInstruction instruction) bool isCollapsableInstruction(const TurnInstruction instruction)
{ {
@ -41,6 +51,8 @@ bool isCollapsableInstruction(const TurnInstruction instruction)
instruction.direction_modifier == DirectionModifier::Straight) || instruction.direction_modifier == DirectionModifier::Straight) ||
(instruction.type == TurnType::Turn && (instruction.type == TurnType::Turn &&
instruction.direction_modifier == DirectionModifier::Straight) || instruction.direction_modifier == DirectionModifier::Straight) ||
(instruction.type == TurnType::Continue &&
instruction.direction_modifier == DirectionModifier::Straight) ||
(instruction.type == TurnType::Merge); (instruction.type == TurnType::Merge);
} }
@ -387,7 +399,11 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
BOOST_ASSERT(!one_back_step.intersections.empty() && !current_step.intersections.empty()); BOOST_ASSERT(!one_back_step.intersections.empty() && !current_step.intersections.empty());
// Very Short New Name // Very Short New Name
if (collapsable(one_back_step)) if (((collapsable(one_back_step) ||
(isCollapsableInstruction(one_back_step.maneuver.instruction) &&
choiceless(current_step, one_back_step))) &&
!(one_back_step.maneuver.instruction.type == TurnType::Merge)))
// the check against merge is a workaround for motorways
{ {
BOOST_ASSERT(two_back_index < steps.size()); BOOST_ASSERT(two_back_index < steps.size());
if (compatible(one_back_step, steps[two_back_index])) if (compatible(one_back_step, steps[two_back_index]))
@ -433,7 +449,11 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
{ {
steps[one_back_index].maneuver.instruction.type = TurnType::Continue; steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
} }
else if (TurnType::Merge == one_back_step.maneuver.instruction.type) else if (TurnType::Merge == one_back_step.maneuver.instruction.type &&
current_step.maneuver.instruction.type !=
TurnType::Suppressed) // This suppressed is a check for highways. We might
// need a highway-suppressed to get the turn onto a
// highway...
{ {
steps[one_back_index].maneuver.instruction.direction_modifier = steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier( util::guidance::mirrorDirectionModifier(
@ -445,7 +465,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
} }
} }
// Potential U-Turn // Potential U-Turn
else if (one_back_step.distance <= MAX_COLLAPSE_DISTANCE && else if ((one_back_step.distance <= MAX_COLLAPSE_DISTANCE ||
choiceless(current_step, one_back_step)) &&
bearingsAreReversed(util::bearing::reverseBearing( bearingsAreReversed(util::bearing::reverseBearing(
one_back_step.intersections.front() one_back_step.intersections.front()
.bearings[one_back_step.intersections.front().in]), .bearings[one_back_step.intersections.front().in]),
@ -529,6 +550,7 @@ std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps)
// that we come across. // that we come across.
std::vector<RouteStep> postProcess(std::vector<RouteStep> steps) std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
{ {
print(steps);
// the steps should always include the first/last step in form of a location // the steps should always include the first/last step in form of a location
BOOST_ASSERT(steps.size() >= 2); BOOST_ASSERT(steps.size() >= 2);
if (steps.size() == 2) if (steps.size() == 2)
@ -542,14 +564,12 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// required. We might end up with only one of them (e.g. starting within a roundabout) // required. We might end up with only one of them (e.g. starting within a roundabout)
// or having a via-point in the roundabout. // or having a via-point in the roundabout.
// In this case, exits are numbered from the start of the lag. // In this case, exits are numbered from the start of the lag.
std::size_t last_valid_instruction = 0;
for (std::size_t step_index = 0; step_index < steps.size(); ++step_index) for (std::size_t step_index = 0; step_index < steps.size(); ++step_index)
{ {
auto &step = steps[step_index]; auto &step = steps[step_index];
const auto instruction = step.maneuver.instruction; const auto instruction = step.maneuver.instruction;
if (entersRoundabout(instruction)) if (entersRoundabout(instruction))
{ {
last_valid_instruction = step_index;
has_entered_roundabout = setUpRoundabout(step); has_entered_roundabout = setUpRoundabout(step);
if (has_entered_roundabout && step_index + 1 < steps.size()) if (has_entered_roundabout && step_index + 1 < steps.size())
@ -570,17 +590,11 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// in case the we are not on a roundabout, the very first instruction // in case the we are not on a roundabout, the very first instruction
// after the depart will be transformed into a roundabout and become // after the depart will be transformed into a roundabout and become
// the first valid instruction // the first valid instruction
last_valid_instruction = 1;
} }
closeOffRoundabout(has_entered_roundabout, steps, step_index); closeOffRoundabout(has_entered_roundabout, steps, step_index);
has_entered_roundabout = false; has_entered_roundabout = false;
on_roundabout = false; on_roundabout = false;
} }
else if (!isSilent(instruction))
{
// Remember the last non silent instruction
last_valid_instruction = step_index;
}
} }
// unterminated roundabout // unterminated roundabout
@ -648,6 +662,8 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
for (std::size_t step_index = 1; step_index + 1 < steps.size(); ++step_index) for (std::size_t step_index = 1; step_index + 1 < steps.size(); ++step_index)
{ {
const auto &current_step = steps[step_index]; const auto &current_step = steps[step_index];
if( current_step.maneuver.instruction.type == TurnType::NoTurn )
continue;
const auto one_back_index = getPreviousIndex(step_index); const auto one_back_index = getPreviousIndex(step_index);
BOOST_ASSERT(one_back_index < steps.size()); BOOST_ASSERT(one_back_index < steps.size());
@ -748,7 +764,8 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
invalidateStep(steps[step_index]); invalidateStep(steps[step_index]);
} }
} }
else if (one_back_step.distance <= MAX_COLLAPSE_DISTANCE) else if (choiceless(current_step, one_back_step) ||
one_back_step.distance <= MAX_COLLAPSE_DISTANCE)
{ {
// check for one of the multiple collapse scenarios and, if possible, collapse the // check for one of the multiple collapse scenarios and, if possible, collapse the
// turn // turn
@ -757,7 +774,8 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
collapseTurnAt(steps, two_back_index, one_back_index, step_index); collapseTurnAt(steps, two_back_index, one_back_index, step_index);
} }
} }
else if (one_back_index > 0 && one_back_step.distance <= MAX_COLLAPSE_DISTANCE) else if (one_back_index > 0 && (one_back_step.distance <= MAX_COLLAPSE_DISTANCE ||
choiceless(current_step, one_back_step)))
{ {
// check for one of the multiple collapse scenarios and, if possible, collapse the turn // check for one of the multiple collapse scenarios and, if possible, collapse the turn
const auto two_back_index = getPreviousIndex(one_back_index); const auto two_back_index = getPreviousIndex(one_back_index);

View File

@ -385,7 +385,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
{ {
// circular order indicates a merge to the left (0-3 onto 4 // circular order indicates a merge to the left (0-3 onto 4
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
NARROW_TURN_ANGLE) 2*NARROW_TURN_ANGLE)
intersection[1].turn.instruction = {TurnType::Merge, intersection[1].turn.instruction = {TurnType::Merge,
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
else // fallback else // fallback
@ -407,12 +407,12 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) && if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) &&
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id != node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id !=
EMPTY_NAMEID && EMPTY_NAMEID &&
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id == node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id ==
node_based_graph.GetEdgeData(intersection[0].turn.eid).name_id) node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
{ {
// circular order (5-0) onto 4 // circular order (5-0) onto 4
if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
NARROW_TURN_ANGLE) 2 * NARROW_TURN_ANGLE)
intersection[2].turn.instruction = {TurnType::Merge, intersection[2].turn.instruction = {TurnType::Merge,
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
else // fallback else // fallback

View File

@ -1,5 +1,5 @@
#include "extractor/guidance/turn_analysis.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/turn_analysis.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
@ -127,15 +127,15 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
auto intersection_node_id = node_based_graph.GetTarget(source_edge_id); auto intersection_node_id = node_based_graph.GetTarget(source_edge_id);
const auto linkTest = [this](const ConnectedRoad &road) { const auto linkTest = [this](const ConnectedRoad &road) {
return isLinkClass( return // isLinkClass(
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class) && // node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class) &&
road.entry_allowed && !node_based_graph.GetEdgeData(road.turn.eid).roundabout && road.entry_allowed &&
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE; angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE;
}; };
bool hasRamp = bool hasNarrow =
std::find_if(intersection.begin(), intersection.end(), linkTest) != intersection.end(); std::find_if(intersection.begin(), intersection.end(), linkTest) != intersection.end();
if (!hasRamp) if (!hasNarrow)
return intersection; return intersection;
const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id); const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id);
@ -171,6 +171,8 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
const auto next_road_next_intersection = const auto next_road_next_intersection =
intersection_generator(intersection_node_id, next_road->turn.eid); intersection_generator(intersection_node_id, next_road->turn.eid);
const auto next_intersection_node = node_based_graph.GetTarget(next_road->turn.eid);
std::unordered_set<NameID> target_road_names; std::unordered_set<NameID> target_road_names;
for (const auto &road : next_road_next_intersection) for (const auto &road : next_road_next_intersection)
@ -187,7 +189,8 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
for (const auto &candidate_road : target_intersection) for (const auto &candidate_road : target_intersection)
{ {
const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid); const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid);
if (target_road_names.count(candidate_data.name_id) > 0) if (target_road_names.count(candidate_data.name_id) > 0 &&
node_based_graph.GetTarget(candidate_road.turn.eid) == next_intersection_node)
{ {
road.turn.instruction.type = TurnType::Sliproad; road.turn.instruction.type = TurnType::Sliproad;
break; break;
@ -196,6 +199,30 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
} }
} }
if (next_road->turn.instruction.type == TurnType::Fork)
{
const auto &next_data = node_based_graph.GetEdgeData(next_road->turn.eid);
if (next_data.name_id == source_edge_data.name_id)
{
if (angularDeviation(next_road->turn.angle, STRAIGHT_ANGLE) < 5)
next_road->turn.instruction.type = TurnType::Suppressed;
else
next_road->turn.instruction.type = TurnType::Continue;
next_road->turn.instruction.direction_modifier =
getTurnDirection(next_road->turn.angle);
}
else if (next_data.name_id != EMPTY_NAMEID)
{
next_road->turn.instruction.type = TurnType::NewName;
next_road->turn.instruction.direction_modifier =
getTurnDirection(next_road->turn.angle);
}
else
{
next_road->turn.instruction.type = TurnType::Suppressed;
}
}
return intersection; return intersection;
} }

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"
@ -377,8 +377,12 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
} }
const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid); const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
auto continue_class = node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
.road_classification.road_class;
if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id && if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
deviation < best_continue_deviation) (best_continue == 0 || continue_class > out_data.road_classification.road_class ||
(deviation < best_continue_deviation &&
out_data.road_classification.road_class == continue_class)))
{ {
best_continue_deviation = deviation; best_continue_deviation = deviation;
best_continue = i; best_continue = i;
@ -392,7 +396,12 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
return 0; return 0;
// has no obvious continued road // has no obvious continued road
if (best_continue == 0 || true) if (best_continue == 0 || best_continue_deviation >= 2 * NARROW_TURN_ANGLE ||
(node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
.road_classification.road_class ==
node_based_graph.GetEdgeData(intersection[best].turn.eid)
.road_classification.road_class &&
std::abs(best_continue_deviation) > 1 && best_deviation / best_continue_deviation < 0.75))
{ {
// Find left/right deviation // Find left/right deviation
const double left_deviation = angularDeviation( const double left_deviation = angularDeviation(
@ -422,8 +431,31 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
return best; return best;
} }
} }
else
{
const double deviation =
angularDeviation(intersection[best_continue].turn.angle, STRAIGHT_ANGLE);
const auto &continue_data =
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
if (std::abs(deviation) < 1)
return best_continue;
return 0; // no obvious turn // check if any other similar best continues exist
for (std::size_t i = 1; i < intersection.size(); ++i)
{
if (i == best_continue || !intersection[i].entry_allowed)
continue;
if (angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE) / deviation < 1.1 &&
continue_data.road_classification.road_class ==
node_based_graph.GetEdgeData(intersection[i].turn.eid)
.road_classification.road_class)
return 0;
}
return best_continue; // no obvious turn
}
return 0;
} }
// Assignment of left turns hands of to right turns. // Assignment of left turns hands of to right turns.