Refactor edge unpacking so that it's CH indepenent and we don't repeat ourselves so much.
This commit is contained in:
parent
14e7460465
commit
c8eb2b2d11
@ -66,6 +66,10 @@ class BaseDataFacade
|
|||||||
virtual EdgeID
|
virtual EdgeID
|
||||||
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
|
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
|
||||||
|
|
||||||
|
virtual EdgeID FindSmallestEdge(const NodeID from,
|
||||||
|
const NodeID to,
|
||||||
|
const std::function<bool(EdgeData)> filter) const = 0;
|
||||||
|
|
||||||
// node and edge information access
|
// node and edge information access
|
||||||
virtual util::Coordinate GetCoordinateOfNode(const unsigned id) const = 0;
|
virtual util::Coordinate GetCoordinateOfNode(const unsigned id) const = 0;
|
||||||
virtual OSMNodeID GetOSMNodeIDOfNode(const unsigned id) const = 0;
|
virtual OSMNodeID GetOSMNodeIDOfNode(const unsigned id) const = 0;
|
||||||
|
@ -472,6 +472,13 @@ class InternalDataFacade final : public BaseDataFacade
|
|||||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EdgeID FindSmallestEdge(const NodeID from,
|
||||||
|
const NodeID to,
|
||||||
|
std::function<bool(EdgeData)> filter) const override final
|
||||||
|
{
|
||||||
|
return m_query_graph->FindSmallestEdge(from, to, filter);
|
||||||
|
}
|
||||||
|
|
||||||
// node and edge information access
|
// node and edge information access
|
||||||
util::Coordinate GetCoordinateOfNode(const unsigned id) const override final
|
util::Coordinate GetCoordinateOfNode(const unsigned id) const override final
|
||||||
{
|
{
|
||||||
|
@ -507,6 +507,13 @@ class SharedDataFacade final : public BaseDataFacade
|
|||||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EdgeID FindSmallestEdge(const NodeID from,
|
||||||
|
const NodeID to,
|
||||||
|
std::function<bool(EdgeData)> filter) const override final
|
||||||
|
{
|
||||||
|
return m_query_graph->FindSmallestEdge(from, to, filter);
|
||||||
|
}
|
||||||
|
|
||||||
// node and edge information access
|
// node and edge information access
|
||||||
util::Coordinate GetCoordinateOfNode(const NodeID id) const override final
|
util::Coordinate GetCoordinateOfNode(const NodeID id) const override final
|
||||||
{
|
{
|
||||||
|
104
include/engine/edge_unpacker.hpp
Normal file
104
include/engine/edge_unpacker.hpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#ifndef EDGE_UNPACKER_H
|
||||||
|
#define EDGE_UNPACKER_H
|
||||||
|
|
||||||
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
|
#include "extractor/travel_mode.hpp"
|
||||||
|
#include "engine/phantom_node.hpp"
|
||||||
|
#include "osrm/coordinate.hpp"
|
||||||
|
#include "util/guidance/turn_lanes.hpp"
|
||||||
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 DataFacadeT, typename RandomIter, typename Callback>
|
||||||
|
inline void UnpackCHEdge(DataFacadeT *facade,
|
||||||
|
RandomIter packed_path_begin,
|
||||||
|
RandomIter packed_path_end,
|
||||||
|
const Callback &callback)
|
||||||
|
{
|
||||||
|
|
||||||
|
using EdgeData = typename DataFacadeT::EdgeData;
|
||||||
|
|
||||||
|
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 EdgeData &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 EdgeData &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.distance != 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.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.
|
||||||
|
callback(edge, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // EDGE_UNPACKER_H
|
@ -25,13 +25,8 @@ namespace plugins
|
|||||||
|
|
||||||
class TilePlugin final : public BasePlugin
|
class TilePlugin final : public BasePlugin
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
routing_algorithms::BasicRoutingInterface<
|
|
||||||
datafacade::BaseDataFacade,
|
|
||||||
routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade>> routing_base;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TilePlugin(datafacade::BaseDataFacade &facade) : BasePlugin(facade), routing_base(&facade) {}
|
TilePlugin(datafacade::BaseDataFacade &facade) : BasePlugin(facade) {}
|
||||||
|
|
||||||
Status HandleRequest(const api::TileParameters ¶meters, std::string &pbf_buffer);
|
Status HandleRequest(const api::TileParameters ¶meters, std::string &pbf_buffer);
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "extractor/guidance/turn_instruction.hpp"
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
#include "engine/internal_route_result.hpp"
|
#include "engine/internal_route_result.hpp"
|
||||||
#include "engine/search_engine_data.hpp"
|
#include "engine/search_engine_data.hpp"
|
||||||
|
#include "engine/edge_unpacker.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
@ -221,14 +222,6 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
|||||||
(*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_segment_id.id);
|
(*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_segment_id.id);
|
||||||
|
|
||||||
BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
|
BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT(*packed_path_begin == phantom_node_pair.source_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);
|
*packed_path_begin == phantom_node_pair.source_phantom.reverse_segment_id.id);
|
||||||
@ -236,69 +229,26 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
|||||||
*std::prev(packed_path_end) == phantom_node_pair.target_phantom.forward_segment_id.id ||
|
*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);
|
*std::prev(packed_path_end) == phantom_node_pair.target_phantom.reverse_segment_id.id);
|
||||||
|
|
||||||
std::pair<NodeID, NodeID> edge;
|
UnpackCHEdge(
|
||||||
while (!recursion_stack.empty())
|
facade,
|
||||||
{
|
packed_path_begin,
|
||||||
// edge.first edge.second
|
packed_path_end,
|
||||||
// *------------------>*
|
[this,
|
||||||
// edge_id
|
&unpacked_path,
|
||||||
edge = recursion_stack.top();
|
&phantom_node_pair,
|
||||||
recursion_stack.pop();
|
&start_traversed_in_reverse,
|
||||||
|
&target_traversed_in_reverse](std::pair<NodeID, NodeID> & /* edge */,
|
||||||
|
const EdgeData &data) {
|
||||||
|
|
||||||
// Contraction might introduce double edges by inserting shortcuts
|
BOOST_ASSERT_MSG(!data.shortcut, "original edge flagged as shortcut");
|
||||||
// this searching for the smallest upwards edge found by the forward search
|
unsigned name_index = facade->GetNameIndexFromEdgeID(data.id);
|
||||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
const auto turn_instruction = facade->GetTurnInstructionForEdgeID(data.id);
|
||||||
EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
|
|
||||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
|
||||||
{
|
|
||||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
|
||||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
|
||||||
facade->GetEdgeData(edge_id).forward)
|
|
||||||
{
|
|
||||||
smaller_edge_id = edge_id;
|
|
||||||
edge_weight = weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// edge.first edge.second
|
|
||||||
// *<------------------*
|
|
||||||
// edge_id
|
|
||||||
// if we don't find a forward edge, this edge must have been an downwards edge
|
|
||||||
// found by the reverse search.
|
|
||||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
|
||||||
{
|
|
||||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
|
||||||
{
|
|
||||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
|
||||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
|
||||||
facade->GetEdgeData(edge_id).backward)
|
|
||||||
{
|
|
||||||
smaller_edge_id = edge_id;
|
|
||||||
edge_weight = weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
|
|
||||||
|
|
||||||
const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
|
|
||||||
if (ed.shortcut)
|
|
||||||
{ // unpack
|
|
||||||
const NodeID middle_node_id = ed.id;
|
|
||||||
// again, we need to this in reversed order
|
|
||||||
recursion_stack.emplace(middle_node_id, edge.second);
|
|
||||||
recursion_stack.emplace(edge.first, middle_node_id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
|
|
||||||
unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
|
|
||||||
const auto turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
|
|
||||||
const extractor::TravelMode travel_mode =
|
const extractor::TravelMode travel_mode =
|
||||||
(unpacked_path.empty() && start_traversed_in_reverse)
|
(unpacked_path.empty() && start_traversed_in_reverse)
|
||||||
? phantom_node_pair.source_phantom.backward_travel_mode
|
? phantom_node_pair.source_phantom.backward_travel_mode
|
||||||
: facade->GetTravelModeForEdgeID(ed.id);
|
: facade->GetTravelModeForEdgeID(data.id);
|
||||||
|
|
||||||
const auto geometry_index = facade->GetGeometryIndexForEdgeID(ed.id);
|
const auto geometry_index = facade->GetGeometryIndexForEdgeID(data.id);
|
||||||
std::vector<NodeID> id_vector;
|
std::vector<NodeID> id_vector;
|
||||||
facade->GetUncompressedGeometry(geometry_index, id_vector);
|
facade->GetUncompressedGeometry(geometry_index, id_vector);
|
||||||
BOOST_ASSERT(id_vector.size() > 0);
|
BOOST_ASSERT(id_vector.size() > 0);
|
||||||
@ -339,14 +289,14 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
|||||||
datasource_vector[i]});
|
datasource_vector[i]});
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(unpacked_path.size() > 0);
|
BOOST_ASSERT(unpacked_path.size() > 0);
|
||||||
if (facade->hasLaneData(ed.id))
|
if (facade->hasLaneData(data.id))
|
||||||
unpacked_path.back().lane_data = facade->GetLaneData(ed.id);
|
unpacked_path.back().lane_data = facade->GetLaneData(data.id);
|
||||||
|
|
||||||
unpacked_path.back().entry_classid = facade->GetEntryClassID(ed.id);
|
unpacked_path.back().entry_classid = facade->GetEntryClassID(data.id);
|
||||||
unpacked_path.back().turn_instruction = turn_instruction;
|
unpacked_path.back().turn_instruction = turn_instruction;
|
||||||
unpacked_path.back().duration_until_turn += (ed.distance - total_weight);
|
unpacked_path.back().duration_until_turn += (data.distance - total_weight);
|
||||||
}
|
});
|
||||||
}
|
|
||||||
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;
|
||||||
std::vector<EdgeWeight> weight_vector;
|
std::vector<EdgeWeight> weight_vector;
|
||||||
@ -455,124 +405,24 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
|
|
||||||
{
|
|
||||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
|
||||||
recursion_stack.emplace(s, t);
|
|
||||||
|
|
||||||
std::pair<NodeID, NodeID> edge;
|
|
||||||
while (!recursion_stack.empty())
|
|
||||||
{
|
|
||||||
edge = recursion_stack.top();
|
|
||||||
recursion_stack.pop();
|
|
||||||
|
|
||||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
|
||||||
EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
|
|
||||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
|
||||||
{
|
|
||||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
|
||||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
|
||||||
facade->GetEdgeData(edge_id).forward)
|
|
||||||
{
|
|
||||||
smaller_edge_id = edge_id;
|
|
||||||
edge_weight = weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
|
||||||
{
|
|
||||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
|
||||||
{
|
|
||||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
|
||||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
|
||||||
facade->GetEdgeData(edge_id).backward)
|
|
||||||
{
|
|
||||||
smaller_edge_id = edge_id;
|
|
||||||
edge_weight = weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(),
|
|
||||||
"edge weight invalid");
|
|
||||||
|
|
||||||
const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
|
|
||||||
if (ed.shortcut)
|
|
||||||
{ // unpack
|
|
||||||
const NodeID middle_node_id = ed.id;
|
|
||||||
// again, we need to this in reversed order
|
|
||||||
recursion_stack.emplace(middle_node_id, edge.second);
|
|
||||||
recursion_stack.emplace(edge.first, middle_node_id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
|
|
||||||
unpacked_path.emplace_back(edge.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unpacked_path.emplace_back(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A duplicate of the above `UnpackEdge` function, but returning full EdgeData
|
* Unpacks a single edge (NodeID->NodeID) from the CH graph down to it's original non-shortcut
|
||||||
* objects for the unpacked path. Used in the tile plugin to find outgoing
|
* route.
|
||||||
* edges from a given turn.
|
* @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 NodeID from, const NodeID to, std::vector<NodeID> &unpacked_path) const
|
||||||
void
|
|
||||||
UnpackEdgeToEdges(const NodeID s, const NodeID t, std::vector<EdgeData> &unpacked_path) const
|
|
||||||
{
|
{
|
||||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
std::array<NodeID, 2> path{{from, to}};
|
||||||
recursion_stack.emplace(s, t);
|
UnpackCHEdge(
|
||||||
|
facade,
|
||||||
std::pair<NodeID, NodeID> edge;
|
path.begin(),
|
||||||
while (!recursion_stack.empty())
|
path.end(),
|
||||||
{
|
[&unpacked_path](const std::pair<NodeID, NodeID> &edge, const EdgeData & /* data */) {
|
||||||
edge = recursion_stack.top();
|
unpacked_path.emplace_back(edge.first);
|
||||||
recursion_stack.pop();
|
});
|
||||||
|
unpacked_path.emplace_back(to);
|
||||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
|
||||||
EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
|
|
||||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
|
||||||
{
|
|
||||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
|
||||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
|
||||||
facade->GetEdgeData(edge_id).forward)
|
|
||||||
{
|
|
||||||
smaller_edge_id = edge_id;
|
|
||||||
edge_weight = weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
|
||||||
{
|
|
||||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
|
||||||
{
|
|
||||||
const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
|
|
||||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
|
||||||
facade->GetEdgeData(edge_id).backward)
|
|
||||||
{
|
|
||||||
smaller_edge_id = edge_id;
|
|
||||||
edge_weight = weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(),
|
|
||||||
"edge weight invalid");
|
|
||||||
|
|
||||||
const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
|
|
||||||
if (ed.shortcut)
|
|
||||||
{ // unpack
|
|
||||||
const NodeID middle_node_id = ed.id;
|
|
||||||
// again, we need to this in reversed order
|
|
||||||
recursion_stack.emplace(middle_node_id, edge.second);
|
|
||||||
recursion_stack.emplace(edge.first, middle_node_id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
|
|
||||||
unpacked_path.emplace_back(ed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
|
void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
|
||||||
|
@ -148,19 +148,32 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
|||||||
return SPECIAL_EDGEID;
|
return SPECIAL_EDGEID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// searches for a specific edge
|
/**
|
||||||
EdgeIterator FindSmallestEdge(const NodeIterator from, const NodeIterator to) const
|
* Finds the edge with the smallest `.distance` going from `from` to `to`
|
||||||
|
* @param from the source node ID
|
||||||
|
* @param to the target node ID
|
||||||
|
* @param filter a functor that returns a `bool` that determines whether an edge should be
|
||||||
|
* tested or not.
|
||||||
|
* Takes `EdgeData` as a parameter.
|
||||||
|
* @return the ID of the smallest edge if any were found that satisfied *filter*, or
|
||||||
|
* `SPECIAL_EDGEID` if no
|
||||||
|
* matching edge is found.
|
||||||
|
*/
|
||||||
|
template <typename FilterFunction>
|
||||||
|
EdgeIterator FindSmallestEdge(const NodeIterator from,
|
||||||
|
const NodeIterator to,
|
||||||
|
const FilterFunction filter) const
|
||||||
{
|
{
|
||||||
EdgeIterator smallest_edge = SPECIAL_EDGEID;
|
EdgeIterator smallest_edge = SPECIAL_EDGEID;
|
||||||
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
|
||||||
for (auto edge : GetAdjacentEdgeRange(from))
|
for (auto edge : GetAdjacentEdgeRange(from))
|
||||||
{
|
{
|
||||||
const NodeID target = GetTarget(edge);
|
const NodeID target = GetTarget(edge);
|
||||||
const EdgeWeight weight = GetEdgeData(edge).distance;
|
const auto data = GetEdgeData(edge);
|
||||||
if (target == to && weight < smallest_weight)
|
if (target == to && data.distance < smallest_weight && filter(data))
|
||||||
{
|
{
|
||||||
smallest_edge = edge;
|
smallest_edge = edge;
|
||||||
smallest_weight = weight;
|
smallest_weight = data.distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return smallest_edge;
|
return smallest_edge;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "engine/plugins/tile.hpp"
|
#include "engine/plugins/tile.hpp"
|
||||||
#include "engine/plugins/plugin_base.hpp"
|
#include "engine/plugins/plugin_base.hpp"
|
||||||
|
#include "engine/edge_unpacker.hpp"
|
||||||
|
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
#include "util/vector_tile.hpp"
|
#include "util/vector_tile.hpp"
|
||||||
@ -13,11 +14,11 @@
|
|||||||
#include <protozero/pbf_writer.hpp>
|
#include <protozero/pbf_writer.hpp>
|
||||||
#include <protozero/varint.hpp>
|
#include <protozero/varint.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
|
||||||
#include <numeric>
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -211,6 +212,27 @@ FixedPoint coordinatesToTilePoint(const util::Coordinate point, const detail::BB
|
|||||||
|
|
||||||
return FixedPoint{px, py};
|
return FixedPoint{px, py};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpacks a single CH edge (NodeID->NodeID) down to the original edges, and returns a list of the edge data
|
||||||
|
* @param from the node the CH edge starts at
|
||||||
|
* @param to the node the CH edge finishes at
|
||||||
|
* @param unpacked_path the sequence of EdgeData objects along the unpacked path
|
||||||
|
*/
|
||||||
|
void UnpackEdgeToEdges(const datafacade::BaseDataFacade &facade,
|
||||||
|
const NodeID from,
|
||||||
|
const NodeID to,
|
||||||
|
std::vector<datafacade::BaseDataFacade::EdgeData> &unpacked_path)
|
||||||
|
{
|
||||||
|
std::array<NodeID, 2> path{{from, to}};
|
||||||
|
UnpackCHEdge(
|
||||||
|
&facade,
|
||||||
|
path.begin(),
|
||||||
|
path.end(),
|
||||||
|
[&unpacked_path](const std::pair<NodeID, NodeID> & /* edge */, const datafacade::BaseDataFacade::EdgeData &data) {
|
||||||
|
unpacked_path.emplace_back(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::string &pbf_buffer)
|
Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::string &pbf_buffer)
|
||||||
@ -236,13 +258,11 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
|
|||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
std::unordered_map<std::string, std::size_t> name_offsets;
|
std::unordered_map<std::string, std::size_t> name_offsets;
|
||||||
|
|
||||||
|
|
||||||
std::vector<int> used_point_ints;
|
std::vector<int> used_point_ints;
|
||||||
std::unordered_map<int, std::size_t> point_int_offsets;
|
std::unordered_map<int, std::size_t> point_int_offsets;
|
||||||
std::vector<std::vector<detail::TurnData>> all_turn_data;
|
std::vector<std::vector<detail::TurnData>> all_turn_data;
|
||||||
|
|
||||||
const auto use_line_value = [&used_line_ints, &line_int_offsets](const int &value)
|
const auto use_line_value = [&used_line_ints, &line_int_offsets](const int &value) {
|
||||||
{
|
|
||||||
const auto found = line_int_offsets.find(value);
|
const auto found = line_int_offsets.find(value);
|
||||||
|
|
||||||
if (found == line_int_offsets.end())
|
if (found == line_int_offsets.end())
|
||||||
@ -254,8 +274,7 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto use_point_value = [&used_point_ints, &point_int_offsets](const int &value)
|
const auto use_point_value = [&used_point_ints, &point_int_offsets](const int &value) {
|
||||||
{
|
|
||||||
const auto found = point_int_offsets.find(value);
|
const auto found = point_int_offsets.find(value);
|
||||||
std::size_t offset;
|
std::size_t offset;
|
||||||
|
|
||||||
@ -336,9 +355,10 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
routing_base.UnpackEdgeToEdges(edge.forward_segment_id.id,
|
detail::UnpackEdgeToEdges(facade,
|
||||||
facade.GetTarget(adj_shortcut),
|
edge.forward_segment_id.id,
|
||||||
unpacked_shortcut);
|
facade.GetTarget(adj_shortcut),
|
||||||
|
unpacked_shortcut);
|
||||||
|
|
||||||
// Sometimes a "shortcut" is just an edge itself: this will not return a turn
|
// Sometimes a "shortcut" is just an edge itself: this will not return a turn
|
||||||
if (unpacked_shortcut.size() < 2)
|
if (unpacked_shortcut.size() < 2)
|
||||||
@ -376,8 +396,14 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
|
|||||||
util::coordinate_calculation::bearing(coord_b, coord_c));
|
util::coordinate_calculation::bearing(coord_b, coord_c));
|
||||||
|
|
||||||
auto turn_angle = c_bearing - angle_in;
|
auto turn_angle = c_bearing - angle_in;
|
||||||
while (turn_angle > 180) { turn_angle -= 360; }
|
while (turn_angle > 180)
|
||||||
while (turn_angle < -180) { turn_angle += 360; }
|
{
|
||||||
|
turn_angle -= 360;
|
||||||
|
}
|
||||||
|
while (turn_angle < -180)
|
||||||
|
{
|
||||||
|
turn_angle += 360;
|
||||||
|
}
|
||||||
|
|
||||||
const auto turn_angle_offset = use_point_value(turn_angle);
|
const auto turn_angle_offset = use_point_value(turn_angle);
|
||||||
const auto angle_weight_offset = use_point_value(possible_next_node.second);
|
const auto angle_weight_offset = use_point_value(possible_next_node.second);
|
||||||
@ -414,7 +440,6 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
|
|||||||
max_datasource_id = std::max(max_datasource_id, forward_datasource);
|
max_datasource_id = std::max(max_datasource_id, forward_datasource);
|
||||||
max_datasource_id = std::max(max_datasource_id, reverse_datasource);
|
max_datasource_id = std::max(max_datasource_id, reverse_datasource);
|
||||||
|
|
||||||
|
|
||||||
std::string name = facade.GetNameForID(edge.name_id);
|
std::string name = facade.GetNameForID(edge.name_id);
|
||||||
if (name_offsets.find(name) == name_offsets.end())
|
if (name_offsets.find(name) == name_offsets.end())
|
||||||
{
|
{
|
||||||
@ -507,65 +532,64 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
|
|||||||
max_datasource_id = std::max(max_datasource_id, forward_datasource);
|
max_datasource_id = std::max(max_datasource_id, forward_datasource);
|
||||||
max_datasource_id = std::max(max_datasource_id, reverse_datasource);
|
max_datasource_id = std::max(max_datasource_id, reverse_datasource);
|
||||||
|
|
||||||
const auto encode_tile_line = [&line_layer_writer,
|
const auto encode_tile_line =
|
||||||
&edge,
|
[&line_layer_writer, &edge, &id, &max_datasource_id, &used_line_ints](
|
||||||
&id,
|
const detail::FixedLine &tile_line,
|
||||||
&max_datasource_id,
|
const std::uint32_t speed_kmh,
|
||||||
&used_line_ints](const detail::FixedLine &tile_line,
|
const std::size_t duration,
|
||||||
const std::uint32_t speed_kmh,
|
const DatasourceID datasource,
|
||||||
const std::size_t duration,
|
const std::size_t name,
|
||||||
const DatasourceID datasource,
|
std::int32_t &start_x,
|
||||||
const std::size_t name,
|
std::int32_t &start_y) {
|
||||||
std::int32_t &start_x,
|
// Here, we save the two attributes for our feature: the speed and the
|
||||||
std::int32_t &start_y)
|
// is_small
|
||||||
{
|
// boolean. We only serve up speeds from 0-139, so all we do is save
|
||||||
// Here, we save the two attributes for our feature: the speed and the
|
// the
|
||||||
// is_small
|
// first
|
||||||
// boolean. We only serve up speeds from 0-139, so all we do is save the
|
protozero::pbf_writer feature_writer(line_layer_writer,
|
||||||
// first
|
util::vector_tile::FEATURE_TAG);
|
||||||
protozero::pbf_writer feature_writer(line_layer_writer,
|
// Field 3 is the "geometry type" field. Value 2 is "line"
|
||||||
util::vector_tile::FEATURE_TAG);
|
feature_writer.add_enum(
|
||||||
// Field 3 is the "geometry type" field. Value 2 is "line"
|
util::vector_tile::GEOMETRY_TAG,
|
||||||
feature_writer.add_enum(
|
util::vector_tile::GEOMETRY_TYPE_LINE); // geometry type
|
||||||
util::vector_tile::GEOMETRY_TAG,
|
// Field 1 for the feature is the "id" field.
|
||||||
util::vector_tile::GEOMETRY_TYPE_LINE); // geometry type
|
feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id
|
||||||
// Field 1 for the feature is the "id" field.
|
{
|
||||||
feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id
|
// When adding attributes to a feature, we have to write
|
||||||
{
|
// pairs of numbers. The first value is the index in the
|
||||||
// When adding attributes to a feature, we have to write
|
// keys array (written later), and the second value is the
|
||||||
// pairs of numbers. The first value is the index in the
|
// index into the "values" array (also written later). We're
|
||||||
// keys array (written later), and the second value is the
|
// not writing the actual speed or bool value here, we're saving
|
||||||
// index into the "values" array (also written later). We're
|
// an index into the "values" array. This means many features
|
||||||
// not writing the actual speed or bool value here, we're saving
|
// can share the same value data, leading to smaller tiles.
|
||||||
// an index into the "values" array. This means many features
|
protozero::packed_field_uint32 field(
|
||||||
// can share the same value data, leading to smaller tiles.
|
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
||||||
protozero::packed_field_uint32 field(
|
|
||||||
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
|
||||||
|
|
||||||
field.add_element(0); // "speed" tag key offset
|
field.add_element(0); // "speed" tag key offset
|
||||||
field.add_element(
|
field.add_element(std::min(
|
||||||
std::min(speed_kmh, 127u)); // save the speed value, capped at 127
|
speed_kmh, 127u)); // save the speed value, capped at 127
|
||||||
field.add_element(1); // "is_small" tag key offset
|
field.add_element(1); // "is_small" tag key offset
|
||||||
field.add_element(128 +
|
field.add_element(
|
||||||
(edge.component.is_tiny ? 0 : 1)); // is_small feature
|
128 + (edge.component.is_tiny ? 0 : 1)); // is_small feature
|
||||||
field.add_element(2); // "datasource" tag key offset
|
field.add_element(2); // "datasource" tag key offset
|
||||||
field.add_element(130 + datasource); // datasource value offset
|
field.add_element(130 + datasource); // datasource value offset
|
||||||
field.add_element(3); // "duration" tag key offset
|
field.add_element(3); // "duration" tag key offset
|
||||||
field.add_element(130 + max_datasource_id + 1 +
|
field.add_element(130 + max_datasource_id + 1 +
|
||||||
duration); // duration value offset
|
duration); // duration value offset
|
||||||
field.add_element(4); // "name" tag key offset
|
field.add_element(4); // "name" tag key offset
|
||||||
|
|
||||||
field.add_element(130 + max_datasource_id + 1 + used_line_ints.size() +
|
field.add_element(130 + max_datasource_id + 1 +
|
||||||
name); // name value offset
|
used_line_ints.size() +
|
||||||
}
|
name); // name value offset
|
||||||
{
|
}
|
||||||
|
{
|
||||||
|
|
||||||
// Encode the geometry for the feature
|
// Encode the geometry for the feature
|
||||||
protozero::packed_field_uint32 geometry(
|
protozero::packed_field_uint32 geometry(
|
||||||
feature_writer, util::vector_tile::FEATURE_GEOMETRIES_TAG);
|
feature_writer, util::vector_tile::FEATURE_GEOMETRIES_TAG);
|
||||||
encodeLinestring(tile_line, geometry, start_x, start_y);
|
encodeLinestring(tile_line, geometry, start_x, start_y);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// If this is a valid forward edge, go ahead and add it to the tile
|
// If this is a valid forward edge, go ahead and add it to the tile
|
||||||
if (forward_weight != 0 && edge.forward_segment_id.enabled)
|
if (forward_weight != 0 && edge.forward_segment_id.enabled)
|
||||||
@ -668,9 +692,11 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
|
|||||||
values_writer.add_double(util::vector_tile::VARIANT_TYPE_DOUBLE, value / 10.);
|
values_writer.add_double(util::vector_tile::VARIANT_TYPE_DOUBLE, value / 10.);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &name : names) {
|
for (const auto &name : names)
|
||||||
|
{
|
||||||
// Writing field type 4 == variant type
|
// Writing field type 4 == variant type
|
||||||
protozero::pbf_writer values_writer(line_layer_writer, util::vector_tile::VARIANT_TAG);
|
protozero::pbf_writer values_writer(line_layer_writer,
|
||||||
|
util::vector_tile::VARIANT_TAG);
|
||||||
// Attribute value 1 == string type
|
// Attribute value 1 == string type
|
||||||
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING, name);
|
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING, name);
|
||||||
}
|
}
|
||||||
@ -716,34 +742,33 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str
|
|||||||
|
|
||||||
const auto encode_tile_point =
|
const auto encode_tile_point =
|
||||||
[&point_layer_writer, &edge, &id](const detail::FixedPoint &tile_point,
|
[&point_layer_writer, &edge, &id](const detail::FixedPoint &tile_point,
|
||||||
const detail::TurnData &point_turn_data)
|
const detail::TurnData &point_turn_data) {
|
||||||
{
|
protozero::pbf_writer feature_writer(point_layer_writer,
|
||||||
protozero::pbf_writer feature_writer(point_layer_writer,
|
util::vector_tile::FEATURE_TAG);
|
||||||
util::vector_tile::FEATURE_TAG);
|
// Field 3 is the "geometry type" field. Value 1 is "point"
|
||||||
// Field 3 is the "geometry type" field. Value 1 is "point"
|
feature_writer.add_enum(
|
||||||
feature_writer.add_enum(
|
util::vector_tile::GEOMETRY_TAG,
|
||||||
util::vector_tile::GEOMETRY_TAG,
|
util::vector_tile::GEOMETRY_TYPE_POINT); // geometry type
|
||||||
util::vector_tile::GEOMETRY_TYPE_POINT); // geometry type
|
// Field 1 for the feature is the "id" field.
|
||||||
// Field 1 for the feature is the "id" field.
|
feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id
|
||||||
feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id
|
{
|
||||||
{
|
// See above for explanation
|
||||||
// See above for explanation
|
protozero::packed_field_uint32 field(
|
||||||
protozero::packed_field_uint32 field(
|
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
||||||
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
|
||||||
|
|
||||||
field.add_element(0); // "bearing_in" tag key offset
|
field.add_element(0); // "bearing_in" tag key offset
|
||||||
field.add_element(point_turn_data.in_angle_offset);
|
field.add_element(point_turn_data.in_angle_offset);
|
||||||
field.add_element(1); // "turn_angle" tag key offset
|
field.add_element(1); // "turn_angle" tag key offset
|
||||||
field.add_element(point_turn_data.turn_angle_offset);
|
field.add_element(point_turn_data.turn_angle_offset);
|
||||||
field.add_element(2); // "weight" tag key offset
|
field.add_element(2); // "weight" tag key offset
|
||||||
field.add_element(point_turn_data.weight_offset);
|
field.add_element(point_turn_data.weight_offset);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
protozero::packed_field_uint32 geometry(
|
protozero::packed_field_uint32 geometry(
|
||||||
feature_writer, util::vector_tile::FEATURE_GEOMETRIES_TAG);
|
feature_writer, util::vector_tile::FEATURE_GEOMETRIES_TAG);
|
||||||
encodePoint(tile_point, geometry);
|
encodePoint(tile_point, geometry);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto turn_coordinate = facade.GetCoordinateOfNode(edge.v);
|
const auto turn_coordinate = facade.GetCoordinateOfNode(edge.v);
|
||||||
const auto tile_point = coordinatesToTilePoint(turn_coordinate, tile_bbox);
|
const auto tile_point = coordinatesToTilePoint(turn_coordinate, tile_bbox);
|
||||||
|
Loading…
Reference in New Issue
Block a user