osrm-backend/src/extractor/way_restriction_map.cpp
Michael Bell 5266ac1635
Add support for multiple via-way restrictions (#5907)
Currently OSRM only supports turn restrictions with a single via-node or one
via-way. OSM allows for multiple via-ways to represent longer and more
complex restrictions.

This PR extends the use of duplicate nodes for representng via-way turn
restrictions to also support multi via-way restrictions. Effectively, this
increases the edge-based graph size by the number of edges in multi via-way
restrictions. However, given the low number of these restrictions it
has little effect on total graph size.

In addition, we add a new step in the extraction phase that constructs
a restriction graph to support more complex relationships between restrictions,
such as nested restrictions and overlapping restrictions.
2020-12-20 13:59:57 -08:00

126 lines
4.6 KiB
C++

#include "extractor/way_restriction_map.hpp"
#include <tuple>
#include <utility>
namespace osrm
{
namespace extractor
{
WayRestrictionMap::WayRestrictionMap(const RestrictionGraph &restriction_graph)
: restriction_graph(restriction_graph)
{
}
std::size_t WayRestrictionMap::NumberOfDuplicatedNodes() const
{
return restriction_graph.num_via_nodes;
}
bool WayRestrictionMap::IsViaWayEdge(const NodeID from, const NodeID to) const
{
return restriction_graph.via_edge_to_node.count({from, to}) > 0;
}
std::vector<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
const NodeID to) const
{
const auto restriction_ways = restriction_graph.via_edge_to_node.equal_range({from, to});
std::vector<DuplicatedNodeID> result;
std::transform(restriction_ways.first,
restriction_ways.second,
std::back_inserter(result),
[](const auto &range_val) { return DuplicatedNodeID(range_val.second); });
return result;
}
bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const
{
// Checks if a turn to 'to' is restricted
BOOST_ASSERT(duplicated_node < restriction_graph.num_via_nodes);
const auto &restrictions = restriction_graph.GetRestrictions(duplicated_node);
return std::any_of(restrictions.begin(), restrictions.end(), [&to](const auto &restriction) {
return restriction->IsTurnRestricted(to);
});
}
std::vector<const TurnRestriction *>
WayRestrictionMap::GetRestrictions(DuplicatedNodeID duplicated_node, const NodeID to) const
{
std::vector<const TurnRestriction *> result;
// Fetch all restrictions that will restrict a turn to 'to'.
BOOST_ASSERT(duplicated_node < restriction_graph.num_via_nodes);
const auto &restrictions = restriction_graph.GetRestrictions(duplicated_node);
std::copy_if(restrictions.begin(),
restrictions.end(),
std::back_inserter(result),
[&to](const auto &restriction) { return restriction->IsTurnRestricted(to); });
if (result.empty())
{
throw(
"Asking for the restriction of an unrestricted turn. Check with `IsRestricted` before "
"calling GetRestriction");
}
return result;
}
std::vector<WayRestrictionMap::ViaEdge> WayRestrictionMap::DuplicatedViaEdges() const
{
std::vector<ViaEdge> result;
result.resize(NumberOfDuplicatedNodes());
// We use the node id from the restriction graph to enumerate all
// duplicate nodes, and map them to their node based edge representation.
// This means an node based edge (from,to) can have many duplicate nodes.
for (auto entry : restriction_graph.via_edge_to_node)
{
result[entry.second] = {entry.first.first, entry.first.second};
}
return result;
}
NodeID WayRestrictionMap::RemapIfRestrictionStart(const NodeID edge_based_node,
const NodeID node_based_from,
const NodeID node_based_via,
const NodeID node_based_to,
const NodeID number_of_edge_based_nodes) const
{
auto restriction_it =
restriction_graph.start_edge_to_node.find({node_based_from, node_based_via});
if (restriction_it != restriction_graph.start_edge_to_node.end())
{
for (const auto &edge : restriction_graph.GetEdges(restriction_it->second))
{
if (edge.node_based_to == node_based_to)
{
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() + edge.target;
}
}
}
return edge_based_node;
}
NodeID WayRestrictionMap::RemapIfRestrictionVia(const NodeID edge_based_target_node,
const NodeID edge_based_via_node,
const NodeID node_based_to,
const NodeID number_of_edge_based_nodes) const
{
auto duplicated_node_id =
edge_based_via_node + NumberOfDuplicatedNodes() - number_of_edge_based_nodes;
BOOST_ASSERT(duplicated_node_id < restriction_graph.num_via_nodes);
for (const auto &edge : restriction_graph.GetEdges(duplicated_node_id))
{
if (edge.node_based_to == node_based_to)
{
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() + edge.target;
}
}
return edge_based_target_node;
}
} // namespace extractor
} // namespace osrm