Port OSRM, Engine and Datafacades to be algorithm aware
This commit is contained in:
committed by
Patrick Niklaus
parent
71e95c92b6
commit
2fa8d0f534
@@ -108,7 +108,8 @@ void filterCandidates(const std::vector<util::Coordinate> &coordinates,
|
||||
}
|
||||
}
|
||||
|
||||
Status MatchPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
||||
Status MatchPlugin::HandleRequest(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
const RoutingAlgorithmsInterface &algorithms,
|
||||
const api::MatchParameters ¶meters,
|
||||
util::json::Object &json_result) const
|
||||
{
|
||||
@@ -144,7 +145,7 @@ Status MatchPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDa
|
||||
if (parameters.radiuses.empty())
|
||||
{
|
||||
search_radiuses.resize(parameters.coordinates.size(),
|
||||
DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER);
|
||||
routing_algorithms::DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -159,13 +160,13 @@ Status MatchPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDa
|
||||
}
|
||||
else
|
||||
{
|
||||
return DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER;
|
||||
return routing_algorithms::DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
auto candidates_lists = GetPhantomNodesInRange(*facade, parameters, search_radiuses);
|
||||
auto candidates_lists = GetPhantomNodesInRange(facade, parameters, search_radiuses);
|
||||
|
||||
filterCandidates(parameters.coordinates, candidates_lists);
|
||||
if (std::all_of(candidates_lists.begin(),
|
||||
@@ -180,11 +181,8 @@ Status MatchPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDa
|
||||
}
|
||||
|
||||
// call the actual map matching
|
||||
SubMatchingList sub_matchings = map_matching(facade,
|
||||
candidates_lists,
|
||||
parameters.coordinates,
|
||||
parameters.timestamps,
|
||||
parameters.radiuses);
|
||||
SubMatchingList sub_matchings = algorithms.MapMatching(
|
||||
candidates_lists, parameters.coordinates, parameters.timestamps, parameters.radiuses);
|
||||
|
||||
if (sub_matchings.size() == 0)
|
||||
{
|
||||
@@ -210,12 +208,12 @@ Status MatchPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDa
|
||||
// force uturns to be on, since we split the phantom nodes anyway and only have
|
||||
// bi-directional
|
||||
// phantom nodes for possible uturns
|
||||
shortest_path(
|
||||
facade, sub_routes[index].segment_end_coordinates, {false}, sub_routes[index]);
|
||||
algorithms.ShortestRouting(
|
||||
sub_routes[index].segment_end_coordinates, {false}, sub_routes[index]);
|
||||
BOOST_ASSERT(sub_routes[index].shortest_path_length != INVALID_EDGE_WEIGHT);
|
||||
}
|
||||
|
||||
api::MatchAPI match_api{*facade, parameters};
|
||||
api::MatchAPI match_api{facade, parameters};
|
||||
match_api.MakeResponse(sub_matchings, sub_routes, json_result);
|
||||
|
||||
return Status::Ok;
|
||||
|
||||
@@ -19,9 +19,11 @@ namespace plugins
|
||||
|
||||
NearestPlugin::NearestPlugin(const int max_results_) : max_results{max_results_} {}
|
||||
|
||||
Status NearestPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
||||
const api::NearestParameters ¶ms,
|
||||
util::json::Object &json_result) const
|
||||
Status
|
||||
NearestPlugin::HandleRequest(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
const RoutingAlgorithmsInterface & /*algorithms*/,
|
||||
const api::NearestParameters ¶ms,
|
||||
util::json::Object &json_result) const
|
||||
{
|
||||
BOOST_ASSERT(params.IsValid());
|
||||
|
||||
@@ -42,7 +44,7 @@ Status NearestPlugin::HandleRequest(const std::shared_ptr<const datafacade::Base
|
||||
return Error("InvalidOptions", "Only one input coordinate is supported", json_result);
|
||||
}
|
||||
|
||||
auto phantom_nodes = GetPhantomNodes(*facade, params, params.number_of_results);
|
||||
auto phantom_nodes = GetPhantomNodes(facade, params, params.number_of_results);
|
||||
|
||||
if (phantom_nodes.front().size() == 0)
|
||||
{
|
||||
@@ -50,7 +52,7 @@ Status NearestPlugin::HandleRequest(const std::shared_ptr<const datafacade::Base
|
||||
}
|
||||
BOOST_ASSERT(phantom_nodes.front().size() > 0);
|
||||
|
||||
api::NearestAPI nearest_api(*facade, params);
|
||||
api::NearestAPI nearest_api(facade, params);
|
||||
nearest_api.MakeResponse(phantom_nodes, json_result);
|
||||
|
||||
return Status::Ok;
|
||||
|
||||
@@ -24,11 +24,12 @@ namespace plugins
|
||||
{
|
||||
|
||||
TablePlugin::TablePlugin(const int max_locations_distance_table)
|
||||
: distance_table(heaps), max_locations_distance_table(max_locations_distance_table)
|
||||
: max_locations_distance_table(max_locations_distance_table)
|
||||
{
|
||||
}
|
||||
|
||||
Status TablePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
||||
Status TablePlugin::HandleRequest(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
const RoutingAlgorithmsInterface &algorithms,
|
||||
const api::TableParameters ¶ms,
|
||||
util::json::Object &result) const
|
||||
{
|
||||
@@ -59,16 +60,16 @@ Status TablePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDa
|
||||
return Error("TooBig", "Too many table coordinates", result);
|
||||
}
|
||||
|
||||
auto snapped_phantoms = SnapPhantomNodes(GetPhantomNodes(*facade, params));
|
||||
auto snapped_phantoms = SnapPhantomNodes(GetPhantomNodes(facade, params));
|
||||
auto result_table =
|
||||
distance_table(facade, snapped_phantoms, params.sources, params.destinations);
|
||||
algorithms.ManyToManyRouting(snapped_phantoms, params.sources, params.destinations);
|
||||
|
||||
if (result_table.empty())
|
||||
{
|
||||
return Error("NoTable", "No table found", result);
|
||||
}
|
||||
|
||||
api::TableAPI table_api{*facade, params};
|
||||
api::TableAPI table_api{facade, params};
|
||||
table_api.MakeResponse(result_table, snapped_phantoms, result);
|
||||
|
||||
return Status::Ok;
|
||||
|
||||
+97
-316
@@ -32,8 +32,13 @@ namespace engine
|
||||
{
|
||||
namespace plugins
|
||||
{
|
||||
|
||||
constexpr const static int MIN_ZOOM_FOR_TURNS = 15;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using RTreeLeaf = datafacade::BaseDataFacade::RTreeLeaf;
|
||||
// TODO: Port all this encoding logic to https://github.com/mapbox/vector-tile, which wasn't
|
||||
// available when this code was originally written.
|
||||
|
||||
@@ -72,33 +77,12 @@ struct point_type_i final
|
||||
const std::int64_t y;
|
||||
};
|
||||
|
||||
// Used to accumulate all the information we want in the tile about
|
||||
// a turn.
|
||||
struct TurnData final
|
||||
{
|
||||
TurnData(const util::Coordinate coordinate_,
|
||||
const std::size_t _in,
|
||||
const std::size_t _out,
|
||||
const std::size_t _weight)
|
||||
: coordinate(std::move(coordinate_)), in_angle_offset(_in), turn_angle_offset(_out),
|
||||
weight_offset(_weight)
|
||||
{
|
||||
}
|
||||
|
||||
const util::Coordinate coordinate;
|
||||
const std::size_t in_angle_offset;
|
||||
const std::size_t turn_angle_offset;
|
||||
const std::size_t weight_offset;
|
||||
};
|
||||
|
||||
using FixedPoint = Point<std::int32_t>;
|
||||
using FloatPoint = Point<double>;
|
||||
|
||||
using FixedLine = std::vector<FixedPoint>;
|
||||
using FloatLine = std::vector<FloatPoint>;
|
||||
|
||||
constexpr const static int MIN_ZOOM_FOR_TURNS = 15;
|
||||
|
||||
// We use boost::geometry to clip lines/points that are outside or cross the boundary
|
||||
// of the tile we're rendering. We need these types defined to use boosts clipping
|
||||
// logic
|
||||
@@ -247,33 +231,58 @@ FixedPoint coordinatesToTilePoint(const util::Coordinate point, const BBox &tile
|
||||
return FixedPoint{px, py};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
||||
const api::TileParameters ¶meters,
|
||||
std::string &pbf_buffer) const
|
||||
std::vector<RTreeLeaf> getEdges(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
unsigned x,
|
||||
unsigned y,
|
||||
unsigned z)
|
||||
{
|
||||
BOOST_ASSERT(parameters.IsValid());
|
||||
|
||||
double min_lon, min_lat, max_lon, max_lat;
|
||||
|
||||
// Convert the z,x,y mercator tile coordinates into WGS84 lon/lat values
|
||||
//
|
||||
util::web_mercator::xyzToWGS84(parameters.x,
|
||||
parameters.y,
|
||||
parameters.z,
|
||||
min_lon,
|
||||
min_lat,
|
||||
max_lon,
|
||||
max_lat,
|
||||
util::web_mercator::TILE_SIZE * 0.10);
|
||||
util::web_mercator::xyzToWGS84(
|
||||
x, y, z, min_lon, min_lat, max_lon, max_lat, util::web_mercator::TILE_SIZE * 0.10);
|
||||
|
||||
util::Coordinate southwest{util::FloatLongitude{min_lon}, util::FloatLatitude{min_lat}};
|
||||
util::Coordinate northeast{util::FloatLongitude{max_lon}, util::FloatLatitude{max_lat}};
|
||||
|
||||
// Fetch all the segments that are in our bounding box.
|
||||
// This hits the OSRM StaticRTree
|
||||
const auto edges = facade->GetEdgesInBox(southwest, northeast);
|
||||
return facade.GetEdgesInBox(southwest, northeast);
|
||||
}
|
||||
|
||||
std::vector<std::size_t> getEdgeIndex(const std::vector<RTreeLeaf> &edges)
|
||||
{
|
||||
// In order to ensure consistent tile encoding, we need to process
|
||||
// all edges in the same order. Differences in OSX/Linux/Windows
|
||||
// sorting methods mean that GetEdgesInBox doesn't return the same
|
||||
// ordered array on all platforms.
|
||||
// GetEdgesInBox is marked `const`, so we can't sort the array itself,
|
||||
// instead we create an array of indexes and sort that instead.
|
||||
std::vector<std::size_t> sorted_edge_indexes(edges.size(), 0);
|
||||
std::iota(sorted_edge_indexes.begin(), sorted_edge_indexes.end(), 0); // fill with 1,2,3,...N
|
||||
|
||||
// Now, sort that array based on the edges list, using the u/v node IDs
|
||||
// as the sort condition
|
||||
std::sort(sorted_edge_indexes.begin(),
|
||||
sorted_edge_indexes.end(),
|
||||
[&edges](const std::size_t &left, const std::size_t &right) -> bool {
|
||||
return (edges[left].u != edges[right].u) ? edges[left].u < edges[right].u
|
||||
: edges[left].v < edges[right].v;
|
||||
});
|
||||
|
||||
return sorted_edge_indexes;
|
||||
}
|
||||
|
||||
void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
unsigned x,
|
||||
unsigned y,
|
||||
unsigned z,
|
||||
const std::vector<RTreeLeaf> &edges,
|
||||
const std::vector<std::size_t> &sorted_edge_indexes,
|
||||
const std::vector<routing_algorithms::TurnData> &all_turn_data,
|
||||
std::string &pbf_buffer)
|
||||
{
|
||||
|
||||
// Vector tiles encode properties as references to a common lookup table.
|
||||
// When we add a property to a "feature", we actually attach the index of the value
|
||||
@@ -302,7 +311,6 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
std::uint8_t max_datasource_id = 0;
|
||||
|
||||
// This is where we accumulate information on turns
|
||||
std::vector<TurnData> all_turn_data;
|
||||
|
||||
// Helper function for adding a new value to the line_ints lookup table. Returns
|
||||
// the index of the value in the table, adding the value if it doesn't already
|
||||
@@ -358,260 +366,6 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
return offset;
|
||||
};
|
||||
|
||||
// In order to ensure consistent tile encoding, we need to process
|
||||
// all edges in the same order. Differences in OSX/Linux/Windows
|
||||
// sorting methods mean that GetEdgesInBox doesn't return the same
|
||||
// ordered array on all platforms.
|
||||
// GetEdgesInBox is marked `const`, so we can't sort the array itself,
|
||||
// instead we create an array of indexes and sort that instead.
|
||||
std::vector<std::size_t> sorted_edge_indexes(edges.size(), 0);
|
||||
std::iota(sorted_edge_indexes.begin(), sorted_edge_indexes.end(), 0); // fill with 1,2,3,...N
|
||||
|
||||
// Now, sort that array based on the edges list, using the u/v node IDs
|
||||
// as the sort condition
|
||||
std::sort(sorted_edge_indexes.begin(),
|
||||
sorted_edge_indexes.end(),
|
||||
[&edges](const std::size_t &left, const std::size_t &right) -> bool {
|
||||
return (edges[left].u != edges[right].u) ? edges[left].u < edges[right].u
|
||||
: edges[left].v < edges[right].v;
|
||||
});
|
||||
// From here on, we'll iterate over the sorted_edge_indexes instead of `edges` directly.
|
||||
// Note, that we do this because `
|
||||
|
||||
// If we're zooming into 16 or higher, include turn data. Why? Because turns make the map
|
||||
// really cramped, so we don't bother including the data for tiles that span a large area.
|
||||
if (parameters.z >= MIN_ZOOM_FOR_TURNS)
|
||||
{
|
||||
// Struct to hold info on all the EdgeBasedNodes that are visible in our tile
|
||||
// When we create these, we insure that (source, target) and packed_geometry_id
|
||||
// are all pointed in the same direction.
|
||||
struct EdgeBasedNodeInfo
|
||||
{
|
||||
bool is_geometry_forward; // Is the geometry forward or reverse?
|
||||
unsigned packed_geometry_id;
|
||||
};
|
||||
// Lookup table for edge-based-nodes
|
||||
std::unordered_map<NodeID, EdgeBasedNodeInfo> edge_based_node_info;
|
||||
|
||||
struct SegmentData
|
||||
{
|
||||
NodeID target_node;
|
||||
EdgeID edge_based_node_id;
|
||||
};
|
||||
|
||||
std::unordered_map<NodeID, std::vector<SegmentData>> directed_graph;
|
||||
// Reserve enough space for unique edge-based-nodes on every edge.
|
||||
// Only a tile with all unique edges will use this much, but
|
||||
// it saves us a bunch of re-allocations during iteration.
|
||||
directed_graph.reserve(edges.size() * 2);
|
||||
|
||||
// Build an adjacency list for all the road segments visible in
|
||||
// the tile
|
||||
for (const auto &edge_index : sorted_edge_indexes)
|
||||
{
|
||||
const auto &edge = edges[edge_index];
|
||||
if (edge.forward_segment_id.enabled)
|
||||
{
|
||||
// operator[] will construct an empty vector at [edge.u] if there is no value.
|
||||
directed_graph[edge.u].push_back({edge.v, edge.forward_segment_id.id});
|
||||
if (edge_based_node_info.count(edge.forward_segment_id.id) == 0)
|
||||
{
|
||||
edge_based_node_info[edge.forward_segment_id.id] = {true,
|
||||
edge.packed_geometry_id};
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
edge_based_node_info[edge.forward_segment_id.id].is_geometry_forward ==
|
||||
true);
|
||||
BOOST_ASSERT(
|
||||
edge_based_node_info[edge.forward_segment_id.id].packed_geometry_id ==
|
||||
edge.packed_geometry_id);
|
||||
}
|
||||
}
|
||||
if (edge.reverse_segment_id.enabled)
|
||||
{
|
||||
directed_graph[edge.v].push_back({edge.u, edge.reverse_segment_id.id});
|
||||
if (edge_based_node_info.count(edge.reverse_segment_id.id) == 0)
|
||||
{
|
||||
edge_based_node_info[edge.reverse_segment_id.id] = {false,
|
||||
edge.packed_geometry_id};
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
edge_based_node_info[edge.reverse_segment_id.id].is_geometry_forward ==
|
||||
false);
|
||||
BOOST_ASSERT(
|
||||
edge_based_node_info[edge.reverse_segment_id.id].packed_geometry_id ==
|
||||
edge.packed_geometry_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Given a turn:
|
||||
// u---v
|
||||
// |
|
||||
// w
|
||||
// uv is the "approach"
|
||||
// vw is the "exit"
|
||||
std::vector<contractor::QueryEdge::EdgeData> unpacked_shortcut;
|
||||
std::vector<EdgeWeight> approach_weight_vector;
|
||||
|
||||
// Make sure we traverse the startnodes in a consistent order
|
||||
// to ensure identical PBF encoding on all platforms.
|
||||
std::vector<NodeID> sorted_startnodes;
|
||||
sorted_startnodes.reserve(directed_graph.size());
|
||||
for (const auto &startnode : directed_graph)
|
||||
sorted_startnodes.push_back(startnode.first);
|
||||
std::sort(sorted_startnodes.begin(), sorted_startnodes.end());
|
||||
|
||||
// Look at every node in the directed graph we created
|
||||
for (const auto &startnode : sorted_startnodes)
|
||||
{
|
||||
const auto &nodedata = directed_graph[startnode];
|
||||
// For all the outgoing edges from the node
|
||||
for (const auto &approachedge : nodedata)
|
||||
{
|
||||
// If the target of this edge doesn't exist in our directed
|
||||
// graph, it's probably outside the tile, so we can skip it
|
||||
if (directed_graph.count(approachedge.target_node) == 0)
|
||||
continue;
|
||||
|
||||
// For each of the outgoing edges from our target coordinate
|
||||
for (const auto &exit_edge : directed_graph[approachedge.target_node])
|
||||
{
|
||||
// If the next edge has the same edge_based_node_id, then it's
|
||||
// not a turn, so skip it
|
||||
if (approachedge.edge_based_node_id == exit_edge.edge_based_node_id)
|
||||
continue;
|
||||
|
||||
// Skip u-turns
|
||||
if (startnode == exit_edge.target_node)
|
||||
continue;
|
||||
|
||||
// Find the connection between our source road and the target node
|
||||
// Since we only want to find direct edges, we cannot check shortcut edges here.
|
||||
// Otherwise we might find a forward edge even though a shorter backward edge
|
||||
// exists (due to oneways).
|
||||
//
|
||||
// a > - > - > - b
|
||||
// | |
|
||||
// |------ c ----|
|
||||
//
|
||||
// would offer a backward edge at `b` to `a` (due to the oneway from a to b)
|
||||
// but could also offer a shortcut (b-c-a) from `b` to `a` which is longer.
|
||||
EdgeID smaller_edge_id =
|
||||
facade->FindSmallestEdge(approachedge.edge_based_node_id,
|
||||
exit_edge.edge_based_node_id,
|
||||
[](const contractor::QueryEdge::EdgeData &data) {
|
||||
return data.forward && !data.shortcut;
|
||||
});
|
||||
|
||||
// Depending on how the graph is constructed, we might have to look for
|
||||
// a backwards edge instead. They're equivalent, just one is available for
|
||||
// a forward routing search, and one is used for the backwards dijkstra
|
||||
// steps. Their weight should be the same, we can use either one.
|
||||
// If we didn't find a forward edge, try for a backward one
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
smaller_edge_id = facade->FindSmallestEdge(
|
||||
exit_edge.edge_based_node_id,
|
||||
approachedge.edge_based_node_id,
|
||||
[](const contractor::QueryEdge::EdgeData &data) {
|
||||
return data.backward && !data.shortcut;
|
||||
});
|
||||
}
|
||||
|
||||
// If no edge was found, it means that there's no connection between these
|
||||
// nodes, due to oneways or turn restrictions. Given the edge-based-nodes
|
||||
// that we're examining here, we *should* only find directly-connected
|
||||
// edges, not shortcuts
|
||||
if (smaller_edge_id != SPECIAL_EDGEID)
|
||||
{
|
||||
const auto &data = facade->GetEdgeData(smaller_edge_id);
|
||||
BOOST_ASSERT_MSG(!data.shortcut, "Connecting edge must not be a shortcut");
|
||||
|
||||
// Now, calculate the sum of the weight of all the segments.
|
||||
if (edge_based_node_info[approachedge.edge_based_node_id]
|
||||
.is_geometry_forward)
|
||||
{
|
||||
approach_weight_vector = facade->GetUncompressedForwardWeights(
|
||||
edge_based_node_info[approachedge.edge_based_node_id]
|
||||
.packed_geometry_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
approach_weight_vector = facade->GetUncompressedReverseWeights(
|
||||
edge_based_node_info[approachedge.edge_based_node_id]
|
||||
.packed_geometry_id);
|
||||
}
|
||||
const auto sum_node_weight = std::accumulate(approach_weight_vector.begin(),
|
||||
approach_weight_vector.end(),
|
||||
EdgeWeight{0});
|
||||
|
||||
// The edge.weight is the whole edge weight, which includes the turn
|
||||
// cost.
|
||||
// The turn cost is the edge.weight minus the sum of the individual road
|
||||
// segment weights. This might not be 100% accurate, because some
|
||||
// intersections include stop signs, traffic signals and other
|
||||
// penalties, but at this stage, we can't divide those out, so we just
|
||||
// treat the whole lot as the "turn cost" that we'll stick on the map.
|
||||
const auto turn_cost = data.weight - sum_node_weight;
|
||||
|
||||
// Find the three nodes that make up the turn movement)
|
||||
const auto node_from = startnode;
|
||||
const auto node_via = approachedge.target_node;
|
||||
const auto node_to = exit_edge.target_node;
|
||||
|
||||
const auto coord_from = facade->GetCoordinateOfNode(node_from);
|
||||
const auto coord_via = facade->GetCoordinateOfNode(node_via);
|
||||
const auto coord_to = facade->GetCoordinateOfNode(node_to);
|
||||
|
||||
// Calculate the bearing that we approach the intersection at
|
||||
const auto angle_in = static_cast<int>(
|
||||
util::coordinate_calculation::bearing(coord_from, coord_via));
|
||||
|
||||
// Add the angle to the values table for the vector tile, and get the
|
||||
// index
|
||||
// of that value in the table
|
||||
const auto angle_in_index = use_point_int_value(angle_in);
|
||||
|
||||
// Calculate the bearing leading away from the intersection
|
||||
const auto exit_bearing = static_cast<int>(
|
||||
util::coordinate_calculation::bearing(coord_via, coord_to));
|
||||
|
||||
// Figure out the angle of the turn
|
||||
auto turn_angle = exit_bearing - angle_in;
|
||||
while (turn_angle > 180)
|
||||
{
|
||||
turn_angle -= 360;
|
||||
}
|
||||
while (turn_angle < -180)
|
||||
{
|
||||
turn_angle += 360;
|
||||
}
|
||||
|
||||
// Add the turn angle value to the value lookup table for the vector
|
||||
// tile.
|
||||
const auto turn_angle_index = use_point_int_value(turn_angle);
|
||||
// And, same for the actual turn cost value - it goes in the lookup
|
||||
// table,
|
||||
// not directly on the feature itself.
|
||||
const auto turn_cost_index = use_point_float_value(
|
||||
turn_cost / 10.0); // Note conversion to float here
|
||||
|
||||
// Save everything we need to later add all the points to the tile.
|
||||
// We need the coordinate of the intersection, the angle in, the turn
|
||||
// angle and the turn cost.
|
||||
all_turn_data.emplace_back(
|
||||
coord_via, angle_in_index, turn_angle_index, turn_cost_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vector tiles encode feature properties as indexes into a lookup table. So, we need
|
||||
// to "pre-loop" over all the edges to create the lookup tables. Once we have those, we
|
||||
// can then encode the features, and we'll know the indexes that feature properties
|
||||
@@ -621,9 +375,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
const auto &edge = edges[edge_index];
|
||||
|
||||
const auto forward_datasource_vector =
|
||||
facade->GetUncompressedForwardDatasources(edge.packed_geometry_id);
|
||||
facade.GetUncompressedForwardDatasources(edge.packed_geometry_id);
|
||||
const auto reverse_datasource_vector =
|
||||
facade->GetUncompressedReverseDatasources(edge.packed_geometry_id);
|
||||
facade.GetUncompressedReverseDatasources(edge.packed_geometry_id);
|
||||
|
||||
BOOST_ASSERT(edge.fwd_segment_position < forward_datasource_vector.size());
|
||||
const auto forward_datasource = forward_datasource_vector[edge.fwd_segment_position];
|
||||
@@ -639,13 +393,8 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
|
||||
// Convert tile coordinates into mercator coordinates
|
||||
double min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat;
|
||||
util::web_mercator::xyzToMercator(parameters.x,
|
||||
parameters.y,
|
||||
parameters.z,
|
||||
min_mercator_lon,
|
||||
min_mercator_lat,
|
||||
max_mercator_lon,
|
||||
max_mercator_lat);
|
||||
util::web_mercator::xyzToMercator(
|
||||
x, y, z, min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat);
|
||||
const BBox tile_bbox{min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat};
|
||||
|
||||
// Protobuf serializes blocks when objects go out of scope, hence
|
||||
@@ -673,9 +422,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
{
|
||||
const auto &edge = edges[edge_index];
|
||||
const auto forward_weight_vector =
|
||||
facade->GetUncompressedForwardWeights(edge.packed_geometry_id);
|
||||
facade.GetUncompressedForwardWeights(edge.packed_geometry_id);
|
||||
const auto reverse_weight_vector =
|
||||
facade->GetUncompressedReverseWeights(edge.packed_geometry_id);
|
||||
facade.GetUncompressedReverseWeights(edge.packed_geometry_id);
|
||||
const auto forward_weight = forward_weight_vector[edge.fwd_segment_position];
|
||||
const auto reverse_weight = reverse_weight_vector[reverse_weight_vector.size() -
|
||||
edge.fwd_segment_position - 1];
|
||||
@@ -691,20 +440,20 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
{
|
||||
const auto &edge = edges[edge_index];
|
||||
// Get coordinates for start/end nodes of segment (NodeIDs u and v)
|
||||
const auto a = facade->GetCoordinateOfNode(edge.u);
|
||||
const auto b = facade->GetCoordinateOfNode(edge.v);
|
||||
const auto a = facade.GetCoordinateOfNode(edge.u);
|
||||
const auto b = facade.GetCoordinateOfNode(edge.v);
|
||||
// Calculate the length in meters
|
||||
const double length =
|
||||
osrm::util::coordinate_calculation::haversineDistance(a, b);
|
||||
|
||||
const auto forward_weight_vector =
|
||||
facade->GetUncompressedForwardWeights(edge.packed_geometry_id);
|
||||
facade.GetUncompressedForwardWeights(edge.packed_geometry_id);
|
||||
const auto reverse_weight_vector =
|
||||
facade->GetUncompressedReverseWeights(edge.packed_geometry_id);
|
||||
facade.GetUncompressedReverseWeights(edge.packed_geometry_id);
|
||||
const auto forward_datasource_vector =
|
||||
facade->GetUncompressedForwardDatasources(edge.packed_geometry_id);
|
||||
facade.GetUncompressedForwardDatasources(edge.packed_geometry_id);
|
||||
const auto reverse_datasource_vector =
|
||||
facade->GetUncompressedReverseDatasources(edge.packed_geometry_id);
|
||||
facade.GetUncompressedReverseDatasources(edge.packed_geometry_id);
|
||||
const auto forward_weight = forward_weight_vector[edge.fwd_segment_position];
|
||||
const auto reverse_weight =
|
||||
reverse_weight_vector[reverse_weight_vector.size() -
|
||||
@@ -715,7 +464,7 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
reverse_datasource_vector[reverse_datasource_vector.size() -
|
||||
edge.fwd_segment_position - 1];
|
||||
|
||||
auto name = facade->GetNameForID(edge.name_id);
|
||||
auto name = facade.GetNameForID(edge.name_id);
|
||||
|
||||
const auto name_offset = [&name, &names, &name_offsets]() {
|
||||
auto iter = name_offsets.find(name);
|
||||
@@ -875,7 +624,7 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
util::vector_tile::VARIANT_TAG);
|
||||
// Attribute value 1 == string type
|
||||
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING,
|
||||
facade->GetDatasourceName(i).to_string());
|
||||
facade.GetDatasourceName(i).to_string());
|
||||
}
|
||||
for (auto value : used_line_ints)
|
||||
{
|
||||
@@ -918,8 +667,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
int id = 1;
|
||||
|
||||
// Helper function to encode a new point feature on a vector tile.
|
||||
const auto encode_tile_point = [&point_layer_writer, &used_point_ints, &id](
|
||||
const FixedPoint &tile_point, const TurnData &point_turn_data) {
|
||||
const auto encode_tile_point = [&](
|
||||
const FixedPoint &tile_point,
|
||||
const routing_algorithms::TurnData &point_turn_data) {
|
||||
protozero::pbf_writer feature_writer(point_layer_writer,
|
||||
util::vector_tile::FEATURE_TAG);
|
||||
// Field 3 is the "geometry type" field. Value 1 is "point"
|
||||
@@ -928,17 +678,23 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
util::vector_tile::GEOMETRY_TYPE_POINT); // geometry type
|
||||
feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id
|
||||
{
|
||||
const auto in_angle_offset = use_point_int_value(point_turn_data.in_angle);
|
||||
const auto turn_angle_offset =
|
||||
use_point_int_value(point_turn_data.turn_angle);
|
||||
const auto weight_offset = use_point_float_value(
|
||||
point_turn_data.weight / 10.0); // Note conversion to float here
|
||||
|
||||
// Write out the 3 properties we want on the feature. These
|
||||
// refer to indexes in the properties lookup table, which we
|
||||
// add to the tile after we add all features.
|
||||
protozero::packed_field_uint32 field(
|
||||
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
||||
field.add_element(0); // "bearing_in" tag key offset
|
||||
field.add_element(point_turn_data.in_angle_offset);
|
||||
field.add_element(in_angle_offset);
|
||||
field.add_element(1); // "turn_angle" tag key offset
|
||||
field.add_element(point_turn_data.turn_angle_offset);
|
||||
field.add_element(turn_angle_offset);
|
||||
field.add_element(2); // "cost" tag key offset
|
||||
field.add_element(used_point_ints.size() + point_turn_data.weight_offset);
|
||||
field.add_element(used_point_ints.size() + weight_offset);
|
||||
}
|
||||
{
|
||||
// Add the geometry as the last field in this feature
|
||||
@@ -983,6 +739,31 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
}
|
||||
// protozero serializes data during object destructors, so once the scope closes,
|
||||
// our result buffer will have all the tile data encoded into it.
|
||||
}
|
||||
}
|
||||
|
||||
Status TilePlugin::HandleRequest(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
const RoutingAlgorithmsInterface &algorithms,
|
||||
const api::TileParameters ¶meters,
|
||||
std::string &pbf_buffer) const
|
||||
{
|
||||
BOOST_ASSERT(parameters.IsValid());
|
||||
|
||||
auto edges = getEdges(facade, parameters.x, parameters.y, parameters.y);
|
||||
|
||||
auto edge_index = getEdgeIndex(edges);
|
||||
|
||||
std::vector<routing_algorithms::TurnData> turns;
|
||||
|
||||
// If we're zooming into 16 or higher, include turn data. Why? Because turns make the map
|
||||
// really cramped, so we don't bother including the data for tiles that span a large area.
|
||||
if (parameters.z >= MIN_ZOOM_FOR_TURNS)
|
||||
{
|
||||
turns = algorithms.TileTurns(edges, edge_index);
|
||||
}
|
||||
|
||||
encodeVectorTile(
|
||||
facade, parameters.x, parameters.y, parameters.y, edges, edge_index, turns, pbf_buffer);
|
||||
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
+12
-11
@@ -52,11 +52,10 @@ bool IsSupportedParameterCombination(const bool fixed_start,
|
||||
|
||||
// given the node order in which to visit, compute the actual route (with geometry, travel time and
|
||||
// so on) and return the result
|
||||
InternalRouteResult
|
||||
TripPlugin::ComputeRoute(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
||||
const std::vector<PhantomNode> &snapped_phantoms,
|
||||
const std::vector<NodeID> &trip,
|
||||
const bool roundtrip) const
|
||||
InternalRouteResult TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||
const std::vector<PhantomNode> &snapped_phantoms,
|
||||
const std::vector<NodeID> &trip,
|
||||
const bool roundtrip) const
|
||||
{
|
||||
InternalRouteResult min_route;
|
||||
// given the final trip, compute total duration and return the route and location permutation
|
||||
@@ -86,7 +85,7 @@ TripPlugin::ComputeRoute(const std::shared_ptr<const datafacade::BaseDataFacade>
|
||||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size() - 1);
|
||||
}
|
||||
|
||||
shortest_path(facade, min_route.segment_end_coordinates, {false}, min_route);
|
||||
algorithms.ShortestRouting(min_route.segment_end_coordinates, {false}, min_route);
|
||||
BOOST_ASSERT_MSG(min_route.shortest_path_length < INVALID_EDGE_WEIGHT, "unroutable route");
|
||||
return min_route;
|
||||
}
|
||||
@@ -143,7 +142,8 @@ void ManipulateTableForFSE(const std::size_t source_id,
|
||||
//********* End of changes to table *************************************
|
||||
}
|
||||
|
||||
Status TripPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
||||
Status TripPlugin::HandleRequest(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
const RoutingAlgorithmsInterface &algorithms,
|
||||
const api::TripParameters ¶meters,
|
||||
util::json::Object &json_result) const
|
||||
{
|
||||
@@ -179,7 +179,7 @@ Status TripPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
return Error("InvalidValue", "Invalid coordinate value.", json_result);
|
||||
}
|
||||
|
||||
auto phantom_node_pairs = GetPhantomNodes(*facade, parameters);
|
||||
auto phantom_node_pairs = GetPhantomNodes(facade, parameters);
|
||||
if (phantom_node_pairs.size() != number_of_locations)
|
||||
{
|
||||
return Error("NoSegment",
|
||||
@@ -201,7 +201,7 @@ Status TripPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
|
||||
// compute the duration table of all phantom nodes
|
||||
auto result_table = util::DistTableWrapper<EdgeWeight>(
|
||||
duration_table(facade, snapped_phantoms, {}, {}), number_of_locations);
|
||||
algorithms.ManyToManyRouting(snapped_phantoms, {}, {}), number_of_locations);
|
||||
|
||||
if (result_table.size() == 0)
|
||||
{
|
||||
@@ -250,12 +250,13 @@ Status TripPlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDat
|
||||
}
|
||||
|
||||
// get the route when visiting all destinations in optimized order
|
||||
InternalRouteResult route = ComputeRoute(facade, snapped_phantoms, trip, parameters.roundtrip);
|
||||
InternalRouteResult route =
|
||||
ComputeRoute(algorithms, snapped_phantoms, trip, parameters.roundtrip);
|
||||
|
||||
// get api response
|
||||
const std::vector<std::vector<NodeID>> trips = {trip};
|
||||
const std::vector<InternalRouteResult> routes = {route};
|
||||
api::TripAPI trip_api{*facade, parameters};
|
||||
api::TripAPI trip_api{facade, parameters};
|
||||
trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result);
|
||||
|
||||
return Status::Ok;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "engine/plugins/viaroute.hpp"
|
||||
#include "engine/api/route_api.hpp"
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
#include "engine/routing_algorithms.hpp"
|
||||
#include "engine/status.hpp"
|
||||
|
||||
#include "util/for_each_pair.hpp"
|
||||
@@ -22,14 +22,15 @@ namespace plugins
|
||||
{
|
||||
|
||||
ViaRoutePlugin::ViaRoutePlugin(int max_locations_viaroute)
|
||||
: shortest_path(heaps), alternative_path(heaps), direct_shortest_path(heaps),
|
||||
max_locations_viaroute(max_locations_viaroute)
|
||||
: max_locations_viaroute(max_locations_viaroute)
|
||||
{
|
||||
}
|
||||
|
||||
Status ViaRoutePlugin::HandleRequest(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
||||
const api::RouteParameters &route_parameters,
|
||||
util::json::Object &json_result) const
|
||||
Status
|
||||
ViaRoutePlugin::HandleRequest(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
const RoutingAlgorithmsInterface &algorithms,
|
||||
const api::RouteParameters &route_parameters,
|
||||
util::json::Object &json_result) const
|
||||
{
|
||||
BOOST_ASSERT(route_parameters.IsValid());
|
||||
|
||||
@@ -48,7 +49,7 @@ Status ViaRoutePlugin::HandleRequest(const std::shared_ptr<const datafacade::Bas
|
||||
return Error("InvalidValue", "Invalid coordinate value.", json_result);
|
||||
}
|
||||
|
||||
auto phantom_node_pairs = GetPhantomNodes(*facade, route_parameters);
|
||||
auto phantom_node_pairs = GetPhantomNodes(facade, route_parameters);
|
||||
if (phantom_node_pairs.size() != route_parameters.coordinates.size())
|
||||
{
|
||||
return Error("NoSegment",
|
||||
@@ -62,7 +63,7 @@ Status ViaRoutePlugin::HandleRequest(const std::shared_ptr<const datafacade::Bas
|
||||
|
||||
const bool continue_straight_at_waypoint = route_parameters.continue_straight
|
||||
? *route_parameters.continue_straight
|
||||
: facade->GetContinueStraightDefault();
|
||||
: facade.GetContinueStraightDefault();
|
||||
|
||||
InternalRouteResult raw_route;
|
||||
auto build_phantom_pairs = [&raw_route, continue_straight_at_waypoint](
|
||||
@@ -86,28 +87,26 @@ Status ViaRoutePlugin::HandleRequest(const std::shared_ptr<const datafacade::Bas
|
||||
|
||||
if (1 == raw_route.segment_end_coordinates.size())
|
||||
{
|
||||
if (route_parameters.alternatives && facade->GetCoreSize() == 0)
|
||||
if (route_parameters.alternatives && algorithms.HasAlternativeRouting())
|
||||
{
|
||||
alternative_path(facade, raw_route.segment_end_coordinates.front(), raw_route);
|
||||
algorithms.AlternativeRouting(raw_route.segment_end_coordinates.front(), raw_route);
|
||||
}
|
||||
else
|
||||
{
|
||||
direct_shortest_path(facade, raw_route.segment_end_coordinates, raw_route);
|
||||
algorithms.DirectShortestPathRouting(raw_route.segment_end_coordinates, raw_route);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shortest_path(facade,
|
||||
raw_route.segment_end_coordinates,
|
||||
route_parameters.continue_straight,
|
||||
raw_route);
|
||||
algorithms.ShortestRouting(
|
||||
raw_route.segment_end_coordinates, route_parameters.continue_straight, raw_route);
|
||||
}
|
||||
|
||||
// we can only know this after the fact, different SCC ids still
|
||||
// allow for connection in one direction.
|
||||
if (raw_route.is_valid())
|
||||
{
|
||||
api::RouteAPI route_api{*facade, route_parameters};
|
||||
api::RouteAPI route_api{facade, route_parameters};
|
||||
route_api.MakeResponse(raw_route, json_result);
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user