From e14bc30428564168d05f7a3b566bb7ac0497f0b5 Mon Sep 17 00:00:00 2001 From: Moritz Kobitzsch Date: Thu, 11 Aug 2016 09:44:30 +0200 Subject: [PATCH] adjusted for comments --- .../guidance/intersection_generator.cpp | 74 ++++++++++++++----- src/extractor/guidance/turn_lane_data.cpp | 7 ++ src/extractor/guidance/turn_lane_handler.cpp | 32 ++++++-- 3 files changed, 85 insertions(+), 28 deletions(-) diff --git a/src/extractor/guidance/intersection_generator.cpp b/src/extractor/guidance/intersection_generator.cpp index a9355cef5..20030f1f9 100644 --- a/src/extractor/guidance/intersection_generator.cpp +++ b/src/extractor/guidance/intersection_generator.cpp @@ -1,5 +1,5 @@ -#include "extractor/guidance/intersection_generator.hpp" #include "extractor/guidance/constants.hpp" +#include "extractor/guidance/intersection_generator.hpp" #include "extractor/guidance/toolkit.hpp" #include @@ -147,9 +147,9 @@ Intersection IntersectionGenerator::getConnectedRoads(const NodeID from_node, // after intersections sorting by angles, find the u-turn with (from_node == to_node) // that was inserted together with setting uturn_could_be_valid flag std::size_t self_u_turn = 0; - while (self_u_turn < intersection.size() - && intersection[self_u_turn].turn.angle < std::numeric_limits::epsilon() - && from_node != node_based_graph.GetTarget(intersection[self_u_turn].turn.eid)) + while (self_u_turn < intersection.size() && + intersection[self_u_turn].turn.angle < std::numeric_limits::epsilon() && + from_node != node_based_graph.GetTarget(intersection[self_u_turn].turn.eid)) { ++self_u_turn; } @@ -244,9 +244,41 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti }(); // check for merges including the basic u-turn - // these result in an adjustment of all other angles + // these result in an adjustment of all other angles. This is due to how these angles are + // perceived. Considering the following example: + // + // c b + // Y + // a + // + // coming from a to b (given a road that splits at the fork into two one-ways), the turn is not + // considered as a turn but rather as going straight. + // Now if we look at the situation merging: + // + // a b + // \ / + // e - + - d + // | + // c + // + // With a,b representing the same road, the intersection itself represents a classif for way + // intersection so we handle it like + // + // (a),b + // | + // e - + - d + // | + // c + // + // To be able to consider this adjusted representation down the line, we merge some roads. + // If the merge occurs at the u-turn edge, we need to adjust all angles, though, since they are + // with respect to the now changed perceived location of a. If we move (a) to the left, we add + // the difference to all angles. Otherwise we subtract it. + bool merged_first = false; if (mergable(0, intersection.size() - 1)) { + merged_first = true; + // moving `a` to the left const double correction_factor = (360 - intersection[intersection.size() - 1].turn.angle) / 2; for (std::size_t i = 1; i + 1 < intersection.size(); ++i) @@ -256,25 +288,12 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti intersection[0] = merge(intersection.front(), intersection.back()); intersection[0].turn.angle = 0; - if (is_connected_to_roundabout) - { - /* - * We are merging a u-turn against the direction of a roundabout - * - * -----------> roundabout - * / \ - * out in - * - * These cases have to be disabled, even if they are not forbidden specifically by a - * relation - */ - intersection[0].entry_allowed = false; - } - intersection.pop_back(); } else if (mergable(0, 1)) { + merged_first = true; + // moving `a` to the right const double correction_factor = (intersection[1].turn.angle) / 2; for (std::size_t i = 2; i < intersection.size(); ++i) intersection[i].turn.angle -= correction_factor; @@ -283,6 +302,21 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti intersection.erase(intersection.begin() + 1); } + if (merged_first && is_connected_to_roundabout) + { + /* + * We are merging a u-turn against the direction of a roundabout + * + * -----------> roundabout + * / \ + * out in + * + * These cases have to be disabled, even if they are not forbidden specifically by a + * relation + */ + intersection[0].entry_allowed = false; + } + // a merge including the first u-turn requres an adjustment of the turn angles // therefore these are handled prior to this step for (std::size_t index = 2; index < intersection.size(); ++index) diff --git a/src/extractor/guidance/turn_lane_data.cpp b/src/extractor/guidance/turn_lane_data.cpp index 84a1c4f07..26e8d5870 100644 --- a/src/extractor/guidance/turn_lane_data.cpp +++ b/src/extractor/guidance/turn_lane_data.cpp @@ -116,6 +116,13 @@ LaneDataVector laneDataFromDescription(const TurnLaneDescription &turn_lane_desc // which is invalid for (std::size_t index = 1; index < lane_data.size(); ++index) { + // u-turn located somewhere in the middle + // Right now we can only handle u-turns at the sides. If we find a u-turn somewhere in + // the middle of the tags, we abort the handling right here. + if (index + 1 < lane_data.size() && + ((lane_data[index].tag & TurnLaneType::uturn) != TurnLaneType::empty)) + return false; + if (lane_data[index - 1].to > lane_data[index].from) return false; } diff --git a/src/extractor/guidance/turn_lane_handler.cpp b/src/extractor/guidance/turn_lane_handler.cpp index b576cc071..3adcddaf5 100644 --- a/src/extractor/guidance/turn_lane_handler.cpp +++ b/src/extractor/guidance/turn_lane_handler.cpp @@ -117,12 +117,18 @@ Intersection TurnLaneHandler::assignTurnLanes(const NodeID at, if (has_merge_lane || has_non_usable_u_turn) return intersection; - if (!lane_data.empty() && canMatchTrivially(intersection, lane_data) && + // check if a u-turn is allowed (for some reason) and is missing from the list of tags (u-turn + // is often allowed from the `left` lane without an additional indication dedicated to u-turns). + const bool is_missing_valid_u_turn = lane_data.size() != static_cast(( !hasTag(TurnLaneType::uturn, lane_data) && intersection[0].entry_allowed ? 1 : 0)) + possible_entries && - intersection[0].entry_allowed && !hasTag(TurnLaneType::none, lane_data)) + intersection[0].entry_allowed; + + // FIXME the lane to add depends on the side of driving/u-turn rules in the country + if (!lane_data.empty() && canMatchTrivially(intersection, lane_data) && + !is_missing_valid_u_turn && !hasTag(TurnLaneType::none, lane_data)) lane_data.push_back({TurnLaneType::uturn, lane_data.back().to, lane_data.back().to}); bool is_simple = isSimpleIntersection(lane_data, intersection); @@ -335,24 +341,34 @@ bool TurnLaneHandler::isSimpleIntersection(const LaneDataVector &lane_data, bool all_simple = true; bool has_none = false; std::unordered_set matched_indices; - for (const auto &data : lane_data) + for (std::size_t data_index = 0; data_index < lane_data.size(); ++data_index) { + const auto &data = lane_data[data_index]; if (data.tag == TurnLaneType::none) { has_none = true; continue; } + // u-turn tags are at the outside of the lane-tags and require special handling, since + // locating their best match requires knowledge on the neighboring tag. (see documentation + // on findBestMatch/findBestMatchForReverse const auto best_match = [&]() { + // normal tag or u-turn as only choice (no other tag present) if (data.tag != TurnLaneType::uturn || lane_data.size() == 1) return findBestMatch(data.tag, intersection); - // lane_data.size() > 1 - if (lane_data.back().tag == TurnLaneType::uturn) - return findBestMatchForReverse(lane_data[lane_data.size() - 2].tag, intersection); + BOOST_ASSERT(data.tag == TurnLaneType::uturn); + // u-turn at the very left, leftmost turn at data_index - 1 + if (data_index + 1 == lane_data.size()) + return findBestMatchForReverse(lane_data[data_index - 1].tag, intersection); - BOOST_ASSERT(lane_data.front().tag == TurnLaneType::uturn); - return findBestMatchForReverse(lane_data[1].tag, intersection); + // u-turn to the right (left-handed driving) -> rightmost turn to the left (data_index + + // 1) + if (data_index == 0) + return findBestMatchForReverse(lane_data[data_index + 1].tag, intersection); + + return intersection.begin(); }(); std::size_t match_index = std::distance(intersection.begin(), best_match); all_simple &= (matched_indices.count(match_index) == 0);