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:
parent
b1809d1667
commit
8d0202d240
@ -537,7 +537,7 @@ Feature: Car - Turn restrictions
|
|||||||
| from | to | route |
|
| from | to | route |
|
||||||
| a | h | abc,cde,efc,cgh,cgh |
|
| a | h | abc,cde,efc,cgh,cgh |
|
||||||
|
|
||||||
@restriction
|
@restriction-way
|
||||||
Scenario: Car - prohibit turn
|
Scenario: Car - prohibit turn
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@ -563,9 +563,11 @@ Feature: Car - Turn restrictions
|
|||||||
| restriction | ab | be | de | no_right_turn |
|
| restriction | ab | be | de | no_right_turn |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route | turns | locations |
|
||||||
| a | d | ab,be,de,de |
|
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
|
||||||
| a | f | ab,be,ef,ef |
|
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
||||||
|
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||||
|
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||||
|
|
||||||
@restriction @overlap
|
@restriction @overlap
|
||||||
Scenario: Car - prohibit turn
|
Scenario: Car - prohibit turn
|
||||||
@ -597,11 +599,11 @@ Feature: Car - Turn restrictions
|
|||||||
| restriction | bc | be | ef | no_left_turn |
|
| restriction | bc | be | ef | no_left_turn |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route |
|
||||||
| a | d | ab,be,de,de |
|
| a | d | ab,be,ef,ef,de,de |
|
||||||
| a | f | ab,be,ef,ef |
|
| a | f | ab,be,ef,ef |
|
||||||
| c | d | bc,be,de,de |
|
| c | d | bc,be,de,de |
|
||||||
| c | f | bc,be,ef,ef |
|
| c | f | bc,be,de,de,ef,ef |
|
||||||
|
|
||||||
@restriction-way @overlap
|
@restriction-way @overlap
|
||||||
Scenario: Two times same way
|
Scenario: Two times same way
|
||||||
@ -618,9 +620,25 @@ Feature: Car - Turn restrictions
|
|||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
a - b - c - f
|
| |
|
||||||
| | \ |
|
| |
|
||||||
i - d - e
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
a - b - c - - - - - - - - - - - - - - - - - - - f
|
||||||
|
| | \ /
|
||||||
|
i - d - e - - - - - - - - - - - - - - - - -
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
@ -641,7 +659,7 @@ Feature: Car - Turn restrictions
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route |
|
||||||
| a | i | ab,bc,cd,fedib,fedib |
|
| a | i | ab,bc,cf,fedib,fedib |
|
||||||
|
|
||||||
|
|
||||||
@restriction-way @overlap
|
@restriction-way @overlap
|
||||||
@ -682,8 +700,8 @@ Feature: Car - Turn restrictions
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route |
|
||||||
| a | j | left,third,right,right |
|
| a | j | left,first,right,right |
|
||||||
| f | e | right,first,left,left |
|
| f | e | right,third,left,left |
|
||||||
|
|
||||||
@restriction
|
@restriction
|
||||||
Scenario: Car - allow only turn
|
Scenario: Car - allow only turn
|
||||||
@ -711,9 +729,11 @@ Feature: Car - Turn restrictions
|
|||||||
| restriction | ab | be | ef | only_left_on |
|
| restriction | ab | be | ef | only_left_on |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route | turns | locations |
|
||||||
| a | d | ab,be,de,de |
|
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
|
||||||
|
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
||||||
|
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||||
|
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||||
|
|
||||||
@restriction
|
@restriction
|
||||||
Scenario: Car - allow only turn
|
Scenario: Car - allow only turn
|
||||||
@ -810,14 +830,15 @@ Feature: Car - Turn restrictions
|
|||||||
| restriction | gf | fb,bc | cd | only_u_turn |
|
| restriction | gf | fb,bc | cd | only_u_turn |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route | turns | locations |
|
||||||
| a | d | abcd,abcd |
|
| a | d | abcd,ce,ce,abcd,abcd | depart,turn left,continue uturn,turn left,arrive | a,c,e,c,d |
|
||||||
| a | e | abcd,ce,ce |
|
| a | e | abcd,ce,ce | depart,turn left,arrive | a,c,e |
|
||||||
| a | f | abcd,hfb,hfb |
|
| a | f | abcd,hfb,hfb | depart,turn right,arrive | a,b,f |
|
||||||
| g | e | gf,hfb,abcd,ce,ce |
|
| g | e | gf,hfb,abcd,ce,ce | depart,turn right,turn right,turn left,arrive | g,f,b,c,e |
|
||||||
| g | d | gf,hfb,abcd,abcd |
|
| g | d | gf,hfb,abcd,abcd | depart,turn right,turn right,arrive | g,f,b,d |
|
||||||
| h | e | hfb,abcd,ce,ce |
|
| h | e | hfb,abcd,ce,ce | depart,end of road right,turn left,arrive | h,b,c,e |
|
||||||
| h | d | hfb,abcd,abcd |
|
| h | d | hfb,abcd,abcd | depart,end of road right,arrive | h,b,d |
|
||||||
|
|
||||||
|
|
||||||
@restriction
|
@restriction
|
||||||
Scenario: Car - prohibit turn, traffic lights
|
Scenario: Car - prohibit turn, traffic lights
|
||||||
@ -855,7 +876,8 @@ Feature: Car - Turn restrictions
|
|||||||
|
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route |
|
| from | to | route | turns | locations |
|
||||||
| h | j | ab,be,de,de |
|
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
|
||||||
| h | f | ab,be,ef,ef |
|
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
||||||
|
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||||
|
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "extractor/profile_properties.hpp"
|
#include "extractor/profile_properties.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
#include "extractor/restriction_map.hpp"
|
#include "extractor/restriction_map.hpp"
|
||||||
|
#include "extractor/way_restriction_map.hpp"
|
||||||
|
|
||||||
#include "util/concurrent_id_map.hpp"
|
#include "util/concurrent_id_map.hpp"
|
||||||
#include "util/deallocating_vector.hpp"
|
#include "util/deallocating_vector.hpp"
|
||||||
@ -78,7 +79,6 @@ class EdgeBasedGraphFactory
|
|||||||
CompressedEdgeContainer &compressed_edge_container,
|
CompressedEdgeContainer &compressed_edge_container,
|
||||||
const std::unordered_set<NodeID> &barrier_nodes,
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
const std::unordered_set<NodeID> &traffic_lights,
|
const std::unordered_set<NodeID> &traffic_lights,
|
||||||
std::shared_ptr<const RestrictionMap> restriction_map,
|
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
const extractor::PackedOSMIDs &osm_node_ids,
|
const extractor::PackedOSMIDs &osm_node_ids,
|
||||||
ProfileProperties profile_properties,
|
ProfileProperties profile_properties,
|
||||||
@ -91,7 +91,9 @@ class EdgeBasedGraphFactory
|
|||||||
const std::string &turn_weight_penalties_filename,
|
const std::string &turn_weight_penalties_filename,
|
||||||
const std::string &turn_duration_penalties_filename,
|
const std::string &turn_duration_penalties_filename,
|
||||||
const std::string &turn_penalties_index_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
|
// The following get access functions destroy the content in the factory
|
||||||
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
|
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
|
||||||
@ -106,7 +108,7 @@ class EdgeBasedGraphFactory
|
|||||||
std::vector<util::guidance::BearingClass> GetBearingClasses() const;
|
std::vector<util::guidance::BearingClass> GetBearingClasses() const;
|
||||||
std::vector<util::guidance::EntryClass> GetEntryClasses() 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)
|
// Basic analysis of a turn (u --(e1)-- v --(e2)-- w)
|
||||||
// with known angle.
|
// with known angle.
|
||||||
@ -134,12 +136,15 @@ class EdgeBasedGraphFactory
|
|||||||
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
|
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
|
||||||
EdgeBasedNodeDataContainer m_edge_based_node_container;
|
EdgeBasedNodeDataContainer m_edge_based_node_container;
|
||||||
util::DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
|
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 std::vector<util::Coordinate> &m_coordinates;
|
||||||
const extractor::PackedOSMIDs &m_osm_node_ids;
|
const extractor::PackedOSMIDs &m_osm_node_ids;
|
||||||
std::shared_ptr<util::NodeBasedDynamicGraph> m_node_based_graph;
|
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_barrier_nodes;
|
||||||
const std::unordered_set<NodeID> &m_traffic_lights;
|
const std::unordered_set<NodeID> &m_traffic_lights;
|
||||||
@ -152,14 +157,16 @@ class EdgeBasedGraphFactory
|
|||||||
|
|
||||||
unsigned RenumberEdges();
|
unsigned RenumberEdges();
|
||||||
|
|
||||||
std::vector<NBGToEBG> GenerateEdgeExpandedNodes();
|
std::vector<NBGToEBG> GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map);
|
||||||
|
|
||||||
void GenerateEdgeExpandedEdges(ScriptingEnvironment &scripting_environment,
|
void GenerateEdgeExpandedEdges(ScriptingEnvironment &scripting_environment,
|
||||||
const std::string &original_edge_data_filename,
|
const std::string &original_edge_data_filename,
|
||||||
const std::string &turn_lane_data_filename,
|
const std::string &turn_lane_data_filename,
|
||||||
const std::string &turn_weight_penalties_filename,
|
const std::string &turn_weight_penalties_filename,
|
||||||
const std::string &turn_duration_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);
|
NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v);
|
||||||
|
|
||||||
|
@ -104,6 +104,16 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
|
|||||||
util::inplacePermutation(classes.begin(), classes.end(), permutation);
|
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:
|
private:
|
||||||
Vector<GeometryID> geometry_ids;
|
Vector<GeometryID> geometry_ids;
|
||||||
Vector<NameID> name_ids;
|
Vector<NameID> name_ids;
|
||||||
|
@ -25,9 +25,9 @@ namespace extractor
|
|||||||
// ab via b to bd
|
// ab via b to bd
|
||||||
struct InputNodeRestriction
|
struct InputNodeRestriction
|
||||||
{
|
{
|
||||||
OSMEdgeID_weak from;
|
OSMWayID from;
|
||||||
OSMNodeID_weak via;
|
OSMNodeID via;
|
||||||
OSMEdgeID_weak to;
|
OSMWayID to;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A restriction that uses a single via-way in between
|
// A restriction that uses a single via-way in between
|
||||||
@ -39,9 +39,9 @@ struct InputNodeRestriction
|
|||||||
// ab via be to ef -- no u turn
|
// ab via be to ef -- no u turn
|
||||||
struct InputWayRestriction
|
struct InputWayRestriction
|
||||||
{
|
{
|
||||||
OSMEdgeID_weak from;
|
OSMWayID from;
|
||||||
OSMEdgeID_weak via;
|
OSMWayID via;
|
||||||
OSMEdgeID_weak to;
|
OSMWayID to;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Outside view of the variant, these are equal to the `which()` results
|
// Outside view of the variant, these are equal to the `which()` results
|
||||||
@ -52,35 +52,20 @@ enum RestrictionType
|
|||||||
NUM_RESTRICTION_TYPES = 2
|
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
|
struct InputTurnRestriction
|
||||||
{
|
{
|
||||||
// keep in the same order as the turn restrictions below
|
// keep in the same order as the turn restrictions below
|
||||||
boost::variant<InputNodeRestriction, InputWayRestriction> node_or_way;
|
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
|
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
|
||||||
? boost::get<InputNodeRestriction>(node_or_way).from
|
? boost::get<InputNodeRestriction>(node_or_way).from
|
||||||
: boost::get<InputWayRestriction>(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
|
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
|
||||||
? boost::get<InputNodeRestriction>(node_or_way).to
|
? 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 " +
|
return "From " + std::to_string(from) + " via " + std::to_string(via) + " to " +
|
||||||
std::to_string(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
|
// 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
|
// case a way restrction is not fully collapsed
|
||||||
NodeRestriction in_restriction;
|
NodeRestriction in_restriction;
|
||||||
NodeRestriction out_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
|
// 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
|
// keep in the same order as the turn restrictions above
|
||||||
boost::variant<NodeRestriction, WayRestriction> node_or_way;
|
boost::variant<NodeRestriction, WayRestriction> node_or_way;
|
||||||
restriction_details::Bits flags;
|
bool is_only;
|
||||||
|
|
||||||
// construction for NodeRestrictions
|
// construction for NodeRestrictions
|
||||||
explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false)
|
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
|
// construction for WayRestrictions
|
||||||
explicit TurnRestriction(WayRestriction way_restriction, bool is_only = false)
|
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()
|
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 ToString() const
|
||||||
{
|
{
|
||||||
std::string representation;
|
std::string representation;
|
||||||
@ -253,7 +265,7 @@ struct TurnRestriction
|
|||||||
auto const &node = AsNodeRestriction();
|
auto const &node = AsNodeRestriction();
|
||||||
representation = node.ToString();
|
representation = node.ToString();
|
||||||
}
|
}
|
||||||
representation += " is_only: " + std::to_string(flags.is_only);
|
representation += " is_only: " + std::to_string(is_only);
|
||||||
return representation;
|
return representation;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -69,7 +69,6 @@ namespace osrm
|
|||||||
{
|
{
|
||||||
namespace extractor
|
namespace extractor
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
|
\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
|
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
|
||||||
@ -80,61 +79,8 @@ class RestrictionMap
|
|||||||
RestrictionMap() : m_count(0) {}
|
RestrictionMap() : m_count(0) {}
|
||||||
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
|
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;
|
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.
|
// Check if edge (u, v) is the start of any turn restriction.
|
||||||
// If so returns id of first target node.
|
// If so returns id of first target node.
|
||||||
NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
|
NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
#include "extractor/restriction.hpp"
|
#include "extractor/restriction.hpp"
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional/optional.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -37,7 +38,6 @@ class ScriptingEnvironment;
|
|||||||
* ...----(a)-----(via)------(b)----...
|
* ...----(a)-----(via)------(b)----...
|
||||||
* So it can be represented by the tripe (a, via, b).
|
* So it can be represented by the tripe (a, via, b).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class RestrictionParser
|
class RestrictionParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -165,7 +165,7 @@ inline void write(storage::io::FileWriter &writer, const WayRestriction &restric
|
|||||||
|
|
||||||
inline void read(storage::io::FileReader &reader, TurnRestriction &restriction)
|
inline void read(storage::io::FileReader &reader, TurnRestriction &restriction)
|
||||||
{
|
{
|
||||||
reader.ReadInto(restriction.flags);
|
reader.ReadInto(restriction.is_only);
|
||||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||||
{
|
{
|
||||||
WayRestriction 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)
|
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)
|
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||||
{
|
{
|
||||||
write(writer, boost::get<WayRestriction>(restriction.node_or_way));
|
write(writer, boost::get<WayRestriction>(restriction.node_or_way));
|
||||||
@ -213,7 +213,7 @@ inline void read(storage::io::FileReader &reader, ConditionalTurnRestriction &re
|
|||||||
TurnRestriction base;
|
TurnRestriction base;
|
||||||
read(reader, base);
|
read(reader, base);
|
||||||
reinterpret_cast<TurnRestriction &>(restriction) = std::move(base);
|
reinterpret_cast<TurnRestriction &>(restriction) = std::move(base);
|
||||||
auto num_conditions = reader.ReadElementCount64();
|
const auto num_conditions = reader.ReadElementCount64();
|
||||||
restriction.condition.resize(num_conditions);
|
restriction.condition.resize(num_conditions);
|
||||||
for (uint64_t i = 0; i < num_conditions; i++)
|
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();
|
auto num_indices = reader.ReadElementCount64();
|
||||||
restrictions.reserve(num_indices);
|
restrictions.reserve(num_indices);
|
||||||
TurnRestriction restriction;
|
TurnRestriction restriction;
|
||||||
while (num_indices > 0)
|
while (num_indices-- > 0)
|
||||||
{
|
{
|
||||||
read(reader, restriction);
|
read(reader, restriction);
|
||||||
restrictions.push_back(std::move(restriction));
|
restrictions.push_back(std::move(restriction));
|
||||||
num_indices--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void write(storage::io::FileWriter &writer, const std::vector<TurnRestriction> &restrictions)
|
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);
|
writer.WriteElementCount64(num_indices);
|
||||||
auto const write_restriction = [&writer](const auto &restriction) {
|
const auto write_restriction = [&writer](const auto &restriction) {
|
||||||
write(writer, restriction);
|
write(writer, restriction);
|
||||||
};
|
};
|
||||||
std::for_each(restrictions.begin(), restrictions.end(), write_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();
|
auto num_indices = reader.ReadElementCount64();
|
||||||
restrictions.reserve(num_indices);
|
restrictions.reserve(num_indices);
|
||||||
ConditionalTurnRestriction restriction;
|
ConditionalTurnRestriction restriction;
|
||||||
while (num_indices > 0)
|
while (num_indices-- > 0)
|
||||||
{
|
{
|
||||||
read(reader, restriction);
|
read(reader, restriction);
|
||||||
restrictions.push_back(std::move(restriction));
|
restrictions.push_back(std::move(restriction));
|
||||||
num_indices--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void write(storage::io::FileWriter &writer,
|
inline void write(storage::io::FileWriter &writer,
|
||||||
const std::vector<ConditionalTurnRestriction> &restrictions)
|
const std::vector<ConditionalTurnRestriction> &restrictions)
|
||||||
{
|
{
|
||||||
std::uint64_t num_indices = restrictions.size();
|
const auto num_indices = restrictions.size();
|
||||||
writer.WriteElementCount64(num_indices);
|
writer.WriteElementCount64(num_indices);
|
||||||
auto const write_restriction = [&writer](const auto &restriction) {
|
const auto write_restriction = [&writer](const auto &restriction) {
|
||||||
write(writer, restriction);
|
write(writer, restriction);
|
||||||
};
|
};
|
||||||
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
|
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
|
||||||
|
89
include/extractor/way_restriction_map.hpp
Normal file
89
include/extractor/way_restriction_map.hpp
Normal 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_
|
@ -66,7 +66,7 @@ template <typename EdgeDataT>
|
|||||||
inline void read(storage::io::FileReader &reader, DynamicGraph<EdgeDataT> &graph)
|
inline void read(storage::io::FileReader &reader, DynamicGraph<EdgeDataT> &graph)
|
||||||
{
|
{
|
||||||
storage::serialization::read(reader, graph.node_array);
|
storage::serialization::read(reader, graph.node_array);
|
||||||
auto num_edges = reader.ReadElementCount64();
|
const auto num_edges = reader.ReadElementCount64();
|
||||||
graph.edge_list.resize(num_edges);
|
graph.edge_list.resize(num_edges);
|
||||||
for (auto index : irange<std::size_t>(0, num_edges))
|
for (auto index : irange<std::size_t>(0, num_edges))
|
||||||
{
|
{
|
||||||
|
@ -51,16 +51,17 @@ static_assert(std::is_pod<OSMNodeID>(), "OSMNodeID is not a valid alias");
|
|||||||
using OSMWayID = osrm::Alias<std::uint64_t, tag::osm_way_id>;
|
using OSMWayID = osrm::Alias<std::uint64_t, tag::osm_way_id>;
|
||||||
static_assert(std::is_pod<OSMWayID>(), "OSMWayID is not a valid alias");
|
static_assert(std::is_pod<OSMWayID>(), "OSMWayID is not a valid alias");
|
||||||
|
|
||||||
static const OSMNodeID SPECIAL_OSM_NODEID = OSMNodeID{std::numeric_limits<std::uint64_t>::max()};
|
static const OSMNodeID SPECIAL_OSM_NODEID =
|
||||||
static const OSMWayID SPECIAL_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint64_t>::max()};
|
OSMNodeID{std::numeric_limits<OSMNodeID::value_type>::max()};
|
||||||
|
static const OSMWayID SPECIAL_OSM_WAYID =
|
||||||
|
OSMWayID{std::numeric_limits<OSMWayID::value_type>::max()};
|
||||||
|
|
||||||
static const OSMNodeID MAX_OSM_NODEID = OSMNodeID{std::numeric_limits<std::uint64_t>::max()};
|
static const OSMNodeID MAX_OSM_NODEID =
|
||||||
static const OSMNodeID MIN_OSM_NODEID = OSMNodeID{std::numeric_limits<std::uint64_t>::min()};
|
OSMNodeID{std::numeric_limits<OSMNodeID::value_type>::max()};
|
||||||
static const OSMWayID MAX_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint64_t>::max()};
|
static const OSMNodeID MIN_OSM_NODEID =
|
||||||
static const OSMWayID MIN_OSM_WAYID = OSMWayID{std::numeric_limits<std::uint64_t>::min()};
|
OSMNodeID{std::numeric_limits<OSMNodeID::value_type>::min()};
|
||||||
|
static const OSMWayID MAX_OSM_WAYID = OSMWayID{std::numeric_limits<OSMWayID::value_type>::max()};
|
||||||
using OSMNodeID_weak = std::uint64_t;
|
static const OSMWayID MIN_OSM_WAYID = OSMWayID{std::numeric_limits<OSMWayID::value_type>::min()};
|
||||||
using OSMEdgeID_weak = std::uint64_t;
|
|
||||||
|
|
||||||
using NodeID = std::uint32_t;
|
using NodeID = std::uint32_t;
|
||||||
using EdgeID = std::uint32_t;
|
using EdgeID = std::uint32_t;
|
||||||
|
@ -46,15 +46,13 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
|||||||
CompressedEdgeContainer &compressed_edge_container,
|
CompressedEdgeContainer &compressed_edge_container,
|
||||||
const std::unordered_set<NodeID> &barrier_nodes,
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
const std::unordered_set<NodeID> &traffic_lights,
|
const std::unordered_set<NodeID> &traffic_lights,
|
||||||
std::shared_ptr<const RestrictionMap> restriction_map,
|
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
const extractor::PackedOSMIDs &osm_node_ids,
|
const extractor::PackedOSMIDs &osm_node_ids,
|
||||||
ProfileProperties profile_properties,
|
ProfileProperties profile_properties,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
guidance::LaneDescriptionMap &lane_description_map)
|
guidance::LaneDescriptionMap &lane_description_map)
|
||||||
: m_max_edge_id(0), m_coordinates(coordinates), m_osm_node_ids(osm_node_ids),
|
: m_number_of_edge_based_nodes(0), m_coordinates(coordinates), m_osm_node_ids(osm_node_ids),
|
||||||
m_node_based_graph(std::move(node_based_graph)),
|
m_node_based_graph(std::move(node_based_graph)), m_barrier_nodes(barrier_nodes),
|
||||||
m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes),
|
|
||||||
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
|
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
|
||||||
profile_properties(std::move(profile_properties)), name_table(name_table),
|
profile_properties(std::move(profile_properties)), name_table(name_table),
|
||||||
lane_description_map(lane_description_map)
|
lane_description_map(lane_description_map)
|
||||||
@ -93,7 +91,10 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &out
|
|||||||
swap(m_edge_based_node_weights, output_node_weights);
|
swap(m_edge_based_node_weights, output_node_weights);
|
||||||
}
|
}
|
||||||
|
|
||||||
EdgeID EdgeBasedGraphFactory::GetHighestEdgeID() { return m_max_edge_id; }
|
std::uint64_t EdgeBasedGraphFactory::GetNumberOfEdgeBasedNodes() const
|
||||||
|
{
|
||||||
|
return m_number_of_edge_based_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v)
|
NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v)
|
||||||
{
|
{
|
||||||
@ -176,8 +177,8 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
|
|||||||
current_edge_target_coordinate_id,
|
current_edge_target_coordinate_id,
|
||||||
i);
|
i);
|
||||||
|
|
||||||
m_edge_based_node_is_startpoint.push_back(forward_data.startpoint ||
|
m_edge_based_node_is_startpoint.push_back(
|
||||||
reverse_data.startpoint);
|
(forward_data.startpoint || reverse_data.startpoint));
|
||||||
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
|
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,15 +193,17 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
|||||||
const std::string &turn_weight_penalties_filename,
|
const std::string &turn_weight_penalties_filename,
|
||||||
const std::string &turn_duration_penalties_filename,
|
const std::string &turn_duration_penalties_filename,
|
||||||
const std::string &turn_penalties_index_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)
|
||||||
{
|
{
|
||||||
TIMER_START(renumber);
|
TIMER_START(renumber);
|
||||||
m_max_edge_id = RenumberEdges() - 1;
|
m_number_of_edge_based_nodes = RenumberEdges() + way_restriction_map.NumberOfDuplicatedNodes();
|
||||||
TIMER_STOP(renumber);
|
TIMER_STOP(renumber);
|
||||||
|
|
||||||
TIMER_START(generate_nodes);
|
TIMER_START(generate_nodes);
|
||||||
{
|
{
|
||||||
auto mapping = GenerateEdgeExpandedNodes();
|
auto mapping = GenerateEdgeExpandedNodes(way_restriction_map);
|
||||||
files::writeNBGMapping(cnbg_ebg_mapping_path, mapping);
|
files::writeNBGMapping(cnbg_ebg_mapping_path, mapping);
|
||||||
}
|
}
|
||||||
TIMER_STOP(generate_nodes);
|
TIMER_STOP(generate_nodes);
|
||||||
@ -211,7 +214,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
|||||||
turn_lane_data_filename,
|
turn_lane_data_filename,
|
||||||
turn_weight_penalties_filename,
|
turn_weight_penalties_filename,
|
||||||
turn_duration_penalties_filename,
|
turn_duration_penalties_filename,
|
||||||
turn_penalties_index_filename);
|
turn_penalties_index_filename,
|
||||||
|
restriction_map,
|
||||||
|
way_restriction_map);
|
||||||
|
|
||||||
TIMER_STOP(generate_edges);
|
TIMER_STOP(generate_edges);
|
||||||
|
|
||||||
@ -257,14 +262,19 @@ unsigned EdgeBasedGraphFactory::RenumberEdges()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
||||||
std::vector<NBGToEBG> EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
std::vector<NBGToEBG>
|
||||||
|
EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map)
|
||||||
{
|
{
|
||||||
std::vector<NBGToEBG> mapping;
|
std::vector<NBGToEBG> mapping;
|
||||||
|
|
||||||
// Allocate memory for edge-based nodes
|
// Allocate memory for edge-based nodes
|
||||||
m_edge_based_node_container = EdgeBasedNodeDataContainer(m_max_edge_id + 1);
|
// In addition to the normal edges, allocate enough space for copied edges from
|
||||||
|
// via-way-restrictions
|
||||||
|
m_edge_based_node_container = EdgeBasedNodeDataContainer(m_number_of_edge_based_nodes);
|
||||||
|
|
||||||
util::Log() << "Generating edge expanded nodes ... ";
|
util::Log() << "Generating edge expanded nodes ... ";
|
||||||
|
// indicating a normal node within the edge-based graph. This node represents an edge in the
|
||||||
|
// node-based graph
|
||||||
{
|
{
|
||||||
util::UnbufferedLog log;
|
util::UnbufferedLog log;
|
||||||
util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
|
util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
|
||||||
@ -305,10 +315,55 @@ std::vector<NBGToEBG> EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(m_edge_based_node_segments.size() == m_edge_based_node_is_startpoint.size());
|
util::Log() << "Expanding via-way turn restrictions ... ";
|
||||||
BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size());
|
// Add copies of the nodes
|
||||||
|
{
|
||||||
|
util::UnbufferedLog log;
|
||||||
|
const auto via_ways = way_restriction_map.DuplicatedNodeRepresentatives();
|
||||||
|
util::Percent progress(log, via_ways.size());
|
||||||
|
|
||||||
util::Log() << "Generated " << (m_max_edge_id + 1) << " nodes and "
|
NodeID edge_based_node_id =
|
||||||
|
NodeID(m_number_of_edge_based_nodes - way_restriction_map.NumberOfDuplicatedNodes());
|
||||||
|
std::size_t progress_counter = 0;
|
||||||
|
// allocate enough space for the mapping
|
||||||
|
for (const auto way : via_ways)
|
||||||
|
{
|
||||||
|
const auto node_u = way.from;
|
||||||
|
const auto node_v = way.to;
|
||||||
|
// we know that the edge exists as non-reversed edge
|
||||||
|
const auto eid = m_node_based_graph->FindEdge(node_u, node_v);
|
||||||
|
|
||||||
|
BOOST_ASSERT(m_node_based_graph->GetEdgeData(eid).edge_id != SPECIAL_NODEID);
|
||||||
|
|
||||||
|
// merge edges together into one EdgeBasedNode
|
||||||
|
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||||
|
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||||
|
|
||||||
|
// find node in the edge based graph, we only require one id:
|
||||||
|
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(eid);
|
||||||
|
// what is this ID all about? :(
|
||||||
|
BOOST_ASSERT(edge_data.edge_id != SPECIAL_NODEID);
|
||||||
|
|
||||||
|
BOOST_ASSERT(edge_data.edge_id < m_edge_based_node_container.Size());
|
||||||
|
m_edge_based_node_container.SetData(
|
||||||
|
edge_based_node_id,
|
||||||
|
// fetch the known geometry ID
|
||||||
|
m_edge_based_node_container.GetGeometryID(static_cast<NodeID>(edge_data.edge_id)),
|
||||||
|
edge_data.name_id,
|
||||||
|
edge_data.travel_mode,
|
||||||
|
edge_data.classes);
|
||||||
|
|
||||||
|
m_edge_based_node_weights.push_back(m_edge_based_node_weights[eid]);
|
||||||
|
|
||||||
|
edge_based_node_id++;
|
||||||
|
progress.PrintStatus(progress_counter++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(m_edge_based_node_segments.size() == m_edge_based_node_is_startpoint.size());
|
||||||
|
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_weights.size());
|
||||||
|
|
||||||
|
util::Log() << "Generated " << m_number_of_edge_based_nodes << " nodes and "
|
||||||
<< m_edge_based_node_segments.size() << " segments in edge-expanded graph";
|
<< m_edge_based_node_segments.size() << " segments in edge-expanded graph";
|
||||||
|
|
||||||
return mapping;
|
return mapping;
|
||||||
@ -321,7 +376,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
const std::string &turn_lane_data_filename,
|
const std::string &turn_lane_data_filename,
|
||||||
const std::string &turn_weight_penalties_filename,
|
const std::string &turn_weight_penalties_filename,
|
||||||
const std::string &turn_duration_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)
|
||||||
{
|
{
|
||||||
|
|
||||||
util::Log() << "Generating edge-expanded edges ";
|
util::Log() << "Generating edge-expanded edges ";
|
||||||
@ -342,7 +399,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
SuffixTable street_name_suffix_table(scripting_environment);
|
SuffixTable street_name_suffix_table(scripting_environment);
|
||||||
guidance::TurnAnalysis turn_analysis(*m_node_based_graph,
|
guidance::TurnAnalysis turn_analysis(*m_node_based_graph,
|
||||||
m_coordinates,
|
m_coordinates,
|
||||||
*m_restriction_map,
|
restriction_map,
|
||||||
m_barrier_nodes,
|
m_barrier_nodes,
|
||||||
m_compressed_edge_container,
|
m_compressed_edge_container,
|
||||||
name_table,
|
name_table,
|
||||||
@ -410,7 +467,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
// appended to the various output arrays/files by the `output_stage`.
|
// appended to the various output arrays/files by the `output_stage`.
|
||||||
struct IntersectionData
|
struct IntersectionData
|
||||||
{
|
{
|
||||||
std::size_t nodes_processed = 0;
|
|
||||||
std::vector<lookup::TurnIndexBlock> turn_indexes;
|
std::vector<lookup::TurnIndexBlock> turn_indexes;
|
||||||
std::vector<EdgeBasedEdge> edges_list;
|
std::vector<EdgeBasedEdge> edges_list;
|
||||||
std::vector<TurnPenalty> turn_weight_penalties;
|
std::vector<TurnPenalty> turn_weight_penalties;
|
||||||
@ -418,13 +474,138 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
std::vector<TurnData> turn_data_container;
|
std::vector<TurnData> turn_data_container;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// same as IntersectionData, but grouped with edge to allow sorting after creating. Edges
|
||||||
|
// are out of order
|
||||||
|
struct EdgeWithData
|
||||||
|
{
|
||||||
|
EdgeBasedEdge edge;
|
||||||
|
lookup::TurnIndexBlock turn_index;
|
||||||
|
TurnPenalty turn_weight_penalty;
|
||||||
|
TurnPenalty turn_duration_penalty;
|
||||||
|
TurnData turn_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PipelineBuffer
|
||||||
|
{
|
||||||
|
std::size_t nodes_processed = 0;
|
||||||
|
IntersectionData continuous_data;
|
||||||
|
std::vector<EdgeWithData> delayed_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// add into delayed data
|
||||||
|
const auto delayed_inserter = [](const auto &edge_with_data, auto &buffer) {
|
||||||
|
buffer.delayed_data.push_back(edge_with_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// add into main data
|
||||||
|
const auto continuous_inserter = [](const auto &edge_with_data, auto &buffer) {
|
||||||
|
buffer.continuous_data.edges_list.push_back(edge_with_data.edge);
|
||||||
|
buffer.continuous_data.turn_indexes.push_back(edge_with_data.turn_index);
|
||||||
|
buffer.continuous_data.turn_weight_penalties.push_back(
|
||||||
|
edge_with_data.turn_weight_penalty);
|
||||||
|
buffer.continuous_data.turn_duration_penalties.push_back(
|
||||||
|
edge_with_data.turn_duration_penalty);
|
||||||
|
buffer.continuous_data.turn_data_container.push_back(edge_with_data.turn_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate edges for either artificial nodes or the main graph
|
||||||
|
const auto generate_edges = [this, &scripting_environment, weight_multiplier](
|
||||||
|
// what nodes will be used? In most cases this will be the id stored in the edge_data.
|
||||||
|
// In case of duplicated nodes (e.g. due to via-way restrictions), one/both of these
|
||||||
|
// might refer to a newly added edge based node
|
||||||
|
const auto edge_based_node_from,
|
||||||
|
const auto edge_based_node_to,
|
||||||
|
// the situation of the turn
|
||||||
|
const auto node_along_road_entering,
|
||||||
|
const auto node_based_edge_from,
|
||||||
|
const auto node_at_center_of_intersection,
|
||||||
|
const auto node_based_edge_to,
|
||||||
|
const auto &intersection,
|
||||||
|
const auto &turn,
|
||||||
|
const auto entry_class_id,
|
||||||
|
// we require a sorted output, additional nodes are collected and added after the
|
||||||
|
// sorting is done Here we can specify how/where to add the data
|
||||||
|
auto inserter,
|
||||||
|
auto &output_buffer) {
|
||||||
|
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(node_based_edge_from);
|
||||||
|
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(node_based_edge_to);
|
||||||
|
|
||||||
|
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
||||||
|
BOOST_ASSERT(!edge_data1.reversed);
|
||||||
|
BOOST_ASSERT(!edge_data2.reversed);
|
||||||
|
|
||||||
|
// the following is the core of the loop.
|
||||||
|
TurnData turn_data = {turn.instruction,
|
||||||
|
turn.lane_data_id,
|
||||||
|
entry_class_id,
|
||||||
|
util::guidance::TurnBearing(intersection[0].bearing),
|
||||||
|
util::guidance::TurnBearing(turn.bearing)};
|
||||||
|
|
||||||
|
// compute weight and duration penalties
|
||||||
|
auto is_traffic_light = m_traffic_lights.count(node_at_center_of_intersection);
|
||||||
|
ExtractionTurn extracted_turn(turn, is_traffic_light);
|
||||||
|
extracted_turn.source_restricted = edge_data1.restricted;
|
||||||
|
extracted_turn.target_restricted = edge_data2.restricted;
|
||||||
|
scripting_environment.ProcessTurn(extracted_turn);
|
||||||
|
|
||||||
|
// turn penalties are limited to [-2^15, 2^15) which roughly
|
||||||
|
// translates to 54 minutes and fits signed 16bit deci-seconds
|
||||||
|
auto weight_penalty =
|
||||||
|
boost::numeric_cast<TurnPenalty>(extracted_turn.weight * weight_multiplier);
|
||||||
|
auto duration_penalty = boost::numeric_cast<TurnPenalty>(extracted_turn.duration * 10.);
|
||||||
|
|
||||||
|
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
|
||||||
|
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
|
||||||
|
|
||||||
|
// auto turn_id = m_edge_based_edge_list.size();
|
||||||
|
auto weight = boost::numeric_cast<EdgeWeight>(edge_data1.weight + weight_penalty);
|
||||||
|
auto duration = boost::numeric_cast<EdgeWeight>(edge_data1.duration + duration_penalty);
|
||||||
|
|
||||||
|
EdgeBasedEdge edge_based_edge = {
|
||||||
|
edge_based_node_from,
|
||||||
|
edge_based_node_to,
|
||||||
|
SPECIAL_NODEID, // This will be updated once the main loop
|
||||||
|
// completes!
|
||||||
|
weight,
|
||||||
|
duration,
|
||||||
|
true,
|
||||||
|
false};
|
||||||
|
|
||||||
|
// We write out the mapping between the edge-expanded edges and
|
||||||
|
// the original nodes. Since each edge represents a possible
|
||||||
|
// maneuver, external programs can use this to quickly perform updates to edge
|
||||||
|
// weights in order to penalize certain turns.
|
||||||
|
|
||||||
|
// If this edge is 'trivial' -- where the compressed edge
|
||||||
|
// corresponds exactly to an original OSM segment -- we can pull the turn's
|
||||||
|
// preceding node ID directly with `node_along_road_entering`;
|
||||||
|
// otherwise, we need to look up the node immediately preceding the turn
|
||||||
|
// from the compressed edge container.
|
||||||
|
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
|
||||||
|
|
||||||
|
const auto &from_node =
|
||||||
|
isTrivial ? node_along_road_entering
|
||||||
|
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
|
||||||
|
const auto &via_node =
|
||||||
|
m_compressed_edge_container.GetLastEdgeTargetID(node_based_edge_from);
|
||||||
|
const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
|
||||||
|
|
||||||
|
lookup::TurnIndexBlock turn_index_block = {from_node, via_node, to_node};
|
||||||
|
|
||||||
|
// insert data into the designated buffer
|
||||||
|
inserter(
|
||||||
|
EdgeWithData{
|
||||||
|
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data},
|
||||||
|
output_buffer);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// Second part of the pipeline is where the intersection analysis is done for
|
// Second part of the pipeline is where the intersection analysis is done for
|
||||||
// each intersection
|
// each intersection
|
||||||
tbb::filter_t<tbb::blocked_range<NodeID>, std::shared_ptr<IntersectionData>>
|
tbb::filter_t<tbb::blocked_range<NodeID>, std::shared_ptr<PipelineBuffer>> processor_stage(
|
||||||
processor_stage(
|
|
||||||
tbb::filter::parallel, [&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
tbb::filter::parallel, [&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
||||||
|
|
||||||
auto buffer = std::make_shared<IntersectionData>();
|
auto buffer = std::make_shared<PipelineBuffer>();
|
||||||
buffer->nodes_processed =
|
buffer->nodes_processed =
|
||||||
intersection_node_range.end() - intersection_node_range.begin();
|
intersection_node_range.end() - intersection_node_range.begin();
|
||||||
|
|
||||||
@ -514,92 +695,105 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
bearing_class_by_node_based_node[node_at_center_of_intersection] =
|
bearing_class_by_node_based_node[node_at_center_of_intersection] =
|
||||||
bearing_class_id;
|
bearing_class_id;
|
||||||
|
|
||||||
|
// check if we are turning off a via way
|
||||||
|
const auto turning_off_via_way = way_restriction_map.IsViaWay(
|
||||||
|
node_along_road_entering, node_at_center_of_intersection);
|
||||||
|
|
||||||
for (const auto &turn : intersection)
|
for (const auto &turn : intersection)
|
||||||
{
|
{
|
||||||
// only keep valid turns
|
// only keep valid turns
|
||||||
if (!turn.entry_allowed)
|
if (!turn.entry_allowed)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// only add an edge if turn is not prohibited
|
|
||||||
const EdgeData &edge_data1 =
|
const EdgeData &edge_data1 =
|
||||||
m_node_based_graph->GetEdgeData(incoming_edge);
|
m_node_based_graph->GetEdgeData(incoming_edge);
|
||||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
|
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
|
||||||
|
|
||||||
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
// In case a way restriction starts at a given location, add a turn onto
|
||||||
BOOST_ASSERT(!edge_data1.reversed);
|
// every artificial node eminating here.
|
||||||
BOOST_ASSERT(!edge_data2.reversed);
|
//
|
||||||
|
// e - f
|
||||||
// the following is the core of the loop.
|
// |
|
||||||
buffer->turn_data_container.push_back(
|
// a - b
|
||||||
{turn.instruction,
|
// |
|
||||||
turn.lane_data_id,
|
// c - d
|
||||||
entry_class_id,
|
//
|
||||||
util::guidance::TurnBearing(intersection[0].bearing),
|
// ab via bc to cd
|
||||||
util::guidance::TurnBearing(turn.bearing)});
|
// ab via be to ef
|
||||||
|
//
|
||||||
// compute weight and duration penalties
|
// has two artifical nodes (be/bc) with restrictions starting at `ab`.
|
||||||
auto is_traffic_light =
|
// Since every restriction group (abc | abe) refers to the same
|
||||||
m_traffic_lights.count(node_at_center_of_intersection);
|
// artificial node, we simply have to find a single representative for
|
||||||
ExtractionTurn extracted_turn(turn, is_traffic_light);
|
// the turn. Here we check whether the turn in question is the start of
|
||||||
extracted_turn.source_restricted = edge_data1.restricted;
|
// a via way restriction. If that should be the case, we switch
|
||||||
extracted_turn.target_restricted = edge_data2.restricted;
|
// edge_data2.edge_id to the ID of the duplicated node associated with
|
||||||
scripting_environment.ProcessTurn(extracted_turn);
|
// the turn. (e.g. ab via bc switches bc to bc_dup)
|
||||||
|
auto const target_id = way_restriction_map.RemapIfRestricted(
|
||||||
// turn penalties are limited to [-2^15, 2^15) which roughly
|
|
||||||
// translates to 54 minutes and fits signed 16bit deci-seconds
|
|
||||||
auto weight_penalty = boost::numeric_cast<TurnPenalty>(
|
|
||||||
extracted_turn.weight * weight_multiplier);
|
|
||||||
auto duration_penalty =
|
|
||||||
boost::numeric_cast<TurnPenalty>(extracted_turn.duration * 10.);
|
|
||||||
|
|
||||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
|
|
||||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
|
|
||||||
|
|
||||||
// auto turn_id = m_edge_based_edge_list.size();
|
|
||||||
auto weight =
|
|
||||||
boost::numeric_cast<EdgeWeight>(edge_data1.weight + weight_penalty);
|
|
||||||
auto duration = boost::numeric_cast<EdgeWeight>(edge_data1.duration +
|
|
||||||
duration_penalty);
|
|
||||||
buffer->edges_list.emplace_back(
|
|
||||||
edge_data1.edge_id,
|
|
||||||
edge_data2.edge_id,
|
edge_data2.edge_id,
|
||||||
SPECIAL_NODEID, // This will be updated once the main loop
|
node_along_road_entering,
|
||||||
// completes!
|
node_at_center_of_intersection,
|
||||||
weight,
|
m_node_based_graph->GetTarget(turn.eid),
|
||||||
duration,
|
m_number_of_edge_based_nodes);
|
||||||
true,
|
|
||||||
false);
|
|
||||||
|
|
||||||
BOOST_ASSERT(buffer->turn_weight_penalties.size() ==
|
generate_edges(edge_data1.edge_id,
|
||||||
buffer->edges_list.size() - 1);
|
target_id,
|
||||||
buffer->turn_weight_penalties.push_back(weight_penalty);
|
node_along_road_entering,
|
||||||
BOOST_ASSERT(buffer->turn_duration_penalties.size() ==
|
incoming_edge,
|
||||||
buffer->edges_list.size() - 1);
|
node_at_center_of_intersection,
|
||||||
buffer->turn_duration_penalties.push_back(duration_penalty);
|
turn.eid,
|
||||||
|
intersection,
|
||||||
|
turn,
|
||||||
|
entry_class_id,
|
||||||
|
continuous_inserter,
|
||||||
|
*buffer);
|
||||||
|
|
||||||
// We write out the mapping between the edge-expanded edges and the
|
// when turning off a a via-way turn restriction, we need to not only
|
||||||
// original nodes. Since each edge represents a possible maneuver,
|
// handle the normal edges for the way, but also add turns for every
|
||||||
// external programs can use this to quickly perform updates to edge
|
// duplicated node. This process is integrated here to avoid doing the
|
||||||
// weights in order to penalize certain turns.
|
// turn analysis multiple times.
|
||||||
|
if (turning_off_via_way)
|
||||||
|
{
|
||||||
|
const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs(
|
||||||
|
node_along_road_entering, node_at_center_of_intersection);
|
||||||
|
|
||||||
// If this edge is 'trivial' -- where the compressed edge corresponds
|
// next to the normal restrictions tracked in `entry_allowed`, via
|
||||||
// exactly to an original OSM segment -- we can pull the turn's
|
// ways might introduce additional restrictions. These are handled
|
||||||
// preceding node ID directly with `node_along_road_entering`;
|
// here when turning off a via-way
|
||||||
// otherwise, we need to look up the node immediately preceding the turn
|
const auto add_unrestricted_turns =
|
||||||
// from the compressed edge container.
|
[&](const auto duplicated_node_id) {
|
||||||
const bool isTrivial =
|
const auto from_id =
|
||||||
m_compressed_edge_container.IsTrivial(incoming_edge);
|
m_number_of_edge_based_nodes -
|
||||||
|
way_restriction_map.NumberOfDuplicatedNodes() +
|
||||||
|
duplicated_node_id;
|
||||||
|
|
||||||
const auto &from_node =
|
auto const node_at_end_of_turn =
|
||||||
isTrivial ? node_along_road_entering
|
m_node_based_graph->GetTarget(turn.eid);
|
||||||
: m_compressed_edge_container.GetLastEdgeSourceID(
|
|
||||||
incoming_edge);
|
|
||||||
const auto &via_node =
|
|
||||||
m_compressed_edge_container.GetLastEdgeTargetID(incoming_edge);
|
|
||||||
const auto &to_node =
|
|
||||||
m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
|
|
||||||
|
|
||||||
buffer->turn_indexes.push_back({from_node, via_node, to_node});
|
const auto is_restricted = way_restriction_map.IsRestricted(
|
||||||
|
duplicated_node_id, node_at_end_of_turn);
|
||||||
|
|
||||||
|
if (is_restricted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
generate_edges(
|
||||||
|
NodeID(from_id),
|
||||||
|
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
|
||||||
|
node_along_road_entering,
|
||||||
|
incoming_edge,
|
||||||
|
node_at_center_of_intersection,
|
||||||
|
turn.eid,
|
||||||
|
intersection,
|
||||||
|
turn,
|
||||||
|
entry_class_id,
|
||||||
|
delayed_inserter,
|
||||||
|
*buffer);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::for_each(duplicated_nodes.begin(),
|
||||||
|
duplicated_nodes.end(),
|
||||||
|
add_unrestricted_turns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -616,36 +810,42 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
std::vector<lookup::TurnIndexBlock> turn_indexes_write_buffer;
|
std::vector<lookup::TurnIndexBlock> turn_indexes_write_buffer;
|
||||||
turn_indexes_write_buffer.reserve(TURN_INDEX_WRITE_BUFFER_SIZE);
|
turn_indexes_write_buffer.reserve(TURN_INDEX_WRITE_BUFFER_SIZE);
|
||||||
|
|
||||||
// Last part of the pipeline puts all the calculated data into the serial buffers
|
std::vector<EdgeWithData> delayed_data;
|
||||||
tbb::filter_t<std::shared_ptr<IntersectionData>, void> output_stage(
|
|
||||||
tbb::filter::serial_in_order, [&](const std::shared_ptr<IntersectionData> buffer) {
|
|
||||||
|
|
||||||
|
auto const append_data_to_output = [&](IntersectionData const &data) {
|
||||||
|
// NOTE: potential overflow here if we hit 2^32 routable edges
|
||||||
|
m_edge_based_edge_list.append(data.edges_list.begin(), data.edges_list.end());
|
||||||
|
|
||||||
|
BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
|
||||||
|
|
||||||
|
turn_weight_penalties.insert(turn_weight_penalties.end(),
|
||||||
|
data.turn_weight_penalties.begin(),
|
||||||
|
data.turn_weight_penalties.end());
|
||||||
|
turn_duration_penalties.insert(turn_duration_penalties.end(),
|
||||||
|
data.turn_duration_penalties.begin(),
|
||||||
|
data.turn_duration_penalties.end());
|
||||||
|
turn_data_container.append(data.turn_data_container);
|
||||||
|
turn_indexes_write_buffer.insert(turn_indexes_write_buffer.end(),
|
||||||
|
data.turn_indexes.begin(),
|
||||||
|
data.turn_indexes.end());
|
||||||
|
|
||||||
|
// Buffer writes to reduce syscall count
|
||||||
|
if (turn_indexes_write_buffer.size() >= TURN_INDEX_WRITE_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
turn_penalties_index_file.WriteFrom(turn_indexes_write_buffer.data(),
|
||||||
|
turn_indexes_write_buffer.size());
|
||||||
|
turn_indexes_write_buffer.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Last part of the pipeline puts all the calculated data into the serial buffers
|
||||||
|
tbb::filter_t<std::shared_ptr<PipelineBuffer>, void> output_stage(
|
||||||
|
tbb::filter::serial_in_order, [&](const std::shared_ptr<PipelineBuffer> buffer) {
|
||||||
nodes_completed += buffer->nodes_processed;
|
nodes_completed += buffer->nodes_processed;
|
||||||
progress.PrintStatus(nodes_completed);
|
progress.PrintStatus(nodes_completed);
|
||||||
|
append_data_to_output(buffer->continuous_data);
|
||||||
// NOTE: potential overflow here if we hit 2^32 routable edges
|
delayed_data.insert(
|
||||||
m_edge_based_edge_list.append(buffer->edges_list.begin(), buffer->edges_list.end());
|
delayed_data.end(), buffer->delayed_data.begin(), buffer->delayed_data.end());
|
||||||
BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
|
|
||||||
|
|
||||||
turn_weight_penalties.insert(turn_weight_penalties.end(),
|
|
||||||
buffer->turn_weight_penalties.begin(),
|
|
||||||
buffer->turn_weight_penalties.end());
|
|
||||||
turn_duration_penalties.insert(turn_duration_penalties.end(),
|
|
||||||
buffer->turn_duration_penalties.begin(),
|
|
||||||
buffer->turn_duration_penalties.end());
|
|
||||||
turn_data_container.append(buffer->turn_data_container);
|
|
||||||
|
|
||||||
turn_indexes_write_buffer.insert(turn_indexes_write_buffer.end(),
|
|
||||||
buffer->turn_indexes.begin(),
|
|
||||||
buffer->turn_indexes.end());
|
|
||||||
|
|
||||||
// Buffer writes to reduce syscall count
|
|
||||||
if (turn_indexes_write_buffer.size() >= TURN_INDEX_WRITE_BUFFER_SIZE)
|
|
||||||
{
|
|
||||||
turn_penalties_index_file.WriteFrom(turn_indexes_write_buffer.data(),
|
|
||||||
turn_indexes_write_buffer.size());
|
|
||||||
turn_indexes_write_buffer.clear();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now, execute the pipeline. The value of "5" here was chosen by experimentation
|
// Now, execute the pipeline. The value of "5" here was chosen by experimentation
|
||||||
@ -656,6 +856,18 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5,
|
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5,
|
||||||
generator_stage & processor_stage & output_stage);
|
generator_stage & processor_stage & output_stage);
|
||||||
|
|
||||||
|
std::sort(delayed_data.begin(), delayed_data.end(), [](auto const &lhs, auto const &rhs) {
|
||||||
|
return lhs.edge.source < rhs.edge.source;
|
||||||
|
});
|
||||||
|
auto const transfer_data = [&](auto const &edge_with_data) {
|
||||||
|
m_edge_based_edge_list.push_back(edge_with_data.edge);
|
||||||
|
turn_weight_penalties.push_back(edge_with_data.turn_weight_penalty);
|
||||||
|
turn_duration_penalties.push_back(edge_with_data.turn_duration_penalty);
|
||||||
|
turn_data_container.push_back(edge_with_data.turn_data);
|
||||||
|
turn_indexes_write_buffer.push_back(edge_with_data.turn_index);
|
||||||
|
};
|
||||||
|
std::for_each(delayed_data.begin(), delayed_data.end(), transfer_data);
|
||||||
|
|
||||||
// Flush the turn_indexes_write_buffer if it's not empty
|
// Flush the turn_indexes_write_buffer if it's not empty
|
||||||
if (!turn_indexes_write_buffer.empty())
|
if (!turn_indexes_write_buffer.empty())
|
||||||
{
|
{
|
||||||
@ -715,7 +927,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
|
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
|
||||||
util::Log() << " skips " << restricted_turns_counter << " turns, "
|
util::Log() << " skips " << restricted_turns_counter << " turns, "
|
||||||
"defined by "
|
"defined by "
|
||||||
<< m_restriction_map->size() << " restrictions";
|
<< restriction_map.size() << " restrictions";
|
||||||
util::Log() << " skips " << skipped_uturns_counter << " U turns";
|
util::Log() << " skips " << skipped_uturns_counter << " U turns";
|
||||||
util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
|
util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
|
||||||
}
|
}
|
||||||
|
@ -668,16 +668,16 @@ void ExtractionContainers::PrepareRestrictions()
|
|||||||
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||||
{
|
{
|
||||||
const auto &way = turn_restriction.AsWayRestriction();
|
const auto &way = turn_restriction.AsWayRestriction();
|
||||||
referenced_ways[OSMWayID{way.from}] = dummy_segment;
|
referenced_ways[way.from] = dummy_segment;
|
||||||
referenced_ways[OSMWayID{way.to}] = dummy_segment;
|
referenced_ways[way.to] = dummy_segment;
|
||||||
referenced_ways[OSMWayID{way.via}] = dummy_segment;
|
referenced_ways[way.via] = dummy_segment;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||||
const auto &node = turn_restriction.AsNodeRestriction();
|
const auto &node = turn_restriction.AsNodeRestriction();
|
||||||
referenced_ways[OSMWayID{node.from}] = dummy_segment;
|
referenced_ways[node.from] = dummy_segment;
|
||||||
referenced_ways[OSMWayID{node.to}] = dummy_segment;
|
referenced_ways[node.to] = dummy_segment;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -702,7 +702,7 @@ void ExtractionContainers::PrepareRestrictions()
|
|||||||
|
|
||||||
auto const to_internal = [&](auto const osm_node) {
|
auto const to_internal = [&](auto const osm_node) {
|
||||||
auto internal = mapExternalToInternalNodeID(
|
auto internal = mapExternalToInternalNodeID(
|
||||||
used_node_id_list.begin(), used_node_id_list.end(), OSMNodeID{osm_node});
|
used_node_id_list.begin(), used_node_id_list.end(), osm_node);
|
||||||
if (internal == SPECIAL_NODEID)
|
if (internal == SPECIAL_NODEID)
|
||||||
{
|
{
|
||||||
util::Log(logDEBUG) << "Restriction references invalid node: " << osm_node;
|
util::Log(logDEBUG) << "Restriction references invalid node: " << osm_node;
|
||||||
@ -763,15 +763,15 @@ void ExtractionContainers::PrepareRestrictions()
|
|||||||
// be connected at a single location)
|
// be connected at a single location)
|
||||||
auto const get_node_restriction_from_OSM_ids = [&](
|
auto const get_node_restriction_from_OSM_ids = [&](
|
||||||
auto const from_id, auto const to_id, const OSMNodeID via_node = MAX_OSM_NODEID) {
|
auto const from_id, auto const to_id, const OSMNodeID via_node = MAX_OSM_NODEID) {
|
||||||
auto const from_segment_itr = referenced_ways.find(OSMWayID{from_id});
|
auto const from_segment_itr = referenced_ways.find(from_id);
|
||||||
if (from_segment_itr->second.way_id != OSMWayID{from_id})
|
if (from_segment_itr->second.way_id != from_id)
|
||||||
{
|
{
|
||||||
util::Log(logDEBUG) << "Restriction references invalid way: " << from_id;
|
util::Log(logDEBUG) << "Restriction references invalid way: " << from_id;
|
||||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const to_segment_itr = referenced_ways.find(OSMWayID{to_id});
|
auto const to_segment_itr = referenced_ways.find(to_id);
|
||||||
if (to_segment_itr->second.way_id != OSMWayID{to_id})
|
if (to_segment_itr->second.way_id != to_id)
|
||||||
{
|
{
|
||||||
util::Log(logDEBUG) << "Restriction references invalid way: " << to_id;
|
util::Log(logDEBUG) << "Restriction references invalid way: " << to_id;
|
||||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||||
@ -781,7 +781,7 @@ void ExtractionContainers::PrepareRestrictions()
|
|||||||
|
|
||||||
// transform an OSMRestriction (based on WayIDs) into an OSRM restriction (base on NodeIDs)
|
// transform an OSMRestriction (based on WayIDs) into an OSRM restriction (base on NodeIDs)
|
||||||
// returns true on successful transformation, false in case of invalid references
|
// returns true on successful transformation, false in case of invalid references
|
||||||
const auto transform = [&](auto const &external_type, auto &internal_type) {
|
const auto transform = [&](const auto &external_type, auto &internal_type) {
|
||||||
if (external_type.Type() == RestrictionType::WAY_RESTRICTION)
|
if (external_type.Type() == RestrictionType::WAY_RESTRICTION)
|
||||||
{
|
{
|
||||||
auto const &external = external_type.AsWayRestriction();
|
auto const &external = external_type.AsWayRestriction();
|
||||||
@ -808,12 +808,11 @@ void ExtractionContainers::PrepareRestrictions()
|
|||||||
auto const via_node = to_internal(external.via);
|
auto const via_node = to_internal(external.via);
|
||||||
|
|
||||||
// check if we were able to resolve all the involved ways
|
// check if we were able to resolve all the involved ways
|
||||||
auto restriction = get_node_restriction_from_OSM_ids(
|
auto restriction =
|
||||||
external.from, external.to, OSMNodeID{external.via});
|
get_node_restriction_from_OSM_ids(external.from, external.to, external.via);
|
||||||
|
|
||||||
if (!restriction.Valid())
|
if (!restriction.Valid())
|
||||||
{
|
{
|
||||||
std::cout << " >>> Invalid" << std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -830,25 +829,26 @@ void ExtractionContainers::PrepareRestrictions()
|
|||||||
|
|
||||||
// wrapper function to handle distinction between conditional and unconditional turn
|
// wrapper function to handle distinction between conditional and unconditional turn
|
||||||
// restrictions
|
// restrictions
|
||||||
const auto transform_into_internal_types = [&](auto &external_restriction) {
|
const auto transform_into_internal_types =
|
||||||
// unconditional restriction
|
[&](const InputConditionalTurnRestriction &external_restriction) {
|
||||||
if (external_restriction.condition.empty())
|
// unconditional restriction
|
||||||
{
|
if (external_restriction.condition.empty())
|
||||||
TurnRestriction restriction;
|
{
|
||||||
restriction.flags = external_restriction.flags;
|
TurnRestriction restriction;
|
||||||
if (transform(external_restriction, restriction))
|
restriction.is_only = external_restriction.is_only;
|
||||||
unconditional_turn_restrictions.push_back(restriction);
|
if (transform(external_restriction, restriction))
|
||||||
}
|
unconditional_turn_restrictions.push_back(restriction);
|
||||||
// conditional turn restriction
|
}
|
||||||
else
|
// conditional turn restriction
|
||||||
{
|
else
|
||||||
ConditionalTurnRestriction restriction;
|
{
|
||||||
restriction.flags = external_restriction.flags;
|
ConditionalTurnRestriction restriction;
|
||||||
restriction.condition = std::move(external_restriction.condition);
|
restriction.is_only = external_restriction.is_only;
|
||||||
if (transform(external_restriction, restriction))
|
restriction.condition = std::move(external_restriction.condition);
|
||||||
conditional_turn_restrictions.push_back(restriction);
|
if (transform(external_restriction, restriction))
|
||||||
}
|
conditional_turn_restrictions.push_back(restriction);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Transforming the restrictions into the dedicated internal types
|
// Transforming the restrictions into the dedicated internal types
|
||||||
{
|
{
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "extractor/compressed_edge_container.hpp"
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
#include "extractor/restriction_map.hpp"
|
#include "extractor/restriction_map.hpp"
|
||||||
|
#include "extractor/way_restriction_map.hpp"
|
||||||
#include "util/static_graph.hpp"
|
#include "util/static_graph.hpp"
|
||||||
#include "util/static_rtree.hpp"
|
#include "util/static_rtree.hpp"
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
|||||||
turn_lane_map);
|
turn_lane_map);
|
||||||
|
|
||||||
auto number_of_node_based_nodes = graph_size.first;
|
auto number_of_node_based_nodes = graph_size.first;
|
||||||
auto max_edge_id = graph_size.second;
|
auto max_edge_id = graph_size.second - 1;
|
||||||
|
|
||||||
TIMER_STOP(expansion);
|
TIMER_STOP(expansion);
|
||||||
|
|
||||||
@ -470,26 +471,36 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
|||||||
|
|
||||||
util::NameTable name_table(config.GetPath(".osrm.names").string());
|
util::NameTable name_table(config.GetPath(".osrm.names").string());
|
||||||
|
|
||||||
auto restriction_map = std::make_shared<RestrictionMap>(turn_restrictions);
|
EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph,
|
||||||
EdgeBasedGraphFactory edge_based_graph_factory(
|
compressed_edge_container,
|
||||||
node_based_graph,
|
barrier_nodes,
|
||||||
compressed_edge_container,
|
traffic_lights,
|
||||||
barrier_nodes,
|
coordinates,
|
||||||
traffic_lights,
|
osm_node_ids,
|
||||||
std::const_pointer_cast<RestrictionMap const>(restriction_map),
|
scripting_environment.GetProfileProperties(),
|
||||||
coordinates,
|
name_table,
|
||||||
osm_node_ids,
|
turn_lane_map);
|
||||||
scripting_environment.GetProfileProperties(),
|
|
||||||
name_table,
|
|
||||||
turn_lane_map);
|
|
||||||
|
|
||||||
edge_based_graph_factory.Run(scripting_environment,
|
const auto create_edge_based_edges = [&]() {
|
||||||
config.GetPath(".osrm.edges").string(),
|
// scoped to relase intermediate datastructures right after the call
|
||||||
config.GetPath(".osrm.tld").string(),
|
RestrictionMap via_node_restriction_map(turn_restrictions);
|
||||||
config.GetPath(".osrm.turn_weight_penalties").string(),
|
WayRestrictionMap via_way_restriction_map(turn_restrictions);
|
||||||
config.GetPath(".osrm.turn_duration_penalties").string(),
|
turn_restrictions.clear();
|
||||||
config.GetPath(".osrm.turn_penalties_index").string(),
|
turn_restrictions.shrink_to_fit();
|
||||||
config.GetPath(".osrm.cnbg_to_ebg").string());
|
|
||||||
|
edge_based_graph_factory.Run(scripting_environment,
|
||||||
|
config.GetPath(".osrm.edges").string(),
|
||||||
|
config.GetPath(".osrm.tld").string(),
|
||||||
|
config.GetPath(".osrm.turn_weight_penalties").string(),
|
||||||
|
config.GetPath(".osrm.turn_duration_penalties").string(),
|
||||||
|
config.GetPath(".osrm.turn_penalties_index").string(),
|
||||||
|
config.GetPath(".osrm.cnbg_to_ebg").string(),
|
||||||
|
via_node_restriction_map,
|
||||||
|
via_way_restriction_map);
|
||||||
|
return edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto number_of_edge_based_nodes = create_edge_based_edges();
|
||||||
|
|
||||||
compressed_edge_container.PrintStatistics();
|
compressed_edge_container.PrintStatistics();
|
||||||
|
|
||||||
@ -531,7 +542,6 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
|||||||
edge_based_graph_factory.GetEdgeBasedNodeSegments(edge_based_node_segments);
|
edge_based_graph_factory.GetEdgeBasedNodeSegments(edge_based_node_segments);
|
||||||
edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
|
edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
|
||||||
edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
|
edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
|
||||||
auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID();
|
|
||||||
|
|
||||||
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
|
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
|
||||||
|
|
||||||
@ -545,7 +555,7 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
|||||||
TIMER_STOP(write_intersections);
|
TIMER_STOP(write_intersections);
|
||||||
util::Log() << "ok, after " << TIMER_SEC(write_intersections) << "s";
|
util::Log() << "ok, after " << TIMER_SEC(write_intersections) << "s";
|
||||||
|
|
||||||
return std::make_pair(number_of_node_based_nodes, max_edge_id);
|
return std::make_pair(number_of_node_based_nodes, number_of_edge_based_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,7 +47,7 @@ RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_l
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (restriction.flags.is_only)
|
else if (restriction.is_only)
|
||||||
{
|
{
|
||||||
// We are going to insert an is_only_*-restriction. There can be only one.
|
// We are going to insert an is_only_*-restriction. There can be only one.
|
||||||
m_count -= m_restriction_bucket_list.at(index).size();
|
m_count -= m_restriction_bucket_list.at(index).size();
|
||||||
@ -55,8 +55,7 @@ RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_l
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
++m_count;
|
++m_count;
|
||||||
m_restriction_bucket_list.at(index).emplace_back(node_restriction.to,
|
m_restriction_bucket_list.at(index).emplace_back(node_restriction.to, restriction.is_only);
|
||||||
restriction.flags.is_only);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,33 +64,6 @@ bool RestrictionMap::IsViaNode(const NodeID node) const
|
|||||||
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
|
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces start edge (v, w) with (u, w). Only start node changes.
|
|
||||||
void RestrictionMap::FixupStartingTurnRestriction(const NodeID node_u,
|
|
||||||
const NodeID node_v,
|
|
||||||
const NodeID node_w)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
|
||||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
|
||||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
|
||||||
|
|
||||||
if (!IsSourceNode(node_v))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto restriction_iterator = m_restriction_map.find({node_v, node_w});
|
|
||||||
if (restriction_iterator != m_restriction_map.end())
|
|
||||||
{
|
|
||||||
const unsigned index = restriction_iterator->second;
|
|
||||||
// remove old restriction start (v,w)
|
|
||||||
m_restriction_map.erase(restriction_iterator);
|
|
||||||
m_restriction_start_nodes.emplace(node_u);
|
|
||||||
// insert new restriction start (u,w) (pointing to index)
|
|
||||||
RestrictionSource new_source = {node_u, node_w};
|
|
||||||
m_restriction_map.emplace(new_source, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if edge (u, v) is the start of any turn restriction.
|
// Check if edge (u, v) is the start of any turn restriction.
|
||||||
// If so returns id of first target node.
|
// If so returns id of first target node.
|
||||||
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
|
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
|
||||||
|
@ -125,7 +125,7 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
|||||||
// we pretend every restriction is a conditional restriction. If we do not find any restriction,
|
// we pretend every restriction is a conditional restriction. If we do not find any restriction,
|
||||||
// we can trim away the vector after parsing
|
// we can trim away the vector after parsing
|
||||||
InputConditionalTurnRestriction restriction_container;
|
InputConditionalTurnRestriction restriction_container;
|
||||||
restriction_container.flags.is_only = is_only_restriction;
|
restriction_container.is_only = is_only_restriction;
|
||||||
|
|
||||||
boost::optional<std::uint64_t> from = boost::none, via = boost::none, to = boost::none;
|
boost::optional<std::uint64_t> from = boost::none, via = boost::none, to = boost::none;
|
||||||
bool is_node_restriction;
|
bool is_node_restriction;
|
||||||
@ -212,11 +212,13 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
|||||||
{
|
{
|
||||||
if (is_node_restriction)
|
if (is_node_restriction)
|
||||||
{
|
{
|
||||||
restriction_container.node_or_way = InputNodeRestriction{*from, *via, *to};
|
// template struct requires bracket for ID initialisation :(
|
||||||
|
restriction_container.node_or_way = InputNodeRestriction{{*from}, {*via}, {*to}};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
restriction_container.node_or_way = InputWayRestriction{*from, *via, *to};
|
// template struct requires bracket for ID initialisation :(
|
||||||
|
restriction_container.node_or_way = InputWayRestriction{{*from}, {*via}, {*to}};
|
||||||
}
|
}
|
||||||
return restriction_container;
|
return restriction_container;
|
||||||
}
|
}
|
||||||
|
199
src/extractor/way_restriction_map.cpp
Normal file
199
src/extractor/way_restriction_map.cpp
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
#include "extractor/way_restriction_map.hpp"
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct FindViaWay
|
||||||
|
{
|
||||||
|
bool operator()(const std::tuple<NodeID, NodeID> value,
|
||||||
|
const TurnRestriction &restriction) const
|
||||||
|
{
|
||||||
|
const auto &way = restriction.AsWayRestriction();
|
||||||
|
return value < std::tie(way.in_restriction.via, way.out_restriction.via);
|
||||||
|
}
|
||||||
|
bool operator()(const TurnRestriction &restriction,
|
||||||
|
const std::tuple<NodeID, NodeID> value) const
|
||||||
|
{
|
||||||
|
const auto &way = restriction.AsWayRestriction();
|
||||||
|
return std::tie(way.in_restriction.via, way.out_restriction.via) < value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions)
|
||||||
|
{
|
||||||
|
// get all way restrictions
|
||||||
|
const auto extract_restrictions = [this](const auto &turn_restriction) {
|
||||||
|
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||||
|
{
|
||||||
|
const auto &way = turn_restriction.AsWayRestriction();
|
||||||
|
|
||||||
|
// so far we can only handle restrictions that are not interrupted
|
||||||
|
if (way.in_restriction.via == way.out_restriction.from &&
|
||||||
|
way.in_restriction.to == way.out_restriction.via)
|
||||||
|
restriction_data.push_back(turn_restriction);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), extract_restrictions);
|
||||||
|
|
||||||
|
const auto as_duplicated_node =
|
||||||
|
[](auto const &restriction) -> std::tuple<NodeID, NodeID, NodeID> {
|
||||||
|
auto &way = restriction.AsWayRestriction();
|
||||||
|
// group restrictions by the via-way. On same via-ways group by from
|
||||||
|
return std::make_tuple(
|
||||||
|
way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto by_duplicated_node = [&](auto const &lhs, auto const &rhs) {
|
||||||
|
return as_duplicated_node(lhs) < as_duplicated_node(rhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::sort(restriction_data.begin(), restriction_data.end(), by_duplicated_node);
|
||||||
|
|
||||||
|
std::size_t index = 0, duplication_id = 0;
|
||||||
|
// map all way restrictions into access containers
|
||||||
|
const auto prepare_way_restriction = [this, &index, &duplication_id, as_duplicated_node](
|
||||||
|
const auto &restriction) {
|
||||||
|
const auto &way = restriction.AsWayRestriction();
|
||||||
|
restriction_starts.insert(
|
||||||
|
std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), index));
|
||||||
|
++index;
|
||||||
|
};
|
||||||
|
std::for_each(restriction_data.begin(), restriction_data.end(), prepare_way_restriction);
|
||||||
|
|
||||||
|
std::size_t offset = 1;
|
||||||
|
// the first group starts at 0
|
||||||
|
if (!restriction_data.empty())
|
||||||
|
duplicated_node_groups.push_back(0);
|
||||||
|
|
||||||
|
auto const add_offset_on_new_groups = [&](auto const &lhs, auto const &rhs) {
|
||||||
|
BOOST_ASSERT(rhs == restriction_data[offset]);
|
||||||
|
// add a new lower bound for rhs
|
||||||
|
if (as_duplicated_node(lhs) != as_duplicated_node(rhs))
|
||||||
|
duplicated_node_groups.push_back(offset);
|
||||||
|
++offset;
|
||||||
|
return false; // continue until the end
|
||||||
|
};
|
||||||
|
std::adjacent_find(restriction_data.begin(), restriction_data.end(), add_offset_on_new_groups);
|
||||||
|
duplicated_node_groups.push_back(restriction_data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t WayRestrictionMap::NumberOfDuplicatedNodes() const
|
||||||
|
{
|
||||||
|
return duplicated_node_groups.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WayRestrictionMap::IsViaWay(const NodeID from, const NodeID to) const
|
||||||
|
{
|
||||||
|
// safe-guards
|
||||||
|
if (restriction_data.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto itr = std::lower_bound(
|
||||||
|
restriction_data.begin(), restriction_data.end(), std::make_tuple(from, to), FindViaWay());
|
||||||
|
|
||||||
|
// no fitting restriction
|
||||||
|
if (itr == restriction_data.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto &way = itr->AsWayRestriction();
|
||||||
|
|
||||||
|
return way.out_restriction.from == from && way.out_restriction.via == to;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t WayRestrictionMap::AsDuplicatedNodeID(const std::size_t restriction_id) const
|
||||||
|
{
|
||||||
|
return std::distance(duplicated_node_groups.begin(),
|
||||||
|
std::upper_bound(duplicated_node_groups.begin(),
|
||||||
|
duplicated_node_groups.end(),
|
||||||
|
restriction_id)) -
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::range<std::size_t> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
|
||||||
|
const NodeID to) const
|
||||||
|
{
|
||||||
|
const auto duplicated_node_range_itr = std::equal_range(
|
||||||
|
restriction_data.begin(), restriction_data.end(), std::make_tuple(from, to), FindViaWay());
|
||||||
|
|
||||||
|
const auto as_restriction_id = [this](const auto itr) {
|
||||||
|
return std::distance(restriction_data.begin(), itr);
|
||||||
|
};
|
||||||
|
|
||||||
|
return util::irange<std::size_t>(
|
||||||
|
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first)),
|
||||||
|
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WayRestrictionMap::IsRestricted(std::size_t duplicated_node, const NodeID to) const
|
||||||
|
{
|
||||||
|
// loop over all restrictions associated with the node. Mark as restricted based on
|
||||||
|
// is_only/restricted targets
|
||||||
|
for (std::size_t restriction_index = duplicated_node_groups[duplicated_node];
|
||||||
|
restriction_index != duplicated_node_groups[duplicated_node + 1];
|
||||||
|
++restriction_index)
|
||||||
|
{
|
||||||
|
const auto &restriction = restriction_data[restriction_index];
|
||||||
|
const auto &way = restriction.AsWayRestriction();
|
||||||
|
|
||||||
|
if (restriction.is_only)
|
||||||
|
return way.out_restriction.to != to;
|
||||||
|
else if (to == way.out_restriction.to)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TurnRestriction const &WayRestrictionMap::GetRestriction(const std::size_t id) const
|
||||||
|
{
|
||||||
|
return restriction_data[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<WayRestrictionMap::ViaWay> WayRestrictionMap::DuplicatedNodeRepresentatives() const
|
||||||
|
{
|
||||||
|
std::vector<ViaWay> result;
|
||||||
|
result.reserve(NumberOfDuplicatedNodes());
|
||||||
|
std::transform(duplicated_node_groups.begin(),
|
||||||
|
duplicated_node_groups.end() - 1,
|
||||||
|
std::back_inserter(result),
|
||||||
|
[&](auto const representative_id) -> ViaWay {
|
||||||
|
auto &way = restriction_data[representative_id].AsWayRestriction();
|
||||||
|
return {representative_id, way.in_restriction.via, way.out_restriction.via};
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeID WayRestrictionMap::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
|
||||||
|
{
|
||||||
|
auto range = restriction_starts.equal_range(std::make_pair(node_based_from, node_based_via));
|
||||||
|
|
||||||
|
// returns true if the ID saved in an iterator belongs to a turn restriction that references
|
||||||
|
// node_based_to as destination of the `in_restriction`
|
||||||
|
const auto restriction_targets_to = [node_based_to, this](const auto &pair) {
|
||||||
|
return restriction_data[pair.second].AsWayRestriction().in_restriction.to == node_based_to;
|
||||||
|
};
|
||||||
|
const auto itr = std::find_if(range.first, range.second, restriction_targets_to);
|
||||||
|
|
||||||
|
// in case we found a matching restriction, we can remap the edge_based_node
|
||||||
|
if (itr != range.second)
|
||||||
|
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() +
|
||||||
|
AsDuplicatedNodeID(itr->second);
|
||||||
|
else
|
||||||
|
return edge_based_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
@ -511,7 +511,7 @@ updateConditionalTurns(const UpdaterConfig &config,
|
|||||||
|
|
||||||
// only add restrictions to the lookups if the restriction is valid now
|
// only add restrictions to the lookups if the restriction is valid now
|
||||||
|
|
||||||
if (node_or_way.flags.is_only)
|
if (node_or_way.is_only)
|
||||||
{
|
{
|
||||||
is_only_lookup.lookup.push_back({std::make_tuple(c.from, c.via), c.to});
|
is_only_lookup.lookup.push_back({std::make_tuple(c.from, c.via), c.to});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user