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:
committed by
Patrick Niklaus
parent
238e77d959
commit
1c1bfd7541
@@ -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);
|
||||
|
||||
@@ -93,6 +93,9 @@ class DirectShortestPathRouting final
|
||||
int distance = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_leg;
|
||||
|
||||
const bool constexpr DO_NOT_FORCE_LOOPS =
|
||||
false; // prevents forcing of loops, since offsets are set correctly
|
||||
|
||||
if (super::facade->GetCoreSize() > 0)
|
||||
{
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
@@ -103,11 +106,12 @@ class DirectShortestPathRouting final
|
||||
reverse_core_heap.Clear();
|
||||
|
||||
super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
|
||||
distance, packed_leg);
|
||||
distance, packed_leg, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
else
|
||||
{
|
||||
super::Search(forward_heap, reverse_heap, distance, packed_leg);
|
||||
super::Search(forward_heap, reverse_heap, distance, packed_leg, DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
|
||||
@@ -139,14 +139,21 @@ class ManyToManyRouting final
|
||||
// get target id from bucket entry
|
||||
const unsigned target_id = current_bucket.target_id;
|
||||
const int target_distance = current_bucket.distance;
|
||||
const EdgeWeight current_distance =
|
||||
(*result_table)[source_id * number_of_targets + target_id];
|
||||
auto ¤t_distance = (*result_table)[source_id * number_of_targets + target_id];
|
||||
// check if new distance is better
|
||||
const EdgeWeight new_distance = source_distance + target_distance;
|
||||
if (new_distance >= 0 && new_distance < current_distance)
|
||||
if (new_distance < 0)
|
||||
{
|
||||
(*result_table)[source_id * number_of_targets + target_id] =
|
||||
(source_distance + target_distance);
|
||||
const EdgeWeight loop_weight = super::GetLoopWeight(node);
|
||||
const int new_distance_with_loop = new_distance + loop_weight;
|
||||
if (loop_weight != INVALID_EDGE_WEIGHT && new_distance_with_loop >= 0)
|
||||
{
|
||||
current_distance = std::min(current_distance, new_distance_with_loop);
|
||||
}
|
||||
}
|
||||
else if (new_distance < current_distance)
|
||||
{
|
||||
(*result_table)[source_id * number_of_targets + target_id] = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,17 @@
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/search_engine_data.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
|
||||
namespace osrm
|
||||
@@ -71,24 +79,54 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
NodeID &middle_node_id,
|
||||
int &upper_bound,
|
||||
int min_edge_offset,
|
||||
std::int32_t &upper_bound,
|
||||
std::int32_t min_edge_offset,
|
||||
const bool forward_direction,
|
||||
const bool stalling = true) const
|
||||
const bool stalling,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse) const
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
const std::int32_t distance = forward_heap.GetKey(node);
|
||||
|
||||
if (reverse_heap.WasInserted(node))
|
||||
{
|
||||
const int new_distance = reverse_heap.GetKey(node) + distance;
|
||||
const std::int32_t new_distance = reverse_heap.GetKey(node) + distance;
|
||||
if (new_distance < upper_bound)
|
||||
{
|
||||
if (new_distance >= 0)
|
||||
if (new_distance >= 0 &&
|
||||
(!force_loop_forward ||
|
||||
forward_heap.GetData(node).parent !=
|
||||
node) // if loops are forced, they are so at the source
|
||||
&& (!force_loop_reverse || reverse_heap.GetData(node).parent != node))
|
||||
{
|
||||
middle_node_id = node;
|
||||
upper_bound = new_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check whether there is a loop present at the node
|
||||
for (const auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
bool forward_directionFlag =
|
||||
(forward_direction ? data.forward : data.backward);
|
||||
if (forward_directionFlag)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
if (to == node)
|
||||
{
|
||||
const EdgeWeight edge_weight = data.distance;
|
||||
const std::int32_t loop_distance = new_distance + edge_weight;
|
||||
if (loop_distance >= 0 && loop_distance < upper_bound)
|
||||
{
|
||||
middle_node_id = node;
|
||||
upper_bound = loop_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +149,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
if (reverse_flag)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
const EdgeWeight edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
|
||||
@@ -134,7 +172,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
const EdgeWeight edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const int to_distance = distance + edge_weight;
|
||||
@@ -155,6 +193,24 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
}
|
||||
}
|
||||
|
||||
inline EdgeWeight GetLoopWeight(NodeID node) const
|
||||
{
|
||||
EdgeWeight loop_weight = INVALID_EDGE_WEIGHT;
|
||||
for (auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = facade->GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
if (to == node)
|
||||
{
|
||||
loop_weight = std::min(loop_weight, data.distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return loop_weight;
|
||||
}
|
||||
|
||||
template <typename RandomIter>
|
||||
void UnpackPath(RandomIter packed_path_begin,
|
||||
RandomIter packed_path_end,
|
||||
@@ -188,10 +244,10 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
// facade->FindEdge does not suffice here in case of shortcuts.
|
||||
// The above explanation unclear? Think!
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
@@ -207,7 +263,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
@@ -345,10 +401,10 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
recursion_stack.pop();
|
||||
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
@@ -361,7 +417,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
@@ -414,10 +470,23 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
}
|
||||
|
||||
// assumes that heaps are already setup correctly.
|
||||
// ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
|
||||
// Offsets.
|
||||
// In case additional offsets are supplied, you might have to force a loop first.
|
||||
// A forced loop might be necessary, if source and target are on the same segment.
|
||||
// If this is the case and the offsets of the respective direction are larger for the source
|
||||
// than the target
|
||||
// then a force loop is required (e.g. source_phantom.forward_node_id ==
|
||||
// target_phantom.forward_node_id
|
||||
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
||||
// requires
|
||||
// a force loop, if the heaps have been initialized with positive offsets.
|
||||
void Search(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
int &distance,
|
||||
std::vector<NodeID> &packed_leg) const
|
||||
std::int32_t &distance,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse) const
|
||||
{
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
@@ -428,15 +497,18 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
||||
|
||||
// run two-Target Dijkstra routing step.
|
||||
const constexpr bool STALLING_ENABLED = true;
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
if (!forward_heap.Empty())
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true);
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true,
|
||||
STALLING_ENABLED, force_loop_forward, force_loop_reverse);
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false);
|
||||
RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false,
|
||||
STALLING_ENABLED, force_loop_reverse, force_loop_forward);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,16 +522,38 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
|
||||
"no path found");
|
||||
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||
// make sure to correctly unpack loops
|
||||
if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
|
||||
{
|
||||
// self loop
|
||||
BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
|
||||
reverse_heap.GetData(middle).parent == middle);
|
||||
packed_leg.push_back(middle);
|
||||
packed_leg.push_back(middle);
|
||||
}
|
||||
else
|
||||
{
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||
}
|
||||
}
|
||||
|
||||
// assumes that heaps are already setup correctly.
|
||||
// A forced loop might be necessary, if source and target are on the same segment.
|
||||
// If this is the case and the offsets of the respective direction are larger for the source
|
||||
// than the target
|
||||
// then a force loop is required (e.g. source_phantom.forward_node_id ==
|
||||
// target_phantom.forward_node_id
|
||||
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
||||
// requires
|
||||
// a force loop, if the heaps have been initialized with positive offsets.
|
||||
void SearchWithCore(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
SearchEngineData::QueryHeap &forward_core_heap,
|
||||
SearchEngineData::QueryHeap &reverse_core_heap,
|
||||
int &distance,
|
||||
std::vector<NodeID> &packed_leg) const
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse) const
|
||||
{
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
@@ -471,6 +565,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
// we only every insert negative offsets for nodes in the forward heap
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
||||
|
||||
const constexpr bool STALLING_ENABLED = true;
|
||||
// run two-Target Dijkstra routing step.
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
@@ -484,8 +579,8 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
}
|
||||
else
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset,
|
||||
true);
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true,
|
||||
STALLING_ENABLED, force_loop_forward, force_loop_reverse);
|
||||
}
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
@@ -499,7 +594,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
else
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset,
|
||||
false);
|
||||
false, STALLING_ENABLED, force_loop_reverse, force_loop_forward);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,18 +643,21 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT(min_core_edge_offset <= 0);
|
||||
|
||||
// run two-target Dijkstra routing step on core with termination criterion
|
||||
const constexpr bool STALLING_DISABLED = false;
|
||||
while (0 < (forward_core_heap.Size() + reverse_core_heap.Size()) &&
|
||||
distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey()))
|
||||
{
|
||||
if (!forward_core_heap.Empty())
|
||||
{
|
||||
RoutingStep(forward_core_heap, reverse_core_heap, middle, distance,
|
||||
min_core_edge_offset, true, false);
|
||||
min_core_edge_offset, true, STALLING_DISABLED, force_loop_forward,
|
||||
force_loop_reverse);
|
||||
}
|
||||
if (!reverse_core_heap.Empty())
|
||||
{
|
||||
RoutingStep(reverse_core_heap, forward_core_heap, middle, distance,
|
||||
min_core_edge_offset, false, false);
|
||||
min_core_edge_offset, false, STALLING_DISABLED, force_loop_reverse,
|
||||
force_loop_forward);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,29 +671,45 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
|
||||
"no path found");
|
||||
|
||||
// we need to unpack sub path from core heaps
|
||||
if (facade->IsCoreNode(middle))
|
||||
if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
|
||||
{
|
||||
std::vector<NodeID> packed_core_leg;
|
||||
RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle,
|
||||
packed_core_leg);
|
||||
BOOST_ASSERT(packed_core_leg.size() > 0);
|
||||
RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg);
|
||||
std::reverse(packed_leg.begin(), packed_leg.end());
|
||||
packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end());
|
||||
RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg);
|
||||
// self loop
|
||||
BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
|
||||
reverse_heap.GetData(middle).parent == middle);
|
||||
packed_leg.push_back(middle);
|
||||
packed_leg.push_back(middle);
|
||||
}
|
||||
else
|
||||
{
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||
// we need to unpack sub path from core heaps
|
||||
if (facade->IsCoreNode(middle))
|
||||
{
|
||||
std::vector<NodeID> packed_core_leg;
|
||||
RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle,
|
||||
packed_core_leg);
|
||||
BOOST_ASSERT(packed_core_leg.size() > 0);
|
||||
RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg);
|
||||
std::reverse(packed_leg.begin(), packed_leg.end());
|
||||
packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end());
|
||||
RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg);
|
||||
}
|
||||
else
|
||||
{
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Requires the heaps for be empty
|
||||
// If heaps should be adjusted to be initialized outside of this function,
|
||||
// the addition of force_loop parameters might be required
|
||||
double get_network_distance(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom) const
|
||||
{
|
||||
BOOST_ASSERT(forward_heap.Empty());
|
||||
BOOST_ASSERT(reverse_heap.Empty());
|
||||
EdgeWeight upper_bound = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle_node = SPECIAL_NODEID;
|
||||
EdgeWeight edge_offset = std::min(0, -source_phantom.GetForwardWeightPlusOffset());
|
||||
@@ -628,17 +742,19 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
}
|
||||
|
||||
// search from s and t till new_min/(1+epsilon) > length_of_shortest_path
|
||||
const constexpr bool STALLING_ENABLED = true;
|
||||
const constexpr bool DO_NOT_FORCE_LOOPS = false;
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
if (0 < forward_heap.Size())
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset,
|
||||
true);
|
||||
RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset, true,
|
||||
STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
if (0 < reverse_heap.Size())
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle_node, upper_bound, edge_offset,
|
||||
false);
|
||||
false, STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,7 +762,19 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
if (upper_bound != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
std::vector<NodeID> packed_leg;
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle_node, packed_leg);
|
||||
if (upper_bound != forward_heap.GetKey(middle_node) + reverse_heap.GetKey(middle_node))
|
||||
{
|
||||
// self loop
|
||||
BOOST_ASSERT(forward_heap.GetData(middle_node).parent == middle_node &&
|
||||
reverse_heap.GetData(middle_node).parent == middle_node);
|
||||
packed_leg.push_back(middle_node);
|
||||
packed_leg.push_back(middle_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle_node, packed_leg);
|
||||
}
|
||||
|
||||
std::vector<PathData> unpacked_path;
|
||||
PhantomNodes nodes;
|
||||
nodes.source_phantom = source_phantom;
|
||||
|
||||
@@ -24,6 +24,9 @@ class ShortestPathRouting final
|
||||
using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>;
|
||||
using QueryHeap = SearchEngineData::QueryHeap;
|
||||
SearchEngineData &engine_working_data;
|
||||
const static constexpr bool FORWARD_DIRECTION = true;
|
||||
const static constexpr bool REVERSE_DIRECTION = false;
|
||||
const static constexpr bool DO_NOT_FORCE_LOOP = false;
|
||||
|
||||
public:
|
||||
ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
@@ -33,6 +36,19 @@ class ShortestPathRouting final
|
||||
|
||||
~ShortestPathRouting() {}
|
||||
|
||||
inline bool
|
||||
forceLoop(bool forward, const PhantomNode &source_phantom, const PhantomNode &target_phantom) const
|
||||
{
|
||||
if (forward)
|
||||
return source_phantom.forward_node_id == target_phantom.forward_node_id &&
|
||||
source_phantom.GetForwardWeightPlusOffset() >
|
||||
target_phantom.GetForwardWeightPlusOffset();
|
||||
else
|
||||
return source_phantom.reverse_node_id == target_phantom.reverse_node_id &&
|
||||
source_phantom.GetReverseWeightPlusOffset() >
|
||||
target_phantom.GetReverseWeightPlusOffset();
|
||||
};
|
||||
|
||||
// allows a uturn at the target_phantom
|
||||
// searches source forward/reverse -> target forward/reverse
|
||||
void SearchWithUTurn(QueryHeap &forward_heap,
|
||||
@@ -76,113 +92,12 @@ class ShortestPathRouting final
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path);
|
||||
}
|
||||
|
||||
// If source and target are reverse on a oneway we need to find a path
|
||||
// that connects the two. This is _not_ the shortest path in our model,
|
||||
// as source and target are on the same edge based node.
|
||||
// We force a detour by inserting "virtaul vias", which means we search a path
|
||||
// from all nodes that are connected by outgoing edges to all nodes that are connected by
|
||||
// incoming edges.
|
||||
// ------^
|
||||
// | ^source
|
||||
// | ^
|
||||
// | ^target
|
||||
// ------^
|
||||
void SearchLoop(QueryHeap &forward_heap,
|
||||
QueryHeap &reverse_heap,
|
||||
const bool search_forward_node,
|
||||
const bool search_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_distance_to_forward,
|
||||
const int total_distance_to_reverse,
|
||||
int &new_total_distance_to_forward,
|
||||
int &new_total_distance_to_reverse,
|
||||
std::vector<NodeID> &leg_packed_path_forward,
|
||||
std::vector<NodeID> &leg_packed_path_reverse) const
|
||||
{
|
||||
BOOST_ASSERT(source_phantom.forward_node_id == target_phantom.forward_node_id);
|
||||
BOOST_ASSERT(source_phantom.reverse_node_id == target_phantom.reverse_node_id);
|
||||
|
||||
if (search_forward_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
auto node_id = source_phantom.forward_node_id;
|
||||
|
||||
for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
|
||||
{
|
||||
const auto &data = super::facade->GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = total_distance_to_forward + data.distance -
|
||||
source_phantom.GetForwardWeightPlusOffset();
|
||||
forward_heap.Insert(target, offset, target);
|
||||
}
|
||||
|
||||
if (data.backward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = data.distance + target_phantom.GetForwardWeightPlusOffset();
|
||||
reverse_heap.Insert(target, offset, target);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
|
||||
leg_packed_path_forward);
|
||||
|
||||
// insert node to both endpoints to close the leg
|
||||
leg_packed_path_forward.push_back(node_id);
|
||||
std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
|
||||
leg_packed_path_forward.push_back(node_id);
|
||||
std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
|
||||
}
|
||||
|
||||
if (search_reverse_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
auto node_id = source_phantom.reverse_node_id;
|
||||
|
||||
for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
|
||||
{
|
||||
const auto &data = super::facade->GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = total_distance_to_reverse + data.distance -
|
||||
source_phantom.GetReverseWeightPlusOffset();
|
||||
forward_heap.Insert(target, offset, target);
|
||||
}
|
||||
|
||||
if (data.backward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = data.distance + target_phantom.GetReverseWeightPlusOffset();
|
||||
reverse_heap.Insert(target, offset, target);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
|
||||
leg_packed_path_reverse);
|
||||
|
||||
// insert node to both endpoints to close the leg
|
||||
leg_packed_path_reverse.push_back(node_id);
|
||||
std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
|
||||
leg_packed_path_reverse.push_back(node_id);
|
||||
std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
|
||||
}
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path,
|
||||
forceLoop(FORWARD_DIRECTION, source_phantom, target_phantom),
|
||||
forceLoop(REVERSE_DIRECTION, source_phantom, target_phantom));
|
||||
}
|
||||
|
||||
// searches shortest path between:
|
||||
@@ -227,8 +142,9 @@ class ShortestPathRouting final
|
||||
}
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
|
||||
leg_packed_path_forward);
|
||||
super::Search(
|
||||
forward_heap, reverse_heap, new_total_distance_to_forward, leg_packed_path_forward,
|
||||
forceLoop(FORWARD_DIRECTION, source_phantom, target_phantom), DO_NOT_FORCE_LOOP);
|
||||
}
|
||||
|
||||
if (search_to_reverse_node)
|
||||
@@ -255,7 +171,8 @@ class ShortestPathRouting final
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
|
||||
leg_packed_path_reverse);
|
||||
leg_packed_path_reverse, DO_NOT_FORCE_LOOP,
|
||||
forceLoop(REVERSE_DIRECTION, source_phantom, target_phantom));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,19 +253,6 @@ class ShortestPathRouting final
|
||||
BOOST_ASSERT(!search_from_reverse_node ||
|
||||
source_phantom.reverse_node_id != SPECIAL_NODEID);
|
||||
|
||||
if (source_phantom.forward_node_id == target_phantom.forward_node_id &&
|
||||
source_phantom.GetForwardWeightPlusOffset() >
|
||||
target_phantom.GetForwardWeightPlusOffset())
|
||||
{
|
||||
search_to_forward_node = search_from_reverse_node;
|
||||
}
|
||||
if (source_phantom.reverse_node_id == target_phantom.reverse_node_id &&
|
||||
source_phantom.GetReverseWeightPlusOffset() >
|
||||
target_phantom.GetReverseWeightPlusOffset())
|
||||
{
|
||||
search_to_reverse_node = search_from_forward_node;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(search_from_forward_node || search_from_reverse_node);
|
||||
|
||||
if (search_to_reverse_node || search_to_forward_node)
|
||||
@@ -385,18 +289,6 @@ class ShortestPathRouting final
|
||||
packed_leg_to_reverse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
|
||||
search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
|
||||
BOOST_ASSERT(search_from_reverse_node == search_to_reverse_node);
|
||||
BOOST_ASSERT(search_from_forward_node == search_to_forward_node);
|
||||
SearchLoop(forward_heap, reverse_heap, search_from_forward_node,
|
||||
search_from_reverse_node, source_phantom, target_phantom,
|
||||
total_distance_to_forward, total_distance_to_reverse,
|
||||
new_total_distance_to_forward, new_total_distance_to_reverse,
|
||||
packed_leg_to_forward, packed_leg_to_reverse);
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if ((INVALID_EDGE_WEIGHT == new_total_distance_to_forward) &&
|
||||
|
||||
Reference in New Issue
Block a user