Prevent loops in extraction based on merge

This commit is contained in:
Moritz Kobitzsch 2016-09-19 12:56:13 +02:00
parent bf2b1a64b9
commit 8522cddd61
5 changed files with 90 additions and 15 deletions

View File

@ -313,3 +313,39 @@ Feature: Slipways and Dedicated Turn Lanes
| a,d | new york,new york | depart,arrive | this is the sinatra route | | a,d | new york,new york | depart,arrive | this is the sinatra route |
| a,j | new york,1st street,1st street | depart,turn left,arrive | | | a,j | new york,1st street,1st street | depart,turn left,arrive | |
| a,1 | new york,m street,1st street,1st street | depart,turn right,turn left,arrive | this can false be seen as a sliproad | | a,1 | new york,m street,1st street,1st street | depart,turn right,turn left,arrive | this can false be seen as a sliproad |
# Merging into degree two loop on dedicated turn detection / 2927
Scenario: Turn Instead of Ramp
Given the node map
| | | | | | | | | | | | | | | | f |
| | | | | g | | | | | | h | | | | | |
| | | | | | | | | | | | | d | | | e |
| i | | | | c | | | | | | j | | | | | |
| | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | |
| | | b | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | |
| | | a | | | | | | | | | | | | | |
And the ways
| nodes | highway | name | oneway |
| abi | primary | road | yes |
| bcjd | primary | loop | yes |
| dhgf | primary | loop | yes |
| fed | primary | loop | yes |
And the nodes
| node | highway |
| g | traffic_signals |
| c | traffic_signals |
# We don't actually care about routes here, this is all about endless loops in turn discovery
When I route I should get
| waypoints | route | turns |
| a,i | road,road,road | depart,fork slight left,arrive |

View File

@ -36,6 +36,25 @@ Feature: Basic Roundabout
| h,c | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | h,c | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| h,e | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | h,e | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
#2927
Scenario: Only Roundabout
Given the node map
| | | a | | |
| | | | | |
| | | | | |
| b | | | | d |
| | | | | |
| | | | | |
| | | c | | |
And the ways
| nodes | junction |
| abcda | roundabout |
When I route I should get
| waypoints | route | turns |
| a,c | abcda,abcda | depart,arrive |
Scenario: Only Exit Scenario: Only Exit
Given the node map Given the node map
| | | a | | | | | | a | | |

View File

@ -1,11 +1,12 @@
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
#include <iterator> #include <iterator>
#include <limits> #include <limits>
#include <unordered_set>
#include <utility> #include <utility>
#include <boost/range/algorithm/count_if.hpp> #include <boost/range/algorithm/count_if.hpp>
@ -268,8 +269,11 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
return becomes_narrower; return becomes_narrower;
}; };
const bool is_y_arm_first = isValidYArm(first_index, second_index);
const bool is_y_arm_second = isValidYArm(second_index, first_index);
// Only merge valid y-arms // Only merge valid y-arms
if (!isValidYArm(first_index, second_index) || !isValidYArm(second_index, first_index)) if (!is_y_arm_first || !is_y_arm_second)
return false; return false;
if (angle_between < 60) if (angle_between < 60)
@ -577,10 +581,14 @@ IntersectionGenerator::GetActualNextIntersection(const NodeID starting_node,
// to prevent endless loops // to prevent endless loops
const auto termination_node = node_based_graph.GetTarget(via_edge); const auto termination_node = node_based_graph.GetTarget(via_edge);
while (result.size() == 2 && // using a maximum lookahead, we make sure not to end up in some form of loop
node_based_graph.GetEdgeData(via_edge).IsCompatibleTo( std::unordered_set<NodeID> visited_nodes;
node_based_graph.GetEdgeData(result[1].turn.eid))) while (visited_nodes.count(node_at_intersection) == 0 &&
(result.size() == 2 &&
node_based_graph.GetEdgeData(via_edge).IsCompatibleTo(
node_based_graph.GetEdgeData(result[1].turn.eid))))
{ {
visited_nodes.insert(node_at_intersection);
node_at_intersection = node_based_graph.GetTarget(incoming_edge); node_at_intersection = node_based_graph.GetTarget(incoming_edge);
incoming_edge = result[1].turn.eid; incoming_edge = result[1].turn.eid;
result = GetConnectedRoads(node_at_intersection, incoming_edge); result = GetConnectedRoads(node_at_intersection, incoming_edge);

View File

@ -56,9 +56,14 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
auto intersection = intersection_generator(at_node, road.turn.eid); auto intersection = intersection_generator(at_node, road.turn.eid);
auto in_edge = road.turn.eid; auto in_edge = road.turn.eid;
// skip over traffic lights // skip over traffic lights
while (intersection.size() == 2) // to prevent ending up in an endless loop, we remember all visited nodes. This is
// necessary, since merging of roads can actually create enterable loops of degree two
std::unordered_set<NodeID> visited_nodes;
auto node = at_node;
while (intersection.size() == 2 && visited_nodes.count(node) == 0)
{ {
const auto node = node_based_graph.GetTarget(in_edge); visited_nodes.insert(node);
node = node_based_graph.GetTarget(in_edge);
if (node == at_node) if (node == at_node)
{ {
// we ended up in a loop without exit // we ended up in a loop without exit
@ -70,6 +75,11 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
output_node = node_based_graph.GetTarget(in_edge); output_node = node_based_graph.GetTarget(in_edge);
intersection = intersection_generator(node, in_edge); intersection = intersection_generator(node, in_edge);
} }
if (intersection.size() <= 2)
{
output_node = SPECIAL_NODEID;
intersection.clear();
}
return intersection; return intersection;
}; };
@ -162,6 +172,9 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
const auto next_road_next_intersection = const auto next_road_next_intersection =
findNextIntersectionForRoad(intersection_node_id, next_road, next_intersection_node); findNextIntersectionForRoad(intersection_node_id, next_road, next_intersection_node);
if (next_road_next_intersection.empty())
return intersection;
// If we are at a traffic loop at the end of a road, don't consider it a sliproad // If we are at a traffic loop at the end of a road, don't consider it a sliproad
if (intersection_node_id == next_intersection_node) if (intersection_node_id == next_intersection_node)
return intersection; return intersection;
@ -194,13 +207,14 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
const auto link_data = node_based_graph.GetEdgeData(road.turn.eid); const auto link_data = node_based_graph.GetEdgeData(road.turn.eid);
// Check if the road continues here // Check if the road continues here
const bool is_through_street = const bool is_through_street =
!target_intersection.empty() &&
target_intersection.end() != target_intersection.end() !=
std::find_if(target_intersection.begin() + 1, std::find_if(target_intersection.begin() + 1,
target_intersection.end(), target_intersection.end(),
[this, &link_data](const ConnectedRoad &road) { [this, &link_data](const ConnectedRoad &road) {
return node_based_graph.GetEdgeData(road.turn.eid).name_id == return node_based_graph.GetEdgeData(road.turn.eid).name_id ==
link_data.name_id; link_data.name_id;
}); });
// if the sliproad candidate is a through street, we cannot handle it as a sliproad // if the sliproad candidate is a through street, we cannot handle it as a sliproad
if (is_through_street) if (is_through_street)

View File

@ -1,5 +1,3 @@
#include "util/debug.hpp"
#include "extractor/guidance/turn_lane_augmentation.hpp" #include "extractor/guidance/turn_lane_augmentation.hpp"
#include "extractor/guidance/turn_lane_types.hpp" #include "extractor/guidance/turn_lane_types.hpp"
#include "util/simple_logger.hpp" #include "util/simple_logger.hpp"