Fix routing when start and target are on the same segment

Fixes issue #1864. Given the simple set-up:

a --> b --> c
^-----------|

This would translate into an edge based graph (ab) -> (bc),
(bc) -> (ca), (ca) -> (ab).

Starting at the end of the one-way street (ab) and going to
the beginning, the query has to find a self-loop within the
graph (ab) -> (bc) -> (ca) -> (ab), as both nodes map to the
same segment (ab).
This commit is contained in:
Moritz Kobitzsch
2016-01-07 10:33:47 +01:00
committed by Patrick Niklaus
parent 238e77d959
commit 1c1bfd7541
22 changed files with 744 additions and 287 deletions
@@ -156,8 +156,23 @@ class AlternativeRouting final
std::vector<NodeID> packed_forward_path;
std::vector<NodeID> packed_reverse_path;
super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
if (upper_bound_to_shortest_path_distance !=
forward_heap1.GetKey(middle_node) + reverse_heap1.GetKey(middle_node))
{
// Self Loop
BOOST_ASSERT(forward_heap1.GetData(middle_node).parent == middle_node &&
reverse_heap1.GetData(middle_node).parent == middle_node);
packed_forward_path.push_back(middle_node);
packed_forward_path.push_back(middle_node);
}
else
{
super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node,
packed_forward_path);
super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node,
packed_reverse_path);
}
// this set is is used as an indicator if a node is on the shortest path
std::unordered_set<NodeID> nodes_in_path(packed_forward_path.size() +
@@ -382,10 +397,13 @@ class AlternativeRouting final
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
new_reverse_heap.Insert(via_node, 0, via_node);
// compute path <s,..,v> by reusing forward search from s
const bool constexpr STALLING_ENABLED = true;
const bool constexpr DO_NOT_FORCE_LOOPS = false;
while (!new_reverse_heap.Empty())
{
super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle,
upper_bound_s_v_path_length, min_edge_offset, false);
upper_bound_s_v_path_length, min_edge_offset, false,
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
// compute path <v,..,t> by reusing backward search from node t
NodeID v_t_middle = SPECIAL_NODEID;
@@ -394,7 +412,8 @@ class AlternativeRouting final
while (!new_forward_heap.Empty())
{
super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle,
upper_bound_of_v_t_path_length, min_edge_offset, true);
upper_bound_of_v_t_path_length, min_edge_offset, true,
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
*real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
@@ -442,10 +461,10 @@ class AlternativeRouting final
partially_unpacked_shortest_path.size())) -
1;
for (int64_t current_node = 0; (current_node < packed_path_length) &&
(partially_unpacked_via_path[current_node] ==
partially_unpacked_shortest_path[current_node] &&
partially_unpacked_via_path[current_node + 1] ==
partially_unpacked_shortest_path[current_node + 1]);
(partially_unpacked_via_path[current_node] ==
partially_unpacked_shortest_path[current_node] &&
partially_unpacked_via_path[current_node + 1] ==
partially_unpacked_shortest_path[current_node + 1]);
++current_node)
{
EdgeID selected_edge =
@@ -600,6 +619,18 @@ class AlternativeRouting final
// << "
// at distance " << new_distance;
}
else
{
// check whether there is a loop present at the node
const auto loop_distance = super::GetLoopWeight(node);
const int new_distance_with_loop = new_distance + loop_distance;
if (loop_distance != INVALID_EDGE_WEIGHT &&
new_distance_with_loop <= *upper_bound_to_shortest_path_distance)
{
*middle_node = node;
*upper_bound_to_shortest_path_distance = loop_distance;
}
}
}
}
@@ -655,10 +686,13 @@ class AlternativeRouting final
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
// compute path <s,..,v> by reusing forward search from s
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
const bool constexpr STALLING_ENABLED = true;
const bool constexpr DO_NOT_FORCE_LOOPS = false;
while (new_reverse_heap.Size() > 0)
{
super::RoutingStep(new_reverse_heap, existing_forward_heap, *s_v_middle,
upper_bound_s_v_path_length, min_edge_offset, false);
upper_bound_s_v_path_length, min_edge_offset, false,
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
@@ -673,7 +707,8 @@ class AlternativeRouting final
while (new_forward_heap.Size() > 0)
{
super::RoutingStep(new_forward_heap, existing_reverse_heap, *v_t_middle,
upper_bound_of_v_t_path_length, min_edge_offset, true);
upper_bound_of_v_t_path_length, min_edge_offset, true,
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
@@ -841,12 +876,14 @@ class AlternativeRouting final
if (!forward_heap3.Empty())
{
super::RoutingStep(forward_heap3, reverse_heap3, middle, upper_bound,
min_edge_offset, true);
min_edge_offset, true, STALLING_ENABLED, DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
}
if (!reverse_heap3.Empty())
{
super::RoutingStep(reverse_heap3, forward_heap3, middle, upper_bound,
min_edge_offset, false);
min_edge_offset, false, STALLING_ENABLED, DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS);
}
}
return (upper_bound <= t_test_path_length);