Add data structure to allow identification of via-way turns during creation of edge-based-graph

initial version of handling via-way turn restrictions (this is dirty)

 - requires update of data structures
 - requires clean-up
 - requires optimisation
This commit is contained in:
Moritz Kobitzsch
2017-07-11 14:22:28 +02:00
parent b1809d1667
commit 8d0202d240
17 changed files with 833 additions and 353 deletions
+14 -7
View File
@@ -17,6 +17,7 @@
#include "extractor/profile_properties.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/way_restriction_map.hpp"
#include "util/concurrent_id_map.hpp"
#include "util/deallocating_vector.hpp"
@@ -78,7 +79,6 @@ class EdgeBasedGraphFactory
CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
std::shared_ptr<const RestrictionMap> restriction_map,
const std::vector<util::Coordinate> &coordinates,
const extractor::PackedOSMIDs &osm_node_ids,
ProfileProperties profile_properties,
@@ -91,7 +91,9 @@ class EdgeBasedGraphFactory
const std::string &turn_weight_penalties_filename,
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &cnbg_ebg_mapping_path);
const std::string &cnbg_ebg_mapping_path,
const RestrictionMap &restriction_map,
const WayRestrictionMap &way_restriction_map);
// The following get access functions destroy the content in the factory
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
@@ -106,7 +108,7 @@ class EdgeBasedGraphFactory
std::vector<util::guidance::BearingClass> GetBearingClasses() const;
std::vector<util::guidance::EntryClass> GetEntryClasses() const;
unsigned GetHighestEdgeID();
std::uint64_t GetNumberOfEdgeBasedNodes() const;
// Basic analysis of a turn (u --(e1)-- v --(e2)-- w)
// with known angle.
@@ -134,12 +136,15 @@ class EdgeBasedGraphFactory
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
EdgeBasedNodeDataContainer m_edge_based_node_container;
util::DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
EdgeID m_max_edge_id;
// the number of edge-based nodes is mostly made up out of the edges in the node-based graph.
// Any edge in the node-based graph represents a node in the edge-based graph. In addition, we
// add a set of artificial edge-based nodes into the mix to model via-way turn restrictions.
std::uint64_t m_number_of_edge_based_nodes;
const std::vector<util::Coordinate> &m_coordinates;
const extractor::PackedOSMIDs &m_osm_node_ids;
std::shared_ptr<util::NodeBasedDynamicGraph> m_node_based_graph;
std::shared_ptr<RestrictionMap const> m_restriction_map;
const std::unordered_set<NodeID> &m_barrier_nodes;
const std::unordered_set<NodeID> &m_traffic_lights;
@@ -152,14 +157,16 @@ class EdgeBasedGraphFactory
unsigned RenumberEdges();
std::vector<NBGToEBG> GenerateEdgeExpandedNodes();
std::vector<NBGToEBG> GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map);
void GenerateEdgeExpandedEdges(ScriptingEnvironment &scripting_environment,
const std::string &original_edge_data_filename,
const std::string &turn_lane_data_filename,
const std::string &turn_weight_penalties_filename,
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename);
const std::string &turn_penalties_index_filename,
const RestrictionMap &restriction_map,
const WayRestrictionMap &way_restriction_map);
NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v);
+10
View File
@@ -104,6 +104,16 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
util::inplacePermutation(classes.begin(), classes.end(), permutation);
}
// all containers have the exact same size
std::size_t Size() const
{
BOOST_ASSERT(geometry_ids.size() == name_ids.size());
BOOST_ASSERT(geometry_ids.size() == component_ids.size());
BOOST_ASSERT(geometry_ids.size() == travel_modes.size());
BOOST_ASSERT(geometry_ids.size() == classes.size());
return geometry_ids.size();
}
private:
Vector<GeometryID> geometry_ids;
Vector<NameID> name_ids;
+42 -30
View File
@@ -25,9 +25,9 @@ namespace extractor
// ab via b to bd
struct InputNodeRestriction
{
OSMEdgeID_weak from;
OSMNodeID_weak via;
OSMEdgeID_weak to;
OSMWayID from;
OSMNodeID via;
OSMWayID to;
};
// A restriction that uses a single via-way in between
@@ -39,9 +39,9 @@ struct InputNodeRestriction
// ab via be to ef -- no u turn
struct InputWayRestriction
{
OSMEdgeID_weak from;
OSMEdgeID_weak via;
OSMEdgeID_weak to;
OSMWayID from;
OSMWayID via;
OSMWayID to;
};
// Outside view of the variant, these are equal to the `which()` results
@@ -52,35 +52,20 @@ enum RestrictionType
NUM_RESTRICTION_TYPES = 2
};
namespace restriction_details
{
// currently these bits only hold an `is_only` value.
struct Bits
{ // mostly unused, initialised to false by default
Bits() : is_only(false) {}
bool is_only;
// when adding more bits, consider using bitfields just as in
// bool unused : 7;
};
} // namespace restriction
struct InputTurnRestriction
{
// keep in the same order as the turn restrictions below
boost::variant<InputNodeRestriction, InputWayRestriction> node_or_way;
restriction_details::Bits flags;
bool is_only;
OSMEdgeID_weak From() const
OSMWayID From() const
{
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
? boost::get<InputNodeRestriction>(node_or_way).from
: boost::get<InputWayRestriction>(node_or_way).from;
}
OSMEdgeID_weak To() const
OSMWayID To() const
{
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
? boost::get<InputNodeRestriction>(node_or_way).to
@@ -141,6 +126,11 @@ struct NodeRestriction
return "From " + std::to_string(from) + " via " + std::to_string(via) + " to " +
std::to_string(to);
}
bool operator==(const NodeRestriction &other) const
{
return std::tie(from, via, to) == std::tie(other.from, other.via, other.to);
}
};
// A way restriction in the context of OSRM requires translation into NodeIDs. This is due to the
@@ -165,6 +155,12 @@ struct WayRestriction
// case a way restrction is not fully collapsed
NodeRestriction in_restriction;
NodeRestriction out_restriction;
bool operator==(const WayRestriction &other) const
{
return std::tie(in_restriction, out_restriction) ==
std::tie(other.in_restriction, other.out_restriction);
}
};
// Wrapper for turn restrictions that gives more information on its type / handles the switch
@@ -173,20 +169,18 @@ struct TurnRestriction
{
// keep in the same order as the turn restrictions above
boost::variant<NodeRestriction, WayRestriction> node_or_way;
restriction_details::Bits flags;
bool is_only;
// construction for NodeRestrictions
explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false)
: node_or_way(node_restriction)
: node_or_way(node_restriction), is_only(is_only)
{
flags.is_only = is_only;
}
// construction for WayRestrictions
explicit TurnRestriction(WayRestriction way_restriction, bool is_only = false)
: node_or_way(way_restriction)
: node_or_way(way_restriction), is_only(is_only)
{
flags.is_only = is_only;
}
explicit TurnRestriction()
@@ -239,6 +233,24 @@ struct TurnRestriction
}
}
bool operator==(const TurnRestriction &other) const
{
if (is_only != other.is_only)
return false;
if (Type() != other.Type())
return false;
if (Type() == RestrictionType::WAY_RESTRICTION)
{
return AsWayRestriction() == other.AsWayRestriction();
}
else
{
return AsNodeRestriction() == other.AsNodeRestriction();
}
}
std::string ToString() const
{
std::string representation;
@@ -253,7 +265,7 @@ struct TurnRestriction
auto const &node = AsNodeRestriction();
representation = node.ToString();
}
representation += " is_only: " + std::to_string(flags.is_only);
representation += " is_only: " + std::to_string(is_only);
return representation;
}
};
-54
View File
@@ -69,7 +69,6 @@ namespace osrm
{
namespace extractor
{
/**
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
@@ -80,61 +79,8 @@ class RestrictionMap
RestrictionMap() : m_count(0) {}
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
// Replace end v with w in each turn restriction containing u as via node
template <class GraphT>
void FixupArrivingTurnRestriction(const NodeID node_u,
const NodeID node_v,
const NodeID node_w,
const GraphT &graph)
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
BOOST_ASSERT(node_w != SPECIAL_NODEID);
if (!IsViaNode(node_u))
{
return;
}
// find all potential start edges. It is more efficient to get a (small) list
// of potential start edges than iterating over all buckets
std::vector<NodeID> predecessors;
for (const EdgeID current_edge_id : graph.GetAdjacentEdgeRange(node_u))
{
const NodeID target = graph.GetTarget(current_edge_id);
if (node_v != target)
{
predecessors.push_back(target);
}
}
for (const NodeID node_x : predecessors)
{
const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
if (restriction_iterator == m_restriction_map.end())
{
continue;
}
const unsigned index = restriction_iterator->second;
auto &bucket = m_restriction_bucket_list.at(index);
for (RestrictionTarget &restriction_target : bucket)
{
if (node_v == restriction_target.target_node)
{
restriction_target.target_node = node_w;
}
}
}
}
bool IsViaNode(const NodeID node) const;
// Replaces start edge (v, w) with (u, w). Only start node changes.
void
FixupStartingTurnRestriction(const NodeID node_u, const NodeID node_v, const NodeID node_w);
// Check if edge (u, v) is the start of any turn restriction.
// If so returns id of first target node.
NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
+2 -2
View File
@@ -3,7 +3,8 @@
#include "extractor/restriction.hpp"
#include <boost/optional.hpp>
#include <boost/optional/optional.hpp>
#include <string>
#include <vector>
@@ -37,7 +38,6 @@ class ScriptingEnvironment;
* ...----(a)-----(via)------(b)----...
* So it can be represented by the tripe (a, via, b).
*/
class RestrictionParser
{
public:
+9 -11
View File
@@ -165,7 +165,7 @@ inline void write(storage::io::FileWriter &writer, const WayRestriction &restric
inline void read(storage::io::FileReader &reader, TurnRestriction &restriction)
{
reader.ReadInto(restriction.flags);
reader.ReadInto(restriction.is_only);
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
{
WayRestriction way_restriction;
@@ -183,7 +183,7 @@ inline void read(storage::io::FileReader &reader, TurnRestriction &restriction)
inline void write(storage::io::FileWriter &writer, const TurnRestriction &restriction)
{
writer.WriteOne(restriction.flags);
writer.WriteOne(restriction.is_only);
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
{
write(writer, boost::get<WayRestriction>(restriction.node_or_way));
@@ -213,7 +213,7 @@ inline void read(storage::io::FileReader &reader, ConditionalTurnRestriction &re
TurnRestriction base;
read(reader, base);
reinterpret_cast<TurnRestriction &>(restriction) = std::move(base);
auto num_conditions = reader.ReadElementCount64();
const auto num_conditions = reader.ReadElementCount64();
restriction.condition.resize(num_conditions);
for (uint64_t i = 0; i < num_conditions; i++)
{
@@ -230,19 +230,18 @@ inline void read(storage::io::FileReader &reader, std::vector<TurnRestriction> &
auto num_indices = reader.ReadElementCount64();
restrictions.reserve(num_indices);
TurnRestriction restriction;
while (num_indices > 0)
while (num_indices-- > 0)
{
read(reader, restriction);
restrictions.push_back(std::move(restriction));
num_indices--;
}
}
inline void write(storage::io::FileWriter &writer, const std::vector<TurnRestriction> &restrictions)
{
std::uint64_t num_indices = restrictions.size();
const auto num_indices = restrictions.size();
writer.WriteElementCount64(num_indices);
auto const write_restriction = [&writer](const auto &restriction) {
const auto write_restriction = [&writer](const auto &restriction) {
write(writer, restriction);
};
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
@@ -255,20 +254,19 @@ inline void read(storage::io::FileReader &reader,
auto num_indices = reader.ReadElementCount64();
restrictions.reserve(num_indices);
ConditionalTurnRestriction restriction;
while (num_indices > 0)
while (num_indices-- > 0)
{
read(reader, restriction);
restrictions.push_back(std::move(restriction));
num_indices--;
}
}
inline void write(storage::io::FileWriter &writer,
const std::vector<ConditionalTurnRestriction> &restrictions)
{
std::uint64_t num_indices = restrictions.size();
const auto num_indices = restrictions.size();
writer.WriteElementCount64(num_indices);
auto const write_restriction = [&writer](const auto &restriction) {
const auto write_restriction = [&writer](const auto &restriction) {
write(writer, restriction);
};
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
+89
View File
@@ -0,0 +1,89 @@
#ifndef OSRM_EXTRACTOR_WAY_RESTRICTION_MAP_HPP_
#define OSRM_EXTRACTOR_WAY_RESTRICTION_MAP_HPP_
#include <utility>
#include <vector>
// to access the turn restrictions
#include <boost/unordered_map.hpp>
#include "extractor/restriction.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
{
class WayRestrictionMap
{
public:
struct ViaWay
{
std::size_t id;
NodeID from;
NodeID to;
};
WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions);
// check if an edge between two nodes is a restricted turn. The check needs to be performed
bool IsViaWay(const NodeID from, const NodeID to) const;
// number of duplicated nodes
std::size_t NumberOfDuplicatedNodes() const;
// returns a representative for the duplicated way, 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;
// Access all duplicated NodeIDs for a set of nodes indicating a via way
util::range<std::size_t> DuplicatedNodeIDs(const NodeID from, const NodeID to) const;
// check whether a turn onto a given node is restricted, when coming from a duplicated node
bool IsRestricted(std::size_t duplicated_node, const NodeID to) const;
TurnRestriction const &GetRestriction(std::size_t) 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;
private:
std::size_t AsDuplicatedNodeID(const std::size_t 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<std::size_t> duplicated_node_groups;
boost::unordered_multimap<std::pair<NodeID, NodeID>, std::size_t> restriction_starts;
boost::unordered_multimap<std::pair<NodeID, NodeID>, std::size_t> restriction_ends;
std::vector<TurnRestriction> restriction_data;
};
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_WAY_RESTRICTION_MAP_HPP_