Split routing_base into CH and non-CH parts
This commit is contained in:
parent
43a7e8e08a
commit
6829f46c31
@ -1,5 +1,5 @@
|
|||||||
#ifndef ROUTING_BASE_HPP
|
#ifndef OSRM_ENGINE_ROUTING_BASE_HPP
|
||||||
#define ROUTING_BASE_HPP
|
#define OSRM_ENGINE_ROUTING_BASE_HPP
|
||||||
|
|
||||||
#include "extractor/guidance/turn_instruction.hpp"
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
|
|
||||||
@ -35,381 +35,150 @@ namespace routing_algorithms
|
|||||||
{
|
{
|
||||||
static constexpr bool FORWARD_DIRECTION = true;
|
static constexpr bool FORWARD_DIRECTION = true;
|
||||||
static constexpr bool REVERSE_DIRECTION = false;
|
static constexpr bool REVERSE_DIRECTION = false;
|
||||||
|
static constexpr bool DO_NOT_FORCE_LOOPS = false;
|
||||||
|
|
||||||
// Stalling
|
template <bool DIRECTION, typename Heap>
|
||||||
template <bool DIRECTION, typename HeapT>
|
void insertNodesInHeap(Heap &heap, const PhantomNode &phantom_node)
|
||||||
bool stallAtNode(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
const NodeID node,
|
|
||||||
const EdgeWeight weight,
|
|
||||||
const HeapT &query_heap)
|
|
||||||
{
|
{
|
||||||
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
BOOST_ASSERT(phantom_node.IsValid());
|
||||||
|
|
||||||
|
const auto weight_sign = DIRECTION == FORWARD_DIRECTION ? -1 : 1;
|
||||||
|
if (phantom_node.forward_segment_id.enabled)
|
||||||
{
|
{
|
||||||
const auto &data = facade.GetEdgeData(edge);
|
heap.Insert(phantom_node.forward_segment_id.id,
|
||||||
if (DIRECTION == REVERSE_DIRECTION ? data.forward : data.backward)
|
weight_sign * phantom_node.GetForwardWeightPlusOffset(),
|
||||||
{
|
phantom_node.forward_segment_id.id);
|
||||||
const NodeID to = facade.GetTarget(edge);
|
}
|
||||||
const EdgeWeight edge_weight = data.weight;
|
if (phantom_node.reverse_segment_id.enabled)
|
||||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
{
|
||||||
if (query_heap.WasInserted(to))
|
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||||
{
|
weight_sign * phantom_node.GetReverseWeightPlusOffset(),
|
||||||
if (query_heap.GetKey(to) + edge_weight < weight)
|
phantom_node.reverse_segment_id.id);
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool DIRECTION>
|
template <bool DIRECTION>
|
||||||
void relaxOutgoingEdges(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
void insertNodesInHeap(SearchEngineData::ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
|
||||||
const NodeID node,
|
|
||||||
const EdgeWeight weight,
|
|
||||||
SearchEngineData::QueryHeap &heap)
|
|
||||||
{
|
{
|
||||||
for (const auto edge : facade.GetAdjacentEdgeRange(node))
|
BOOST_ASSERT(phantom_node.IsValid());
|
||||||
|
|
||||||
|
const auto weight_sign = DIRECTION == FORWARD_DIRECTION ? -1 : 1;
|
||||||
|
if (phantom_node.forward_segment_id.enabled)
|
||||||
{
|
{
|
||||||
const auto &data = facade.GetEdgeData(edge);
|
heap.Insert(
|
||||||
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
|
phantom_node.forward_segment_id.id,
|
||||||
{
|
weight_sign * phantom_node.GetForwardWeightPlusOffset(),
|
||||||
const NodeID to = facade.GetTarget(edge);
|
{phantom_node.forward_segment_id.id, weight_sign * phantom_node.GetForwardDuration()});
|
||||||
const EdgeWeight edge_weight = data.weight;
|
}
|
||||||
|
if (phantom_node.reverse_segment_id.enabled)
|
||||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
{
|
||||||
const EdgeWeight to_weight = weight + edge_weight;
|
heap.Insert(
|
||||||
|
phantom_node.reverse_segment_id.id,
|
||||||
// New Node discovered -> Add to Heap + Node Info Storage
|
weight_sign * phantom_node.GetReverseWeightPlusOffset(),
|
||||||
if (!heap.WasInserted(to))
|
{phantom_node.reverse_segment_id.id, weight_sign * phantom_node.GetReverseDuration()});
|
||||||
{
|
|
||||||
heap.Insert(to, to_weight, node);
|
|
||||||
}
|
|
||||||
// Found a shorter Path -> Update weight
|
|
||||||
else if (to_weight < heap.GetKey(to))
|
|
||||||
{
|
|
||||||
// new parent
|
|
||||||
heap.GetData(to).parent = node;
|
|
||||||
heap.DecreaseKey(to, to_weight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
template <typename Heap>
|
||||||
min_edge_offset is needed in case we use multiple
|
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
|
||||||
nodes as start/target nodes with different (even negative) offsets.
|
|
||||||
In that case the termination criterion is not correct
|
|
||||||
anymore.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
forward heap: a(-100), b(0),
|
|
||||||
reverse heap: c(0), d(100)
|
|
||||||
|
|
||||||
a --- d
|
|
||||||
\ /
|
|
||||||
/ \
|
|
||||||
b --- c
|
|
||||||
|
|
||||||
This is equivalent to running a bi-directional Dijkstra on the following graph:
|
|
||||||
|
|
||||||
a --- d
|
|
||||||
/ \ / \
|
|
||||||
y x z
|
|
||||||
\ / \ /
|
|
||||||
b --- c
|
|
||||||
|
|
||||||
The graph is constructed by inserting nodes y and z that are connected to the initial nodes
|
|
||||||
using edges (y, a) with weight -100, (y, b) with weight 0 and,
|
|
||||||
(d, z) with weight 100, (c, z) with weight 0 corresponding.
|
|
||||||
Since we are dealing with a graph that contains _negative_ edges,
|
|
||||||
we need to add an offset to the termination criterion.
|
|
||||||
*/
|
|
||||||
static constexpr bool ENABLE_STALLING = true;
|
|
||||||
static constexpr bool DISABLE_STALLING = false;
|
|
||||||
static constexpr bool DO_NOT_FORCE_LOOPS = false;
|
|
||||||
template <bool DIRECTION, bool STALLING = ENABLE_STALLING>
|
|
||||||
void routingStep(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
NodeID &middle_node_id,
|
|
||||||
EdgeWeight &upper_bound,
|
|
||||||
EdgeWeight min_edge_offset,
|
|
||||||
const bool force_loop_forward,
|
|
||||||
const bool force_loop_reverse)
|
|
||||||
{
|
{
|
||||||
const NodeID node = forward_heap.DeleteMin();
|
insertNodesInHeap<FORWARD_DIRECTION>(forward_heap, nodes.source_phantom);
|
||||||
const EdgeWeight weight = forward_heap.GetKey(node);
|
insertNodesInHeap<REVERSE_DIRECTION>(reverse_heap, nodes.target_phantom);
|
||||||
|
|
||||||
if (reverse_heap.WasInserted(node))
|
|
||||||
{
|
|
||||||
const EdgeWeight new_weight = reverse_heap.GetKey(node) + weight;
|
|
||||||
if (new_weight < upper_bound)
|
|
||||||
{
|
|
||||||
// if loops are forced, they are so at the source
|
|
||||||
if ((force_loop_forward && forward_heap.GetData(node).parent == node) ||
|
|
||||||
(force_loop_reverse && reverse_heap.GetData(node).parent == node) ||
|
|
||||||
// in this case we are looking at a bi-directional way where the source
|
|
||||||
// and target phantom are on the same edge based node
|
|
||||||
new_weight < 0)
|
|
||||||
{
|
|
||||||
// check whether there is a loop present at the node
|
|
||||||
for (const auto edge : facade.GetAdjacentEdgeRange(node))
|
|
||||||
{
|
|
||||||
const auto &data = facade.GetEdgeData(edge);
|
|
||||||
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
|
|
||||||
{
|
|
||||||
const NodeID to = facade.GetTarget(edge);
|
|
||||||
if (to == node)
|
|
||||||
{
|
|
||||||
const EdgeWeight edge_weight = data.weight;
|
|
||||||
const EdgeWeight loop_weight = new_weight + edge_weight;
|
|
||||||
if (loop_weight >= 0 && loop_weight < upper_bound)
|
|
||||||
{
|
|
||||||
middle_node_id = node;
|
|
||||||
upper_bound = loop_weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(new_weight >= 0);
|
|
||||||
|
|
||||||
middle_node_id = node;
|
|
||||||
upper_bound = new_weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure we don't terminate too early if we initialize the weight
|
|
||||||
// for the nodes in the forward heap with the forward/reverse offset
|
|
||||||
BOOST_ASSERT(min_edge_offset <= 0);
|
|
||||||
if (weight + min_edge_offset > upper_bound)
|
|
||||||
{
|
|
||||||
forward_heap.DeleteAll();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stalling
|
|
||||||
if (STALLING && stallAtNode<DIRECTION>(facade, node, weight, forward_heap))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
relaxOutgoingEdges<DIRECTION>(facade, node, weight, forward_heap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool UseDuration>
|
template <typename FacadeT>
|
||||||
EdgeWeight
|
void annotatePath(const FacadeT &facade,
|
||||||
getLoopWeight(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
const NodeID source_node,
|
||||||
NodeID node)
|
const NodeID target_node,
|
||||||
|
const std::vector<EdgeID> &unpacked_edges,
|
||||||
|
const PhantomNodes &phantom_node_pair,
|
||||||
|
std::vector<PathData> &unpacked_path)
|
||||||
{
|
{
|
||||||
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT;
|
BOOST_ASSERT(source_node != SPECIAL_NODEID && target_node != SPECIAL_NODEID);
|
||||||
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
BOOST_ASSERT(!unpacked_edges.empty() || source_node == target_node);
|
||||||
|
|
||||||
|
const bool start_traversed_in_reverse =
|
||||||
|
phantom_node_pair.source_phantom.forward_segment_id.id != source_node;
|
||||||
|
const bool target_traversed_in_reverse =
|
||||||
|
phantom_node_pair.target_phantom.forward_segment_id.id != target_node;
|
||||||
|
|
||||||
|
BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id == source_node ||
|
||||||
|
phantom_node_pair.source_phantom.reverse_segment_id.id == source_node);
|
||||||
|
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id == target_node ||
|
||||||
|
phantom_node_pair.target_phantom.reverse_segment_id.id == target_node);
|
||||||
|
|
||||||
|
for (auto edge_id : unpacked_edges)
|
||||||
{
|
{
|
||||||
const auto &data = facade.GetEdgeData(edge);
|
const auto &edge_data = facade.GetEdgeData(edge_id);
|
||||||
if (data.forward)
|
const auto turn_id = edge_data.turn_id; // edge-based node ID
|
||||||
|
const auto name_index = facade.GetNameIndexFromEdgeID(turn_id);
|
||||||
|
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id);
|
||||||
|
const extractor::TravelMode travel_mode =
|
||||||
|
(unpacked_path.empty() && start_traversed_in_reverse)
|
||||||
|
? phantom_node_pair.source_phantom.backward_travel_mode
|
||||||
|
: facade.GetTravelModeForEdgeID(turn_id);
|
||||||
|
|
||||||
|
const auto geometry_index = facade.GetGeometryIndexForEdgeID(turn_id);
|
||||||
|
std::vector<NodeID> id_vector;
|
||||||
|
|
||||||
|
std::vector<EdgeWeight> weight_vector;
|
||||||
|
std::vector<EdgeWeight> duration_vector;
|
||||||
|
std::vector<DatasourceID> datasource_vector;
|
||||||
|
if (geometry_index.forward)
|
||||||
{
|
{
|
||||||
const NodeID to = facade.GetTarget(edge);
|
id_vector = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
||||||
if (to == node)
|
weight_vector = facade.GetUncompressedForwardWeights(geometry_index.id);
|
||||||
{
|
duration_vector = facade.GetUncompressedForwardDurations(geometry_index.id);
|
||||||
const auto value = UseDuration ? data.duration : data.weight;
|
datasource_vector = facade.GetUncompressedForwardDatasources(geometry_index.id);
|
||||||
loop_weight = std::min(loop_weight, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return loop_weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a sequence of connected `NodeID`s in the CH graph, performs a depth-first unpacking of
|
|
||||||
* the shortcut
|
|
||||||
* edges. For every "original" edge found, it calls the `callback` with the two NodeIDs for the
|
|
||||||
* edge, and the EdgeData
|
|
||||||
* for that edge.
|
|
||||||
*
|
|
||||||
* The primary purpose of this unpacking is to expand a path through the CH into the original
|
|
||||||
* route through the
|
|
||||||
* pre-contracted graph.
|
|
||||||
*
|
|
||||||
* Because of the depth-first-search, the `callback` will effectively be called in sequence for
|
|
||||||
* the original route
|
|
||||||
* from beginning to end.
|
|
||||||
*
|
|
||||||
* @param packed_path_begin iterator pointing to the start of the NodeID list
|
|
||||||
* @param packed_path_end iterator pointing to the end of the NodeID list
|
|
||||||
* @param callback void(const std::pair<NodeID, NodeID>, const EdgeData &) called for each
|
|
||||||
* original edge found.
|
|
||||||
*/
|
|
||||||
template <typename BidirectionalIterator, typename Callback>
|
|
||||||
void unpackPath(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
BidirectionalIterator packed_path_begin,
|
|
||||||
BidirectionalIterator packed_path_end,
|
|
||||||
Callback &&callback)
|
|
||||||
{
|
|
||||||
// make sure we have at least something to unpack
|
|
||||||
if (packed_path_begin == packed_path_end)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
|
||||||
|
|
||||||
// We have to push the path in reverse order onto the stack because it's LIFO.
|
|
||||||
for (auto current = std::prev(packed_path_end); current != packed_path_begin;
|
|
||||||
current = std::prev(current))
|
|
||||||
{
|
|
||||||
recursion_stack.emplace(*std::prev(current), *current);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<NodeID, NodeID> edge;
|
|
||||||
while (!recursion_stack.empty())
|
|
||||||
{
|
|
||||||
edge = recursion_stack.top();
|
|
||||||
recursion_stack.pop();
|
|
||||||
|
|
||||||
// Look for an edge on the forward CH graph (.forward)
|
|
||||||
EdgeID smaller_edge_id = facade.FindSmallestEdge(
|
|
||||||
edge.first, edge.second, [](const auto &data) { return data.forward; });
|
|
||||||
|
|
||||||
// If we didn't find one there, the we might be looking at a part of the path that
|
|
||||||
// was found using the backward search. Here, we flip the node order (.second, .first)
|
|
||||||
// and only consider edges with the `.backward` flag.
|
|
||||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
|
||||||
{
|
|
||||||
smaller_edge_id = facade.FindSmallestEdge(
|
|
||||||
edge.second, edge.first, [](const auto &data) { return data.backward; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we didn't find anything *still*, then something is broken and someone has
|
|
||||||
// called this function with bad values.
|
|
||||||
BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID");
|
|
||||||
|
|
||||||
const auto &data = facade.GetEdgeData(smaller_edge_id);
|
|
||||||
BOOST_ASSERT_MSG(data.weight != std::numeric_limits<EdgeWeight>::max(),
|
|
||||||
"edge weight invalid");
|
|
||||||
|
|
||||||
// If the edge is a shortcut, we need to add the two halfs to the stack.
|
|
||||||
if (data.shortcut)
|
|
||||||
{ // unpack
|
|
||||||
const NodeID middle_node_id = data.turn_id;
|
|
||||||
// Note the order here - we're adding these to a stack, so we
|
|
||||||
// want the first->middle to get visited before middle->second
|
|
||||||
recursion_stack.emplace(middle_node_id, edge.second);
|
|
||||||
recursion_stack.emplace(edge.first, middle_node_id);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We found an original edge, call our callback.
|
id_vector = facade.GetUncompressedReverseGeometry(geometry_index.id);
|
||||||
std::forward<Callback>(callback)(edge, data);
|
weight_vector = facade.GetUncompressedReverseWeights(geometry_index.id);
|
||||||
|
duration_vector = facade.GetUncompressedReverseDurations(geometry_index.id);
|
||||||
|
datasource_vector = facade.GetUncompressedReverseDatasources(geometry_index.id);
|
||||||
}
|
}
|
||||||
|
BOOST_ASSERT(id_vector.size() > 0);
|
||||||
|
BOOST_ASSERT(datasource_vector.size() > 0);
|
||||||
|
BOOST_ASSERT(weight_vector.size() == id_vector.size() - 1);
|
||||||
|
BOOST_ASSERT(duration_vector.size() == id_vector.size() - 1);
|
||||||
|
const bool is_first_segment = unpacked_path.empty();
|
||||||
|
|
||||||
|
const std::size_t start_index =
|
||||||
|
(is_first_segment ? ((start_traversed_in_reverse)
|
||||||
|
? weight_vector.size() -
|
||||||
|
phantom_node_pair.source_phantom.fwd_segment_position - 1
|
||||||
|
: phantom_node_pair.source_phantom.fwd_segment_position)
|
||||||
|
: 0);
|
||||||
|
const std::size_t end_index = weight_vector.size();
|
||||||
|
|
||||||
|
BOOST_ASSERT(start_index >= 0);
|
||||||
|
BOOST_ASSERT(start_index < end_index);
|
||||||
|
for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
|
||||||
|
{
|
||||||
|
unpacked_path.push_back(PathData{id_vector[segment_idx + 1],
|
||||||
|
name_index,
|
||||||
|
weight_vector[segment_idx],
|
||||||
|
duration_vector[segment_idx],
|
||||||
|
extractor::guidance::TurnInstruction::NO_TURN(),
|
||||||
|
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
|
||||||
|
travel_mode,
|
||||||
|
INVALID_ENTRY_CLASSID,
|
||||||
|
datasource_vector[segment_idx],
|
||||||
|
util::guidance::TurnBearing(0),
|
||||||
|
util::guidance::TurnBearing(0)});
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(unpacked_path.size() > 0);
|
||||||
|
if (facade.hasLaneData(turn_id))
|
||||||
|
unpacked_path.back().lane_data = facade.GetLaneData(turn_id);
|
||||||
|
|
||||||
|
unpacked_path.back().entry_classid = facade.GetEntryClassID(turn_id);
|
||||||
|
unpacked_path.back().turn_instruction = turn_instruction;
|
||||||
|
unpacked_path.back().duration_until_turn += facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||||
|
unpacked_path.back().weight_until_turn += facade.GetWeightPenaltyForEdgeID(turn_id);
|
||||||
|
unpacked_path.back().pre_turn_bearing = facade.PreTurnBearing(turn_id);
|
||||||
|
unpacked_path.back().post_turn_bearing = facade.PostTurnBearing(turn_id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Should work both for CH and not CH if the unpackPath function above is implemented a proper
|
|
||||||
// implementation.
|
|
||||||
template <typename RandomIter, typename FacadeT>
|
|
||||||
void unpackPath(const FacadeT &facade,
|
|
||||||
RandomIter packed_path_begin,
|
|
||||||
RandomIter packed_path_end,
|
|
||||||
const PhantomNodes &phantom_node_pair,
|
|
||||||
std::vector<PathData> &unpacked_path)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
|
|
||||||
|
|
||||||
const bool start_traversed_in_reverse =
|
|
||||||
(*packed_path_begin != phantom_node_pair.source_phantom.forward_segment_id.id);
|
|
||||||
const bool target_traversed_in_reverse =
|
|
||||||
(*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_segment_id.id);
|
|
||||||
|
|
||||||
BOOST_ASSERT(*packed_path_begin == phantom_node_pair.source_phantom.forward_segment_id.id ||
|
|
||||||
*packed_path_begin == phantom_node_pair.source_phantom.reverse_segment_id.id);
|
|
||||||
BOOST_ASSERT(
|
|
||||||
*std::prev(packed_path_end) == phantom_node_pair.target_phantom.forward_segment_id.id ||
|
|
||||||
*std::prev(packed_path_end) == phantom_node_pair.target_phantom.reverse_segment_id.id);
|
|
||||||
|
|
||||||
unpackPath(
|
|
||||||
facade,
|
|
||||||
packed_path_begin,
|
|
||||||
packed_path_end,
|
|
||||||
[&facade,
|
|
||||||
&unpacked_path,
|
|
||||||
&phantom_node_pair,
|
|
||||||
&start_traversed_in_reverse,
|
|
||||||
&target_traversed_in_reverse](std::pair<NodeID, NodeID> & /* edge */,
|
|
||||||
const auto &edge_data) {
|
|
||||||
|
|
||||||
BOOST_ASSERT_MSG(!edge_data.shortcut, "original edge flagged as shortcut");
|
|
||||||
const auto turn_id = edge_data.turn_id; // edge-based node ID
|
|
||||||
const auto name_index = facade.GetNameIndexFromEdgeID(turn_id);
|
|
||||||
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id);
|
|
||||||
const extractor::TravelMode travel_mode =
|
|
||||||
(unpacked_path.empty() && start_traversed_in_reverse)
|
|
||||||
? phantom_node_pair.source_phantom.backward_travel_mode
|
|
||||||
: facade.GetTravelModeForEdgeID(turn_id);
|
|
||||||
|
|
||||||
const auto geometry_index = facade.GetGeometryIndexForEdgeID(turn_id);
|
|
||||||
std::vector<NodeID> id_vector;
|
|
||||||
|
|
||||||
std::vector<EdgeWeight> weight_vector;
|
|
||||||
std::vector<EdgeWeight> duration_vector;
|
|
||||||
std::vector<DatasourceID> datasource_vector;
|
|
||||||
if (geometry_index.forward)
|
|
||||||
{
|
|
||||||
id_vector = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
|
||||||
weight_vector = facade.GetUncompressedForwardWeights(geometry_index.id);
|
|
||||||
duration_vector = facade.GetUncompressedForwardDurations(geometry_index.id);
|
|
||||||
datasource_vector = facade.GetUncompressedForwardDatasources(geometry_index.id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
id_vector = facade.GetUncompressedReverseGeometry(geometry_index.id);
|
|
||||||
weight_vector = facade.GetUncompressedReverseWeights(geometry_index.id);
|
|
||||||
duration_vector = facade.GetUncompressedReverseDurations(geometry_index.id);
|
|
||||||
datasource_vector = facade.GetUncompressedReverseDatasources(geometry_index.id);
|
|
||||||
}
|
|
||||||
BOOST_ASSERT(id_vector.size() > 0);
|
|
||||||
BOOST_ASSERT(datasource_vector.size() > 0);
|
|
||||||
BOOST_ASSERT(weight_vector.size() == id_vector.size() - 1);
|
|
||||||
BOOST_ASSERT(duration_vector.size() == id_vector.size() - 1);
|
|
||||||
const bool is_first_segment = unpacked_path.empty();
|
|
||||||
|
|
||||||
const std::size_t start_index =
|
|
||||||
(is_first_segment
|
|
||||||
? ((start_traversed_in_reverse)
|
|
||||||
? weight_vector.size() -
|
|
||||||
phantom_node_pair.source_phantom.fwd_segment_position - 1
|
|
||||||
: phantom_node_pair.source_phantom.fwd_segment_position)
|
|
||||||
: 0);
|
|
||||||
const std::size_t end_index = weight_vector.size();
|
|
||||||
|
|
||||||
BOOST_ASSERT(start_index >= 0);
|
|
||||||
BOOST_ASSERT(start_index < end_index);
|
|
||||||
for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
|
|
||||||
{
|
|
||||||
unpacked_path.push_back(PathData{id_vector[segment_idx + 1],
|
|
||||||
name_index,
|
|
||||||
weight_vector[segment_idx],
|
|
||||||
duration_vector[segment_idx],
|
|
||||||
extractor::guidance::TurnInstruction::NO_TURN(),
|
|
||||||
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
|
|
||||||
travel_mode,
|
|
||||||
INVALID_ENTRY_CLASSID,
|
|
||||||
datasource_vector[segment_idx],
|
|
||||||
util::guidance::TurnBearing(0),
|
|
||||||
util::guidance::TurnBearing(0)});
|
|
||||||
}
|
|
||||||
BOOST_ASSERT(unpacked_path.size() > 0);
|
|
||||||
if (facade.hasLaneData(turn_id))
|
|
||||||
unpacked_path.back().lane_data = facade.GetLaneData(turn_id);
|
|
||||||
|
|
||||||
unpacked_path.back().entry_classid = facade.GetEntryClassID(turn_id);
|
|
||||||
unpacked_path.back().turn_instruction = turn_instruction;
|
|
||||||
unpacked_path.back().duration_until_turn += facade.GetDurationPenaltyForEdgeID(turn_id);
|
|
||||||
unpacked_path.back().weight_until_turn += facade.GetWeightPenaltyForEdgeID(turn_id);
|
|
||||||
unpacked_path.back().pre_turn_bearing = facade.PreTurnBearing(turn_id);
|
|
||||||
unpacked_path.back().post_turn_bearing = facade.PostTurnBearing(turn_id);
|
|
||||||
});
|
|
||||||
|
|
||||||
std::size_t start_index = 0, end_index = 0;
|
std::size_t start_index = 0, end_index = 0;
|
||||||
std::vector<unsigned> id_vector;
|
std::vector<unsigned> id_vector;
|
||||||
@ -536,140 +305,8 @@ void unpackPath(const FacadeT &facade,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpacks a single edge (NodeID->NodeID) from the CH graph down to it's original non-shortcut
|
|
||||||
* route.
|
|
||||||
* @param from the node the CH edge starts at
|
|
||||||
* @param to the node the CH edge finishes at
|
|
||||||
* @param unpacked_path the sequence of original NodeIDs that make up the expanded CH edge
|
|
||||||
*/
|
|
||||||
void unpackEdge(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
const NodeID from,
|
|
||||||
const NodeID to,
|
|
||||||
std::vector<NodeID> &unpacked_path);
|
|
||||||
|
|
||||||
void retrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
const SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
const NodeID middle_node_id,
|
|
||||||
std::vector<NodeID> &packed_path);
|
|
||||||
|
|
||||||
void retrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
|
|
||||||
const NodeID middle_node_id,
|
|
||||||
std::vector<NodeID> &packed_path);
|
|
||||||
|
|
||||||
// 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_segment_id ==
|
|
||||||
// target_phantom.forward_segment_id
|
|
||||||
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
|
||||||
// requires
|
|
||||||
// a force loop, if the heaps have been initialized with positive offsets.
|
|
||||||
void search(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
std::int32_t &weight,
|
|
||||||
std::vector<NodeID> &packed_leg,
|
|
||||||
const bool force_loop_forward,
|
|
||||||
const bool force_loop_reverse,
|
|
||||||
const int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
|
||||||
|
|
||||||
// Alias to be compatible with the overload for CoreCH that needs 4 heaps
|
|
||||||
inline void search(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
SearchEngineData::QueryHeap &,
|
|
||||||
SearchEngineData::QueryHeap &,
|
|
||||||
std::int32_t &weight,
|
|
||||||
std::vector<NodeID> &packed_leg,
|
|
||||||
const bool force_loop_forward,
|
|
||||||
const bool force_loop_reverse,
|
|
||||||
const int duration_upper_bound = INVALID_EDGE_WEIGHT)
|
|
||||||
{
|
|
||||||
search(facade,
|
|
||||||
forward_heap,
|
|
||||||
reverse_heap,
|
|
||||||
weight,
|
|
||||||
packed_leg,
|
|
||||||
force_loop_forward,
|
|
||||||
force_loop_reverse,
|
|
||||||
duration_upper_bound);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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_segment_id ==
|
|
||||||
// target_phantom.forward_segment_id
|
|
||||||
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
|
||||||
// requires
|
|
||||||
// a force loop, if the heaps have been initialized with positive offsets.
|
|
||||||
void search(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CoreCH> &facade,
|
|
||||||
SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
SearchEngineData::QueryHeap &forward_core_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_core_heap,
|
|
||||||
int &weight,
|
|
||||||
std::vector<NodeID> &packed_leg,
|
|
||||||
const bool force_loop_forward,
|
|
||||||
const bool force_loop_reverse,
|
|
||||||
int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
|
||||||
|
|
||||||
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
|
||||||
|
|
||||||
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
|
||||||
|
|
||||||
double getPathDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
const std::vector<NodeID> &packed_path,
|
|
||||||
const PhantomNode &source_phantom,
|
|
||||||
const PhantomNode &target_phantom);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
getNetworkDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CoreCH> &facade,
|
|
||||||
SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
SearchEngineData::QueryHeap &forward_core_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_core_heap,
|
|
||||||
const PhantomNode &source_phantom,
|
|
||||||
const PhantomNode &target_phantom,
|
|
||||||
int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
getNetworkDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
const PhantomNode &source_phantom,
|
|
||||||
const PhantomNode &target_phantom,
|
|
||||||
int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
|
||||||
|
|
||||||
// Alias to be compatible with the overload for CoreCH that needs 4 heaps
|
|
||||||
inline double
|
|
||||||
getNetworkDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
|
||||||
SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
SearchEngineData::QueryHeap &,
|
|
||||||
SearchEngineData::QueryHeap &,
|
|
||||||
const PhantomNode &source_phantom,
|
|
||||||
const PhantomNode &target_phantom,
|
|
||||||
int duration_upper_bound = INVALID_EDGE_WEIGHT)
|
|
||||||
{
|
|
||||||
return getNetworkDistance(
|
|
||||||
facade, forward_heap, reverse_heap, source_phantom, target_phantom, duration_upper_bound);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|
||||||
#endif // ROUTING_BASE_HPP
|
#endif // OSRM_ENGINE_ROUTING_BASE_HPP
|
||||||
|
475
include/engine/routing_algorithms/routing_base_ch.hpp
Normal file
475
include/engine/routing_algorithms/routing_base_ch.hpp
Normal file
@ -0,0 +1,475 @@
|
|||||||
|
#ifndef OSRM_ENGINE_ROUTING_BASE_CH_HPP
|
||||||
|
#define OSRM_ENGINE_ROUTING_BASE_CH_HPP
|
||||||
|
|
||||||
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
|
|
||||||
|
#include "engine/algorithm.hpp"
|
||||||
|
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
|
||||||
|
#include "engine/internal_route_result.hpp"
|
||||||
|
#include "engine/routing_algorithms/routing_base.hpp"
|
||||||
|
#include "engine/search_engine_data.hpp"
|
||||||
|
|
||||||
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
#include "util/guidance/turn_bearing.hpp"
|
||||||
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
#include <numeric>
|
||||||
|
#include <stack>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace routing_algorithms
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace ch
|
||||||
|
{
|
||||||
|
|
||||||
|
// Stalling
|
||||||
|
template <bool DIRECTION, typename HeapT>
|
||||||
|
bool stallAtNode(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
const NodeID node,
|
||||||
|
const EdgeWeight weight,
|
||||||
|
const HeapT &query_heap)
|
||||||
|
{
|
||||||
|
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
||||||
|
{
|
||||||
|
const auto &data = facade.GetEdgeData(edge);
|
||||||
|
if (DIRECTION == REVERSE_DIRECTION ? data.forward : data.backward)
|
||||||
|
{
|
||||||
|
const NodeID to = facade.GetTarget(edge);
|
||||||
|
const EdgeWeight edge_weight = data.weight;
|
||||||
|
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||||
|
if (query_heap.WasInserted(to))
|
||||||
|
{
|
||||||
|
if (query_heap.GetKey(to) + edge_weight < weight)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool DIRECTION>
|
||||||
|
void relaxOutgoingEdges(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
const NodeID node,
|
||||||
|
const EdgeWeight weight,
|
||||||
|
SearchEngineData::QueryHeap &heap)
|
||||||
|
{
|
||||||
|
for (const auto edge : facade.GetAdjacentEdgeRange(node))
|
||||||
|
{
|
||||||
|
const auto &data = facade.GetEdgeData(edge);
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
|
||||||
|
{
|
||||||
|
const NodeID to = facade.GetTarget(edge);
|
||||||
|
const EdgeWeight edge_weight = data.weight;
|
||||||
|
|
||||||
|
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||||
|
const EdgeWeight to_weight = weight + edge_weight;
|
||||||
|
|
||||||
|
// New Node discovered -> Add to Heap + Node Info Storage
|
||||||
|
if (!heap.WasInserted(to))
|
||||||
|
{
|
||||||
|
heap.Insert(to, to_weight, node);
|
||||||
|
}
|
||||||
|
// Found a shorter Path -> Update weight
|
||||||
|
else if (to_weight < heap.GetKey(to))
|
||||||
|
{
|
||||||
|
// new parent
|
||||||
|
heap.GetData(to).parent = node;
|
||||||
|
heap.DecreaseKey(to, to_weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
min_edge_offset is needed in case we use multiple
|
||||||
|
nodes as start/target nodes with different (even negative) offsets.
|
||||||
|
In that case the termination criterion is not correct
|
||||||
|
anymore.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
forward heap: a(-100), b(0),
|
||||||
|
reverse heap: c(0), d(100)
|
||||||
|
|
||||||
|
a --- d
|
||||||
|
\ /
|
||||||
|
/ \
|
||||||
|
b --- c
|
||||||
|
|
||||||
|
This is equivalent to running a bi-directional Dijkstra on the following graph:
|
||||||
|
|
||||||
|
a --- d
|
||||||
|
/ \ / \
|
||||||
|
y x z
|
||||||
|
\ / \ /
|
||||||
|
b --- c
|
||||||
|
|
||||||
|
The graph is constructed by inserting nodes y and z that are connected to the initial nodes
|
||||||
|
using edges (y, a) with weight -100, (y, b) with weight 0 and,
|
||||||
|
(d, z) with weight 100, (c, z) with weight 0 corresponding.
|
||||||
|
Since we are dealing with a graph that contains _negative_ edges,
|
||||||
|
we need to add an offset to the termination criterion.
|
||||||
|
*/
|
||||||
|
static constexpr bool ENABLE_STALLING = true;
|
||||||
|
static constexpr bool DISABLE_STALLING = false;
|
||||||
|
template <bool DIRECTION, bool STALLING = ENABLE_STALLING>
|
||||||
|
void routingStep(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_heap,
|
||||||
|
NodeID &middle_node_id,
|
||||||
|
EdgeWeight &upper_bound,
|
||||||
|
EdgeWeight min_edge_offset,
|
||||||
|
const bool force_loop_forward,
|
||||||
|
const bool force_loop_reverse)
|
||||||
|
{
|
||||||
|
const NodeID node = forward_heap.DeleteMin();
|
||||||
|
const EdgeWeight weight = forward_heap.GetKey(node);
|
||||||
|
|
||||||
|
if (reverse_heap.WasInserted(node))
|
||||||
|
{
|
||||||
|
const EdgeWeight new_weight = reverse_heap.GetKey(node) + weight;
|
||||||
|
if (new_weight < upper_bound)
|
||||||
|
{
|
||||||
|
// if loops are forced, they are so at the source
|
||||||
|
if ((force_loop_forward && forward_heap.GetData(node).parent == node) ||
|
||||||
|
(force_loop_reverse && reverse_heap.GetData(node).parent == node) ||
|
||||||
|
// in this case we are looking at a bi-directional way where the source
|
||||||
|
// and target phantom are on the same edge based node
|
||||||
|
new_weight < 0)
|
||||||
|
{
|
||||||
|
// check whether there is a loop present at the node
|
||||||
|
for (const auto edge : facade.GetAdjacentEdgeRange(node))
|
||||||
|
{
|
||||||
|
const auto &data = facade.GetEdgeData(edge);
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
|
||||||
|
{
|
||||||
|
const NodeID to = facade.GetTarget(edge);
|
||||||
|
if (to == node)
|
||||||
|
{
|
||||||
|
const EdgeWeight edge_weight = data.weight;
|
||||||
|
const EdgeWeight loop_weight = new_weight + edge_weight;
|
||||||
|
if (loop_weight >= 0 && loop_weight < upper_bound)
|
||||||
|
{
|
||||||
|
middle_node_id = node;
|
||||||
|
upper_bound = loop_weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(new_weight >= 0);
|
||||||
|
|
||||||
|
middle_node_id = node;
|
||||||
|
upper_bound = new_weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we don't terminate too early if we initialize the weight
|
||||||
|
// for the nodes in the forward heap with the forward/reverse offset
|
||||||
|
BOOST_ASSERT(min_edge_offset <= 0);
|
||||||
|
if (weight + min_edge_offset > upper_bound)
|
||||||
|
{
|
||||||
|
forward_heap.DeleteAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stalling
|
||||||
|
if (STALLING && stallAtNode<DIRECTION>(facade, node, weight, forward_heap))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relaxOutgoingEdges<DIRECTION>(facade, node, weight, forward_heap);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool UseDuration>
|
||||||
|
EdgeWeight
|
||||||
|
getLoopWeight(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
NodeID node)
|
||||||
|
{
|
||||||
|
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : 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)
|
||||||
|
{
|
||||||
|
const auto value = UseDuration ? data.duration : data.weight;
|
||||||
|
loop_weight = std::min(loop_weight, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loop_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a sequence of connected `NodeID`s in the CH graph, performs a depth-first unpacking of
|
||||||
|
* the shortcut
|
||||||
|
* edges. For every "original" edge found, it calls the `callback` with the two NodeIDs for the
|
||||||
|
* edge, and the EdgeData
|
||||||
|
* for that edge.
|
||||||
|
*
|
||||||
|
* The primary purpose of this unpacking is to expand a path through the CH into the original
|
||||||
|
* route through the
|
||||||
|
* pre-contracted graph.
|
||||||
|
*
|
||||||
|
* Because of the depth-first-search, the `callback` will effectively be called in sequence for
|
||||||
|
* the original route
|
||||||
|
* from beginning to end.
|
||||||
|
*
|
||||||
|
* @param packed_path_begin iterator pointing to the start of the NodeID list
|
||||||
|
* @param packed_path_end iterator pointing to the end of the NodeID list
|
||||||
|
* @param callback void(const std::pair<NodeID, NodeID>, const EdgeID &) called for each
|
||||||
|
* original edge found.
|
||||||
|
*/
|
||||||
|
template <typename BidirectionalIterator, typename Callback>
|
||||||
|
void unpackPath(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
BidirectionalIterator packed_path_begin,
|
||||||
|
BidirectionalIterator packed_path_end,
|
||||||
|
Callback &&callback)
|
||||||
|
{
|
||||||
|
// make sure we have at least something to unpack
|
||||||
|
if (packed_path_begin == packed_path_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
||||||
|
|
||||||
|
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||||
|
for (auto current = std::prev(packed_path_end); current != packed_path_begin;
|
||||||
|
current = std::prev(current))
|
||||||
|
{
|
||||||
|
recursion_stack.emplace(*std::prev(current), *current);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<NodeID, NodeID> edge;
|
||||||
|
while (!recursion_stack.empty())
|
||||||
|
{
|
||||||
|
edge = recursion_stack.top();
|
||||||
|
recursion_stack.pop();
|
||||||
|
|
||||||
|
// Look for an edge on the forward CH graph (.forward)
|
||||||
|
EdgeID smaller_edge_id = facade.FindSmallestEdge(
|
||||||
|
edge.first, edge.second, [](const auto &data) { return data.forward; });
|
||||||
|
|
||||||
|
// If we didn't find one there, the we might be looking at a part of the path that
|
||||||
|
// was found using the backward search. Here, we flip the node order (.second, .first)
|
||||||
|
// and only consider edges with the `.backward` flag.
|
||||||
|
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||||
|
{
|
||||||
|
smaller_edge_id = facade.FindSmallestEdge(
|
||||||
|
edge.second, edge.first, [](const auto &data) { return data.backward; });
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find anything *still*, then something is broken and someone has
|
||||||
|
// called this function with bad values.
|
||||||
|
BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID");
|
||||||
|
|
||||||
|
const auto &data = facade.GetEdgeData(smaller_edge_id);
|
||||||
|
BOOST_ASSERT_MSG(data.weight != std::numeric_limits<EdgeWeight>::max(),
|
||||||
|
"edge weight invalid");
|
||||||
|
|
||||||
|
// If the edge is a shortcut, we need to add the two halfs to the stack.
|
||||||
|
if (data.shortcut)
|
||||||
|
{ // unpack
|
||||||
|
const NodeID middle_node_id = data.turn_id;
|
||||||
|
// Note the order here - we're adding these to a stack, so we
|
||||||
|
// want the first->middle to get visited before middle->second
|
||||||
|
recursion_stack.emplace(middle_node_id, edge.second);
|
||||||
|
recursion_stack.emplace(edge.first, middle_node_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We found an original edge, call our callback.
|
||||||
|
std::forward<Callback>(callback)(edge, smaller_edge_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename RandomIter, typename FacadeT>
|
||||||
|
void unpackPath(const FacadeT &facade,
|
||||||
|
RandomIter packed_path_begin,
|
||||||
|
RandomIter packed_path_end,
|
||||||
|
const PhantomNodes &phantom_nodes,
|
||||||
|
std::vector<PathData> &unpacked_path)
|
||||||
|
{
|
||||||
|
const auto nodes_number = std::distance(packed_path_begin, packed_path_end);
|
||||||
|
BOOST_ASSERT(nodes_number > 0);
|
||||||
|
|
||||||
|
std::vector<EdgeID> unpacked_edges;
|
||||||
|
|
||||||
|
auto source_node = *packed_path_begin, target_node = *packed_path_begin;
|
||||||
|
if (nodes_number > 1)
|
||||||
|
{
|
||||||
|
target_node = *std::prev(packed_path_end);
|
||||||
|
unpacked_edges.reserve(std::distance(packed_path_begin, packed_path_end));
|
||||||
|
unpackPath(
|
||||||
|
facade,
|
||||||
|
packed_path_begin,
|
||||||
|
packed_path_end,
|
||||||
|
[&facade, &unpacked_edges](std::pair<NodeID, NodeID> & /* edge */,
|
||||||
|
const auto &edge_id) { unpacked_edges.push_back(edge_id); });
|
||||||
|
}
|
||||||
|
|
||||||
|
annotatePath(facade, source_node, target_node, unpacked_edges, phantom_nodes, unpacked_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpacks a single edge (NodeID->NodeID) from the CH graph down to it's original non-shortcut
|
||||||
|
* route.
|
||||||
|
* @param from the node the CH edge starts at
|
||||||
|
* @param to the node the CH edge finishes at
|
||||||
|
* @param unpacked_path the sequence of original NodeIDs that make up the expanded CH edge
|
||||||
|
*/
|
||||||
|
void unpackEdge(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
const NodeID from,
|
||||||
|
const NodeID to,
|
||||||
|
std::vector<NodeID> &unpacked_path);
|
||||||
|
|
||||||
|
void retrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
const SearchEngineData::QueryHeap &reverse_heap,
|
||||||
|
const NodeID middle_node_id,
|
||||||
|
std::vector<NodeID> &packed_path);
|
||||||
|
|
||||||
|
void retrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
|
||||||
|
const NodeID middle_node_id,
|
||||||
|
std::vector<NodeID> &packed_path);
|
||||||
|
|
||||||
|
// 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_segment_id ==
|
||||||
|
// target_phantom.forward_segment_id
|
||||||
|
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
||||||
|
// requires
|
||||||
|
// a force loop, if the heaps have been initialized with positive offsets.
|
||||||
|
void search(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_heap,
|
||||||
|
std::int32_t &weight,
|
||||||
|
std::vector<NodeID> &packed_leg,
|
||||||
|
const bool force_loop_forward,
|
||||||
|
const bool force_loop_reverse,
|
||||||
|
const int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||||
|
|
||||||
|
// Alias to be compatible with the overload for CoreCH that needs 4 heaps
|
||||||
|
inline void search(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_heap,
|
||||||
|
SearchEngineData::QueryHeap &,
|
||||||
|
SearchEngineData::QueryHeap &,
|
||||||
|
std::int32_t &weight,
|
||||||
|
std::vector<NodeID> &packed_leg,
|
||||||
|
const bool force_loop_forward,
|
||||||
|
const bool force_loop_reverse,
|
||||||
|
const int duration_upper_bound = INVALID_EDGE_WEIGHT)
|
||||||
|
{
|
||||||
|
search(facade,
|
||||||
|
forward_heap,
|
||||||
|
reverse_heap,
|
||||||
|
weight,
|
||||||
|
packed_leg,
|
||||||
|
force_loop_forward,
|
||||||
|
force_loop_reverse,
|
||||||
|
duration_upper_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_segment_id ==
|
||||||
|
// target_phantom.forward_segment_id
|
||||||
|
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
||||||
|
// requires
|
||||||
|
// a force loop, if the heaps have been initialized with positive offsets.
|
||||||
|
void search(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CoreCH> &facade,
|
||||||
|
SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_heap,
|
||||||
|
SearchEngineData::QueryHeap &forward_core_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_core_heap,
|
||||||
|
int &weight,
|
||||||
|
std::vector<NodeID> &packed_leg,
|
||||||
|
const bool force_loop_forward,
|
||||||
|
const bool force_loop_reverse,
|
||||||
|
int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||||
|
|
||||||
|
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
||||||
|
|
||||||
|
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
||||||
|
|
||||||
|
double getPathDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
const std::vector<NodeID> &packed_path,
|
||||||
|
const PhantomNode &source_phantom,
|
||||||
|
const PhantomNode &target_phantom);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
getNetworkDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CoreCH> &facade,
|
||||||
|
SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_heap,
|
||||||
|
SearchEngineData::QueryHeap &forward_core_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_core_heap,
|
||||||
|
const PhantomNode &source_phantom,
|
||||||
|
const PhantomNode &target_phantom,
|
||||||
|
int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
getNetworkDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_heap,
|
||||||
|
const PhantomNode &source_phantom,
|
||||||
|
const PhantomNode &target_phantom,
|
||||||
|
int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||||
|
|
||||||
|
// Alias to be compatible with the overload for CoreCH that needs 4 heaps
|
||||||
|
inline double
|
||||||
|
getNetworkDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
|
SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
SearchEngineData::QueryHeap &reverse_heap,
|
||||||
|
SearchEngineData::QueryHeap &,
|
||||||
|
SearchEngineData::QueryHeap &,
|
||||||
|
const PhantomNode &source_phantom,
|
||||||
|
const PhantomNode &target_phantom,
|
||||||
|
int duration_upper_bound = INVALID_EDGE_WEIGHT)
|
||||||
|
{
|
||||||
|
return getNetworkDistance(
|
||||||
|
facade, forward_heap, reverse_heap, source_phantom, target_phantom, duration_upper_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ch
|
||||||
|
} // namespace routing_algorithms
|
||||||
|
} // namespace engine
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif // OSRM_ENGINE_ROUTING_BASE_CH_HPP
|
@ -1,5 +1,5 @@
|
|||||||
#include "engine/routing_algorithms/alternative_path.hpp"
|
#include "engine/routing_algorithms/alternative_path.hpp"
|
||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||||
|
|
||||||
#include "util/integer_range.hpp"
|
#include "util/integer_range.hpp"
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ void alternativeRoutingStep(
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// check whether there is a loop present at the node
|
// check whether there is a loop present at the node
|
||||||
const auto loop_weight = getLoopWeight<false>(facade, node);
|
const auto loop_weight = ch::getLoopWeight<false>(facade, node);
|
||||||
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
|
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
|
||||||
if (loop_weight != INVALID_EDGE_WEIGHT &&
|
if (loop_weight != INVALID_EDGE_WEIGHT &&
|
||||||
new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
|
new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
|
||||||
@ -139,11 +139,11 @@ void retrievePackedAlternatePath(const QueryHeap &forward_heap1,
|
|||||||
{
|
{
|
||||||
// fetch packed path [s,v)
|
// fetch packed path [s,v)
|
||||||
std::vector<NodeID> packed_v_t_path;
|
std::vector<NodeID> packed_v_t_path;
|
||||||
retrievePackedPathFromHeap(forward_heap1, reverse_heap2, s_v_middle, packed_path);
|
ch::retrievePackedPathFromHeap(forward_heap1, reverse_heap2, s_v_middle, packed_path);
|
||||||
packed_path.pop_back(); // remove middle node. It's in both half-paths
|
packed_path.pop_back(); // remove middle node. It's in both half-paths
|
||||||
|
|
||||||
// fetch patched path [v,t]
|
// fetch patched path [v,t]
|
||||||
retrievePackedPathFromHeap(forward_heap2, reverse_heap1, v_t_middle, packed_v_t_path);
|
ch::retrievePackedPathFromHeap(forward_heap2, reverse_heap1, v_t_middle, packed_v_t_path);
|
||||||
|
|
||||||
packed_path.insert(packed_path.end(), packed_v_t_path.begin(), packed_v_t_path.end());
|
packed_path.insert(packed_path.end(), packed_v_t_path.begin(), packed_v_t_path.end());
|
||||||
}
|
}
|
||||||
@ -180,14 +180,14 @@ void computeLengthAndSharingOfViaPath(
|
|||||||
// compute path <s,..,v> by reusing forward search from s
|
// compute path <s,..,v> by reusing forward search from s
|
||||||
while (!new_reverse_heap.Empty())
|
while (!new_reverse_heap.Empty())
|
||||||
{
|
{
|
||||||
routingStep<REVERSE_DIRECTION>(facade,
|
ch::routingStep<REVERSE_DIRECTION>(facade,
|
||||||
new_reverse_heap,
|
new_reverse_heap,
|
||||||
existing_forward_heap,
|
existing_forward_heap,
|
||||||
s_v_middle,
|
s_v_middle,
|
||||||
upper_bound_s_v_path_length,
|
upper_bound_s_v_path_length,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
DO_NOT_FORCE_LOOPS,
|
||||||
DO_NOT_FORCE_LOOPS);
|
DO_NOT_FORCE_LOOPS);
|
||||||
}
|
}
|
||||||
// compute path <v,..,t> by reusing backward search from node t
|
// compute path <v,..,t> by reusing backward search from node t
|
||||||
NodeID v_t_middle = SPECIAL_NODEID;
|
NodeID v_t_middle = SPECIAL_NODEID;
|
||||||
@ -195,14 +195,14 @@ void computeLengthAndSharingOfViaPath(
|
|||||||
new_forward_heap.Insert(via_node, 0, via_node);
|
new_forward_heap.Insert(via_node, 0, via_node);
|
||||||
while (!new_forward_heap.Empty())
|
while (!new_forward_heap.Empty())
|
||||||
{
|
{
|
||||||
routingStep<FORWARD_DIRECTION>(facade,
|
ch::routingStep<FORWARD_DIRECTION>(facade,
|
||||||
new_forward_heap,
|
new_forward_heap,
|
||||||
existing_reverse_heap,
|
existing_reverse_heap,
|
||||||
v_t_middle,
|
v_t_middle,
|
||||||
upper_bound_of_v_t_path_length,
|
upper_bound_of_v_t_path_length,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
DO_NOT_FORCE_LOOPS,
|
||||||
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;
|
*real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
|
||||||
|
|
||||||
@ -212,9 +212,9 @@ void computeLengthAndSharingOfViaPath(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// retrieve packed paths
|
// retrieve packed paths
|
||||||
retrievePackedPathFromHeap(
|
ch::retrievePackedPathFromHeap(
|
||||||
existing_forward_heap, new_reverse_heap, s_v_middle, packed_s_v_path);
|
existing_forward_heap, new_reverse_heap, s_v_middle, packed_s_v_path);
|
||||||
retrievePackedPathFromHeap(
|
ch::retrievePackedPathFromHeap(
|
||||||
new_forward_heap, existing_reverse_heap, v_t_middle, packed_v_t_path);
|
new_forward_heap, existing_reverse_heap, v_t_middle, packed_v_t_path);
|
||||||
|
|
||||||
// partial unpacking, compute sharing
|
// partial unpacking, compute sharing
|
||||||
@ -234,14 +234,14 @@ void computeLengthAndSharingOfViaPath(
|
|||||||
{
|
{
|
||||||
if (packed_s_v_path[current_node] == packed_shortest_path[current_node])
|
if (packed_s_v_path[current_node] == packed_shortest_path[current_node])
|
||||||
{
|
{
|
||||||
unpackEdge(facade,
|
ch::unpackEdge(facade,
|
||||||
packed_s_v_path[current_node],
|
packed_s_v_path[current_node],
|
||||||
packed_s_v_path[current_node + 1],
|
packed_s_v_path[current_node + 1],
|
||||||
partially_unpacked_via_path);
|
partially_unpacked_via_path);
|
||||||
unpackEdge(facade,
|
ch::unpackEdge(facade,
|
||||||
packed_shortest_path[current_node],
|
packed_shortest_path[current_node],
|
||||||
packed_shortest_path[current_node + 1],
|
packed_shortest_path[current_node + 1],
|
||||||
partially_unpacked_shortest_path);
|
partially_unpacked_shortest_path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,14 +280,14 @@ void computeLengthAndSharingOfViaPath(
|
|||||||
{
|
{
|
||||||
if (packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
|
if (packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
|
||||||
{
|
{
|
||||||
unpackEdge(facade,
|
ch::unpackEdge(facade,
|
||||||
packed_v_t_path[via_path_index - 1],
|
packed_v_t_path[via_path_index - 1],
|
||||||
packed_v_t_path[via_path_index],
|
packed_v_t_path[via_path_index],
|
||||||
partially_unpacked_via_path);
|
partially_unpacked_via_path);
|
||||||
unpackEdge(facade,
|
ch::unpackEdge(facade,
|
||||||
packed_shortest_path[shortest_path_index - 1],
|
packed_shortest_path[shortest_path_index - 1],
|
||||||
packed_shortest_path[shortest_path_index],
|
packed_shortest_path[shortest_path_index],
|
||||||
partially_unpacked_shortest_path);
|
partially_unpacked_shortest_path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,14 +342,14 @@ bool viaNodeCandidatePassesTTest(
|
|||||||
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
|
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
|
||||||
while (new_reverse_heap.Size() > 0)
|
while (new_reverse_heap.Size() > 0)
|
||||||
{
|
{
|
||||||
routingStep<REVERSE_DIRECTION>(facade,
|
ch::routingStep<REVERSE_DIRECTION>(facade,
|
||||||
new_reverse_heap,
|
new_reverse_heap,
|
||||||
existing_forward_heap,
|
existing_forward_heap,
|
||||||
*s_v_middle,
|
*s_v_middle,
|
||||||
upper_bound_s_v_path_length,
|
upper_bound_s_v_path_length,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
DO_NOT_FORCE_LOOPS,
|
||||||
DO_NOT_FORCE_LOOPS);
|
DO_NOT_FORCE_LOOPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
|
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
|
||||||
@ -363,14 +363,14 @@ bool viaNodeCandidatePassesTTest(
|
|||||||
new_forward_heap.Insert(candidate.node, 0, candidate.node);
|
new_forward_heap.Insert(candidate.node, 0, candidate.node);
|
||||||
while (new_forward_heap.Size() > 0)
|
while (new_forward_heap.Size() > 0)
|
||||||
{
|
{
|
||||||
routingStep<FORWARD_DIRECTION>(facade,
|
ch::routingStep<FORWARD_DIRECTION>(facade,
|
||||||
new_forward_heap,
|
new_forward_heap,
|
||||||
existing_reverse_heap,
|
existing_reverse_heap,
|
||||||
*v_t_middle,
|
*v_t_middle,
|
||||||
upper_bound_of_v_t_path_length,
|
upper_bound_of_v_t_path_length,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
DO_NOT_FORCE_LOOPS,
|
||||||
DO_NOT_FORCE_LOOPS);
|
DO_NOT_FORCE_LOOPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
|
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
|
||||||
@ -381,10 +381,10 @@ bool viaNodeCandidatePassesTTest(
|
|||||||
*length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
|
*length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
|
||||||
|
|
||||||
// retrieve packed paths
|
// retrieve packed paths
|
||||||
retrievePackedPathFromHeap(
|
ch::retrievePackedPathFromHeap(
|
||||||
existing_forward_heap, new_reverse_heap, *s_v_middle, packed_s_v_path);
|
existing_forward_heap, new_reverse_heap, *s_v_middle, packed_s_v_path);
|
||||||
|
|
||||||
retrievePackedPathFromHeap(
|
ch::retrievePackedPathFromHeap(
|
||||||
new_forward_heap, existing_reverse_heap, *v_t_middle, packed_v_t_path);
|
new_forward_heap, existing_reverse_heap, *v_t_middle, packed_v_t_path);
|
||||||
|
|
||||||
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
|
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
|
||||||
@ -536,25 +536,25 @@ bool viaNodeCandidatePassesTTest(
|
|||||||
{
|
{
|
||||||
if (!forward_heap3.Empty())
|
if (!forward_heap3.Empty())
|
||||||
{
|
{
|
||||||
routingStep<FORWARD_DIRECTION>(facade,
|
ch::routingStep<FORWARD_DIRECTION>(facade,
|
||||||
forward_heap3,
|
forward_heap3,
|
||||||
reverse_heap3,
|
reverse_heap3,
|
||||||
middle,
|
middle,
|
||||||
upper_bound,
|
upper_bound,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
DO_NOT_FORCE_LOOPS,
|
||||||
DO_NOT_FORCE_LOOPS);
|
DO_NOT_FORCE_LOOPS);
|
||||||
}
|
}
|
||||||
if (!reverse_heap3.Empty())
|
if (!reverse_heap3.Empty())
|
||||||
{
|
{
|
||||||
routingStep<REVERSE_DIRECTION>(facade,
|
ch::routingStep<REVERSE_DIRECTION>(facade,
|
||||||
reverse_heap3,
|
reverse_heap3,
|
||||||
forward_heap3,
|
forward_heap3,
|
||||||
middle,
|
middle,
|
||||||
upper_bound,
|
upper_bound,
|
||||||
min_edge_offset,
|
min_edge_offset,
|
||||||
DO_NOT_FORCE_LOOPS,
|
DO_NOT_FORCE_LOOPS,
|
||||||
DO_NOT_FORCE_LOOPS);
|
DO_NOT_FORCE_LOOPS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (upper_bound <= t_test_path_length);
|
return (upper_bound <= t_test_path_length);
|
||||||
@ -593,35 +593,7 @@ alternativePathSearch(SearchEngineData &engine_working_data,
|
|||||||
? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset()
|
? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset()
|
||||||
: 0);
|
: 0);
|
||||||
|
|
||||||
if (phantom_node_pair.source_phantom.forward_segment_id.enabled)
|
insertNodesInHeaps(forward_heap1, reverse_heap1, phantom_node_pair);
|
||||||
{
|
|
||||||
BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id != SPECIAL_SEGMENTID);
|
|
||||||
forward_heap1.Insert(phantom_node_pair.source_phantom.forward_segment_id.id,
|
|
||||||
-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
|
||||||
phantom_node_pair.source_phantom.forward_segment_id.id);
|
|
||||||
}
|
|
||||||
if (phantom_node_pair.source_phantom.reverse_segment_id.enabled)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(phantom_node_pair.source_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID);
|
|
||||||
forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_segment_id.id,
|
|
||||||
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
|
|
||||||
phantom_node_pair.source_phantom.reverse_segment_id.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (phantom_node_pair.target_phantom.forward_segment_id.enabled)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id != SPECIAL_SEGMENTID);
|
|
||||||
reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_segment_id.id,
|
|
||||||
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
|
|
||||||
phantom_node_pair.target_phantom.forward_segment_id.id);
|
|
||||||
}
|
|
||||||
if (phantom_node_pair.target_phantom.reverse_segment_id.enabled)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(phantom_node_pair.target_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID);
|
|
||||||
reverse_heap1.Insert(phantom_node_pair.target_phantom.reverse_segment_id.id,
|
|
||||||
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
|
|
||||||
phantom_node_pair.target_phantom.reverse_segment_id.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// search from s and t till new_min/(1+epsilon) > length_of_shortest_path
|
// search from s and t till new_min/(1+epsilon) > length_of_shortest_path
|
||||||
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
||||||
@ -674,8 +646,8 @@ alternativePathSearch(SearchEngineData &engine_working_data,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
retrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
|
ch::retrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
|
||||||
retrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
|
ch::retrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this set is is used as an indicator if a node is on the shortest path
|
// this set is is used as an indicator if a node is on the shortest path
|
||||||
@ -827,14 +799,14 @@ alternativePathSearch(SearchEngineData &engine_working_data,
|
|||||||
raw_route_data.target_traversed_in_reverse.push_back((
|
raw_route_data.target_traversed_in_reverse.push_back((
|
||||||
packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
|
packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
|
||||||
|
|
||||||
unpackPath(facade,
|
ch::unpackPath(facade,
|
||||||
// -- packed input
|
// -- packed input
|
||||||
packed_shortest_path.begin(),
|
packed_shortest_path.begin(),
|
||||||
packed_shortest_path.end(),
|
packed_shortest_path.end(),
|
||||||
// -- start of route
|
// -- start of route
|
||||||
phantom_node_pair,
|
phantom_node_pair,
|
||||||
// -- unpacked output
|
// -- unpacked output
|
||||||
raw_route_data.unpacked_path_segments.front());
|
raw_route_data.unpacked_path_segments.front());
|
||||||
raw_route_data.shortest_path_length = upper_bound_to_shortest_path_weight;
|
raw_route_data.shortest_path_length = upper_bound_to_shortest_path_weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -858,11 +830,11 @@ alternativePathSearch(SearchEngineData &engine_working_data,
|
|||||||
phantom_node_pair.target_phantom.forward_segment_id.id));
|
phantom_node_pair.target_phantom.forward_segment_id.id));
|
||||||
|
|
||||||
// unpack the alternate path
|
// unpack the alternate path
|
||||||
unpackPath(facade,
|
ch::unpackPath(facade,
|
||||||
packed_alternate_path.begin(),
|
packed_alternate_path.begin(),
|
||||||
packed_alternate_path.end(),
|
packed_alternate_path.end(),
|
||||||
phantom_node_pair,
|
phantom_node_pair,
|
||||||
raw_route_data.unpacked_alternative);
|
raw_route_data.unpacked_alternative);
|
||||||
|
|
||||||
raw_route_data.alternative_path_length = length_of_via_path;
|
raw_route_data.alternative_path_length = length_of_via_path;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "engine/routing_algorithms/direct_shortest_path.hpp"
|
#include "engine/routing_algorithms/direct_shortest_path.hpp"
|
||||||
|
|
||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base.hpp"
|
||||||
|
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
@ -9,44 +10,8 @@ namespace engine
|
|||||||
namespace routing_algorithms
|
namespace routing_algorithms
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace
|
namespace ch
|
||||||
{
|
{
|
||||||
void insertInHeaps(SearchEngineData::QueryHeap &forward_heap,
|
|
||||||
SearchEngineData::QueryHeap &reverse_heap,
|
|
||||||
const PhantomNodes &nodes)
|
|
||||||
{
|
|
||||||
const auto &source_phantom = nodes.source_phantom;
|
|
||||||
const auto &target_phantom = nodes.target_phantom;
|
|
||||||
BOOST_ASSERT(source_phantom.IsValid());
|
|
||||||
BOOST_ASSERT(target_phantom.IsValid());
|
|
||||||
|
|
||||||
if (source_phantom.forward_segment_id.enabled)
|
|
||||||
{
|
|
||||||
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
|
||||||
-source_phantom.GetForwardWeightPlusOffset(),
|
|
||||||
source_phantom.forward_segment_id.id);
|
|
||||||
}
|
|
||||||
if (source_phantom.reverse_segment_id.enabled)
|
|
||||||
{
|
|
||||||
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
|
||||||
-source_phantom.GetReverseWeightPlusOffset(),
|
|
||||||
source_phantom.reverse_segment_id.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_phantom.forward_segment_id.enabled)
|
|
||||||
{
|
|
||||||
reverse_heap.Insert(target_phantom.forward_segment_id.id,
|
|
||||||
target_phantom.GetForwardWeightPlusOffset(),
|
|
||||||
target_phantom.forward_segment_id.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_phantom.reverse_segment_id.enabled)
|
|
||||||
{
|
|
||||||
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
|
|
||||||
target_phantom.GetReverseWeightPlusOffset(),
|
|
||||||
target_phantom.reverse_segment_id.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename AlgorithmT>
|
template <typename AlgorithmT>
|
||||||
InternalRouteResult
|
InternalRouteResult
|
||||||
@ -82,7 +47,6 @@ extractRoute(const datafacade::ContiguousInternalMemoryDataFacade<AlgorithmT> &f
|
|||||||
|
|
||||||
return raw_route_data;
|
return raw_route_data;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// This is a striped down version of the general shortest path algorithm.
|
/// This is a striped down version of the general shortest path algorithm.
|
||||||
/// The general algorithm always computes two queries for each leg. This is only
|
/// The general algorithm always computes two queries for each leg. This is only
|
||||||
@ -109,7 +73,7 @@ InternalRouteResult directShortestPathSearchImpl(
|
|||||||
|
|
||||||
int weight = INVALID_EDGE_WEIGHT;
|
int weight = INVALID_EDGE_WEIGHT;
|
||||||
std::vector<NodeID> packed_leg;
|
std::vector<NodeID> packed_leg;
|
||||||
insertInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
||||||
|
|
||||||
search(facade,
|
search(facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
@ -124,12 +88,14 @@ InternalRouteResult directShortestPathSearchImpl(
|
|||||||
return extractRoute(facade, weight, packed_leg, phantom_nodes);
|
return extractRoute(facade, weight, packed_leg, phantom_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace ch
|
||||||
|
|
||||||
InternalRouteResult directShortestPathSearch(
|
InternalRouteResult directShortestPathSearch(
|
||||||
SearchEngineData &engine_working_data,
|
SearchEngineData &engine_working_data,
|
||||||
const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CoreCH> &facade,
|
const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CoreCH> &facade,
|
||||||
const PhantomNodes &phantom_nodes)
|
const PhantomNodes &phantom_nodes)
|
||||||
{
|
{
|
||||||
return directShortestPathSearchImpl(engine_working_data, facade, phantom_nodes);
|
return ch::directShortestPathSearchImpl(engine_working_data, facade, phantom_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalRouteResult directShortestPathSearch(
|
InternalRouteResult directShortestPathSearch(
|
||||||
@ -137,7 +103,7 @@ InternalRouteResult directShortestPathSearch(
|
|||||||
const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
|
||||||
const PhantomNodes &phantom_nodes)
|
const PhantomNodes &phantom_nodes)
|
||||||
{
|
{
|
||||||
return directShortestPathSearchImpl(engine_working_data, facade, phantom_nodes);
|
return ch::directShortestPathSearchImpl(engine_working_data, facade, phantom_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "engine/routing_algorithms/many_to_many.hpp"
|
#include "engine/routing_algorithms/many_to_many.hpp"
|
||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
@ -101,14 +101,14 @@ void forwardRoutingStep(const datafacade::ContiguousInternalMemoryDataFacade<alg
|
|||||||
const EdgeWeight new_weight = source_weight + target_weight;
|
const EdgeWeight new_weight = source_weight + target_weight;
|
||||||
if (new_weight < 0)
|
if (new_weight < 0)
|
||||||
{
|
{
|
||||||
const EdgeWeight loop_weight = getLoopWeight<false>(facade, node);
|
const EdgeWeight loop_weight = ch::getLoopWeight<false>(facade, node);
|
||||||
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
|
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
|
||||||
if (loop_weight != INVALID_EDGE_WEIGHT && new_weight_with_loop >= 0)
|
if (loop_weight != INVALID_EDGE_WEIGHT && new_weight_with_loop >= 0)
|
||||||
{
|
{
|
||||||
current_weight = std::min(current_weight, new_weight_with_loop);
|
current_weight = std::min(current_weight, new_weight_with_loop);
|
||||||
current_duration = std::min(current_duration,
|
current_duration = std::min(current_duration,
|
||||||
source_duration + target_duration +
|
source_duration + target_duration +
|
||||||
getLoopWeight<true>(facade, node));
|
ch::getLoopWeight<true>(facade, node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (new_weight < current_weight)
|
else if (new_weight < current_weight)
|
||||||
@ -118,7 +118,7 @@ void forwardRoutingStep(const datafacade::ContiguousInternalMemoryDataFacade<alg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stallAtNode<FORWARD_DIRECTION>(facade, node, source_weight, query_heap))
|
if (ch::stallAtNode<FORWARD_DIRECTION>(facade, node, source_weight, query_heap))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ void backwardRoutingStep(
|
|||||||
// store settled nodes in search space bucket
|
// store settled nodes in search space bucket
|
||||||
search_space_with_buckets[node].emplace_back(column_idx, target_weight, target_duration);
|
search_space_with_buckets[node].emplace_back(column_idx, target_weight, target_duration);
|
||||||
|
|
||||||
if (stallAtNode<REVERSE_DIRECTION>(facade, node, target_weight, query_heap))
|
if (ch::stallAtNode<REVERSE_DIRECTION>(facade, node, target_weight, query_heap))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -172,21 +172,9 @@ manyToManySearch(SearchEngineData &engine_working_data,
|
|||||||
|
|
||||||
unsigned column_idx = 0;
|
unsigned column_idx = 0;
|
||||||
const auto search_target_phantom = [&](const PhantomNode &phantom) {
|
const auto search_target_phantom = [&](const PhantomNode &phantom) {
|
||||||
|
// clear heap and insert target nodes
|
||||||
query_heap.Clear();
|
query_heap.Clear();
|
||||||
// insert target(s) at weight 0
|
insertNodesInHeap<REVERSE_DIRECTION>(query_heap, phantom);
|
||||||
|
|
||||||
if (phantom.forward_segment_id.enabled)
|
|
||||||
{
|
|
||||||
query_heap.Insert(phantom.forward_segment_id.id,
|
|
||||||
phantom.GetForwardWeightPlusOffset(),
|
|
||||||
{phantom.forward_segment_id.id, phantom.GetForwardDuration()});
|
|
||||||
}
|
|
||||||
if (phantom.reverse_segment_id.enabled)
|
|
||||||
{
|
|
||||||
query_heap.Insert(phantom.reverse_segment_id.id,
|
|
||||||
phantom.GetReverseWeightPlusOffset(),
|
|
||||||
{phantom.reverse_segment_id.id, phantom.GetReverseDuration()});
|
|
||||||
}
|
|
||||||
|
|
||||||
// explore search space
|
// explore search space
|
||||||
while (!query_heap.Empty())
|
while (!query_heap.Empty())
|
||||||
@ -199,21 +187,9 @@ manyToManySearch(SearchEngineData &engine_working_data,
|
|||||||
// for each source do forward search
|
// for each source do forward search
|
||||||
unsigned row_idx = 0;
|
unsigned row_idx = 0;
|
||||||
const auto search_source_phantom = [&](const PhantomNode &phantom) {
|
const auto search_source_phantom = [&](const PhantomNode &phantom) {
|
||||||
|
// clear heap and insert source nodes
|
||||||
query_heap.Clear();
|
query_heap.Clear();
|
||||||
// insert target(s) at weight 0
|
insertNodesInHeap<FORWARD_DIRECTION>(query_heap, phantom);
|
||||||
|
|
||||||
if (phantom.forward_segment_id.enabled)
|
|
||||||
{
|
|
||||||
query_heap.Insert(phantom.forward_segment_id.id,
|
|
||||||
-phantom.GetForwardWeightPlusOffset(),
|
|
||||||
{phantom.forward_segment_id.id, -phantom.GetForwardDuration()});
|
|
||||||
}
|
|
||||||
if (phantom.reverse_segment_id.enabled)
|
|
||||||
{
|
|
||||||
query_heap.Insert(phantom.reverse_segment_id.id,
|
|
||||||
-phantom.GetReverseWeightPlusOffset(),
|
|
||||||
{phantom.reverse_segment_id.id, -phantom.GetReverseDuration()});
|
|
||||||
}
|
|
||||||
|
|
||||||
// explore search space
|
// explore search space
|
||||||
while (!query_heap.Empty())
|
while (!query_heap.Empty())
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "engine/routing_algorithms/map_matching.hpp"
|
#include "engine/routing_algorithms/map_matching.hpp"
|
||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||||
|
|
||||||
#include "engine/map_matching/hidden_markov_model.hpp"
|
#include "engine/map_matching/hidden_markov_model.hpp"
|
||||||
#include "engine/map_matching/matching_confidence.hpp"
|
#include "engine/map_matching/matching_confidence.hpp"
|
||||||
@ -210,14 +210,14 @@ mapMatchingImpl(SearchEngineData &engine_working_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
double network_distance =
|
double network_distance =
|
||||||
getNetworkDistance(facade,
|
ch::getNetworkDistance(facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
reverse_heap,
|
reverse_heap,
|
||||||
forward_core_heap,
|
forward_core_heap,
|
||||||
reverse_core_heap,
|
reverse_core_heap,
|
||||||
prev_unbroken_timestamps_list[s].phantom_node,
|
prev_unbroken_timestamps_list[s].phantom_node,
|
||||||
current_timestamps_list[s_prime].phantom_node,
|
current_timestamps_list[s_prime].phantom_node,
|
||||||
duration_upper_bound);
|
duration_upper_bound);
|
||||||
|
|
||||||
// get distance diff between loc1/2 and locs/s_prime
|
// get distance diff between loc1/2 and locs/s_prime
|
||||||
const auto d_t = std::abs(network_distance - haversine_distance);
|
const auto d_t = std::abs(network_distance - haversine_distance);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
@ -6,6 +6,8 @@ namespace engine
|
|||||||
{
|
{
|
||||||
namespace routing_algorithms
|
namespace routing_algorithms
|
||||||
{
|
{
|
||||||
|
namespace ch
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unpacks a single edge (NodeID->NodeID) from the CH graph down to it's original non-shortcut
|
* Unpacks a single edge (NodeID->NodeID) from the CH graph down to it's original non-shortcut
|
||||||
@ -411,31 +413,7 @@ getNetworkDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorith
|
|||||||
forward_core_heap.Clear();
|
forward_core_heap.Clear();
|
||||||
reverse_core_heap.Clear();
|
reverse_core_heap.Clear();
|
||||||
|
|
||||||
if (source_phantom.forward_segment_id.enabled)
|
insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom});
|
||||||
{
|
|
||||||
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
|
||||||
-source_phantom.GetForwardWeightPlusOffset(),
|
|
||||||
source_phantom.forward_segment_id.id);
|
|
||||||
}
|
|
||||||
if (source_phantom.reverse_segment_id.enabled)
|
|
||||||
{
|
|
||||||
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
|
||||||
-source_phantom.GetReverseWeightPlusOffset(),
|
|
||||||
source_phantom.reverse_segment_id.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_phantom.forward_segment_id.enabled)
|
|
||||||
{
|
|
||||||
reverse_heap.Insert(target_phantom.forward_segment_id.id,
|
|
||||||
target_phantom.GetForwardWeightPlusOffset(),
|
|
||||||
target_phantom.forward_segment_id.id);
|
|
||||||
}
|
|
||||||
if (target_phantom.reverse_segment_id.enabled)
|
|
||||||
{
|
|
||||||
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
|
|
||||||
target_phantom.GetReverseWeightPlusOffset(),
|
|
||||||
target_phantom.reverse_segment_id.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||||
std::vector<NodeID> packed_path;
|
std::vector<NodeID> packed_path;
|
||||||
@ -517,6 +495,7 @@ getNetworkDistance(const datafacade::ContiguousInternalMemoryDataFacade<algorith
|
|||||||
return getPathDistance(facade, packed_path, source_phantom, target_phantom);
|
return getPathDistance(facade, packed_path, source_phantom, target_phantom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace ch
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
@ -1,5 +1,5 @@
|
|||||||
#include "engine/routing_algorithms/shortest_path.hpp"
|
#include "engine/routing_algorithms/shortest_path.hpp"
|
||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
@ -71,23 +71,24 @@ void searchWithUTurn(const datafacade::ContiguousInternalMemoryDataFacade<Algori
|
|||||||
auto is_oneway_source = !(search_from_forward_node && search_from_reverse_node);
|
auto is_oneway_source = !(search_from_forward_node && search_from_reverse_node);
|
||||||
auto is_oneway_target = !(search_to_forward_node && search_to_reverse_node);
|
auto is_oneway_target = !(search_to_forward_node && search_to_reverse_node);
|
||||||
// we only enable loops here if we can't search from forward to backward node
|
// we only enable loops here if we can't search from forward to backward node
|
||||||
auto needs_loop_forwad = is_oneway_source && needsLoopForward(source_phantom, target_phantom);
|
auto needs_loop_forwad =
|
||||||
|
is_oneway_source && ch::needsLoopForward(source_phantom, target_phantom);
|
||||||
auto needs_loop_backwards =
|
auto needs_loop_backwards =
|
||||||
is_oneway_target && needsLoopBackwards(source_phantom, target_phantom);
|
is_oneway_target && ch::needsLoopBackwards(source_phantom, target_phantom);
|
||||||
|
|
||||||
forward_core_heap.Clear();
|
forward_core_heap.Clear();
|
||||||
reverse_core_heap.Clear();
|
reverse_core_heap.Clear();
|
||||||
BOOST_ASSERT(forward_core_heap.Size() == 0);
|
BOOST_ASSERT(forward_core_heap.Size() == 0);
|
||||||
BOOST_ASSERT(reverse_core_heap.Size() == 0);
|
BOOST_ASSERT(reverse_core_heap.Size() == 0);
|
||||||
routing_algorithms::search(facade,
|
ch::search(facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
reverse_heap,
|
reverse_heap,
|
||||||
forward_core_heap,
|
forward_core_heap,
|
||||||
reverse_core_heap,
|
reverse_core_heap,
|
||||||
new_total_weight,
|
new_total_weight,
|
||||||
leg_packed_path,
|
leg_packed_path,
|
||||||
needs_loop_forwad,
|
needs_loop_forwad,
|
||||||
needs_loop_backwards);
|
needs_loop_backwards);
|
||||||
|
|
||||||
// if no route is found between two parts of the via-route, the entire route becomes
|
// if no route is found between two parts of the via-route, the entire route becomes
|
||||||
// invalid. Adding to invalid edge weight sadly doesn't return an invalid edge weight. Here
|
// invalid. Adding to invalid edge weight sadly doesn't return an invalid edge weight. Here
|
||||||
@ -147,15 +148,15 @@ void search(const datafacade::ContiguousInternalMemoryDataFacade<AlgorithmT> &fa
|
|||||||
reverse_core_heap.Clear();
|
reverse_core_heap.Clear();
|
||||||
BOOST_ASSERT(forward_core_heap.Size() == 0);
|
BOOST_ASSERT(forward_core_heap.Size() == 0);
|
||||||
BOOST_ASSERT(reverse_core_heap.Size() == 0);
|
BOOST_ASSERT(reverse_core_heap.Size() == 0);
|
||||||
routing_algorithms::search(facade,
|
ch::search(facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
reverse_heap,
|
reverse_heap,
|
||||||
forward_core_heap,
|
forward_core_heap,
|
||||||
reverse_core_heap,
|
reverse_core_heap,
|
||||||
new_total_weight_to_forward,
|
new_total_weight_to_forward,
|
||||||
leg_packed_path_forward,
|
leg_packed_path_forward,
|
||||||
needsLoopForward(source_phantom, target_phantom),
|
ch::needsLoopForward(source_phantom, target_phantom),
|
||||||
DO_NOT_FORCE_LOOP);
|
DO_NOT_FORCE_LOOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (search_to_reverse_node)
|
if (search_to_reverse_node)
|
||||||
@ -185,15 +186,15 @@ void search(const datafacade::ContiguousInternalMemoryDataFacade<AlgorithmT> &fa
|
|||||||
reverse_core_heap.Clear();
|
reverse_core_heap.Clear();
|
||||||
BOOST_ASSERT(forward_core_heap.Size() == 0);
|
BOOST_ASSERT(forward_core_heap.Size() == 0);
|
||||||
BOOST_ASSERT(reverse_core_heap.Size() == 0);
|
BOOST_ASSERT(reverse_core_heap.Size() == 0);
|
||||||
routing_algorithms::search(facade,
|
ch::search(facade,
|
||||||
forward_heap,
|
forward_heap,
|
||||||
reverse_heap,
|
reverse_heap,
|
||||||
forward_core_heap,
|
forward_core_heap,
|
||||||
reverse_core_heap,
|
reverse_core_heap,
|
||||||
new_total_weight_to_reverse,
|
new_total_weight_to_reverse,
|
||||||
leg_packed_path_reverse,
|
leg_packed_path_reverse,
|
||||||
DO_NOT_FORCE_LOOP,
|
DO_NOT_FORCE_LOOP,
|
||||||
needsLoopBackwards(source_phantom, target_phantom));
|
ch::needsLoopBackwards(source_phantom, target_phantom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,11 +214,11 @@ void unpackLegs(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::
|
|||||||
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
|
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
|
||||||
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
|
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
|
||||||
const auto &unpack_phantom_node_pair = phantom_nodes_vector[current_leg];
|
const auto &unpack_phantom_node_pair = phantom_nodes_vector[current_leg];
|
||||||
unpackPath(facade,
|
ch::unpackPath(facade,
|
||||||
leg_begin,
|
leg_begin,
|
||||||
leg_end,
|
leg_end,
|
||||||
unpack_phantom_node_pair,
|
unpack_phantom_node_pair,
|
||||||
raw_route_data.unpacked_path_segments[current_leg]);
|
raw_route_data.unpacked_path_segments[current_leg]);
|
||||||
|
|
||||||
raw_route_data.source_traversed_in_reverse.push_back(
|
raw_route_data.source_traversed_in_reverse.push_back(
|
||||||
(*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_segment_id.id));
|
(*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_segment_id.id));
|
||||||
|
Loading…
Reference in New Issue
Block a user