From a6987e371a328b2c0182504d7c2833ae9753b38a Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Mon, 18 Jul 2016 15:34:12 +0200 Subject: [PATCH 1/4] Initial left hand driving implementation --- include/engine/api/route_api.hpp | 2 +- include/engine/datafacade/datafacade_base.hpp | 2 + .../engine/datafacade/internal_datafacade.hpp | 5 +++ .../engine/datafacade/shared_datafacade.hpp | 5 +++ include/engine/guidance/post_processing.hpp | 3 +- .../extractor/guidance/roundabout_handler.hpp | 5 ++- include/extractor/guidance/turn_analysis.hpp | 3 +- include/extractor/profile_properties.hpp | 3 +- profiles/car.lua | 3 +- profiles/lhs.lua | 19 ++++++++ profiles/rhs.lua | 19 ++++++++ src/engine/guidance/post_processing.cpp | 21 ++++++--- src/extractor/edge_based_graph_factory.cpp | 3 +- src/extractor/guidance/roundabout_handler.cpp | 44 +++++++++++++++---- src/extractor/guidance/turn_analysis.cpp | 6 ++- src/extractor/scripting_environment.cpp | 3 +- 16 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 profiles/lhs.lua create mode 100644 profiles/rhs.lua diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index f3965caa107..ba7d9612612 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -143,7 +143,7 @@ class RouteAPI : public BaseAPI */ guidance::trimShortSegments(steps, leg_geometry); - leg.steps = guidance::postProcess(std::move(steps)); + leg.steps = guidance::postProcess(std::move(steps), BaseAPI::facade); leg.steps = guidance::collapseTurns(std::move(leg.steps)); leg.steps = guidance::buildIntersections(std::move(leg.steps)); leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 81cdde129fc..54b7d503e2e 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -162,6 +162,8 @@ class BaseDataFacade virtual bool GetContinueStraightDefault() const = 0; + virtual bool UseLeftSideDriving() const = 0; + virtual BearingClassID GetBearingClassID(const NodeID id) const = 0; virtual util::guidance::BearingClass diff --git a/include/engine/datafacade/internal_datafacade.hpp b/include/engine/datafacade/internal_datafacade.hpp index 7123f9c632c..a9c99a78d26 100644 --- a/include/engine/datafacade/internal_datafacade.hpp +++ b/include/engine/datafacade/internal_datafacade.hpp @@ -747,6 +747,11 @@ class InternalDataFacade final : public BaseDataFacade return m_profile_properties.continue_straight_at_waypoint; } + bool UseLeftSideDriving() const override final + { + return m_profile_properties.left_hand_driving; + } + BearingClassID GetBearingClassID(const NodeID nid) const override final { return m_bearing_class_id_table.at(nid); diff --git a/include/engine/datafacade/shared_datafacade.hpp b/include/engine/datafacade/shared_datafacade.hpp index 91e2a02862b..1ec2fef3c87 100644 --- a/include/engine/datafacade/shared_datafacade.hpp +++ b/include/engine/datafacade/shared_datafacade.hpp @@ -793,6 +793,11 @@ class SharedDataFacade final : public BaseDataFacade return m_profile_properties->continue_straight_at_waypoint; } + bool UseLeftSideDriving() const override final + { + return m_profile_properties->left_hand_driving; + } + BearingClassID GetBearingClassID(const NodeID id) const override final { return m_bearing_class_id_table.at(id); diff --git a/include/engine/guidance/post_processing.hpp b/include/engine/guidance/post_processing.hpp index 16d383df69b..774312329e6 100644 --- a/include/engine/guidance/post_processing.hpp +++ b/include/engine/guidance/post_processing.hpp @@ -4,6 +4,7 @@ #include "engine/guidance/leg_geometry.hpp" #include "engine/guidance/route_step.hpp" #include "engine/phantom_node.hpp" +#include "engine/datafacade/datafacade_base.hpp" #include @@ -15,7 +16,7 @@ namespace guidance { // passed as none-reference to modify in-place and move out again -std::vector postProcess(std::vector steps); +std::vector postProcess(std::vector steps, const datafacade::BaseDataFacade &facade); // Multiple possible reasons can result in unnecessary/confusing instructions // A prime example would be a segregated intersection. Turning around at this diff --git a/include/extractor/guidance/roundabout_handler.hpp b/include/extractor/guidance/roundabout_handler.hpp index 055982a82b4..40c085e39b4 100644 --- a/include/extractor/guidance/roundabout_handler.hpp +++ b/include/extractor/guidance/roundabout_handler.hpp @@ -6,6 +6,7 @@ #include "extractor/guidance/intersection_handler.hpp" #include "extractor/guidance/roundabout_type.hpp" #include "extractor/query_node.hpp" +#include "extractor/profile_properties.hpp" #include "util/name_table.hpp" #include "util/node_based_graph.hpp" @@ -42,7 +43,8 @@ class RoundaboutHandler : public IntersectionHandler const std::vector &node_info_list, const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, - const SuffixTable &street_name_suffix_table); + const SuffixTable &street_name_suffix_table, + const ProfileProperties &profile_properties); ~RoundaboutHandler() override final; @@ -81,6 +83,7 @@ class RoundaboutHandler : public IntersectionHandler bool qualifiesAsRoundaboutIntersection(const std::set &roundabout_nodes) const; const CompressedEdgeContainer &compressed_edge_container; + const ProfileProperties &profile_properties; }; } // namespace guidance diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp index 5642ea5af79..f06aef02686 100644 --- a/include/extractor/guidance/turn_analysis.hpp +++ b/include/extractor/guidance/turn_analysis.hpp @@ -41,7 +41,8 @@ class TurnAnalysis const std::unordered_set &barrier_nodes, const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, - const SuffixTable &street_name_suffix_table); + const SuffixTable &street_name_suffix_table, + const ProfileProperties &profile_properties); // the entry into the turn analysis Intersection getIntersection(const NodeID from_node, const EdgeID via_eid) const; diff --git a/include/extractor/profile_properties.hpp b/include/extractor/profile_properties.hpp index 0d078855dff..58a191d4a5b 100644 --- a/include/extractor/profile_properties.hpp +++ b/include/extractor/profile_properties.hpp @@ -12,7 +12,7 @@ struct ProfileProperties { ProfileProperties() : traffic_signal_penalty(0), u_turn_penalty(0), continue_straight_at_waypoint(true), - use_turn_restrictions(false) + use_turn_restrictions(false), left_hand_driving(false) { } @@ -36,6 +36,7 @@ struct ProfileProperties int u_turn_penalty; bool continue_straight_at_waypoint; bool use_turn_restrictions; + bool left_hand_driving; }; } } diff --git a/profiles/car.lua b/profiles/car.lua index c138f866ebb..11410c6d5b7 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -137,13 +137,14 @@ properties.u_turn_penalty = 20 properties.traffic_signal_penalty = 2 properties.use_turn_restrictions = true properties.continue_straight_at_waypoint = true +properties.left_hand_driving = false local side_road_speed_multiplier = 0.8 local turn_penalty = 10 -- Note: this biases right-side driving. Should be -- inverted for left-driving countries. -local turn_bias = 1.2 +local turn_bias = properties.left_hand_driving and 1/1.2 or 1.2 local obey_oneway = true local ignore_areas = true diff --git a/profiles/lhs.lua b/profiles/lhs.lua new file mode 100644 index 00000000000..64068bc2e64 --- /dev/null +++ b/profiles/lhs.lua @@ -0,0 +1,19 @@ +-- Testbot, with turn penalty +-- Used for testing turn penalties + +require 'testbot' + +properties.left_hand_driving = true + +local turn_penalty = 500 +local turn_bias = properties.left_hand_driving and 1/1.2 or 1.2 + +function turn_function (angle) + ---- compute turn penalty as angle^2, with a left/right bias + k = turn_penalty/(90.0*90.0) + if angle>=0 then + return angle*angle*k/turn_bias + else + return angle*angle*k*turn_bias + end +end diff --git a/profiles/rhs.lua b/profiles/rhs.lua new file mode 100644 index 00000000000..9b0ebba16d1 --- /dev/null +++ b/profiles/rhs.lua @@ -0,0 +1,19 @@ +-- Testbot, with turn penalty +-- Used for testing turn penalties + +require 'testbot' + +properties.left_hand_driving = false + +local turn_penalty = 500 +local turn_bias = properties.left_hand_driving and 1/1.2 or 1.2 + +function turn_function (angle) + ---- compute turn penalty as angle^2, with a left/right bias + k = turn_penalty/(90.0*90.0) + if angle>=0 then + return angle*angle*k/turn_bias + else + return angle*angle*k*turn_bias + end +end diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index f22599a5c5a..0a254c57412 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -501,7 +501,7 @@ void collapseTurnAt(std::vector &steps, // Works on steps including silent and invalid instructions in order to do lane anticipation for // roundabouts which later on get collapsed into a single multi-hop instruction. -std::vector anticipateLaneChangeForRoundabouts(std::vector steps) +std::vector anticipateLaneChangeForRoundabouts(std::vector steps, const datafacade::BaseDataFacade &facade) { using namespace util::guidance; @@ -520,9 +520,18 @@ std::vector anticipateLaneChangeForRoundabouts(std::vector // FIXME: assumes right-side driving (counter-clockwise roundabout flow) const auto enter_direction = enter.maneuver.instruction.direction_modifier; - if (util::guidance::isRightTurn(enter.maneuver.instruction)) - enter.maneuver.instruction.direction_modifier = - mirrorDirectionModifier(enter_direction); + if (facade.UseLeftSideDriving()) + { + if (util::guidance::isLeftTurn(enter.maneuver.instruction)) + enter.maneuver.instruction.direction_modifier = + mirrorDirectionModifier(enter_direction); + } + else + { + if (util::guidance::isRightTurn(enter.maneuver.instruction)) + enter.maneuver.instruction.direction_modifier = + mirrorDirectionModifier(enter_direction); + } auto enterAndLeave = anticipateLaneChange({enter, leave}); @@ -579,7 +588,7 @@ std::vector removeNoTurnInstructions(std::vector steps) // They are required for maintenance purposes. We can calculate the number // of exits to pass in a roundabout and the number of intersections // that we come across. -std::vector postProcess(std::vector steps) +std::vector postProcess(std::vector steps, const datafacade::BaseDataFacade &facade) { // the steps should always include the first/last step in form of a location BOOST_ASSERT(steps.size() >= 2); @@ -589,7 +598,7 @@ std::vector postProcess(std::vector steps) // Before we invalidate and remove silent instructions, we handle roundabouts (before they're // getting collapsed into a single multi-hop instruction) by back-propagating exit lane // constraints already to a roundabout's enter instruction. - steps = anticipateLaneChangeForRoundabouts(std::move(steps)); + steps = anticipateLaneChangeForRoundabouts(std::move(steps), facade); // Count Street Exits forward bool on_roundabout = false; diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index d7182f0e151..11ffcd1acb2 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -345,7 +345,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( m_barrier_nodes, m_compressed_edge_container, name_table, - street_name_suffix_table); + street_name_suffix_table, + profile_properties); guidance::lanes::TurnLaneHandler turn_lane_handler( *m_node_based_graph, turn_lane_offsets, turn_lane_masks, m_node_info_list, turn_analysis); diff --git a/src/extractor/guidance/roundabout_handler.cpp b/src/extractor/guidance/roundabout_handler.cpp index df0455b605b..b57cbb73641 100644 --- a/src/extractor/guidance/roundabout_handler.cpp +++ b/src/extractor/guidance/roundabout_handler.cpp @@ -25,9 +25,11 @@ RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_bas const std::vector &node_info_list, const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, - const SuffixTable &street_name_suffix_table) + const SuffixTable &street_name_suffix_table, + const ProfileProperties &profile_properties) : IntersectionHandler(node_based_graph, node_info_list, name_table, street_name_suffix_table), - compressed_edge_container(compressed_edge_container) + compressed_edge_container(compressed_edge_container), + profile_properties(profile_properties) { } @@ -66,8 +68,15 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags( bool on_roundabout = in_edge_data.roundabout; bool can_enter_roundabout = false; bool can_exit_roundabout_separately = false; - for (const auto &road : intersection) + + const bool lhs = profile_properties.left_hand_driving; + const int step = lhs ? -1 : 1; + const signed int_size = static_cast(intersection.size()); + + for (signed i = lhs ? int_size - 1 : 0; + i >= 0 && i < int_size; i += step) { + const auto &road = intersection[i]; const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); // only check actual outgoing edges if (edge_data.reversed || !road.entry_allowed) @@ -103,8 +112,14 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, return; bool past_roundabout_angle = false; - for (auto &road : intersection) + const bool lhs = profile_properties.left_hand_driving; + const int step = lhs ? -1 : 1; + const signed int_size = static_cast(intersection.size()); + + for (signed i = lhs ? int_size - 1 : 0; + i >= 0 && i < int_size; i += step) { + auto &road = intersection[i]; const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); // only check actual outgoing edges if (edge_data.reversed) @@ -257,7 +272,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const }; // the roundabout radius has to be the same for all locations we look at it from // to guarantee this, we search the full roundabout for its vertices - // and select the three smalles ids + // and select the three smallest ids std::set roundabout_nodes; // needs to be sorted // this value is a hard abort to deal with potential self-loops @@ -337,9 +352,9 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const if (radius <= MAX_ROUNDABOUT_INTERSECTION_RADIUS) { - const bool qualifies_as_roundabout_nitersection = + const bool qualifies_as_roundabout_intersection = qualifiesAsRoundaboutIntersection(roundabout_nodes); - if (qualifies_as_roundabout_nitersection) + if (qualifies_as_roundabout_intersection) { return RoundaboutType::RoundaboutIntersection; } @@ -359,12 +374,19 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou { // detect via radius (get via circle through three vertices) NodeID node_v = node_based_graph.GetTarget(via_eid); + + const bool lhs = profile_properties.left_hand_driving; + const int step = lhs ? -1 : 1; + const signed int_size = static_cast(intersection.size()); + if (on_roundabout) { // Shoule hopefully have only a single exit and continue // at least for cars. How about bikes? - for (auto &road : intersection) + for (signed i = lhs ? int_size - 1 : 0; + i >= 0 && i < int_size; i += step) { + auto &road = intersection[i]; auto &turn = road.turn; const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); if (out_data.roundabout) @@ -397,8 +419,11 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou return intersection; } else - for (auto &road : intersection) + { + for (signed i = lhs ? int_size - 1 : 0; + i >= 0 && i < int_size; i += step) { + auto &road = intersection[i]; if (!road.entry_allowed) continue; auto &turn = road.turn; @@ -418,6 +443,7 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou roundabout_type, getTurnDirection(turn.angle)); } } + } return intersection; } diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp index a95ff907ec5..717abf2dc25 100644 --- a/src/extractor/guidance/turn_analysis.cpp +++ b/src/extractor/guidance/turn_analysis.cpp @@ -37,7 +37,8 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, const std::unordered_set &barrier_nodes, const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, - const SuffixTable &street_name_suffix_table) + const SuffixTable &street_name_suffix_table, + const ProfileProperties &profile_properties) : node_based_graph(node_based_graph), intersection_generator(node_based_graph, restriction_map, barrier_nodes, @@ -47,7 +48,8 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_info_list, compressed_edge_container, name_table, - street_name_suffix_table), + street_name_suffix_table, + profile_properties), motorway_handler(node_based_graph, node_info_list, name_table, street_name_suffix_table), turn_handler(node_based_graph, node_info_list, name_table, street_name_suffix_table) { diff --git a/src/extractor/scripting_environment.cpp b/src/extractor/scripting_environment.cpp index 899537e4467..3854db8b994 100644 --- a/src/extractor/scripting_environment.cpp +++ b/src/extractor/scripting_environment.cpp @@ -109,7 +109,8 @@ void ScriptingEnvironment::InitContext(ScriptingEnvironment::Context &context) &ProfileProperties::SetUturnPenalty) .def_readwrite("use_turn_restrictions", &ProfileProperties::use_turn_restrictions) .def_readwrite("continue_straight_at_waypoint", - &ProfileProperties::continue_straight_at_waypoint), + &ProfileProperties::continue_straight_at_waypoint) + .def_readwrite("left_hand_driving", &ProfileProperties::left_hand_driving), luabind::class_>("vector").def( "Add", From 438b1797a9b4ffc90ccded91850379326c171609 Mon Sep 17 00:00:00 2001 From: Lauren Budorick Date: Tue, 19 Jul 2016 10:30:11 +0200 Subject: [PATCH 2/4] commit test file --- features/testbot/side_bias.feature | 83 ++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 features/testbot/side_bias.feature diff --git a/features/testbot/side_bias.feature b/features/testbot/side_bias.feature new file mode 100644 index 00000000000..3a6eb37f425 --- /dev/null +++ b/features/testbot/side_bias.feature @@ -0,0 +1,83 @@ +@routing @testbot @sidebias +Feature: Testbot - side bias + + Scenario: Left hand bias + Given the profile "lhs" + And the node map + | a | | b | | c | + | | | | | | + | | | d | | | + And the ways + | nodes | + | ab | + | bc | + | bd | + + When I route I should get + | from | to | route | time | + | d | a | bd,ab,ab | 82s +-1 | + | d | c | bd,bc,bc | 100s +-1 | + + Scenario: Right hand bias + Given the profile "rhs" + And the node map + | a | | b | | c | + | | | | | | + | | | d | | | + And the ways + | nodes | + | ab | + | bc | + | bd | + + When I route I should get + | from | to | route | time | + | d | a | bd,ab,ab | 100s +-1 | + | d | c | bd,bc,bc | 82s +-1 | + + Scenario: Roundabout exit counting for left sided driving + Given the profile "lhs" + And a grid size of 10 meters + And the node map + | | | a | | | + | | | b | | | + | h | g | | c | d | + | | | e | | | + | | | f | | | + And the ways + | nodes | junction | + | ab | | + | cd | | + | ef | | + | gh | | + | bcegb | roundabout | + + When I route I should get + | waypoints | route | turns | + | a,d | ab,cd,cd | depart,roundabout-exit-1,arrive | + | a,f | ab,ef,ef | depart,roundabout-exit-2,arrive | + | a,h | ab,gh,gh | depart,roundabout-exit-3,arrive | + + Scenario: Mixed Entry and Exit + Given the profile "lhs" + And a grid size of 10 meters + And the node map + | | c | | a | | + | j | | b | | f | + | | k | | e | | + | l | | h | | d | + | | g | | i | | + + And the ways + | nodes | junction | oneway | + | cba | | yes | + | fed | | yes | + | ihg | | yes | + | lkj | | yes | + | behkb | roundabout | yes | + + When I route I should get + | waypoints | route | turns | + | c,a | cba,cba,cba | depart,roundabout-exit-1,arrive | + | l,a | lkj,cba,cba | depart,roundabout-exit-2,arrive | + | i,a | ihg,cba,cba | depart,roundabout-exit-3,arrive | From b8b41651c3ce868ddf2000edbf9a24b2e8f8e112 Mon Sep 17 00:00:00 2001 From: Michael Krasnyk Date: Tue, 19 Jul 2016 08:42:21 +0200 Subject: [PATCH 3/4] addressed comments Signed-off-by: Lauren Budorick --- src/engine/guidance/post_processing.cpp | 2 -- src/extractor/guidance/roundabout_handler.cpp | 33 +++++++------------ unit_tests/mocks/mock_datafacade.hpp | 1 + 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index 0a254c57412..27a3bd5bcca 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -517,7 +517,6 @@ std::vector anticipateLaneChangeForRoundabouts(std::vector // Although the enter instruction may be a left/right turn, for right-sided driving the // roundabout is counter-clockwise and therefore we need to always set it to a left turn. - // FIXME: assumes right-side driving (counter-clockwise roundabout flow) const auto enter_direction = enter.maneuver.instruction.direction_modifier; if (facade.UseLeftSideDriving()) @@ -536,7 +535,6 @@ std::vector anticipateLaneChangeForRoundabouts(std::vector auto enterAndLeave = anticipateLaneChange({enter, leave}); // Undo flipping direction on a right turn in a right-sided counter-clockwise roundabout. - // FIXME: assumes right-side driving (counter-clockwise roundabout flow) enterAndLeave[0].maneuver.instruction.direction_modifier = enter_direction; std::swap(*roundabout.first, enterAndLeave[0]); diff --git a/src/extractor/guidance/roundabout_handler.cpp b/src/extractor/guidance/roundabout_handler.cpp index b57cbb73641..62fd84bdbb0 100644 --- a/src/extractor/guidance/roundabout_handler.cpp +++ b/src/extractor/guidance/roundabout_handler.cpp @@ -71,12 +71,10 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags( const bool lhs = profile_properties.left_hand_driving; const int step = lhs ? -1 : 1; - const signed int_size = static_cast(intersection.size()); - - for (signed i = lhs ? int_size - 1 : 0; - i >= 0 && i < int_size; i += step) + for (std::size_t cnt = 0, idx = lhs ? intersection.size() - 1 : 0; + cnt < intersection.size(); ++cnt, idx += step) { - const auto &road = intersection[i]; + const auto &road = intersection[idx]; const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); // only check actual outgoing edges if (edge_data.reversed || !road.entry_allowed) @@ -92,8 +90,6 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags( // separate vertex than the one we are coming from that are in the direction of // the roundabout. // The sorting of the angles represents a problem for left-sided driving, though. - // FIXME in case of left-sided driving, we have to check whether we can enter the - // roundabout later in the cycle, rather than prior. // FIXME requires consideration of crossing the roundabout else if (node_based_graph.GetTarget(road.turn.eid) != from_nid && !can_enter_roundabout) { @@ -114,12 +110,10 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, bool past_roundabout_angle = false; const bool lhs = profile_properties.left_hand_driving; const int step = lhs ? -1 : 1; - const signed int_size = static_cast(intersection.size()); - - for (signed i = lhs ? int_size - 1 : 0; - i >= 0 && i < int_size; i += step) + for (std::size_t cnt = 0, idx = lhs ? intersection.size() - 1 : 0; + cnt < intersection.size(); ++cnt, idx += step) { - auto &road = intersection[i]; + auto &road = intersection[idx]; const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); // only check actual outgoing edges if (edge_data.reversed) @@ -135,8 +129,6 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, // This workaround handles cases in which an exit precedes and entry. The resulting // u-turn against the roundabout direction is invalidated. // The sorting of the angles represents a problem for left-sided driving, though. - // FIXME in case of left-sided driving, we have to check whether we can enter the - // roundabout later in the cycle, rather than prior. if (!edge_data.roundabout && node_based_graph.GetTarget(road.turn.eid) != from_nid && past_roundabout_angle) { @@ -377,16 +369,15 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou const bool lhs = profile_properties.left_hand_driving; const int step = lhs ? -1 : 1; - const signed int_size = static_cast(intersection.size()); if (on_roundabout) { // Shoule hopefully have only a single exit and continue // at least for cars. How about bikes? - for (signed i = lhs ? int_size - 1 : 0; - i >= 0 && i < int_size; i += step) + for (std::size_t cnt = 0, idx = lhs ? intersection.size() - 1 : 0; + cnt < intersection.size(); ++cnt, idx += step) { - auto &road = intersection[i]; + auto &road = intersection[idx]; auto &turn = road.turn; const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); if (out_data.roundabout) @@ -420,10 +411,10 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou } else { - for (signed i = lhs ? int_size - 1 : 0; - i >= 0 && i < int_size; i += step) + for (std::size_t cnt = 0, idx = lhs ? intersection.size() - 1 : 0; + cnt < intersection.size(); ++cnt, idx += step) { - auto &road = intersection[i]; + auto &road = intersection[idx]; if (!road.entry_allowed) continue; auto &turn = road.turn; diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index f36276c6ad4..c2064db125e 100644 --- a/unit_tests/mocks/mock_datafacade.hpp +++ b/unit_tests/mocks/mock_datafacade.hpp @@ -180,6 +180,7 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade bool GetContinueStraightDefault() const override { return true; } BearingClassID GetBearingClassID(const NodeID /*id*/) const override { return 0; }; EntryClassID GetEntryClassID(const EdgeID /*id*/) const override { return 0; } + bool UseLeftSideDriving() const override { return false; } bool hasLaneData(const EdgeID /*id*/) const override final { return true; }; util::guidance::LaneTupelIdPair GetLaneData(const EdgeID /*id*/) const override final From 0dbf2bce69f94caddceb7137d700043dd5bf8e5f Mon Sep 17 00:00:00 2001 From: Michael Krasnyk Date: Wed, 20 Jul 2016 14:05:53 +0200 Subject: [PATCH 4/4] added a lanes test in clockwise roundabouts --- features/guidance/anticipate-lanes.feature | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/features/guidance/anticipate-lanes.feature b/features/guidance/anticipate-lanes.feature index e6b6bff5fc1..ffd49800873 100644 --- a/features/guidance/anticipate-lanes.feature +++ b/features/guidance/anticipate-lanes.feature @@ -343,6 +343,38 @@ Feature: Turn Lane Guidance | waypoints | route | turns | lanes | | a,h | ab,gh,gh | depart,roundabout-exit-5,arrive | ,slight right:false slight right:true, | + @anticipate @todo + Scenario: Anticipate with lanes in roundabout where we stay on the roundabout for multiple exits + # Scenario requires correct lane handling for clockwise roundabouts + Given the profile "lhs" + And the node map + | | | a | | | + | | | b | | | + | h | c | | g | | + | | | | | | + | | d | | f | | + | | | e | | | + | x | | | | y | + + And the ways + | nodes | turn:lanes:forward | highway | junction | + | ab | slight_left\|slight_left | primary | | + | bg | | primary | roundabout | + | gf | | primary | roundabout | + | fe | | primary | roundabout | + | ed | | primary | roundabout | + | dc | slight_left | primary | roundabout | + | cb | | primary | roundabout | + | ch | | primary | | + | ex | | primary | | + | dx | | primary | | + | gy | | primary | | + | fy | | primary | | + + When I route I should get + | waypoints | route | turns | lanes | + | a,h | ab,ch,ch | depart,roundabout-exit-5,arrive | ,slight right:false slight right:true, | + @anticipate Scenario: Departing or arriving inside a roundabout does not yet anticipate lanes Given the node map