Unpack paths and return total distance in matrix plugin for CH (#4990)
This commit is contained in:
@@ -21,17 +21,26 @@ namespace
|
||||
struct NodeBucket
|
||||
{
|
||||
NodeID middle_node;
|
||||
NodeID parent_node;
|
||||
unsigned column_index; // a column in the weight/duration matrix
|
||||
EdgeWeight weight;
|
||||
EdgeDuration duration;
|
||||
|
||||
NodeBucket(NodeID middle_node, unsigned column_index, EdgeWeight weight, EdgeDuration duration)
|
||||
: middle_node(middle_node), column_index(column_index), weight(weight), duration(duration)
|
||||
NodeBucket(NodeID middle_node,
|
||||
NodeID parent_node,
|
||||
unsigned column_index,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration)
|
||||
: middle_node(middle_node), parent_node(parent_node), column_index(column_index),
|
||||
weight(weight), duration(duration)
|
||||
{
|
||||
}
|
||||
|
||||
// partial order comparison
|
||||
bool operator<(const NodeBucket &rhs) const { return middle_node < rhs.middle_node; }
|
||||
bool operator<(const NodeBucket &rhs) const
|
||||
{
|
||||
return std::tie(middle_node, column_index) < std::tie(rhs.middle_node, rhs.column_index);
|
||||
}
|
||||
|
||||
// functor for equal_range
|
||||
struct Compare
|
||||
@@ -46,15 +55,36 @@ struct NodeBucket
|
||||
return lhs < rhs.middle_node;
|
||||
}
|
||||
};
|
||||
|
||||
// functor for equal_range
|
||||
struct ColumnCompare
|
||||
{
|
||||
unsigned column_idx;
|
||||
|
||||
ColumnCompare(unsigned column_idx) : column_idx(column_idx){};
|
||||
|
||||
bool operator()(const NodeBucket &lhs, const NodeID &rhs) const // lowerbound
|
||||
{
|
||||
return std::tie(lhs.middle_node, lhs.column_index) < std::tie(rhs, column_idx);
|
||||
}
|
||||
|
||||
bool operator()(const NodeID &lhs, const NodeBucket &rhs) const // upperbound
|
||||
{
|
||||
return std::tie(lhs, column_idx) < std::tie(rhs.middle_node, rhs.column_index);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices);
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
|
||||
@@ -181,6 +181,7 @@ void annotatePath(const FacadeT &facade,
|
||||
BOOST_ASSERT(datasource_vector.size() > 0);
|
||||
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
|
||||
BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size());
|
||||
|
||||
const bool is_first_segment = unpacked_path.empty();
|
||||
|
||||
const std::size_t start_index =
|
||||
@@ -405,6 +406,22 @@ InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
||||
return raw_route_data;
|
||||
}
|
||||
|
||||
template <typename FacadeT> EdgeDistance computeEdgeDistance(const FacadeT &facade, NodeID node_id)
|
||||
{
|
||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||
|
||||
EdgeDistance total_distance = 0.0;
|
||||
|
||||
auto geometry_range = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
||||
for (auto current = geometry_range.begin(); current < geometry_range.end() - 1; ++current)
|
||||
{
|
||||
total_distance += util::coordinate_calculation::haversineDistance(
|
||||
facade.GetCoordinateOfNode(*current), facade.GetCoordinateOfNode(*std::next(current)));
|
||||
}
|
||||
|
||||
return total_distance;
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
@@ -288,6 +288,106 @@ void unpackPath(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BidirectionalIterator>
|
||||
EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
||||
BidirectionalIterator packed_path_begin,
|
||||
BidirectionalIterator packed_path_end)
|
||||
{
|
||||
// Make sure we have at least something to unpack
|
||||
if (packed_path_begin == packed_path_end ||
|
||||
std::distance(packed_path_begin, packed_path_end) <= 1)
|
||||
return 0;
|
||||
|
||||
std::stack<std::tuple<NodeID, NodeID, bool>> recursion_stack;
|
||||
std::stack<EdgeDistance> distance_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, false);
|
||||
}
|
||||
|
||||
std::tuple<NodeID, NodeID, bool> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
// Have we processed the edge before? tells us if we have values in the durations stack that
|
||||
// we can add up
|
||||
if (!std::get<2>(edge))
|
||||
{ // haven't processed edge before, so process it in the body!
|
||||
|
||||
std::get<2>(edge) = true; // mark that this edge will now be processed
|
||||
|
||||
// Look for an edge on the forward CH graph (.forward)
|
||||
EdgeID smaller_edge_id =
|
||||
facade.FindSmallestEdge(std::get<0>(edge), std::get<1>(edge), [](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(std::get<1>(edge),
|
||||
std::get<0>(edge),
|
||||
[](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(edge);
|
||||
recursion_stack.emplace(middle_node_id, std::get<1>(edge), false);
|
||||
recursion_stack.emplace(std::get<0>(edge), middle_node_id, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// compute the duration here and put it onto the duration stack using method
|
||||
// similar to annotatePath but smaller
|
||||
EdgeDistance distance = computeEdgeDistance(facade, std::get<0>(edge));
|
||||
distance_stack.emplace(distance);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // the edge has already been processed. this means that there are enough values in the
|
||||
// distances stack
|
||||
|
||||
BOOST_ASSERT_MSG(distance_stack.size() >= 2,
|
||||
"There are not enough (at least 2) values on the distance stack");
|
||||
EdgeDistance distance1 = distance_stack.top();
|
||||
distance_stack.pop();
|
||||
EdgeDistance distance2 = distance_stack.top();
|
||||
distance_stack.pop();
|
||||
EdgeDistance distance = distance1 + distance2;
|
||||
distance_stack.emplace(distance);
|
||||
}
|
||||
}
|
||||
|
||||
EdgeDistance total_distance = 0;
|
||||
while (!distance_stack.empty())
|
||||
{
|
||||
total_distance += distance_stack.top();
|
||||
distance_stack.pop();
|
||||
}
|
||||
|
||||
return total_distance;
|
||||
}
|
||||
|
||||
template <typename RandomIter, typename FacadeT>
|
||||
void unpackPath(const FacadeT &facade,
|
||||
RandomIter packed_path_begin,
|
||||
@@ -340,6 +440,11 @@ void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHe
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> &packed_path);
|
||||
|
||||
void retrievePackedPathFromSingleManyToManyHeap(
|
||||
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &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.
|
||||
|
||||
Reference in New Issue
Block a user