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.
This commit is contained in:
Michael Bell
2020-12-20 21:59:57 +00:00
committed by GitHub
parent eb1d399f3b
commit 5266ac1635
48 changed files with 3170 additions and 1406 deletions
@@ -12,8 +12,8 @@
#include "extractor/name_table.hpp"
#include "extractor/nbg_to_ebg.hpp"
#include "extractor/node_data_container.hpp"
#include "extractor/node_restriction_map.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/turn_lane_types.hpp"
#include "extractor/way_restriction_map.hpp"
+24 -16
View File
@@ -1,14 +1,16 @@
#ifndef EXTRACTION_CONTAINERS_HPP
#define EXTRACTION_CONTAINERS_HPP
#include "extractor/first_and_last_segment_of_way.hpp"
#include "extractor/internal_extractor_edge.hpp"
#include "extractor/nodes_of_way.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction.hpp"
#include "extractor/scripting_environment.hpp"
#include "storage/tar_fwd.hpp"
#include <unordered_map>
namespace osrm
{
namespace extractor
@@ -22,9 +24,16 @@ namespace extractor
*/
class ExtractionContainers
{
using ReferencedWays = std::unordered_map<OSMWayID, NodesOfWay>;
// The relationship between way and nodes is lost during node preparation.
// We identify the ways and nodes relevant to restrictions/overrides prior to
// node processing so that they can be referenced in the preparation phase.
ReferencedWays IdentifyRestrictionWays();
ReferencedWays IdentifyManeuverOverrideWays();
void PrepareNodes();
void PrepareManeuverOverrides();
void PrepareRestrictions();
void PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways);
void PrepareRestrictions(const ReferencedWays &restriction_ways);
void PrepareEdges(ScriptingEnvironment &scripting_environment);
void WriteNodes(storage::tar::FileWriter &file_out) const;
@@ -37,9 +46,10 @@ class ExtractionContainers
using NodeVector = std::vector<QueryNode>;
using EdgeVector = std::vector<InternalExtractorEdge>;
using AnnotationDataVector = std::vector<NodeBasedEdgeAnnotation>;
using WayIDStartEndVector = std::vector<FirstAndLastSegmentOfWay>;
using NameCharData = std::vector<unsigned char>;
using NameOffsets = std::vector<unsigned>;
using NameOffsets = std::vector<size_t>;
using WayIDVector = std::vector<OSMWayID>;
using WayNodeIDOffsets = std::vector<size_t>;
std::vector<OSMNodeID> barrier_nodes;
std::vector<OSMNodeID> traffic_signals;
@@ -49,20 +59,18 @@ class ExtractionContainers
AnnotationDataVector all_edges_annotation_data_list;
NameCharData name_char_data;
NameOffsets name_offsets;
// an adjacency array containing all turn lane masks
WayIDStartEndVector way_start_end_id_list;
WayIDVector ways_list;
// Offsets into used nodes for each way_list entry
WayNodeIDOffsets way_node_id_offsets;
unsigned max_internal_node_id;
// list of restrictions before we transform them into the output types. Input containers
// reference OSMNodeIDs. We can only transform them to the correct internal IDs after we've read
// everything. Without a multi-parse approach, we have to remember the output restrictions
// before converting them to the internal formats
std::vector<InputConditionalTurnRestriction> restrictions_list;
// turn restrictions split into conditional and unconditional turn restrictions
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
std::vector<TurnRestriction> unconditional_turn_restrictions;
// List of restrictions (conditional and unconditional) before we transform them into the
// output types. Input containers reference OSMNodeIDs. We can only transform them to the
// correct internal IDs after we've read everything. Without a multi-parse approach,
// we have to remember the output restrictions before converting them to the internal formats
std::vector<InputTurnRestriction> restrictions_list;
std::vector<TurnRestriction> turn_restrictions;
std::vector<InputManeuverOverride> external_maneuver_overrides_list;
std::vector<UnresolvedManeuverOverride> internal_maneuver_overrides;
+11 -19
View File
@@ -42,6 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "util/guidance/entry_class.hpp"
#include "util/guidance/turn_lanes.hpp"
#include "restriction_graph.hpp"
#include "util/typedefs.hpp"
namespace osrm
@@ -63,7 +64,6 @@ class Extractor
std::tuple<LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<ConditionalTurnRestriction>,
std::vector<UnresolvedManeuverOverride>>
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
@@ -74,8 +74,7 @@ class Extractor
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
const std::vector<TurnRestriction> &turn_restrictions,
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
const RestrictionGraph &restriction_graph,
const std::unordered_set<EdgeID> &segregated_edges,
const NameTable &name_table,
const std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
@@ -97,23 +96,16 @@ class Extractor
EdgeBasedNodeDataContainer &nodes_container) const;
void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments,
const std::vector<util::Coordinate> &coordinates);
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
void WriteConditionalRestrictions(
const std::string &path,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
void ProcessGuidanceTurns(
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &edge_based_node_container,
const std::vector<util::Coordinate> &node_coordinates,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::vector<TurnRestriction> &turn_restrictions,
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
const NameTable &name_table,
LaneDescriptionMap lane_description_map,
ScriptingEnvironment &scripting_environment);
void ProcessGuidanceTurns(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &edge_based_node_container,
const std::vector<util::Coordinate> &node_coordinates,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const RestrictionGraph &restriction_graph,
const NameTable &name_table,
LaneDescriptionMap lane_description_map,
ScriptingEnvironment &scripting_environment);
};
} // namespace extractor
} // namespace osrm
+2 -2
View File
@@ -47,7 +47,7 @@ struct ExtractionNode;
struct ExtractionWay;
struct ExtractionRelation;
struct ProfileProperties;
struct InputConditionalTurnRestriction;
struct InputTurnRestriction;
struct InputManeuverOverride;
/**
@@ -87,7 +87,7 @@ class ExtractorCallbacks
void ProcessNode(const osmium::Node &current_node, const ExtractionNode &result_node);
// warning: caller needs to take care of synchronization!
void ProcessRestriction(const InputConditionalTurnRestriction &restriction);
void ProcessRestriction(const InputTurnRestriction &restriction);
// warning: caller needs to take care of synchronization!
void ProcessWay(const osmium::Way &current_way, const ExtractionWay &result_way);
@@ -1,59 +0,0 @@
#ifndef FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
#include "util/typedefs.hpp"
#include <limits>
#include <string>
namespace osrm
{
namespace extractor
{
struct FirstAndLastSegmentOfWay
{
OSMWayID way_id;
OSMNodeID first_segment_source_id;
OSMNodeID first_segment_target_id;
OSMNodeID last_segment_source_id;
OSMNodeID last_segment_target_id;
FirstAndLastSegmentOfWay()
: way_id(SPECIAL_OSM_WAYID), first_segment_source_id(SPECIAL_OSM_NODEID),
first_segment_target_id(SPECIAL_OSM_NODEID), last_segment_source_id(SPECIAL_OSM_NODEID),
last_segment_target_id(SPECIAL_OSM_NODEID)
{
}
FirstAndLastSegmentOfWay(OSMWayID w, OSMNodeID fs, OSMNodeID ft, OSMNodeID ls, OSMNodeID lt)
: way_id(std::move(w)), first_segment_source_id(std::move(fs)),
first_segment_target_id(std::move(ft)), last_segment_source_id(std::move(ls)),
last_segment_target_id(std::move(lt))
{
}
static FirstAndLastSegmentOfWay min_value()
{
return {MIN_OSM_WAYID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID};
}
static FirstAndLastSegmentOfWay max_value()
{
return {MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID};
}
};
struct FirstAndLastSegmentOfWayCompare
{
using value_type = FirstAndLastSegmentOfWay;
bool operator()(const FirstAndLastSegmentOfWay &a, const FirstAndLastSegmentOfWay &b) const
{
return a.way_id < b.way_id;
}
value_type max_value() { return FirstAndLastSegmentOfWay::max_value(); }
value_type min_value() { return FirstAndLastSegmentOfWay::min_value(); }
};
} // namespace extractor
} // namespace osrm
#endif /* FIRST_AND_LAST_SEGMENT_OF_WAY_HPP */
-1
View File
@@ -28,7 +28,6 @@ class GraphCompressor
const std::unordered_set<NodeID> &traffic_lights,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
util::NodeBasedDynamicGraph &graph,
const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
@@ -5,7 +5,7 @@
#include "extractor/intersection/intersection_edge.hpp"
#include "extractor/intersection/intersection_view.hpp"
#include "extractor/intersection/mergable_road_detector.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/node_restriction_map.hpp"
#include "extractor/turn_lane_types.hpp"
#include "util/coordinate.hpp"
@@ -5,7 +5,7 @@
#include "extractor/intersection/coordinate_extractor.hpp"
#include "extractor/intersection/have_identical_names.hpp"
#include "extractor/name_table.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/node_restriction_map.hpp"
#include "extractor/turn_lane_types.hpp"
#include "guidance/intersection.hpp"
@@ -40,7 +40,6 @@ class NodeBasedGraphFactory
NodeBasedGraphFactory(const boost::filesystem::path &input_file,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
auto const &GetGraph() const { return compressed_output_graph; }
@@ -69,7 +68,6 @@ class NodeBasedGraphFactory
// edges into a single representative form
void Compress(ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
// Most ways are bidirectional, making the geometry in forward and backward direction the same,
@@ -0,0 +1,80 @@
#ifndef OSRM_EXTRACTOR_NODE_RESTRICTION_MAP_HPP_
#define OSRM_EXTRACTOR_NODE_RESTRICTION_MAP_HPP_
#include "extractor/restriction.hpp"
#include "restriction_graph.hpp"
#include "util/typedefs.hpp"
#include <boost/range/adaptor/filtered.hpp>
#include <boost/unordered_map.hpp>
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
// Allows easy check for whether a node restriction is present at a given intersection
template <typename RestrictionFilter> class NodeRestrictionMap
{
public:
NodeRestrictionMap(const RestrictionGraph &restriction_graph)
: restriction_graph(restriction_graph), index_filter(RestrictionFilter{})
{
}
// Find all restrictions applicable to (from,via,*) turns
auto Restrictions(NodeID from, NodeID via) const
{
return getRange(from, via) | boost::adaptors::filtered(index_filter);
};
// Find all restrictions applicable to (from,via,to) turns
auto Restrictions(NodeID from, NodeID via, NodeID to) const
{
const auto turnFilter = [this, to](const auto &restriction) {
return index_filter(restriction) && restriction->IsTurnRestricted(to);
};
return getRange(from, via) | boost::adaptors::filtered(turnFilter);
};
private:
RestrictionGraph::RestrictionRange getRange(NodeID from, NodeID via) const
{
const auto start_node_it = restriction_graph.start_edge_to_node.find({from, via});
if (start_node_it != restriction_graph.start_edge_to_node.end())
{
return restriction_graph.GetRestrictions(start_node_it->second);
}
return {};
}
const RestrictionGraph &restriction_graph;
const RestrictionFilter index_filter;
};
// Restriction filters to use as index defaults
struct ConditionalOnly
{
bool operator()(const TurnRestriction *restriction) const
{
return !restriction->IsUnconditional();
};
};
struct UnconditionalOnly
{
bool operator()(const TurnRestriction *restriction) const
{
return restriction->IsUnconditional();
};
};
using RestrictionMap = NodeRestrictionMap<UnconditionalOnly>;
using ConditionalRestrictionMap = NodeRestrictionMap<ConditionalOnly>;
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_NODE_RESTRICTION_MAP_HPP_
+56
View File
@@ -0,0 +1,56 @@
#ifndef NODES_OF_WAY_HPP
#define NODES_OF_WAY_HPP
#include "util/typedefs.hpp"
#include <limits>
#include <string>
#include <vector>
namespace osrm
{
namespace extractor
{
// NodesOfWay contains the ordered nodes of a way and provides convenience functions for getting
// nodes in the first and last segments.
struct NodesOfWay
{
OSMWayID way_id;
std::vector<OSMNodeID> node_ids;
NodesOfWay() : way_id(SPECIAL_OSM_WAYID), node_ids{SPECIAL_OSM_NODEID, SPECIAL_OSM_NODEID} {}
NodesOfWay(OSMWayID w, std::vector<OSMNodeID> ns) : way_id(w), node_ids(std::move(ns)) {}
static NodesOfWay min_value() { return {MIN_OSM_WAYID, {MIN_OSM_NODEID, MIN_OSM_NODEID}}; }
static NodesOfWay max_value() { return {MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}}; }
const OSMNodeID &first_segment_source_id() const
{
BOOST_ASSERT(!node_ids.empty());
return node_ids[0];
}
const OSMNodeID &first_segment_target_id() const
{
BOOST_ASSERT(node_ids.size() > 1);
return node_ids[1];
}
const OSMNodeID &last_segment_source_id() const
{
BOOST_ASSERT(node_ids.size() > 1);
return node_ids[node_ids.size() - 2];
}
const OSMNodeID &last_segment_target_id() const
{
BOOST_ASSERT(!node_ids.empty());
return node_ids[node_ids.size() - 1];
}
};
} // namespace extractor
} // namespace osrm
#endif /* NODES_OF_WAY_HPP */
+74 -34
View File
@@ -30,17 +30,19 @@ struct InputNodeRestriction
OSMWayID to;
};
// A restriction that uses a single via-way in between
// A restriction that uses one or more via-way in between
//
// f - e - d
// e - f - g
// |
// d
// |
// a - b - c
//
// ab via be to ef -- no u turn
// ab via bd,df to fe -- no u turn
struct InputWayRestriction
{
OSMWayID from;
OSMWayID via;
std::vector<OSMWayID> via;
OSMWayID to;
};
@@ -57,6 +59,9 @@ struct InputTurnRestriction
// keep in the same order as the turn restrictions below
mapbox::util::variant<InputNodeRestriction, InputWayRestriction> node_or_way;
bool is_only;
// We represent conditional and unconditional restrictions with the same structure.
// Unconditional restrictions will have empty conditions.
std::vector<util::OpeningHours> condition;
OSMWayID From() const
{
@@ -102,13 +107,15 @@ struct InputTurnRestriction
return mapbox::util::get<InputNodeRestriction>(node_or_way);
}
};
struct InputConditionalTurnRestriction : InputTurnRestriction
{
std::vector<util::OpeningHours> condition;
};
// OSRM manages restrictions based on node IDs which refer to the last node along the edge. Note
// that this has the side-effect of not allowing parallel edges!
//
// a - b - c
// |
// d
//
// ab via b to bd
struct NodeRestriction
{
NodeID from;
@@ -131,39 +138,46 @@ struct NodeRestriction
// compression happening in the graph creation process which would make it difficult to track
// way-ids over a series of operations. Having access to the nodes directly allows look-up of the
// edges in the processed structures
//
// e - f - g
// |
// d
// |
// a - b - c
//
// ab via bd,df to fe -- no u turn
struct WayRestriction
{
// a way restriction in OSRM is essentially a dual node turn restriction;
//
// | |
// c -x- b
// | |
// d a
//
// from ab via bxc to cd: no_uturn
//
// Technically, we would need only a,b,c,d to describe the full turn in terms of nodes. When
// parsing the relation, though, we do not know about the final representation in the node-based
// graph for the restriction. In case of a traffic light, for example, we might end up with bxc
// not being compressed to bc. For that reason, we need to maintain two node restrictions in
// case a way restrction is not fully collapsed
NodeRestriction in_restriction;
NodeRestriction out_restriction;
// A way restriction in OSRM needs to track all nodes that make up the via ways. Whilst most
// of these nodes will be removed by compression, some nodes will contain features that need to
// be considered when routing (e.g. intersections, nested restrictions, etc).
NodeID from;
std::vector<NodeID> via;
NodeID to;
// check if all parts of the restriction reference an actual node
bool Valid() const
{
return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via.size() >= 2 &&
std::all_of(via.begin(), via.end(), [](NodeID i) { return i != SPECIAL_NODEID; });
};
bool operator==(const WayRestriction &other) const
{
return std::tie(in_restriction, out_restriction) ==
std::tie(other.in_restriction, other.out_restriction);
return std::tie(from, via, to) == std::tie(other.from, other.via, other.to);
}
};
// Wrapper for turn restrictions that gives more information on its type / handles the switch
// between node/way/multi-way restrictions
// between node/way restrictions
struct TurnRestriction
{
// keep in the same order as the turn restrictions above
mapbox::util::variant<NodeRestriction, WayRestriction> node_or_way;
bool is_only;
// We represent conditional and unconditional restrictions with the same structure.
// Unconditional restrictions will have empty conditions.
std::vector<util::OpeningHours> condition;
// construction for NodeRestrictions
explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false)
@@ -179,9 +193,40 @@ struct TurnRestriction
explicit TurnRestriction()
{
node_or_way = NodeRestriction{SPECIAL_EDGEID, SPECIAL_NODEID, SPECIAL_EDGEID};
node_or_way = NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
}
NodeID To() const
{
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
? mapbox::util::get<NodeRestriction>(node_or_way).to
: mapbox::util::get<WayRestriction>(node_or_way).to;
}
NodeID From() const
{
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
? mapbox::util::get<NodeRestriction>(node_or_way).from
: mapbox::util::get<WayRestriction>(node_or_way).from;
}
NodeID FirstVia() const
{
if (node_or_way.which() == RestrictionType::NODE_RESTRICTION)
{
return mapbox::util::get<NodeRestriction>(node_or_way).via;
}
else
{
BOOST_ASSERT(!mapbox::util::get<WayRestriction>(node_or_way).via.empty());
return mapbox::util::get<WayRestriction>(node_or_way).via[0];
}
}
bool IsTurnRestricted(NodeID to) const { return is_only ? To() != to : To() == to; }
bool IsUnconditional() const { return condition.empty(); }
WayRestriction &AsWayRestriction()
{
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
@@ -218,7 +263,7 @@ struct TurnRestriction
if (node_or_way.which() == RestrictionType::WAY_RESTRICTION)
{
auto const &restriction = AsWayRestriction();
return restriction.in_restriction.Valid() && restriction.out_restriction.Valid();
return restriction.Valid();
}
else
{
@@ -245,11 +290,6 @@ struct TurnRestriction
}
}
};
struct ConditionalTurnRestriction : TurnRestriction
{
std::vector<util::OpeningHours> condition;
};
} // namespace extractor
} // namespace osrm
+11 -8
View File
@@ -16,8 +16,8 @@ namespace extractor
struct NodeRestriction;
struct TurnRestriction;
// OSRM stores restrictions in the form node -> node -> node instead of way -> node -> way (or
// way->way->way) as it is done in OSM. These restrictions need to match the state of graph
// OSRM stores restrictions as node -> [node] -> node instead of way -> node -> way (or
// way->[way]->way) as it is done in OSM. These restrictions need to match the state of graph
// compression which we perform in the graph compressor that removes certain degree two nodes from
// the graph (all but the ones with penalties/barriers, as of the state of writing).
// Since this graph compression ins performed after creating the restrictions in the extraction
@@ -29,19 +29,22 @@ class RestrictionCompressor
{
public:
RestrictionCompressor(std::vector<TurnRestriction> &restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
// account for the compression of `from-via-to` into `from-to`
void Compress(const NodeID from, const NodeID via, const NodeID to);
private:
// a turn restriction is given as `from star via node to end`. Edges ending at `head` being
// A turn restriction is given as `from star via node to end`. Edges ending at `head` being
// contracted move the head pointer to their respective head. Edges starting at tail move the
// tail values to their respective tails. Way turn restrictions are represented by two
// node-restrictions, so we can focus on them alone
boost::unordered_multimap<NodeID, NodeRestriction *> starts;
boost::unordered_multimap<NodeID, NodeRestriction *> ends;
// tail values to their respective tails.
// Via nodes that are compressed are removed from the restriction representation.
// We do not compress the first and last via nodes of a restriction as they act as
// entrance/exit points into the restriction graph. For a node restriction, the first and last
// via nodes are the same.
boost::unordered_multimap<NodeID, TurnRestriction *> starts;
boost::unordered_multimap<NodeID, TurnRestriction *> vias;
boost::unordered_multimap<NodeID, TurnRestriction *> ends;
boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_starts;
boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_ends;
+2 -4
View File
@@ -14,10 +14,8 @@ namespace extractor
// To avoid handling invalid restrictions / creating unnecessary duplicate nodes for via-ways, we do
// a pre-flight check for restrictions and remove all invalid restrictions from the data. Use as
// `restrictions = removeInvalidRestrictions(std::move(restrictions))`
std::vector<ConditionalTurnRestriction>
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction>,
const util::NodeBasedDynamicGraph &);
std::vector<TurnRestriction> removeInvalidRestrictions(std::vector<TurnRestriction>,
const util::NodeBasedDynamicGraph &);
} // namespace extractor
} // namespace osrm
+134
View File
@@ -0,0 +1,134 @@
#ifndef OSRM_EXTRACTOR_RESTRICTION_GRAPH_HPP_
#define OSRM_EXTRACTOR_RESTRICTION_GRAPH_HPP_
#include <boost/assert.hpp>
#include <boost/unordered_map.hpp>
#include "extractor/restriction_filter.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
namespace osrm
{
namespace extractor
{
namespace restriction_graph_details
{
struct transferBuilder;
struct pathBuilder;
} // namespace restriction_graph_details
struct RestrictionEdge
{
NodeID node_based_to;
RestrictionID target;
bool is_transfer;
};
struct RestrictionNode
{
size_t restrictions_begin_idx;
size_t num_restrictions;
size_t edges_begin_idx;
size_t num_edges;
};
/**
* The restriction graph is used to represent all possible restrictions within the routing graph.
* The graph uses an edge-based node representation. Each node represents a compressed
* node-based edge along a restriction path.
*
* Given a list of turn restrictions, the graph is created in multiple steps.
*
* INPUT
* a -> b -> d: no_e
* a -> b -> c: only_d
* b -> c -> d: only_f
* b -> c: no_g
* e -> b -> d: no_g
*
* Step 1: create a disjoint union of prefix trees for all restriction paths.
* The restriction instructions are added to the final node in its path.
*
* STEP 1
* (a,b) -> (b,d,[no_e])
* \->(b,c,[only_d])
*
* (b,c,[no_g]) -> (c,d,[only_f])
* (e,b) -> (b,d,[no_g])
*
* Step 2: add transfers between restriction paths that overlap.
* We do this by traversing each restriction path, tracking where the suffix of our current path
* matches the prefix of any other. If it does, there's opportunity to transfer to the suffix
* restriction path *if* the transfer would not be restricted *and* that edge does not take us
* further on our current path. Nested restrictions are also added from any of the suffix paths.
*
* STEP 2
* (a,b) -> (b,d,[no_e])
* \->(b,c,[only_d,no_g])
* \
* (b,c,[no_g]) -> \-> (c,d,[only_f])
*
* (e,b) -> (b,d,[no_g])
* If a transfer applies to multiple suffix paths, we only add the edge to the largest suffix path.
* This ensures we correctly track all overlapping paths.
*
*
* Step 3: The nodes are split into
* start nodes - compressed edges that are entry points into a restriction path.
* via nodes - compressed edges that are intermediate steps along a restriction path.
* Start nodes and via nodes are indexed by the compressed node-based edge for easy retrieval
*
* STEP 3
* Start Node Index
* (a,b) => (a,b)
* (b,c) => (b,c,[no_g])
* (e,b) => (e,b)
*
* Via Nodes Index
* (b,c) => (b,c,[only_d,no_g])
* (b,d) => (b,d,[no_e]) , (b,d,[no_g])
* (c,d) => (c,d,[only_f])
*
* Duplicate Nodes:
* There is a 1-1 mapping between restriction graph via nodes and edge-based-graph duplicate nodes.
* This relationship is used in the creation of restrictions in the routing edge-based graph.
* */
struct RestrictionGraph
{
friend restriction_graph_details::pathBuilder;
friend restriction_graph_details::transferBuilder;
friend RestrictionGraph constructRestrictionGraph(const std::vector<TurnRestriction> &);
using EdgeRange = boost::iterator_range<std::vector<RestrictionEdge>::const_iterator>;
using RestrictionRange =
boost::iterator_range<std::vector<const TurnRestriction *>::const_iterator>;
using EdgeKey = std::pair<NodeID, NodeID>;
// Helper functions for iterating over node restrictions and edges
EdgeRange GetEdges(RestrictionID id) const;
RestrictionRange GetRestrictions(RestrictionID id) const;
// A compressed node-based edge can only have one start node in the restriction graph.
boost::unordered_map<EdgeKey, RestrictionID> start_edge_to_node{};
// A compressed node-based edge can have multiple via nodes in the restriction graph
// (as the compressed edge can appear in paths with different prefixes).
boost::unordered_multimap<EdgeKey, RestrictionID> via_edge_to_node{};
std::vector<RestrictionNode> nodes;
// TODO: Investigate reusing DynamicGraph. Currently it requires specific attributes
// (e.g. reversed, weight) that would not make sense for restrictions.
std::vector<RestrictionEdge> edges;
std::vector<const TurnRestriction *> restrictions;
size_t num_via_nodes{};
private:
RestrictionGraph() = default;
};
RestrictionGraph constructRestrictionGraph(const std::vector<TurnRestriction> &turn_restrictions);
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_RESTRICTION_GRAPH_HPP_
-101
View File
@@ -1,101 +0,0 @@
#ifndef OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
#define OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
#include "extractor/restriction.hpp"
#include "util/typedefs.hpp"
#include <boost/unordered_map.hpp>
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
// allows easy check for whether a node intersection is present at a given intersection
template <typename restriction_type> class RestrictionIndex
{
public:
using value_type = restriction_type;
template <typename extractor_type>
RestrictionIndex(std::vector<restriction_type> &restrictions, extractor_type extractor);
bool IsIndexed(NodeID first, NodeID second) const;
auto Restrictions(NodeID first, NodeID second) const
{
return restriction_hash.equal_range(std::make_pair(first, second));
};
auto Size() const { return restriction_hash.size(); }
private:
boost::unordered_multimap<std::pair<NodeID, NodeID>, restriction_type *> restriction_hash;
};
template <typename restriction_type>
template <typename extractor_type>
RestrictionIndex<restriction_type>::RestrictionIndex(std::vector<restriction_type> &restrictions,
extractor_type extractor)
{
// build a multi-map
for (auto &restriction : restrictions)
restriction_hash.insert(std::make_pair(extractor(restriction), &restriction));
}
template <typename restriction_type>
bool RestrictionIndex<restriction_type>::IsIndexed(const NodeID first, const NodeID second) const
{
return restriction_hash.count(std::make_pair(first, second));
}
struct IndexNodeByFromAndVia
{
std::pair<NodeID, NodeID> operator()(const TurnRestriction &restriction)
{
const auto &node = restriction.AsNodeRestriction();
return std::make_pair(node.from, node.via);
};
};
// check wheter a turn is restricted within a restriction_index
template <typename restriction_map_type>
std::pair<bool, typename restriction_map_type::value_type *>
isRestricted(const NodeID from,
const NodeID via,
const NodeID to,
const restriction_map_type &restriction_map)
{
const auto range = restriction_map.Restrictions(from, via);
// check if a given node_restriction is targeting node
const auto to_is_restricted = [to](const auto &pair) {
const auto &restriction = *pair.second;
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
{
auto const &as_node = restriction.AsNodeRestriction();
auto const restricted = restriction.is_only ? (to != as_node.to) : (to == as_node.to);
return restricted;
}
return false;
};
auto itr = std::find_if(range.first, range.second, to_is_restricted);
if (itr != range.second)
return {true, itr->second};
else
return {false, NULL};
}
using RestrictionMap = RestrictionIndex<TurnRestriction>;
using ConditionalRestrictionMap = RestrictionIndex<ConditionalTurnRestriction>;
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
+1 -2
View File
@@ -44,8 +44,7 @@ class RestrictionParser
RestrictionParser(bool use_turn_restrictions,
bool parse_conditionals,
std::vector<std::string> &restrictions);
boost::optional<InputConditionalTurnRestriction>
TryParse(const osmium::Relation &relation) const;
boost::optional<InputTurnRestriction> TryParse(const osmium::Relation &relation) const;
private:
bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
+1 -1
View File
@@ -68,7 +68,7 @@ class ScriptingEnvironment
const ExtractionRelationContainer &relations,
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
std::vector<InputConditionalTurnRestriction> &resulting_restrictions,
std::vector<InputTurnRestriction> &resulting_restrictions,
std::vector<InputManeuverOverride> &resulting_maneuver_overrides) = 0;
virtual bool HasLocationDependentData() const = 0;
@@ -92,7 +92,7 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
const ExtractionRelationContainer &relations,
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
std::vector<InputConditionalTurnRestriction> &resulting_restrictions,
std::vector<InputTurnRestriction> &resulting_restrictions,
std::vector<InputManeuverOverride> &resulting_maneuver_overrides) override;
bool HasLocationDependentData() const override { return !location_dependent_data.empty(); }
+35 -51
View File
@@ -8,82 +8,66 @@
#include <boost/unordered_map.hpp>
#include "extractor/restriction.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/restriction_graph.hpp"
#include "util/integer_range.hpp"
#include "util/typedefs.hpp"
// Given the compressed representation of via-way turn restrictions, we provide a fast access into
// the restrictions to indicate which turns may be restricted due to a way in between
namespace osrm
{
namespace extractor
{
// The WayRestrictionMap uses ConditionalTurnRestrictions in general. Most restrictions will have
// empty conditions, though.
// Given the compressed representation of via-way turn restrictions, we provide a fast access into
// the restrictions to indicate which turns may be restricted due to a way in between.
class WayRestrictionMap
{
public:
struct ViaWay
struct ViaEdge
{
NodeID from;
NodeID to;
};
WayRestrictionMap(const std::vector<ConditionalTurnRestriction> &conditional_restrictions);
WayRestrictionMap(const RestrictionGraph &restriction_graph);
// Check if an edge between two nodes is a restricted turn. The check needs to be performed to
// Check if an edge between two nodes is part of a via-way. The check needs to be performed to
// find duplicated nodes during the creation of edge-based-edges
bool IsViaWay(const NodeID from, const NodeID to) const;
bool IsViaWayEdge(NodeID from, NodeID to) const;
// Every via-way results in a duplicated node that is required in the edge-based-graph. This
// count is essentially the same as the number of valid via-way restrictions (except for
// non-only restrictions that share the same in/via combination)
// There is a bijection between restriction graph via-nodes and edge-based duplicated nodes.
// This counts the number of duplicated nodes contributed by the way restrictions.
std::size_t NumberOfDuplicatedNodes() const;
// Returns a representative for each duplicated node, consisting of the representative ID (first
// ID of the nodes restrictions) and the from/to vertices of the via-way
// This is used to construct edge based nodes that act as intermediate nodes.
std::vector<ViaWay> DuplicatedNodeRepresentatives() const;
// For each restriction graph via-node, we return its node-based edge representation (from,to).
// This is used to create the duplicate node in the edge based graph.
std::vector<ViaEdge> DuplicatedViaEdges() const;
// Access all duplicated NodeIDs for a set of nodes indicating a via way
std::vector<DuplicatedNodeID> DuplicatedNodeIDs(const NodeID from, const NodeID to) const;
// Access all duplicated NodeIDs from the restriction graph via-node represented by (from,to)
std::vector<DuplicatedNodeID> DuplicatedNodeIDs(NodeID from, NodeID to) const;
// check whether a turn onto a given node is restricted, when coming from a duplicated node
bool IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const;
// Get the restriction resulting in ^ IsRestricted. Requires IsRestricted to evaluate to true
const ConditionalTurnRestriction &GetRestriction(DuplicatedNodeID duplicated_node,
const NodeID to) const;
// Check whether a turn onto a given node is restricted, when coming from a duplicated node
bool IsRestricted(DuplicatedNodeID duplicated_node, NodeID to) const;
// changes edge_based_node to the correct duplicated_node_id in case node_based_from,
// node_based_via, node_based_to can be identified with a restriction group
NodeID RemapIfRestricted(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;
// Get the restrictions resulting in ^ IsRestricted. Requires IsRestricted to evaluate to true
std::vector<const TurnRestriction *> GetRestrictions(DuplicatedNodeID duplicated_node,
NodeID to) const;
// Changes edge_based_node to the correct duplicated_node_id in case node_based_from,
// node_based_via, node_based_to can be identified as the start of a way restriction.
NodeID RemapIfRestrictionStart(NodeID edge_based_node,
NodeID node_based_from,
NodeID node_based_via,
NodeID node_based_to,
NodeID number_of_edge_based_nodes) const;
// Changes edge_based_node to the correct duplicated_node_id in case node_based_from,
// node_based_via, node_based_to can be identified as successive via steps of a way restriction.
NodeID RemapIfRestrictionVia(NodeID edge_based_target_node,
NodeID edge_based_via_node,
NodeID node_based_to,
NodeID number_of_edge_based_nodes) const;
private:
DuplicatedNodeID AsDuplicatedNodeID(const RestrictionID restriction_id) const;
// access all restrictions that have the same starting way and via way. Any duplicated node
// represents the same in-way + via-way combination. This vector contains data about all
// restrictions and their assigned duplicated nodes. It indicates the minimum restriciton ID
// that is represented by the next node. The ID of a node is defined as the position of the
// lower bound of the restrictions ID within this array
//
// a - b
// |
// y - c - x
//
// restriction nodes | restriction id
// a - b - c - x : 5
// a - b - c - y : 6
//
// EBN: 0 . | 2 | 3 | 4 ...
// duplicated node groups: ... | 5 | 7 | ...
std::vector<DuplicatedNodeID> duplicated_node_groups;
std::vector<ConditionalTurnRestriction> restriction_data;
RestrictionIndex<ConditionalTurnRestriction> restriction_starts;
const RestrictionGraph &restriction_graph;
};
} // namespace extractor