Add support for multiple via-way restrictions (#5907)

Currently OSRM only supports turn restrictions with a single via-node or one
via-way. OSM allows for multiple via-ways to represent longer and more
complex restrictions.

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

In addition, we add a new step in the extraction phase that constructs
a restriction graph to support more complex relationships between restrictions,
such as nested restrictions and overlapping restrictions.
This commit is contained in:
Michael Bell 2020-12-20 21:59:57 +00:00 committed by GitHub
parent eb1d399f3b
commit 5266ac1635
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 3170 additions and 1406 deletions

View File

@ -1,6 +1,7 @@
# Unreleased # Unreleased
- Changes from 5.23.0 - Changes from 5.23.0
- Features: - Features
- ADDED: Added support for multiple via-way restrictions. [#5907](https://github.com/Project-OSRM/osrm-backend/pull/5907)
- ADDED: Add node bindings support for Node 12, 14, and publish binaries [#5918](https://github.com/Project-OSRM/osrm-backend/pull/5918) - ADDED: Add node bindings support for Node 12, 14, and publish binaries [#5918](https://github.com/Project-OSRM/osrm-backend/pull/5918)
- REMOVED: we no longer publish Node 8 binary modules (they are still buildable from source) [#5918](https://github.com/Project-OSRM/osrm-backend/pull/5918) - REMOVED: we no longer publish Node 8 binary modules (they are still buildable from source) [#5918](https://github.com/Project-OSRM/osrm-backend/pull/5918)
- Misc: - Misc:

View File

@ -387,217 +387,37 @@ Feature: Car - Turn restrictions
| m | p | mj,jp,jp | | m | p | mj,jp,jp |
@no_turning @conditionals @no_turning @conditionals
Scenario: Car - only_right_turn Scenario: Car - Multiple conditional restrictions applicable to same turn
Given the extract extra arguments "--parse-conditional-restrictions" Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT # time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map Given the node map
""" """
a j
d j b |
c k - l - m
|
n
""" """
And the ways And the ways
| nodes | oneway | | nodes |
| aj | no | | kl |
| jc | no | | jl |
| bj | yes | | ln |
| jd | yes | | lm |
And the relations And the relations
| type | way:from | way:to | node:via | restriction:conditional | | type | way:from | way:to | node:via | restriction:conditional |
| restriction | bj | aj | j | only_right_turn @ (Mo-Su 07:00-14:00) | | restriction | kl | lj | l | only_left_turn @ (Sa-Su 07:00-10:30) |
| restriction | kl | ln | l | only_right_turn @ (Mo-Fr 07:00-10:30) |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| b | c | bj,aj,aj,jc,jc | | k | m | kl,ln,ln,lm,lm |
| b | a | bj,aj,aj |
| b | d | bj,aj,aj,jd,jd |
@no_turning @conditionals
Scenario: Car - No right turn
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map
"""
a
d j b
c
"""
And the ways
| nodes | oneway |
| aj | no |
| jc | no |
| bj | yes |
| jd | yes |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | bj | aj | j | no_right_turn @ (Mo-Fr 07:00-13:00) |
When I route I should get
| from | to | route | # |
| b | c | bj,jc,jc | normal turn |
| b | a | bj,jc,jc,aj,aj | avoids right turn |
| b | d | bj,jd,jd | normal maneuver |
@only_turning @conditionals
Scenario: Car - only_left_turn
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map
"""
a
d j b
c
"""
And the ways
| nodes | oneway |
| aj | no |
| jc | no |
| bj | yes |
| jd | yes |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | bj | jc | j | only_left_turn @ (Mo-Fr 07:00-16:00) |
When I route I should get
| from | to | route |
| b | c | bj,jc,jc |
| b | a | bj,jc,jc,aj,aj |
| b | d | bj,jc,jc,jd,jd |
@no_turning @conditionals
Scenario: Car - No left turn
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map
"""
a
d j b
c
"""
And the ways
| nodes | oneway |
| aj | no |
| jc | no |
| bj | yes |
| jd | yes |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | bj | jc | j | no_left_turn @ (Mo-Su 00:00-23:59) |
When I route I should get
| from | to | route |
| b | c | bj,aj,aj,jc,jc |
| b | a | bj,aj,aj |
| b | d | bj,jd,jd |
@no_turning @conditionals
Scenario: Car - Conditional restriction is off
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map
"""
a
d j b
c
"""
And the ways
| nodes | oneway |
| aj | no |
| jc | no |
| bj | yes |
| jd | yes |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | bj | aj | j | no_right_turn @ (Mo-Su 16:00-20:00) |
When I route I should get
| from | to | route |
| b | c | bj,jc,jc |
| b | a | bj,aj,aj |
| b | d | bj,jd,jd |
@no_turning @conditionals
Scenario: Car - Conditional restriction is on
Given the extract extra arguments "--parse-conditional-restrictions"
# 10am utc, wed
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493805600"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493805600"
Given the node map
"""
a
d j b
c
"""
And the ways
| nodes | oneway |
| aj | no |
| jc | no |
| bj | yes |
| jd | yes |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | jb | aj | j | no_right_turn @ (Mo-Fr 07:00-14:00) |
When I route I should get
| from | to | route |
| b | c | bj,jc,jc |
| b | a | bj,jc,jc,aj,aj |
| b | d | bj,jd,jd |
@no_turning @conditionals
Scenario: Car - Conditional restriction with multiple time windows
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
a
p |
\ |
j
| \
c m
"""
And the ways
| nodes | oneway |
| aj | no |
| jc | no |
| jp | yes |
| mj | yes |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | aj | jp | j | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
When I route I should get
| from | to | route |
| a | p | aj,jc,jc,jp,jp |
| m | p | mj,jp,jp |
@restriction-way @restriction-way
Scenario: Car - prohibit turn Scenario: Car - prohibit turn
@ -719,7 +539,7 @@ Feature: Car - Turn restrictions
When I route I should get When I route I should get
| from | to | route | turns | | from | to | route | turns |
| a | e | cap south,florida nw,florida nw,florida ne | depart,turn right,continue uturn,arrive | | a | e | cap south,florida nw,florida nw,florida ne | depart,turn right,continue uturn,arrive |
| f | d | cap north,florida nw,florida nw | depart,turn left,arrive | | f | d | cap north,florida nw,florida nw | depart,turn left,arrive |
| e | c | florida ne,florida nw,cap south,cap south | depart,continue uturn,turn right,arrive | | e | c | florida ne,florida nw,cap south,cap south | depart,continue uturn,turn right,arrive |
@no_turning @conditionals @no_turning @conditionals
@ -796,8 +616,8 @@ Feature: Car - Turn restrictions
| nodes | name | | nodes | name |
| ab | albic | | ab | albic |
| bc | albic | | bc | albic |
| db | dobe | | db | dobe |
| be | dobe | | be | dobe |
And the relations And the relations
| type | way:from | way:to | node:via | restriction:conditional | | type | way:from | way:to | node:via | restriction:conditional |
@ -1047,7 +867,7 @@ Feature: Car - Turn restrictions
| type | way:from | node:via | way:to | restriction:conditional | | type | way:from | node:via | way:to | restriction:conditional |
| restriction | be | e | de | no_right_turn @ (Mo-Fr 07:00-11:00) | | restriction | be | e | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
# node restrictino is off, way restriction is on # node restriction is off, way restriction is on
When I route I should get When I route I should get
| from | to | route | turns | locations | | from | to | route | turns | locations |
| 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 | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |

File diff suppressed because it is too large Load Diff

View File

@ -798,82 +798,6 @@ Feature: Car - Turn restrictions
| from | to | route | | from | to | route |
| a | d | ab,be,de,de | | a | d | ab,be,de,de |
@restriction-way
Scenario: Multi Way restriction
Given the node map
"""
k j
| |
h - - g - f - - e
| |
| |
a - - b - c - - d
| |
l i
"""
And the ways
| nodes | name | oneway |
| ab | horiz | yes |
| bc | horiz | yes |
| cd | horiz | yes |
| ef | horiz | yes |
| fg | horiz | yes |
| gh | horiz | yes |
| ic | vert | yes |
| cf | vert | yes |
| fj | vert | yes |
| kg | vert | yes |
| gb | vert | yes |
| bl | vert | yes |
And the relations
| type | way:from | way:via | way:to | restriction |
| restriction | ab | bc,cf,fg | gh | no_u_turn |
When I route I should get
| from | to | route |
| a | h | horiz,vert,horiz,horiz |
@restriction-way
Scenario: Multi-Way overlapping single-way
Given the node map
"""
e
|
a - b - c - d
|
f - g
|
h
"""
And the ways
| nodes | name |
| ab | abcd |
| bc | abcd |
| cd | abcd |
| hf | hfb |
| fb | hfb |
| gf | gf |
| ce | ce |
And the relations
| type | way:from | way:via | way:to | restriction |
| restriction | ab | bc | ce | only_left_turn |
| restriction | gf | fb,bc | cd | only_u_turn |
When I route I should get
| from | to | route | turns | locations |
| 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 | depart,turn left,arrive | a,c,e |
| a | f | abcd,hfb,hfb | depart,turn right,arrive | a,b,f |
| 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 | depart,turn right,turn right,arrive | g,f,b,d |
| h | e | hfb,abcd,ce,ce | depart,end of road right,turn left,arrive | h,b,c,e |
| h | d | hfb,abcd,abcd | depart,end of road right,arrive | h,b,d |
@restriction-way @restriction-way
Scenario: Car - prohibit turn, traffic lights Scenario: Car - prohibit turn, traffic lights
Given the node map Given the node map
@ -984,8 +908,6 @@ Feature: Car - Turn restrictions
| restriction | ab | bge | de | no_right_turn | | restriction | ab | bge | de | no_right_turn |
| restriction | bc | bge | ef | no_left_turn | | restriction | bc | bge | ef | no_left_turn |
# this case is currently not handling the via-way restrictions and we need support for looking across traffic signals.
# It is mainly included to show limitations and to prove that we don't crash hard here
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | d | ab,bge,ef,ef,de,de | | a | d | ab,bge,ef,ef,de,de |

View File

@ -12,8 +12,8 @@
#include "extractor/name_table.hpp" #include "extractor/name_table.hpp"
#include "extractor/nbg_to_ebg.hpp" #include "extractor/nbg_to_ebg.hpp"
#include "extractor/node_data_container.hpp" #include "extractor/node_data_container.hpp"
#include "extractor/node_restriction_map.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/turn_lane_types.hpp" #include "extractor/turn_lane_types.hpp"
#include "extractor/way_restriction_map.hpp" #include "extractor/way_restriction_map.hpp"

View File

@ -1,14 +1,16 @@
#ifndef EXTRACTION_CONTAINERS_HPP #ifndef EXTRACTION_CONTAINERS_HPP
#define EXTRACTION_CONTAINERS_HPP #define EXTRACTION_CONTAINERS_HPP
#include "extractor/first_and_last_segment_of_way.hpp"
#include "extractor/internal_extractor_edge.hpp" #include "extractor/internal_extractor_edge.hpp"
#include "extractor/nodes_of_way.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "extractor/restriction.hpp" #include "extractor/restriction.hpp"
#include "extractor/scripting_environment.hpp" #include "extractor/scripting_environment.hpp"
#include "storage/tar_fwd.hpp" #include "storage/tar_fwd.hpp"
#include <unordered_map>
namespace osrm namespace osrm
{ {
namespace extractor namespace extractor
@ -22,9 +24,16 @@ namespace extractor
*/ */
class ExtractionContainers class ExtractionContainers
{ {
using ReferencedWays = std::unordered_map<OSMWayID, NodesOfWay>;
// The relationship between way and nodes is lost during node preparation.
// We identify the ways and nodes relevant to restrictions/overrides prior to
// node processing so that they can be referenced in the preparation phase.
ReferencedWays IdentifyRestrictionWays();
ReferencedWays IdentifyManeuverOverrideWays();
void PrepareNodes(); void PrepareNodes();
void PrepareManeuverOverrides(); void PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways);
void PrepareRestrictions(); void PrepareRestrictions(const ReferencedWays &restriction_ways);
void PrepareEdges(ScriptingEnvironment &scripting_environment); void PrepareEdges(ScriptingEnvironment &scripting_environment);
void WriteNodes(storage::tar::FileWriter &file_out) const; void WriteNodes(storage::tar::FileWriter &file_out) const;
@ -37,9 +46,10 @@ class ExtractionContainers
using NodeVector = std::vector<QueryNode>; using NodeVector = std::vector<QueryNode>;
using EdgeVector = std::vector<InternalExtractorEdge>; using EdgeVector = std::vector<InternalExtractorEdge>;
using AnnotationDataVector = std::vector<NodeBasedEdgeAnnotation>; using AnnotationDataVector = std::vector<NodeBasedEdgeAnnotation>;
using WayIDStartEndVector = std::vector<FirstAndLastSegmentOfWay>;
using NameCharData = std::vector<unsigned char>; using NameCharData = std::vector<unsigned char>;
using NameOffsets = std::vector<unsigned>; using NameOffsets = std::vector<size_t>;
using WayIDVector = std::vector<OSMWayID>;
using WayNodeIDOffsets = std::vector<size_t>;
std::vector<OSMNodeID> barrier_nodes; std::vector<OSMNodeID> barrier_nodes;
std::vector<OSMNodeID> traffic_signals; std::vector<OSMNodeID> traffic_signals;
@ -49,20 +59,18 @@ class ExtractionContainers
AnnotationDataVector all_edges_annotation_data_list; AnnotationDataVector all_edges_annotation_data_list;
NameCharData name_char_data; NameCharData name_char_data;
NameOffsets name_offsets; NameOffsets name_offsets;
// an adjacency array containing all turn lane masks WayIDVector ways_list;
WayIDStartEndVector way_start_end_id_list; // Offsets into used nodes for each way_list entry
WayNodeIDOffsets way_node_id_offsets;
unsigned max_internal_node_id; unsigned max_internal_node_id;
// list of restrictions before we transform them into the output types. Input containers // List of restrictions (conditional and unconditional) before we transform them into the
// reference OSMNodeIDs. We can only transform them to the correct internal IDs after we've read // output types. Input containers reference OSMNodeIDs. We can only transform them to the
// everything. Without a multi-parse approach, we have to remember the output restrictions // correct internal IDs after we've read everything. Without a multi-parse approach,
// before converting them to the internal formats // we have to remember the output restrictions before converting them to the internal formats
std::vector<InputConditionalTurnRestriction> restrictions_list; std::vector<InputTurnRestriction> restrictions_list;
std::vector<TurnRestriction> turn_restrictions;
// turn restrictions split into conditional and unconditional turn restrictions
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
std::vector<TurnRestriction> unconditional_turn_restrictions;
std::vector<InputManeuverOverride> external_maneuver_overrides_list; std::vector<InputManeuverOverride> external_maneuver_overrides_list;
std::vector<UnresolvedManeuverOverride> internal_maneuver_overrides; std::vector<UnresolvedManeuverOverride> internal_maneuver_overrides;

View File

@ -42,6 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "util/guidance/entry_class.hpp" #include "util/guidance/entry_class.hpp"
#include "util/guidance/turn_lanes.hpp" #include "util/guidance/turn_lanes.hpp"
#include "restriction_graph.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
namespace osrm namespace osrm
@ -63,7 +64,6 @@ class Extractor
std::tuple<LaneDescriptionMap, std::tuple<LaneDescriptionMap,
std::vector<TurnRestriction>, std::vector<TurnRestriction>,
std::vector<ConditionalTurnRestriction>,
std::vector<UnresolvedManeuverOverride>> std::vector<UnresolvedManeuverOverride>>
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads); ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
@ -74,8 +74,7 @@ class Extractor
const CompressedEdgeContainer &compressed_edge_container, const 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,
const std::vector<TurnRestriction> &turn_restrictions, const RestrictionGraph &restriction_graph,
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
const std::unordered_set<EdgeID> &segregated_edges, const std::unordered_set<EdgeID> &segregated_edges,
const NameTable &name_table, const NameTable &name_table,
const std::vector<UnresolvedManeuverOverride> &maneuver_overrides, const std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
@ -97,23 +96,16 @@ class Extractor
EdgeBasedNodeDataContainer &nodes_container) const; EdgeBasedNodeDataContainer &nodes_container) const;
void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments, void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments,
const std::vector<util::Coordinate> &coordinates); const std::vector<util::Coordinate> &coordinates);
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
void WriteConditionalRestrictions( void ProcessGuidanceTurns(const util::NodeBasedDynamicGraph &node_based_graph,
const std::string &path, const EdgeBasedNodeDataContainer &edge_based_node_container,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions); const std::vector<util::Coordinate> &node_coordinates,
const CompressedEdgeContainer &compressed_edge_container,
void ProcessGuidanceTurns( const std::unordered_set<NodeID> &barrier_nodes,
const util::NodeBasedDynamicGraph &node_based_graph, const RestrictionGraph &restriction_graph,
const EdgeBasedNodeDataContainer &edge_based_node_container, const NameTable &name_table,
const std::vector<util::Coordinate> &node_coordinates, LaneDescriptionMap lane_description_map,
const CompressedEdgeContainer &compressed_edge_container, ScriptingEnvironment &scripting_environment);
const std::unordered_set<NodeID> &barrier_nodes,
const std::vector<TurnRestriction> &turn_restrictions,
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
const NameTable &name_table,
LaneDescriptionMap lane_description_map,
ScriptingEnvironment &scripting_environment);
}; };
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm

View File

@ -47,7 +47,7 @@ struct ExtractionNode;
struct ExtractionWay; struct ExtractionWay;
struct ExtractionRelation; struct ExtractionRelation;
struct ProfileProperties; struct ProfileProperties;
struct InputConditionalTurnRestriction; struct InputTurnRestriction;
struct InputManeuverOverride; struct InputManeuverOverride;
/** /**
@ -87,7 +87,7 @@ class ExtractorCallbacks
void ProcessNode(const osmium::Node &current_node, const ExtractionNode &result_node); void ProcessNode(const osmium::Node &current_node, const ExtractionNode &result_node);
// warning: caller needs to take care of synchronization! // warning: caller needs to take care of synchronization!
void ProcessRestriction(const InputConditionalTurnRestriction &restriction); void ProcessRestriction(const InputTurnRestriction &restriction);
// warning: caller needs to take care of synchronization! // warning: caller needs to take care of synchronization!
void ProcessWay(const osmium::Way &current_way, const ExtractionWay &result_way); void ProcessWay(const osmium::Way &current_way, const ExtractionWay &result_way);

View File

@ -1,59 +0,0 @@
#ifndef FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
#include "util/typedefs.hpp"
#include <limits>
#include <string>
namespace osrm
{
namespace extractor
{
struct FirstAndLastSegmentOfWay
{
OSMWayID way_id;
OSMNodeID first_segment_source_id;
OSMNodeID first_segment_target_id;
OSMNodeID last_segment_source_id;
OSMNodeID last_segment_target_id;
FirstAndLastSegmentOfWay()
: way_id(SPECIAL_OSM_WAYID), first_segment_source_id(SPECIAL_OSM_NODEID),
first_segment_target_id(SPECIAL_OSM_NODEID), last_segment_source_id(SPECIAL_OSM_NODEID),
last_segment_target_id(SPECIAL_OSM_NODEID)
{
}
FirstAndLastSegmentOfWay(OSMWayID w, OSMNodeID fs, OSMNodeID ft, OSMNodeID ls, OSMNodeID lt)
: way_id(std::move(w)), first_segment_source_id(std::move(fs)),
first_segment_target_id(std::move(ft)), last_segment_source_id(std::move(ls)),
last_segment_target_id(std::move(lt))
{
}
static FirstAndLastSegmentOfWay min_value()
{
return {MIN_OSM_WAYID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID};
}
static FirstAndLastSegmentOfWay max_value()
{
return {MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID};
}
};
struct FirstAndLastSegmentOfWayCompare
{
using value_type = FirstAndLastSegmentOfWay;
bool operator()(const FirstAndLastSegmentOfWay &a, const FirstAndLastSegmentOfWay &b) const
{
return a.way_id < b.way_id;
}
value_type max_value() { return FirstAndLastSegmentOfWay::max_value(); }
value_type min_value() { return FirstAndLastSegmentOfWay::min_value(); }
};
} // namespace extractor
} // namespace osrm
#endif /* FIRST_AND_LAST_SEGMENT_OF_WAY_HPP */

View File

@ -28,7 +28,6 @@ class GraphCompressor
const std::unordered_set<NodeID> &traffic_lights, const std::unordered_set<NodeID> &traffic_lights,
ScriptingEnvironment &scripting_environment, ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions, std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides, std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
util::NodeBasedDynamicGraph &graph, util::NodeBasedDynamicGraph &graph,
const std::vector<NodeBasedEdgeAnnotation> &node_data_container, const std::vector<NodeBasedEdgeAnnotation> &node_data_container,

View File

@ -5,7 +5,7 @@
#include "extractor/intersection/intersection_edge.hpp" #include "extractor/intersection/intersection_edge.hpp"
#include "extractor/intersection/intersection_view.hpp" #include "extractor/intersection/intersection_view.hpp"
#include "extractor/intersection/mergable_road_detector.hpp" #include "extractor/intersection/mergable_road_detector.hpp"
#include "extractor/restriction_index.hpp" #include "extractor/node_restriction_map.hpp"
#include "extractor/turn_lane_types.hpp" #include "extractor/turn_lane_types.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"

View File

@ -5,7 +5,7 @@
#include "extractor/intersection/coordinate_extractor.hpp" #include "extractor/intersection/coordinate_extractor.hpp"
#include "extractor/intersection/have_identical_names.hpp" #include "extractor/intersection/have_identical_names.hpp"
#include "extractor/name_table.hpp" #include "extractor/name_table.hpp"
#include "extractor/restriction_index.hpp" #include "extractor/node_restriction_map.hpp"
#include "extractor/turn_lane_types.hpp" #include "extractor/turn_lane_types.hpp"
#include "guidance/intersection.hpp" #include "guidance/intersection.hpp"

View File

@ -40,7 +40,6 @@ class NodeBasedGraphFactory
NodeBasedGraphFactory(const boost::filesystem::path &input_file, NodeBasedGraphFactory(const boost::filesystem::path &input_file,
ScriptingEnvironment &scripting_environment, ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions, std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides); std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
auto const &GetGraph() const { return compressed_output_graph; } auto const &GetGraph() const { return compressed_output_graph; }
@ -69,7 +68,6 @@ class NodeBasedGraphFactory
// edges into a single representative form // edges into a single representative form
void Compress(ScriptingEnvironment &scripting_environment, void Compress(ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions, std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides); std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
// Most ways are bidirectional, making the geometry in forward and backward direction the same, // Most ways are bidirectional, making the geometry in forward and backward direction the same,

View File

@ -0,0 +1,80 @@
#ifndef OSRM_EXTRACTOR_NODE_RESTRICTION_MAP_HPP_
#define OSRM_EXTRACTOR_NODE_RESTRICTION_MAP_HPP_
#include "extractor/restriction.hpp"
#include "restriction_graph.hpp"
#include "util/typedefs.hpp"
#include <boost/range/adaptor/filtered.hpp>
#include <boost/unordered_map.hpp>
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
// Allows easy check for whether a node restriction is present at a given intersection
template <typename RestrictionFilter> class NodeRestrictionMap
{
public:
NodeRestrictionMap(const RestrictionGraph &restriction_graph)
: restriction_graph(restriction_graph), index_filter(RestrictionFilter{})
{
}
// Find all restrictions applicable to (from,via,*) turns
auto Restrictions(NodeID from, NodeID via) const
{
return getRange(from, via) | boost::adaptors::filtered(index_filter);
};
// Find all restrictions applicable to (from,via,to) turns
auto Restrictions(NodeID from, NodeID via, NodeID to) const
{
const auto turnFilter = [this, to](const auto &restriction) {
return index_filter(restriction) && restriction->IsTurnRestricted(to);
};
return getRange(from, via) | boost::adaptors::filtered(turnFilter);
};
private:
RestrictionGraph::RestrictionRange getRange(NodeID from, NodeID via) const
{
const auto start_node_it = restriction_graph.start_edge_to_node.find({from, via});
if (start_node_it != restriction_graph.start_edge_to_node.end())
{
return restriction_graph.GetRestrictions(start_node_it->second);
}
return {};
}
const RestrictionGraph &restriction_graph;
const RestrictionFilter index_filter;
};
// Restriction filters to use as index defaults
struct ConditionalOnly
{
bool operator()(const TurnRestriction *restriction) const
{
return !restriction->IsUnconditional();
};
};
struct UnconditionalOnly
{
bool operator()(const TurnRestriction *restriction) const
{
return restriction->IsUnconditional();
};
};
using RestrictionMap = NodeRestrictionMap<UnconditionalOnly>;
using ConditionalRestrictionMap = NodeRestrictionMap<ConditionalOnly>;
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_NODE_RESTRICTION_MAP_HPP_

View File

@ -0,0 +1,56 @@
#ifndef NODES_OF_WAY_HPP
#define NODES_OF_WAY_HPP
#include "util/typedefs.hpp"
#include <limits>
#include <string>
#include <vector>
namespace osrm
{
namespace extractor
{
// NodesOfWay contains the ordered nodes of a way and provides convenience functions for getting
// nodes in the first and last segments.
struct NodesOfWay
{
OSMWayID way_id;
std::vector<OSMNodeID> node_ids;
NodesOfWay() : way_id(SPECIAL_OSM_WAYID), node_ids{SPECIAL_OSM_NODEID, SPECIAL_OSM_NODEID} {}
NodesOfWay(OSMWayID w, std::vector<OSMNodeID> ns) : way_id(w), node_ids(std::move(ns)) {}
static NodesOfWay min_value() { return {MIN_OSM_WAYID, {MIN_OSM_NODEID, MIN_OSM_NODEID}}; }
static NodesOfWay max_value() { return {MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}}; }
const OSMNodeID &first_segment_source_id() const
{
BOOST_ASSERT(!node_ids.empty());
return node_ids[0];
}
const OSMNodeID &first_segment_target_id() const
{
BOOST_ASSERT(node_ids.size() > 1);
return node_ids[1];
}
const OSMNodeID &last_segment_source_id() const
{
BOOST_ASSERT(node_ids.size() > 1);
return node_ids[node_ids.size() - 2];
}
const OSMNodeID &last_segment_target_id() const
{
BOOST_ASSERT(!node_ids.empty());
return node_ids[node_ids.size() - 1];
}
};
} // namespace extractor
} // namespace osrm
#endif /* NODES_OF_WAY_HPP */

View File

@ -30,17 +30,19 @@ struct InputNodeRestriction
OSMWayID to; OSMWayID to;
}; };
// A restriction that uses a single via-way in between // A restriction that uses one or more via-way in between
// //
// f - e - d // e - f - g
// |
// d
// | // |
// a - b - c // a - b - c
// //
// ab via be to ef -- no u turn // ab via bd,df to fe -- no u turn
struct InputWayRestriction struct InputWayRestriction
{ {
OSMWayID from; OSMWayID from;
OSMWayID via; std::vector<OSMWayID> via;
OSMWayID to; OSMWayID to;
}; };
@ -57,6 +59,9 @@ struct InputTurnRestriction
// keep in the same order as the turn restrictions below // keep in the same order as the turn restrictions below
mapbox::util::variant<InputNodeRestriction, InputWayRestriction> node_or_way; mapbox::util::variant<InputNodeRestriction, InputWayRestriction> node_or_way;
bool is_only; bool is_only;
// We represent conditional and unconditional restrictions with the same structure.
// Unconditional restrictions will have empty conditions.
std::vector<util::OpeningHours> condition;
OSMWayID From() const OSMWayID From() const
{ {
@ -102,13 +107,15 @@ struct InputTurnRestriction
return mapbox::util::get<InputNodeRestriction>(node_or_way); return mapbox::util::get<InputNodeRestriction>(node_or_way);
} }
}; };
struct InputConditionalTurnRestriction : InputTurnRestriction
{
std::vector<util::OpeningHours> condition;
};
// OSRM manages restrictions based on node IDs which refer to the last node along the edge. Note // OSRM manages restrictions based on node IDs which refer to the last node along the edge. Note
// that this has the side-effect of not allowing parallel edges! // that this has the side-effect of not allowing parallel edges!
//
// a - b - c
// |
// d
//
// ab via b to bd
struct NodeRestriction struct NodeRestriction
{ {
NodeID from; NodeID from;
@ -131,39 +138,46 @@ struct NodeRestriction
// compression happening in the graph creation process which would make it difficult to track // compression happening in the graph creation process which would make it difficult to track
// way-ids over a series of operations. Having access to the nodes directly allows look-up of the // way-ids over a series of operations. Having access to the nodes directly allows look-up of the
// edges in the processed structures // edges in the processed structures
//
// e - f - g
// |
// d
// |
// a - b - c
//
// ab via bd,df to fe -- no u turn
struct WayRestriction struct WayRestriction
{ {
// a way restriction in OSRM is essentially a dual node turn restriction; // A way restriction in OSRM needs to track all nodes that make up the via ways. Whilst most
// // of these nodes will be removed by compression, some nodes will contain features that need to
// | | // be considered when routing (e.g. intersections, nested restrictions, etc).
// c -x- b NodeID from;
// | | std::vector<NodeID> via;
// d a NodeID to;
//
// from ab via bxc to cd: no_uturn // check if all parts of the restriction reference an actual node
// bool Valid() const
// Technically, we would need only a,b,c,d to describe the full turn in terms of nodes. When {
// parsing the relation, though, we do not know about the final representation in the node-based return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via.size() >= 2 &&
// graph for the restriction. In case of a traffic light, for example, we might end up with bxc std::all_of(via.begin(), via.end(), [](NodeID i) { return i != SPECIAL_NODEID; });
// not being compressed to bc. For that reason, we need to maintain two node restrictions in };
// case a way restrction is not fully collapsed
NodeRestriction in_restriction;
NodeRestriction out_restriction;
bool operator==(const WayRestriction &other) const bool operator==(const WayRestriction &other) const
{ {
return std::tie(in_restriction, out_restriction) == return std::tie(from, via, to) == std::tie(other.from, other.via, other.to);
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
// between node/way/multi-way restrictions // between node/way restrictions
struct TurnRestriction struct TurnRestriction
{ {
// keep in the same order as the turn restrictions above // keep in the same order as the turn restrictions above
mapbox::util::variant<NodeRestriction, WayRestriction> node_or_way; mapbox::util::variant<NodeRestriction, WayRestriction> node_or_way;
bool is_only; bool is_only;
// We represent conditional and unconditional restrictions with the same structure.
// Unconditional restrictions will have empty conditions.
std::vector<util::OpeningHours> condition;
// construction for NodeRestrictions // construction for NodeRestrictions
explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false) explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false)
@ -179,9 +193,40 @@ struct TurnRestriction
explicit TurnRestriction() explicit TurnRestriction()
{ {
node_or_way = NodeRestriction{SPECIAL_EDGEID, SPECIAL_NODEID, SPECIAL_EDGEID}; node_or_way = NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
} }
NodeID To() const
{
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
? mapbox::util::get<NodeRestriction>(node_or_way).to
: mapbox::util::get<WayRestriction>(node_or_way).to;
}
NodeID From() const
{
return node_or_way.which() == RestrictionType::NODE_RESTRICTION
? mapbox::util::get<NodeRestriction>(node_or_way).from
: mapbox::util::get<WayRestriction>(node_or_way).from;
}
NodeID FirstVia() const
{
if (node_or_way.which() == RestrictionType::NODE_RESTRICTION)
{
return mapbox::util::get<NodeRestriction>(node_or_way).via;
}
else
{
BOOST_ASSERT(!mapbox::util::get<WayRestriction>(node_or_way).via.empty());
return mapbox::util::get<WayRestriction>(node_or_way).via[0];
}
}
bool IsTurnRestricted(NodeID to) const { return is_only ? To() != to : To() == to; }
bool IsUnconditional() const { return condition.empty(); }
WayRestriction &AsWayRestriction() WayRestriction &AsWayRestriction()
{ {
BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION); BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
@ -218,7 +263,7 @@ struct TurnRestriction
if (node_or_way.which() == RestrictionType::WAY_RESTRICTION) if (node_or_way.which() == RestrictionType::WAY_RESTRICTION)
{ {
auto const &restriction = AsWayRestriction(); auto const &restriction = AsWayRestriction();
return restriction.in_restriction.Valid() && restriction.out_restriction.Valid(); return restriction.Valid();
} }
else else
{ {
@ -245,11 +290,6 @@ struct TurnRestriction
} }
} }
}; };
struct ConditionalTurnRestriction : TurnRestriction
{
std::vector<util::OpeningHours> condition;
};
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm

View File

@ -16,8 +16,8 @@ namespace extractor
struct NodeRestriction; struct NodeRestriction;
struct TurnRestriction; struct TurnRestriction;
// OSRM stores restrictions in the form node -> node -> node instead of way -> node -> way (or // OSRM stores restrictions as node -> [node] -> node instead of way -> node -> way (or
// way->way->way) as it is done in OSM. These restrictions need to match the state of graph // way->[way]->way) as it is done in OSM. These restrictions need to match the state of graph
// compression which we perform in the graph compressor that removes certain degree two nodes from // compression which we perform in the graph compressor that removes certain degree two nodes from
// the graph (all but the ones with penalties/barriers, as of the state of writing). // the graph (all but the ones with penalties/barriers, as of the state of writing).
// Since this graph compression ins performed after creating the restrictions in the extraction // Since this graph compression ins performed after creating the restrictions in the extraction
@ -29,19 +29,22 @@ class RestrictionCompressor
{ {
public: public:
RestrictionCompressor(std::vector<TurnRestriction> &restrictions, RestrictionCompressor(std::vector<TurnRestriction> &restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides); std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
// account for the compression of `from-via-to` into `from-to` // account for the compression of `from-via-to` into `from-to`
void Compress(const NodeID from, const NodeID via, const NodeID to); void Compress(const NodeID from, const NodeID via, const NodeID to);
private: private:
// a turn restriction is given as `from star via node to end`. Edges ending at `head` being // A turn restriction is given as `from star via node to end`. Edges ending at `head` being
// contracted move the head pointer to their respective head. Edges starting at tail move the // contracted move the head pointer to their respective head. Edges starting at tail move the
// tail values to their respective tails. Way turn restrictions are represented by two // tail values to their respective tails.
// node-restrictions, so we can focus on them alone // Via nodes that are compressed are removed from the restriction representation.
boost::unordered_multimap<NodeID, NodeRestriction *> starts; // We do not compress the first and last via nodes of a restriction as they act as
boost::unordered_multimap<NodeID, NodeRestriction *> ends; // entrance/exit points into the restriction graph. For a node restriction, the first and last
// via nodes are the same.
boost::unordered_multimap<NodeID, TurnRestriction *> starts;
boost::unordered_multimap<NodeID, TurnRestriction *> vias;
boost::unordered_multimap<NodeID, TurnRestriction *> ends;
boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_starts; boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_starts;
boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_ends; boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_ends;

View File

@ -14,10 +14,8 @@ namespace extractor
// To avoid handling invalid restrictions / creating unnecessary duplicate nodes for via-ways, we do // To avoid handling invalid restrictions / creating unnecessary duplicate nodes for via-ways, we do
// a pre-flight check for restrictions and remove all invalid restrictions from the data. Use as // a pre-flight check for restrictions and remove all invalid restrictions from the data. Use as
// `restrictions = removeInvalidRestrictions(std::move(restrictions))` // `restrictions = removeInvalidRestrictions(std::move(restrictions))`
std::vector<ConditionalTurnRestriction> std::vector<TurnRestriction> removeInvalidRestrictions(std::vector<TurnRestriction>,
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction>, const util::NodeBasedDynamicGraph &);
const util::NodeBasedDynamicGraph &);
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm

View File

@ -0,0 +1,134 @@
#ifndef OSRM_EXTRACTOR_RESTRICTION_GRAPH_HPP_
#define OSRM_EXTRACTOR_RESTRICTION_GRAPH_HPP_
#include <boost/assert.hpp>
#include <boost/unordered_map.hpp>
#include "extractor/restriction_filter.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
namespace osrm
{
namespace extractor
{
namespace restriction_graph_details
{
struct transferBuilder;
struct pathBuilder;
} // namespace restriction_graph_details
struct RestrictionEdge
{
NodeID node_based_to;
RestrictionID target;
bool is_transfer;
};
struct RestrictionNode
{
size_t restrictions_begin_idx;
size_t num_restrictions;
size_t edges_begin_idx;
size_t num_edges;
};
/**
* The restriction graph is used to represent all possible restrictions within the routing graph.
* The graph uses an edge-based node representation. Each node represents a compressed
* node-based edge along a restriction path.
*
* Given a list of turn restrictions, the graph is created in multiple steps.
*
* INPUT
* a -> b -> d: no_e
* a -> b -> c: only_d
* b -> c -> d: only_f
* b -> c: no_g
* e -> b -> d: no_g
*
* Step 1: create a disjoint union of prefix trees for all restriction paths.
* The restriction instructions are added to the final node in its path.
*
* STEP 1
* (a,b) -> (b,d,[no_e])
* \->(b,c,[only_d])
*
* (b,c,[no_g]) -> (c,d,[only_f])
* (e,b) -> (b,d,[no_g])
*
* Step 2: add transfers between restriction paths that overlap.
* We do this by traversing each restriction path, tracking where the suffix of our current path
* matches the prefix of any other. If it does, there's opportunity to transfer to the suffix
* restriction path *if* the transfer would not be restricted *and* that edge does not take us
* further on our current path. Nested restrictions are also added from any of the suffix paths.
*
* STEP 2
* (a,b) -> (b,d,[no_e])
* \->(b,c,[only_d,no_g])
* \
* (b,c,[no_g]) -> \-> (c,d,[only_f])
*
* (e,b) -> (b,d,[no_g])
* If a transfer applies to multiple suffix paths, we only add the edge to the largest suffix path.
* This ensures we correctly track all overlapping paths.
*
*
* Step 3: The nodes are split into
* start nodes - compressed edges that are entry points into a restriction path.
* via nodes - compressed edges that are intermediate steps along a restriction path.
* Start nodes and via nodes are indexed by the compressed node-based edge for easy retrieval
*
* STEP 3
* Start Node Index
* (a,b) => (a,b)
* (b,c) => (b,c,[no_g])
* (e,b) => (e,b)
*
* Via Nodes Index
* (b,c) => (b,c,[only_d,no_g])
* (b,d) => (b,d,[no_e]) , (b,d,[no_g])
* (c,d) => (c,d,[only_f])
*
* Duplicate Nodes:
* There is a 1-1 mapping between restriction graph via nodes and edge-based-graph duplicate nodes.
* This relationship is used in the creation of restrictions in the routing edge-based graph.
* */
struct RestrictionGraph
{
friend restriction_graph_details::pathBuilder;
friend restriction_graph_details::transferBuilder;
friend RestrictionGraph constructRestrictionGraph(const std::vector<TurnRestriction> &);
using EdgeRange = boost::iterator_range<std::vector<RestrictionEdge>::const_iterator>;
using RestrictionRange =
boost::iterator_range<std::vector<const TurnRestriction *>::const_iterator>;
using EdgeKey = std::pair<NodeID, NodeID>;
// Helper functions for iterating over node restrictions and edges
EdgeRange GetEdges(RestrictionID id) const;
RestrictionRange GetRestrictions(RestrictionID id) const;
// A compressed node-based edge can only have one start node in the restriction graph.
boost::unordered_map<EdgeKey, RestrictionID> start_edge_to_node{};
// A compressed node-based edge can have multiple via nodes in the restriction graph
// (as the compressed edge can appear in paths with different prefixes).
boost::unordered_multimap<EdgeKey, RestrictionID> via_edge_to_node{};
std::vector<RestrictionNode> nodes;
// TODO: Investigate reusing DynamicGraph. Currently it requires specific attributes
// (e.g. reversed, weight) that would not make sense for restrictions.
std::vector<RestrictionEdge> edges;
std::vector<const TurnRestriction *> restrictions;
size_t num_via_nodes{};
private:
RestrictionGraph() = default;
};
RestrictionGraph constructRestrictionGraph(const std::vector<TurnRestriction> &turn_restrictions);
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_RESTRICTION_GRAPH_HPP_

View File

@ -1,101 +0,0 @@
#ifndef OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
#define OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
#include "extractor/restriction.hpp"
#include "util/typedefs.hpp"
#include <boost/unordered_map.hpp>
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
// allows easy check for whether a node intersection is present at a given intersection
template <typename restriction_type> class RestrictionIndex
{
public:
using value_type = restriction_type;
template <typename extractor_type>
RestrictionIndex(std::vector<restriction_type> &restrictions, extractor_type extractor);
bool IsIndexed(NodeID first, NodeID second) const;
auto Restrictions(NodeID first, NodeID second) const
{
return restriction_hash.equal_range(std::make_pair(first, second));
};
auto Size() const { return restriction_hash.size(); }
private:
boost::unordered_multimap<std::pair<NodeID, NodeID>, restriction_type *> restriction_hash;
};
template <typename restriction_type>
template <typename extractor_type>
RestrictionIndex<restriction_type>::RestrictionIndex(std::vector<restriction_type> &restrictions,
extractor_type extractor)
{
// build a multi-map
for (auto &restriction : restrictions)
restriction_hash.insert(std::make_pair(extractor(restriction), &restriction));
}
template <typename restriction_type>
bool RestrictionIndex<restriction_type>::IsIndexed(const NodeID first, const NodeID second) const
{
return restriction_hash.count(std::make_pair(first, second));
}
struct IndexNodeByFromAndVia
{
std::pair<NodeID, NodeID> operator()(const TurnRestriction &restriction)
{
const auto &node = restriction.AsNodeRestriction();
return std::make_pair(node.from, node.via);
};
};
// check wheter a turn is restricted within a restriction_index
template <typename restriction_map_type>
std::pair<bool, typename restriction_map_type::value_type *>
isRestricted(const NodeID from,
const NodeID via,
const NodeID to,
const restriction_map_type &restriction_map)
{
const auto range = restriction_map.Restrictions(from, via);
// check if a given node_restriction is targeting node
const auto to_is_restricted = [to](const auto &pair) {
const auto &restriction = *pair.second;
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
{
auto const &as_node = restriction.AsNodeRestriction();
auto const restricted = restriction.is_only ? (to != as_node.to) : (to == as_node.to);
return restricted;
}
return false;
};
auto itr = std::find_if(range.first, range.second, to_is_restricted);
if (itr != range.second)
return {true, itr->second};
else
return {false, NULL};
}
using RestrictionMap = RestrictionIndex<TurnRestriction>;
using ConditionalRestrictionMap = RestrictionIndex<ConditionalTurnRestriction>;
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_

View File

@ -44,8 +44,7 @@ class RestrictionParser
RestrictionParser(bool use_turn_restrictions, RestrictionParser(bool use_turn_restrictions,
bool parse_conditionals, bool parse_conditionals,
std::vector<std::string> &restrictions); std::vector<std::string> &restrictions);
boost::optional<InputConditionalTurnRestriction> boost::optional<InputTurnRestriction> TryParse(const osmium::Relation &relation) const;
TryParse(const osmium::Relation &relation) const;
private: private:
bool ShouldIgnoreRestriction(const std::string &except_tag_string) const; bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;

View File

@ -68,7 +68,7 @@ class ScriptingEnvironment
const ExtractionRelationContainer &relations, const ExtractionRelationContainer &relations,
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes, std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways, std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
std::vector<InputConditionalTurnRestriction> &resulting_restrictions, std::vector<InputTurnRestriction> &resulting_restrictions,
std::vector<InputManeuverOverride> &resulting_maneuver_overrides) = 0; std::vector<InputManeuverOverride> &resulting_maneuver_overrides) = 0;
virtual bool HasLocationDependentData() const = 0; virtual bool HasLocationDependentData() const = 0;

View File

@ -92,7 +92,7 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
const ExtractionRelationContainer &relations, const ExtractionRelationContainer &relations,
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes, std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways, std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
std::vector<InputConditionalTurnRestriction> &resulting_restrictions, std::vector<InputTurnRestriction> &resulting_restrictions,
std::vector<InputManeuverOverride> &resulting_maneuver_overrides) override; std::vector<InputManeuverOverride> &resulting_maneuver_overrides) override;
bool HasLocationDependentData() const override { return !location_dependent_data.empty(); } bool HasLocationDependentData() const override { return !location_dependent_data.empty(); }

View File

@ -8,82 +8,66 @@
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include "extractor/restriction.hpp" #include "extractor/restriction.hpp"
#include "extractor/restriction_index.hpp" #include "extractor/restriction_graph.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/typedefs.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 osrm
{ {
namespace extractor namespace extractor
{ {
// The WayRestrictionMap uses ConditionalTurnRestrictions in general. Most restrictions will have // Given the compressed representation of via-way turn restrictions, we provide a fast access into
// empty conditions, though. // the restrictions to indicate which turns may be restricted due to a way in between.
class WayRestrictionMap class WayRestrictionMap
{ {
public: public:
struct ViaWay struct ViaEdge
{ {
NodeID from; NodeID from;
NodeID to; NodeID to;
}; };
WayRestrictionMap(const std::vector<ConditionalTurnRestriction> &conditional_restrictions); WayRestrictionMap(const RestrictionGraph &restriction_graph);
// Check if an edge between two nodes is a restricted turn. The check needs to be performed to // Check if an edge between two nodes is part of a via-way. The check needs to be performed to
// find duplicated nodes during the creation of edge-based-edges // find duplicated nodes during the creation of edge-based-edges
bool IsViaWay(const NodeID from, const NodeID to) const; bool IsViaWayEdge(NodeID from, NodeID to) const;
// Every via-way results in a duplicated node that is required in the edge-based-graph. This // There is a bijection between restriction graph via-nodes and edge-based duplicated nodes.
// count is essentially the same as the number of valid via-way restrictions (except for // This counts the number of duplicated nodes contributed by the way restrictions.
// non-only restrictions that share the same in/via combination)
std::size_t NumberOfDuplicatedNodes() const; std::size_t NumberOfDuplicatedNodes() const;
// Returns a representative for each duplicated node, consisting of the representative ID (first // For each restriction graph via-node, we return its node-based edge representation (from,to).
// ID of the nodes restrictions) and the from/to vertices of the via-way // This is used to create the duplicate node in the edge based graph.
// This is used to construct edge based nodes that act as intermediate nodes. std::vector<ViaEdge> DuplicatedViaEdges() const;
std::vector<ViaWay> DuplicatedNodeRepresentatives() const;
// Access all duplicated NodeIDs for a set of nodes indicating a via way // Access all duplicated NodeIDs from the restriction graph via-node represented by (from,to)
std::vector<DuplicatedNodeID> DuplicatedNodeIDs(const NodeID from, const NodeID to) const; std::vector<DuplicatedNodeID> DuplicatedNodeIDs(NodeID from, NodeID to) const;
// check whether a turn onto a given node is restricted, when coming from a duplicated node // Check whether a turn onto a given node is restricted, when coming from a duplicated node
bool IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const; bool IsRestricted(DuplicatedNodeID duplicated_node, NodeID to) const;
// Get the restriction resulting in ^ IsRestricted. Requires IsRestricted to evaluate to true
const ConditionalTurnRestriction &GetRestriction(DuplicatedNodeID duplicated_node,
const NodeID to) const;
// changes edge_based_node to the correct duplicated_node_id in case node_based_from, // Get the restrictions resulting in ^ IsRestricted. Requires IsRestricted to evaluate to true
// node_based_via, node_based_to can be identified with a restriction group std::vector<const TurnRestriction *> GetRestrictions(DuplicatedNodeID duplicated_node,
NodeID RemapIfRestricted(const NodeID edge_based_node, NodeID to) const;
const NodeID node_based_from,
const NodeID node_based_via, // Changes edge_based_node to the correct duplicated_node_id in case node_based_from,
const NodeID node_based_to, // node_based_via, node_based_to can be identified as the start of a way restriction.
const NodeID number_of_edge_based_nodes) const; NodeID RemapIfRestrictionStart(NodeID edge_based_node,
NodeID node_based_from,
NodeID node_based_via,
NodeID node_based_to,
NodeID number_of_edge_based_nodes) const;
// Changes edge_based_node to the correct duplicated_node_id in case node_based_from,
// node_based_via, node_based_to can be identified as successive via steps of a way restriction.
NodeID RemapIfRestrictionVia(NodeID edge_based_target_node,
NodeID edge_based_via_node,
NodeID node_based_to,
NodeID number_of_edge_based_nodes) const;
private: private:
DuplicatedNodeID AsDuplicatedNodeID(const RestrictionID restriction_id) const; const RestrictionGraph &restriction_graph;
// access all restrictions that have the same starting way and via way. Any duplicated node
// represents the same in-way + via-way combination. This vector contains data about all
// restrictions and their assigned duplicated nodes. It indicates the minimum restriciton ID
// that is represented by the next node. The ID of a node is defined as the position of the
// lower bound of the restrictions ID within this array
//
// a - b
// |
// y - c - x
//
// restriction nodes | restriction id
// a - b - c - x : 5
// a - b - c - y : 6
//
// EBN: 0 . | 2 | 3 | 4 ...
// duplicated node groups: ... | 5 | 7 | ...
std::vector<DuplicatedNodeID> duplicated_node_groups;
std::vector<ConditionalTurnRestriction> restriction_data;
RestrictionIndex<ConditionalTurnRestriction> restriction_starts;
}; };
} // namespace extractor } // namespace extractor

View File

@ -6,6 +6,7 @@
#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_edge_container.hpp"
#include "extractor/name_table.hpp" #include "extractor/name_table.hpp"
#include "extractor/node_data_container.hpp" #include "extractor/node_data_container.hpp"
#include "extractor/node_restriction_map.hpp"
#include "extractor/suffix_table.hpp" #include "extractor/suffix_table.hpp"
#include "extractor/turn_lane_types.hpp" #include "extractor/turn_lane_types.hpp"
#include "extractor/way_restriction_map.hpp" #include "extractor/way_restriction_map.hpp"

View File

@ -4,7 +4,7 @@
#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_edge_container.hpp"
#include "extractor/intersection/intersection_view.hpp" #include "extractor/intersection/intersection_view.hpp"
#include "extractor/name_table.hpp" #include "extractor/name_table.hpp"
#include "extractor/restriction_index.hpp" #include "extractor/node_restriction_map.hpp"
#include "extractor/suffix_table.hpp" #include "extractor/suffix_table.hpp"
#include "guidance/driveway_handler.hpp" #include "guidance/driveway_handler.hpp"

View File

@ -1,7 +1,7 @@
#ifndef OSRM_GUIDANCE_TURN_DISCOVERY_HPP_ #ifndef OSRM_GUIDANCE_TURN_DISCOVERY_HPP_
#define OSRM_GUIDANCE_TURN_DISCOVERY_HPP_ #define OSRM_GUIDANCE_TURN_DISCOVERY_HPP_
#include "extractor/restriction_index.hpp" #include "extractor/node_restriction_map.hpp"
#include "guidance/intersection.hpp" #include "guidance/intersection.hpp"
#include "guidance/turn_lane_data.hpp" #include "guidance/turn_lane_data.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"

View File

@ -0,0 +1,31 @@
#ifndef FOR_EACH_INDEXED_HPP
#define FOR_EACH_INDEXED_HPP
#include <iterator>
#include <numeric>
#include <utility>
namespace osrm
{
namespace util
{
template <typename ForwardIterator, typename Function>
void for_each_indexed(ForwardIterator first, ForwardIterator last, Function function)
{
for (size_t i = 0; first != last; ++first, ++i)
{
function(i, *first);
}
}
template <class ContainerT, typename Function>
void for_each_pair(ContainerT &container, Function function)
{
for_each_indexed(std::begin(container), std::end(container), function);
}
} // namespace util
} // namespace osrm
#endif /* FOR_EACH_INDEXED_HPP */

View File

@ -61,8 +61,8 @@ void inplacePermutation(RandomAccessIterator begin,
template <typename IndexT> template <typename IndexT>
std::vector<IndexT> orderingToPermutation(const std::vector<IndexT> &ordering) std::vector<IndexT> orderingToPermutation(const std::vector<IndexT> &ordering)
{ {
std::vector<std::uint32_t> permutation(ordering.size()); std::vector<IndexT> permutation(ordering.size());
for (auto index : util::irange<std::uint32_t>(0, ordering.size())) for (auto index : util::irange<IndexT>(0, ordering.size()))
permutation[ordering[index]] = index; permutation[ordering[index]] = index;
return permutation; return permutation;

View File

@ -103,6 +103,7 @@ static const NodeID SPECIAL_NODEID = std::numeric_limits<NodeID>::max();
static const NodeID SPECIAL_SEGMENTID = std::numeric_limits<NodeID>::max() >> 1; static const NodeID SPECIAL_SEGMENTID = std::numeric_limits<NodeID>::max() >> 1;
static const NodeID SPECIAL_GEOMETRYID = std::numeric_limits<NodeID>::max() >> 1; static const NodeID SPECIAL_GEOMETRYID = std::numeric_limits<NodeID>::max() >> 1;
static const EdgeID SPECIAL_EDGEID = std::numeric_limits<EdgeID>::max(); static const EdgeID SPECIAL_EDGEID = std::numeric_limits<EdgeID>::max();
static const RestrictionID SPECIAL_RESTRICTIONID = std::numeric_limits<RestrictionID>::max();
static const NameID INVALID_NAMEID = std::numeric_limits<NameID>::max(); static const NameID INVALID_NAMEID = std::numeric_limits<NameID>::max();
static const NameID EMPTY_NAMEID = 0; static const NameID EMPTY_NAMEID = 0;
static const unsigned INVALID_COMPONENTID = 0; static const unsigned INVALID_COMPONENTID = 0;

View File

@ -239,7 +239,7 @@ void EdgeBasedGraphFactory::Run(
const std::string &cnbg_ebg_mapping_path, const std::string &cnbg_ebg_mapping_path,
const std::string &conditional_penalties_filename, const std::string &conditional_penalties_filename,
const std::string &maneuver_overrides_filename, const std::string &maneuver_overrides_filename,
const RestrictionMap &node_restriction_map, const RestrictionMap &unconditional_node_restriction_map,
const ConditionalRestrictionMap &conditional_node_restriction_map, const ConditionalRestrictionMap &conditional_node_restriction_map,
const WayRestrictionMap &way_restriction_map, const WayRestrictionMap &way_restriction_map,
const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides) const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides)
@ -268,7 +268,7 @@ void EdgeBasedGraphFactory::Run(
turn_penalties_index_filename, turn_penalties_index_filename,
conditional_penalties_filename, conditional_penalties_filename,
maneuver_overrides_filename, maneuver_overrides_filename,
node_restriction_map, unconditional_node_restriction_map,
conditional_node_restriction_map, conditional_node_restriction_map,
way_restriction_map, way_restriction_map,
unresolved_maneuver_overrides); unresolved_maneuver_overrides);
@ -374,17 +374,17 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
// Add copies of the nodes // Add copies of the nodes
{ {
util::UnbufferedLog log; util::UnbufferedLog log;
const auto via_ways = way_restriction_map.DuplicatedNodeRepresentatives(); const auto via_edges = way_restriction_map.DuplicatedViaEdges();
util::Percent progress(log, via_ways.size()); util::Percent progress(log, via_edges.size());
NodeID edge_based_node_id = NodeID edge_based_node_id =
NodeID(m_number_of_edge_based_nodes - way_restriction_map.NumberOfDuplicatedNodes()); NodeID(m_number_of_edge_based_nodes - way_restriction_map.NumberOfDuplicatedNodes());
std::size_t progress_counter = 0; std::size_t progress_counter = 0;
// allocate enough space for the mapping // allocate enough space for the mapping
for (const auto way : via_ways) for (const auto edge : via_edges)
{ {
const auto node_u = way.from; const auto node_u = edge.from;
const auto node_v = way.to; const auto node_v = edge.to;
// we know that the edge exists as non-reversed edge // we know that the edge exists as non-reversed edge
const auto eid = m_node_based_graph.FindEdge(node_u, node_v); const auto eid = m_node_based_graph.FindEdge(node_u, node_v);
@ -437,8 +437,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const std::string &turn_penalties_index_filename, const std::string &turn_penalties_index_filename,
const std::string &conditional_penalties_filename, const std::string &conditional_penalties_filename,
const std::string &maneuver_overrides_filename, const std::string &maneuver_overrides_filename,
const RestrictionMap &node_restriction_map, const RestrictionMap &unconditional_node_restriction_map,
const ConditionalRestrictionMap &conditional_restriction_map, const ConditionalRestrictionMap &conditional_node_restriction_map,
const WayRestrictionMap &way_restriction_map, const WayRestrictionMap &way_restriction_map,
const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides) const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides)
{ {
@ -452,7 +452,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
m_edge_based_node_container, m_edge_based_node_container,
m_coordinates, m_coordinates,
m_compressed_edge_container, m_compressed_edge_container,
node_restriction_map, unconditional_node_restriction_map,
m_barrier_nodes, m_barrier_nodes,
turn_lanes_data, turn_lanes_data,
name_table, name_table,
@ -544,10 +544,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
}); });
// Generate edges for either artificial nodes or the main graph // Generate edges for either artificial nodes or the main graph
const auto generate_edge = [this, const auto generate_edge = [this, &scripting_environment, weight_multiplier](
&scripting_environment,
weight_multiplier,
&conditional_restriction_map](
// what nodes will be used? In most cases this will be the id // 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. // stored in the edge_data. In case of duplicated nodes (e.g.
// due to via-way restrictions), one/both of these might // due to via-way restrictions), one/both of these might
@ -563,24 +560,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto &road_legs_on_the_right, const auto &road_legs_on_the_right,
const auto &road_legs_on_the_left, const auto &road_legs_on_the_left,
const auto &edge_geometries) { const auto &edge_geometries) {
const auto node_restricted =
isRestricted(node_along_road_entering,
intersection_node,
m_node_based_graph.GetTarget(node_based_edge_to),
conditional_restriction_map);
boost::optional<Conditional> conditional = boost::none;
if (node_restricted.first)
{
auto const &conditions = node_restricted.second->condition;
// get conditions of the restriction limiting the node
conditional = {{edge_based_node_from,
edge_based_node_to,
{static_cast<std::uint64_t>(-1),
m_coordinates[intersection_node],
conditions}}};
}
const auto &edge_data1 = m_node_based_graph.GetEdgeData(node_based_edge_from); const auto &edge_data1 = m_node_based_graph.GetEdgeData(node_based_edge_from);
const auto &edge_data2 = m_node_based_graph.GetEdgeData(node_based_edge_to); const auto &edge_data2 = m_node_based_graph.GetEdgeData(node_based_edge_to);
@ -676,9 +655,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
lookup::TurnIndexBlock turn_index_block = {from_node, intersection_node, to_node}; lookup::TurnIndexBlock turn_index_block = {from_node, intersection_node, to_node};
// insert data into the designated buffer // insert data into the designated buffer
return std::make_pair( return EdgeWithData{
EdgeWithData{edge_based_edge, turn_index_block, weight_penalty, duration_penalty}, edge_based_edge, turn_index_block, weight_penalty, duration_penalty};
conditional);
}; };
// //
@ -739,7 +717,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto intersection_view = const auto intersection_view =
convertToIntersectionView(m_node_based_graph, convertToIntersectionView(m_node_based_graph,
m_edge_based_node_container, m_edge_based_node_container,
node_restriction_map, unconditional_node_restriction_map,
m_barrier_nodes, m_barrier_nodes,
edge_geometries, edge_geometries,
turn_lanes_data, turn_lanes_data,
@ -747,16 +725,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
outgoing_edges, outgoing_edges,
merged_edge_ids); merged_edge_ids);
// check if we are turning off a via way // check if this edge is part of a restriction via-way
const auto turning_off_via_way = const auto is_restriction_via_edge =
way_restriction_map.IsViaWay(incoming_edge.node, intersection_node); way_restriction_map.IsViaWayEdge(incoming_edge.node, intersection_node);
for (const auto &outgoing_edge : outgoing_edges) for (const auto &outgoing_edge : outgoing_edges)
{ {
auto is_turn_allowed = auto is_turn_allowed =
intersection::isTurnAllowed(m_node_based_graph, intersection::isTurnAllowed(m_node_based_graph,
m_edge_based_node_container, m_edge_based_node_container,
node_restriction_map, unconditional_node_restriction_map,
m_barrier_nodes, m_barrier_nodes,
edge_geometries, edge_geometries,
turn_lanes_data, turn_lanes_data,
@ -850,7 +828,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
} }
// In case a way restriction starts at a given location, add a turn onto // In case a way restriction starts at a given location, add a turn onto
// every artificial node eminating here. // every artificial node emanating here.
// //
// e - f // e - f
// | // |
@ -861,14 +839,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// ab via bc to cd // ab via bc to cd
// ab via be to ef // ab via be to ef
// //
// has two artifical nodes (be/bc) with restrictions starting at `ab`. // has two artificial nodes (be/bc) with restrictions starting at `ab`.
// Since every restriction group (abc | abe) refers to the same // Since every restriction group (abc | abe) refers to the same
// artificial node, we simply have to find a single representative for // artificial node, we simply have to find a single representative for
// the turn. Here we check whether the turn in question is the start of // the turn. Here we check whether the turn in question is the start of
// a via way restriction. If that should be the case, we switch the id // a via way restriction. If that should be the case, we switch the id
// of the edge-based-node for the target to the ID of the duplicated // of the edge-based-node for the target to the ID of the duplicated
// node associated with the turn. (e.g. ab via bc switches bc to bc_dup) // node associated with the turn. (e.g. ab via bc switches bc to bc_dup)
auto const target_id = way_restriction_map.RemapIfRestricted( auto const target_id = way_restriction_map.RemapIfRestrictionStart(
nbe_to_ebn_mapping[outgoing_edge.edge], nbe_to_ebn_mapping[outgoing_edge.edge],
incoming_edge.node, incoming_edge.node,
outgoing_edge.node, outgoing_edge.node,
@ -877,7 +855,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
/***************************/ /***************************/
const auto edgetarget = const auto outgoing_edge_target =
m_node_based_graph.GetTarget(outgoing_edge.edge); m_node_based_graph.GetTarget(outgoing_edge.edge);
// TODO: this loop is not optimized - once we have a few // TODO: this loop is not optimized - once we have a few
@ -888,7 +866,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
for (auto &turn : override.turn_sequence) for (auto &turn : override.turn_sequence)
{ {
if (turn.from == incoming_edge.node && if (turn.from == incoming_edge.node &&
turn.via == intersection_node && turn.to == edgetarget) turn.via == intersection_node &&
turn.to == outgoing_edge_target)
{ {
const auto &ebn_from = const auto &ebn_from =
nbe_to_ebn_mapping[incoming_edge.edge]; nbe_to_ebn_mapping[incoming_edge.edge];
@ -900,7 +879,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
} }
{ // scope to forget edge_with_data after { // scope to forget edge_with_data after
const auto edge_with_data_and_condition = const auto edge_with_data =
generate_edge(nbe_to_ebn_mapping[incoming_edge.edge], generate_edge(nbe_to_ebn_mapping[incoming_edge.edge],
target_id, target_id,
incoming_edge.node, incoming_edge.node,
@ -912,20 +891,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
road_legs_on_the_left, road_legs_on_the_left,
edge_geometries); edge_geometries);
buffer->continuous_data.push_back( buffer->continuous_data.push_back(edge_with_data);
edge_with_data_and_condition.first);
if (edge_with_data_and_condition.second) // get conditional restrictions that apply to this turn
const auto &restrictions =
conditional_node_restriction_map.Restrictions(
incoming_edge.node,
outgoing_edge.node,
outgoing_edge_target);
for (const auto &restriction : restrictions)
{ {
buffer->conditionals.push_back( buffer->conditionals.push_back(
*edge_with_data_and_condition.second); {nbe_to_ebn_mapping[incoming_edge.edge],
target_id,
{static_cast<std::uint64_t>(-1),
m_coordinates[intersection_node],
restriction->condition}});
} }
} }
// when turning off a a via-way turn restriction, we need to not only // When on the edge of a via-way turn restriction, we need to not only
// handle the normal edges for the way, but also add turns for every // handle the normal edges for the way, but also add turns for every
// duplicated node. This process is integrated here to avoid doing the // duplicated node. This process is integrated here to avoid doing the
// turn analysis multiple times. // turn analysis multiple times.
if (turning_off_via_way) if (is_restriction_via_edge)
{ {
const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs( const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs(
incoming_edge.node, intersection_node); incoming_edge.node, intersection_node);
@ -943,71 +932,91 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
auto const node_at_end_of_turn = auto const node_at_end_of_turn =
m_node_based_graph.GetTarget(outgoing_edge.edge); m_node_based_graph.GetTarget(outgoing_edge.edge);
const auto is_way_restricted = way_restriction_map.IsRestricted( const auto is_restricted = way_restriction_map.IsRestricted(
duplicated_node_id, node_at_end_of_turn); duplicated_node_id, node_at_end_of_turn);
if (is_way_restricted) if (is_restricted)
{ {
auto const restriction = way_restriction_map.GetRestriction( auto const &restrictions =
duplicated_node_id, node_at_end_of_turn); way_restriction_map.GetRestrictions(
duplicated_node_id, node_at_end_of_turn);
if (restriction.condition.empty()) auto const has_unconditional =
std::any_of(restrictions.begin(),
restrictions.end(),
[](const auto &restriction) {
return restriction->IsUnconditional();
});
if (has_unconditional)
continue; continue;
// add into delayed data // From this via way, the outgoing edge will either:
auto edge_with_data_and_condition = // a) take a conditional turn transferring to a via
generate_edge(from_id, // path of an overlapping restriction.
nbe_to_ebn_mapping[outgoing_edge.edge], // b) take a conditional turn to exit the restriction.
incoming_edge.node, // If a) is applicable here, we change the target to be
incoming_edge.edge, // the duplicate restriction node.
outgoing_edge.node, auto const via_target_id =
outgoing_edge.edge, way_restriction_map.RemapIfRestrictionVia(
turn->angle, nbe_to_ebn_mapping[outgoing_edge.edge],
road_legs_on_the_right, from_id,
road_legs_on_the_left, m_node_based_graph.GetTarget(outgoing_edge.edge),
edge_geometries); m_number_of_edge_based_nodes);
buffer->delayed_data.push_back( // add into delayed data
edge_with_data_and_condition.first); auto edge_with_data = generate_edge(from_id,
if (edge_with_data_and_condition.second) via_target_id,
{ incoming_edge.node,
buffer->conditionals.push_back( incoming_edge.edge,
*edge_with_data_and_condition.second); outgoing_edge.node,
} outgoing_edge.edge,
turn->angle,
road_legs_on_the_right,
road_legs_on_the_left,
edge_geometries);
buffer->delayed_data.push_back(edge_with_data);
// also add the conditions for the way // also add the conditions for the way
if (is_way_restricted && !restriction.condition.empty()) for (const auto &restriction : restrictions)
{ {
// add a new conditional for the edge we just created // add a new conditional for the edge we just
// created
buffer->conditionals.push_back( buffer->conditionals.push_back(
{from_id, {from_id,
nbe_to_ebn_mapping[outgoing_edge.edge], via_target_id,
{static_cast<std::uint64_t>(-1), {static_cast<std::uint64_t>(-1),
m_coordinates[intersection_node], m_coordinates[intersection_node],
restriction.condition}}); restriction->condition}});
} }
} }
else else
{ {
auto edge_with_data_and_condition = // From this via way, the outgoing edge will either:
generate_edge(from_id, // a) continue along the current via path
nbe_to_ebn_mapping[outgoing_edge.edge], // b) transfer to a via path of an overlapping restriction.
incoming_edge.node, // c) exit the restriction
incoming_edge.edge, // If a) or b) are applicable here, we change the target to
outgoing_edge.node, // be the duplicate restriction node.
outgoing_edge.edge, auto const via_target_id =
turn->angle, way_restriction_map.RemapIfRestrictionVia(
road_legs_on_the_right, nbe_to_ebn_mapping[outgoing_edge.edge],
road_legs_on_the_left, from_id,
edge_geometries); m_node_based_graph.GetTarget(outgoing_edge.edge),
m_number_of_edge_based_nodes);
buffer->delayed_data.push_back( auto edge_with_data = generate_edge(from_id,
edge_with_data_and_condition.first); via_target_id,
if (edge_with_data_and_condition.second) incoming_edge.node,
{ incoming_edge.edge,
buffer->conditionals.push_back( outgoing_edge.node,
*edge_with_data_and_condition.second); outgoing_edge.edge,
} turn->angle,
road_legs_on_the_right,
road_legs_on_the_left,
edge_geometries);
buffer->delayed_data.push_back(edge_with_data);
} }
} }
} }

View File

@ -10,17 +10,12 @@
#include "util/exception.hpp" #include "util/exception.hpp"
#include "util/exception_utils.hpp" #include "util/exception_utils.hpp"
#include "util/fingerprint.hpp" #include "util/for_each_indexed.hpp"
#include "util/log.hpp" #include "util/log.hpp"
#include "util/timing_util.hpp" #include "util/timing_util.hpp"
#include "storage/io.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/numeric/conversion/cast.hpp> #include <boost/numeric/conversion/cast.hpp>
#include <boost/ref.hpp>
#include <tbb/parallel_sort.h> #include <tbb/parallel_sort.h>
@ -99,6 +94,64 @@ inline NodeID mapExternalToInternalNodeID(Iter first, Iter last, const OSMNodeID
return (it == last || value < *it) ? SPECIAL_NODEID return (it == last || value < *it) ? SPECIAL_NODEID
: static_cast<NodeID>(std::distance(first, it)); : static_cast<NodeID>(std::distance(first, it));
} }
/**
* Here's what these properties represent on the node-based-graph
* way "ABCD" way "AB"
* -----------------------------------------------------------------
* A first_segment_source_id
* |
* B first_segment_target_id A first_segment_source_id
* | | last_segment_source_id
* | |
* | B first_segment_target_id
* C last_segment_source_id last_segment_target_id
* |
* D last_segment_target_id
*
* Finds the point where two ways connect at the end, and returns the 3
* node-based nodes that describe the turn (the node just before, the
* node at the turn, and the next node after the turn)
**/
std::tuple<OSMNodeID, OSMNodeID, OSMNodeID> find_turn_nodes(const oe::NodesOfWay &from,
const oe::NodesOfWay &via,
const OSMNodeID &intersection_node)
{
// connection node needed to choose orientation if from and via are the same way. E.g. u-turns
if (intersection_node == SPECIAL_OSM_NODEID ||
intersection_node == from.first_segment_source_id())
{
if (from.first_segment_source_id() == via.first_segment_source_id())
{
return std::make_tuple(from.first_segment_target_id(),
via.first_segment_source_id(),
via.first_segment_target_id());
}
if (from.first_segment_source_id() == via.last_segment_target_id())
{
return std::make_tuple(from.first_segment_target_id(),
via.last_segment_target_id(),
via.last_segment_source_id());
}
}
if (intersection_node == SPECIAL_OSM_NODEID ||
intersection_node == from.last_segment_target_id())
{
if (from.last_segment_target_id() == via.first_segment_source_id())
{
return std::make_tuple(from.last_segment_source_id(),
via.first_segment_source_id(),
via.first_segment_target_id());
}
if (from.last_segment_target_id() == via.last_segment_target_id())
{
return std::make_tuple(from.last_segment_source_id(),
via.last_segment_target_id(),
via.last_segment_source_id());
}
}
return std::make_tuple(SPECIAL_OSM_NODEID, SPECIAL_OSM_NODEID, SPECIAL_OSM_NODEID);
}
} // namespace } // namespace
namespace osrm namespace osrm
@ -116,6 +169,8 @@ ExtractionContainers::ExtractionContainers()
name_offsets.push_back(0); name_offsets.push_back(0);
// Insert the total length sentinel (corresponds to the next name string offset) // Insert the total length sentinel (corresponds to the next name string offset)
name_offsets.push_back(0); name_offsets.push_back(0);
// Sentinel for offset into used_nodes
way_node_id_offsets.push_back(0);
} }
/** /**
@ -134,6 +189,9 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
{ {
storage::tar::FileWriter writer(osrm_path, storage::tar::FileWriter::GenerateFingerprint); storage::tar::FileWriter writer(osrm_path, storage::tar::FileWriter::GenerateFingerprint);
const auto restriction_ways = IdentifyRestrictionWays();
const auto maneuver_override_ways = IdentifyManeuverOverrideWays();
PrepareNodes(); PrepareNodes();
WriteNodes(writer); WriteNodes(writer);
PrepareEdges(scripting_environment); PrepareEdges(scripting_environment);
@ -142,20 +200,8 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
WriteEdges(writer); WriteEdges(writer);
WriteMetadata(writer); WriteMetadata(writer);
/* Sort these so that searching is a bit faster later on */ PrepareManeuverOverrides(maneuver_override_ways);
{ PrepareRestrictions(restriction_ways);
util::UnbufferedLog log;
log << "Sorting used ways ... ";
TIMER_START(sort_ways);
tbb::parallel_sort(way_start_end_id_list.begin(),
way_start_end_id_list.end(),
FirstAndLastSegmentOfWayCompare());
TIMER_STOP(sort_ways);
log << "ok, after " << TIMER_SEC(sort_ways) << "s";
}
PrepareManeuverOverrides();
PrepareRestrictions();
WriteCharData(name_file_name); WriteCharData(name_file_name);
} }
@ -665,47 +711,52 @@ void ExtractionContainers::WriteNodes(storage::tar::FileWriter &writer) const
util::Log() << "Processed " << max_internal_node_id << " nodes"; util::Log() << "Processed " << max_internal_node_id << " nodes";
} }
void ExtractionContainers::PrepareManeuverOverrides() ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyManeuverOverrideWays()
{ {
std::unordered_map<OSMWayID, FirstAndLastSegmentOfWay> referenced_ways; ReferencedWays maneuver_override_ways;
// prepare for extracting source/destination nodes for all maneuvers // prepare for extracting source/destination nodes for all maneuvers
{ util::UnbufferedLog log;
util::UnbufferedLog log; log << "Collecting way information on " << external_maneuver_overrides_list.size()
log << "Collecting start/end information on " << external_maneuver_overrides_list.size() << " maneuver overrides...";
<< " maneuver overrides..."; TIMER_START(identify_maneuver_override_ways);
TIMER_START(prepare_maneuver_overrides);
const auto mark_ids = [&](auto const &external_maneuver_override) { const auto mark_ids = [&](auto const &external_maneuver_override) {
FirstAndLastSegmentOfWay dummy_segment{ NodesOfWay dummy_segment{MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}};
MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID}; std::for_each(external_maneuver_override.via_ways.begin(),
std::for_each(external_maneuver_override.via_ways.begin(), external_maneuver_override.via_ways.end(),
external_maneuver_override.via_ways.end(), [&maneuver_override_ways, dummy_segment](const auto &element) {
[&referenced_ways, dummy_segment](const auto &element) { maneuver_override_ways[element] = dummy_segment;
referenced_ways[element] = dummy_segment; });
}); };
};
// First, make an empty hashtable keyed by the ways referenced // First, make an empty hashtable keyed by the ways referenced
// by the maneuver overrides // by the maneuver overrides
std::for_each(external_maneuver_overrides_list.begin(), std::for_each(
external_maneuver_overrides_list.end(), external_maneuver_overrides_list.begin(), external_maneuver_overrides_list.end(), mark_ids);
mark_ids);
const auto set_ids = [&](auto const &start_end) { const auto set_ids = [&](size_t way_list_idx, auto const &way_id) {
auto itr = referenced_ways.find(start_end.way_id); auto itr = maneuver_override_ways.find(way_id);
if (itr != referenced_ways.end()) if (itr != maneuver_override_ways.end())
itr->second = start_end; {
}; auto node_start_itr = used_node_id_list.begin() + way_node_id_offsets[way_list_idx];
auto node_end_itr = used_node_id_list.begin() + way_node_id_offsets[way_list_idx + 1];
itr->second = NodesOfWay(way_id, std::vector<OSMNodeID>(node_start_itr, node_end_itr));
}
};
// Then, populate the values in that hashtable for only the ways // Then, populate the values in that hashtable for only the ways
// referenced // referenced
std::for_each(way_start_end_id_list.cbegin(), way_start_end_id_list.cend(), set_ids); util::for_each_indexed(ways_list.cbegin(), ways_list.cend(), set_ids);
TIMER_STOP(prepare_maneuver_overrides); TIMER_STOP(identify_maneuver_override_ways);
log << "ok, after " << TIMER_SEC(prepare_maneuver_overrides) << "s"; log << "ok, after " << TIMER_SEC(identify_maneuver_override_ways) << "s";
}
return maneuver_override_ways;
}
void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways)
{
auto const osm_node_to_internal_nbn = [&](auto const osm_node) { auto const osm_node_to_internal_nbn = [&](auto const osm_node) {
auto internal = mapExternalToInternalNodeID( auto internal = mapExternalToInternalNodeID(
used_node_id_list.begin(), used_node_id_list.end(), osm_node); used_node_id_list.begin(), used_node_id_list.end(), osm_node);
@ -716,82 +767,34 @@ void ExtractionContainers::PrepareManeuverOverrides()
return internal; return internal;
}; };
// Given
// a -- b - ????????? - c -- d as via segment
// and either
// d -- e - ????????? - f -- g or
// h -- i - ????????? - j -- a
// return
// (d,e) or (j,a) as entry-segment
/**
* Here's what these properties represent on the node-based-graph
* way "ABCD" way "AB"
* -----------------------------------------------------------------
* A first_segment_source_id
* |
* B first_segment_target_id A first_segment_source_id
* | | last_segment_source_id
* | |
* | B first_segment_target_id
* C last_segment_source_id last_segment_target_id
* |
* D last_segment_target_id
*
* Finds the point where two ways connect at the end, and returns the 3
* node-based nodes that describe the turn (the node just before, the
* node at the turn, and the next node after the turn)
**/
auto const find_turn_from_way_tofrom_nodes = [&](auto const &from_segment,
auto const &to_segment) {
if (from_segment.first_segment_source_id == to_segment.first_segment_source_id)
{
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.first_segment_target_id),
osm_node_to_internal_nbn(from_segment.first_segment_source_id),
osm_node_to_internal_nbn(to_segment.first_segment_target_id)};
}
else if (from_segment.first_segment_source_id == to_segment.last_segment_target_id)
{
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.first_segment_target_id),
osm_node_to_internal_nbn(from_segment.first_segment_source_id),
osm_node_to_internal_nbn(to_segment.last_segment_source_id)};
}
else if (from_segment.last_segment_target_id == to_segment.first_segment_source_id)
{
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.last_segment_source_id),
osm_node_to_internal_nbn(from_segment.last_segment_target_id),
osm_node_to_internal_nbn(to_segment.first_segment_target_id)};
}
else if (from_segment.last_segment_target_id == to_segment.last_segment_target_id)
{
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.last_segment_source_id),
osm_node_to_internal_nbn(from_segment.last_segment_target_id),
osm_node_to_internal_nbn(to_segment.last_segment_source_id)};
}
util::Log(logDEBUG) << "Maneuver override ways " << from_segment.way_id << " and "
<< to_segment.way_id << " are not connected";
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
};
auto const get_turn_from_way_pair = [&](const OSMWayID &from_id, const OSMWayID &to_id) { auto const get_turn_from_way_pair = [&](const OSMWayID &from_id, const OSMWayID &to_id) {
auto const from_segment_itr = referenced_ways.find(from_id); auto const from_segment_itr = maneuver_override_ways.find(from_id);
if (from_segment_itr->second.way_id != from_id) if (from_segment_itr->second.way_id != from_id)
{ {
util::Log(logDEBUG) << "Override references invalid way: " << from_id; util::Log(logDEBUG) << "Override references invalid way: " << from_id;
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID}; return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
} }
auto const to_segment_itr = referenced_ways.find(to_id); auto const to_segment_itr = maneuver_override_ways.find(to_id);
if (to_segment_itr->second.way_id != to_id) if (to_segment_itr->second.way_id != to_id)
{ {
util::Log(logDEBUG) << "Override references invalid way: " << to_id; util::Log(logDEBUG) << "Override references invalid way: " << to_id;
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID}; return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
} }
auto result = OSMNodeID from, via, to;
find_turn_from_way_tofrom_nodes(from_segment_itr->second, to_segment_itr->second); std::tie(from, via, to) =
find_turn_nodes(from_segment_itr->second, to_segment_itr->second, SPECIAL_OSM_NODEID);
return result; if (via == SPECIAL_OSM_NODEID)
{
// unconnected
util::Log(logDEBUG) << "Maneuver override ways " << from_segment_itr->second.way_id
<< " and " << to_segment_itr->second.way_id << " are not connected";
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
}
return NodeBasedTurn{osm_node_to_internal_nbn(from),
osm_node_to_internal_nbn(via),
osm_node_to_internal_nbn(to)};
}; };
const auto strings_to_turn_type_and_direction = [](const std::string &turn_string, const auto strings_to_turn_type_and_direction = [](const std::string &turn_string,
@ -909,7 +912,7 @@ void ExtractionContainers::PrepareManeuverOverrides()
// Transforming the overrides into the dedicated internal types // Transforming the overrides into the dedicated internal types
{ {
util::UnbufferedLog log; util::UnbufferedLog log;
log << "Collecting start/end information on " << external_maneuver_overrides_list.size() log << "Collecting node information on " << external_maneuver_overrides_list.size()
<< " maneuver overrides..."; << " maneuver overrides...";
TIMER_START(transform); TIMER_START(transform);
std::for_each(external_maneuver_overrides_list.begin(), std::for_each(external_maneuver_overrides_list.begin(),
@ -920,54 +923,64 @@ void ExtractionContainers::PrepareManeuverOverrides()
} }
} }
void ExtractionContainers::PrepareRestrictions() ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWays()
{ {
// Contains the nodes of each way that is part of an restriction
ReferencedWays restriction_ways;
// contain the start/end nodes of each way that is part of an restriction // Prepare for extracting nodes for all restrictions
std::unordered_map<OSMWayID, FirstAndLastSegmentOfWay> referenced_ways; util::UnbufferedLog log;
log << "Collecting way information on " << restrictions_list.size() << " restrictions...";
TIMER_START(identify_restriction_ways);
// prepare for extracting source/destination nodes for all restrictions // Enter invalid IDs into the map to indicate that we want to find out about
{ // nodes of these ways.
util::UnbufferedLog log; const auto mark_ids = [&](auto const &turn_restriction) {
log << "Collecting start/end information on " << restrictions_list.size() NodesOfWay dummy_segment{MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}};
<< " restrictions..."; if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
TIMER_START(prepare_restrictions); {
const auto &way = turn_restriction.AsWayRestriction();
const auto mark_ids = [&](auto const &turn_restriction) { restriction_ways[way.from] = dummy_segment;
FirstAndLastSegmentOfWay dummy_segment{ restriction_ways[way.to] = dummy_segment;
MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID}; for (const auto &v : way.via)
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
{ {
const auto &way = turn_restriction.AsWayRestriction(); restriction_ways[v] = dummy_segment;
referenced_ways[way.from] = dummy_segment;
referenced_ways[way.to] = dummy_segment;
referenced_ways[way.via] = dummy_segment;
} }
else }
{ else
BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION); {
const auto &node = turn_restriction.AsNodeRestriction(); BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION);
referenced_ways[node.from] = dummy_segment; const auto &node = turn_restriction.AsNodeRestriction();
referenced_ways[node.to] = dummy_segment; restriction_ways[node.from] = dummy_segment;
} restriction_ways[node.to] = dummy_segment;
}; }
};
std::for_each(restrictions_list.begin(), restrictions_list.end(), mark_ids); std::for_each(restrictions_list.begin(), restrictions_list.end(), mark_ids);
// enter invalid IDs into the above maps to indicate that we want to find out about // Update the values for all ways already sporting SPECIAL_NODEID
// start/end const auto set_ids = [&](const size_t way_list_idx, auto const &way_id) {
// nodes of these ways auto itr = restriction_ways.find(way_id);
// update the values for all edges already sporting SPECIAL_NODEID if (itr != restriction_ways.end())
const auto set_ids = [&](auto const &start_end) { {
auto itr = referenced_ways.find(start_end.way_id); const auto node_start_offset =
if (itr != referenced_ways.end()) used_node_id_list.begin() + way_node_id_offsets[way_list_idx];
itr->second = start_end; const auto node_end_offset =
}; used_node_id_list.begin() + way_node_id_offsets[way_list_idx + 1];
itr->second =
NodesOfWay(way_id, std::vector<OSMNodeID>(node_start_offset, node_end_offset));
}
};
std::for_each(way_start_end_id_list.cbegin(), way_start_end_id_list.cend(), set_ids); util::for_each_indexed(ways_list.cbegin(), ways_list.cend(), set_ids);
TIMER_STOP(prepare_restrictions); TIMER_STOP(identify_restriction_ways);
log << "ok, after " << TIMER_SEC(prepare_restrictions) << "s"; log << "ok, after " << TIMER_SEC(identify_restriction_ways) << "s";
}
return restriction_ways;
}
void ExtractionContainers::PrepareRestrictions(const ReferencedWays &restriction_ways)
{
auto const to_internal = [&](auto const osm_node) { auto const to_internal = [&](auto const osm_node) {
auto internal = mapExternalToInternalNodeID( auto internal = mapExternalToInternalNodeID(
@ -979,167 +992,242 @@ void ExtractionContainers::PrepareRestrictions()
return internal; return internal;
}; };
// Given // Way restrictions are comprised of:
// a -- b - ????????? - c -- d as via segment // 1. The segment in the from way that intersects with the via path
// and either // 2. All segments that make up the via path
// d -- e - ????????? - f -- g or // 3. The segment in the to way that intersects with the via path.
// h -- i - ????????? - j -- a //
// (d,e) or (j,a) as entry-segment // from: [a, b, c, d, e]
auto const find_node_restriction = // via: [[f, g, h, i, j], [k, l], [m, n, o]]
[&](auto const &segment, auto const &via_segment, auto const via_node) { // to: [p, q, r, s]
// In case of way-restrictions, via-node will be set to MAX_OSM_NODEID to signal //
// that // First establish the orientation of the from/via intersection by finding which end
// the node is not present. // nodes both ways share. From this we can select the from segment.
// connected at the front of the segment //
// Turn restrictions are described as a restriction between the two segments closest // intersect | from segment | next_connection
// to // a=f | b,a | f
// the shared via-node on the from and to ways. Graph compression will later // a=j | b,a | j
// renumber // e=f | e,d | f
// the from and to internal node IDs as nodes are plucked out of the node-based // e=j | e,d | j
// graph. //
if (via_node == MAX_OSM_NODEID || segment.first_segment_source_id == via_node) // Use the next connection to inform the orientation of the first via
// way and the intersection between first and second via ways.
//
// next_connection | intersect | via result | next_next_connection
// f | j=k | [f,g,h,i,j] | k
// f | j=l | [f,g,h,i,j] | l
// j | f=k | [j,i,h,g,f] | k
// j | f=l | [j,i,h,g,f] | l
//
// This is continued for the remaining via ways, appending to the via result
//
// The final via/to intersection also uses the next_connection information in a similar fashion.
//
// next_connection | intersect | to_segment
// m | o=p | p,q
// m | o=s | s,r
// o | m=p | p,q
// o | m=s | s,r
//
// The final result is a list of nodes that represent a valid from->via->to path through the
// ways.
//
// E.g. if intersection nodes are a=j, f=l, k=o, m=s
// the result will be {e [d,c,b,a,i,h,g,f,k,n,m] r}
auto const find_way_restriction = [&](const NodesOfWay &from_way,
const std::vector<NodesOfWay> &via_ways,
const NodesOfWay &to_way) {
BOOST_ASSERT(!via_ways.empty());
WayRestriction restriction;
// Find the orientation of the connected ways starting with the from-via intersection.
OSMNodeID from, via;
std::tie(from, via, std::ignore) =
find_turn_nodes(from_way, via_ways.front(), SPECIAL_OSM_NODEID);
if (via == SPECIAL_OSM_NODEID)
{
util::Log(logDEBUG) << "Restriction has unconnected from and via ways: "
<< from_way.way_id << ", " << via_ways.front().way_id;
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
}
restriction.from = to_internal(from);
restriction.via.push_back(to_internal(via));
// Use the connection node from the previous intersection to inform our conversion of
// via ways into internal nodes.
OSMNodeID next_connection = via;
for (const auto &via_way : via_ways)
{
if (next_connection == via_way.first_segment_source_id())
{ {
if (segment.first_segment_source_id == via_segment.first_segment_source_id) std::transform(std::next(via_way.node_ids.begin()),
{ via_way.node_ids.end(),
return NodeRestriction{to_internal(segment.first_segment_target_id), std::back_inserter(restriction.via),
to_internal(segment.first_segment_source_id), to_internal);
to_internal(via_segment.first_segment_target_id)}; next_connection = via_way.last_segment_target_id();
} }
else if (segment.first_segment_source_id == via_segment.last_segment_target_id) else if (next_connection == via_way.last_segment_target_id())
{ {
return NodeRestriction{to_internal(segment.first_segment_target_id), std::transform(std::next(via_way.node_ids.rbegin()),
to_internal(segment.first_segment_source_id), via_way.node_ids.rend(),
to_internal(via_segment.last_segment_source_id)}; std::back_inserter(restriction.via),
} to_internal);
next_connection = via_way.first_segment_source_id();
}
else
{
util::Log(logDEBUG) << "Restriction has unconnected via way: " << via_way.way_id
<< " to node " << next_connection;
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
}
}
// Add the final to node after the via-to intersection.
if (next_connection == to_way.first_segment_source_id())
{
restriction.to = to_internal(to_way.first_segment_target_id());
}
else if (next_connection == to_way.last_segment_target_id())
{
restriction.to = to_internal(to_way.last_segment_source_id());
}
else
{
util::Log(logDEBUG) << "Restriction has unconnected via and to ways: "
<< via_ways.back().way_id << ", " << to_way.way_id;
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
}
return restriction;
};
// Check if we were able to resolve all the involved OSM elements before translating to an
// internal restriction
auto const get_way_restriction_from_OSM_ids =
[&](auto const from_id, auto const to_id, const std::vector<OSMWayID> &via_ids) {
auto const from_way_itr = restriction_ways.find(from_id);
if (from_way_itr->second.way_id != from_id)
{
util::Log(logDEBUG) << "Restriction references invalid from way: " << from_id;
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
} }
// connected at the end of the segment std::vector<NodesOfWay> via_ways;
if (via_node == MAX_OSM_NODEID || segment.last_segment_target_id == via_node) for (const auto &via_id : via_ids)
{ {
if (segment.last_segment_target_id == via_segment.first_segment_source_id) auto const via_segment_itr = restriction_ways.find(via_id);
if (via_segment_itr->second.way_id != via_id)
{ {
return NodeRestriction{to_internal(segment.last_segment_source_id), util::Log(logDEBUG) << "Restriction references invalid via way: " << via_id;
to_internal(segment.last_segment_target_id), return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
to_internal(via_segment.first_segment_target_id)};
}
else if (segment.last_segment_target_id == via_segment.last_segment_target_id)
{
return NodeRestriction{to_internal(segment.last_segment_source_id),
to_internal(segment.last_segment_target_id),
to_internal(via_segment.last_segment_source_id)};
} }
via_ways.push_back(via_segment_itr->second);
} }
// unconnected auto const to_way_itr = restriction_ways.find(to_id);
util::Log(logDEBUG) << "Restriction references unconnected way: " << segment.way_id; if (to_way_itr->second.way_id != to_id)
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID}; {
util::Log(logDEBUG) << "Restriction references invalid to way: " << to_id;
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
}
return find_way_restriction(from_way_itr->second, via_ways, to_way_itr->second);
}; };
// translate the turn from one segment onto another into a node restriction (the ways can // Node restrictions are described as a restriction between the two segments closest
// only // to the shared via-node on the from and to ways.
// be connected at a single location) // from: [a, b, c, d, e]
// to: [f, g, h, i, j]
//
// The via node establishes the orientation of the from/to intersection when choosing the
// segments.
// via | node restriction
// a=f | b,a,g
// a=j | b,a,i
// e=f | d,e,g
// e=j | d,e,i
auto const find_node_restriction =
[&](auto const &from_segment, auto const &to_segment, auto const via_node) {
OSMNodeID from, via, to;
std::tie(from, via, to) = find_turn_nodes(from_segment, to_segment, via_node);
if (via == SPECIAL_OSM_NODEID)
{
// unconnected
util::Log(logDEBUG)
<< "Restriction references unconnected way: " << from_segment.way_id;
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
}
return NodeRestriction{to_internal(from), to_internal(via), to_internal(to)};
};
// Check if we were able to resolve all the involved OSM elements before translating to an
// internal restriction
auto const get_node_restriction_from_OSM_ids = [&](auto const from_id, auto const get_node_restriction_from_OSM_ids = [&](auto const from_id,
auto const to_id, auto const to_id,
const OSMNodeID via_node) { const OSMNodeID via_node) {
auto const from_segment_itr = referenced_ways.find(from_id); auto const from_segment_itr = restriction_ways.find(from_id);
if (from_segment_itr->second.way_id != 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(to_id); auto const to_segment_itr = restriction_ways.find(to_id);
if (to_segment_itr->second.way_id != 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};
} }
return find_node_restriction(from_segment_itr->second, to_segment_itr->second, via_node); return find_node_restriction(from_segment_itr->second, to_segment_itr->second, via_node);
}; };
// 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.
// Based on the auto type deduction, this transfor handles both conditional and
// unconditional
// turn restrictions.
const auto transform = [&](const auto &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();
// check if we were able to resolve all the involved ways auto const restriction =
auto const from_restriction = get_way_restriction_from_OSM_ids(external.from, external.to, external.via);
get_node_restriction_from_OSM_ids(external.from, external.via, MAX_OSM_NODEID);
auto const to_restriction =
get_node_restriction_from_OSM_ids(external.via, external.to, MAX_OSM_NODEID);
// failed to translate either of the involved nodes? if (!restriction.Valid())
if (!from_restriction.Valid() || !to_restriction.Valid())
return false; return false;
// point located at both via and segment is alway on `second`, to FSSF is the order internal_type.node_or_way = restriction;
// we
// need
WayRestriction way_restriction{from_restriction, to_restriction};
internal_type.node_or_way = std::move(way_restriction);
return true; return true;
} }
else else
{ {
BOOST_ASSERT(external_type.Type() == RestrictionType::NODE_RESTRICTION); BOOST_ASSERT(external_type.Type() == RestrictionType::NODE_RESTRICTION);
auto const &external = external_type.AsNodeRestriction(); auto const &external = external_type.AsNodeRestriction();
auto const via_node = to_internal(external.via);
// check if we were able to resolve all the involved ways
auto restriction = auto restriction =
get_node_restriction_from_OSM_ids(external.from, external.to, external.via); get_node_restriction_from_OSM_ids(external.from, external.to, external.via);
if (!restriction.Valid()) if (!restriction.Valid())
{
return false; return false;
}
if (restriction.via != via_node) internal_type.node_or_way = restriction;
{
util::Log(logDEBUG) << "Restriction references invalid way: " << external.via;
return false;
}
internal_type.node_or_way = std::move(restriction);
return true; return true;
} }
}; };
// wrapper function to handle distinction between conditional and unconditional turn const auto transform_into_internal_types = [&](InputTurnRestriction &external_restriction) {
// restrictions TurnRestriction restriction;
const auto transform_into_internal_types = if (transform(external_restriction, restriction))
[&](const InputConditionalTurnRestriction &external_restriction) { {
// unconditional restriction restriction.is_only = external_restriction.is_only;
if (external_restriction.condition.empty() && restriction.condition = std::move(external_restriction.condition);
external_restriction.Type() == RestrictionType::NODE_RESTRICTION) turn_restrictions.push_back(std::move(restriction));
{ }
TurnRestriction restriction; };
restriction.is_only = external_restriction.is_only;
if (transform(external_restriction, restriction))
unconditional_turn_restrictions.push_back(std::move(restriction));
}
// conditional turn restriction
else
{
ConditionalTurnRestriction restriction;
restriction.is_only = external_restriction.is_only;
restriction.condition = std::move(external_restriction.condition);
if (transform(external_restriction, restriction))
{
conditional_turn_restrictions.push_back(std::move(restriction));
}
}
};
// Transforming the restrictions into the dedicated internal types // Transforming the restrictions into the dedicated internal types
{ {
util::UnbufferedLog log; util::UnbufferedLog log;
log << "Collecting start/end information on " << restrictions_list.size() log << "Collecting node information on " << restrictions_list.size() << " restrictions...";
<< " restrictions...";
TIMER_START(transform); TIMER_START(transform);
std::for_each( std::for_each(
restrictions_list.begin(), restrictions_list.end(), transform_into_internal_types); restrictions_list.begin(), restrictions_list.end(), transform_into_internal_types);

View File

@ -12,8 +12,9 @@
#include "extractor/maneuver_override_relation_parser.hpp" #include "extractor/maneuver_override_relation_parser.hpp"
#include "extractor/name_table.hpp" #include "extractor/name_table.hpp"
#include "extractor/node_based_graph_factory.hpp" #include "extractor/node_based_graph_factory.hpp"
#include "extractor/node_restriction_map.hpp"
#include "extractor/restriction_filter.hpp" #include "extractor/restriction_filter.hpp"
#include "extractor/restriction_index.hpp" #include "extractor/restriction_graph.hpp"
#include "extractor/restriction_parser.hpp" #include "extractor/restriction_parser.hpp"
#include "extractor/scripting_environment.hpp" #include "extractor/scripting_environment.hpp"
#include "extractor/tarjan_scc.hpp" #include "extractor/tarjan_scc.hpp"
@ -215,12 +216,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
LaneDescriptionMap turn_lane_map; LaneDescriptionMap turn_lane_map;
std::vector<TurnRestriction> turn_restrictions; std::vector<TurnRestriction> turn_restrictions;
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
std::vector<UnresolvedManeuverOverride> unresolved_maneuver_overrides; std::vector<UnresolvedManeuverOverride> unresolved_maneuver_overrides;
std::tie(turn_lane_map, std::tie(turn_lane_map, turn_restrictions, unresolved_maneuver_overrides) =
turn_restrictions,
conditional_turn_restrictions,
unresolved_maneuver_overrides) =
ParseOSMData(scripting_environment, number_of_threads); ParseOSMData(scripting_environment, number_of_threads);
// Transform the node-based graph that OSM is based on into an edge-based graph // Transform the node-based graph that OSM is based on into an edge-based graph
@ -242,7 +239,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"), NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"),
scripting_environment, scripting_environment,
turn_restrictions, turn_restrictions,
conditional_turn_restrictions,
unresolved_maneuver_overrides); unresolved_maneuver_overrides);
NameTable name_table; NameTable name_table;
@ -283,8 +279,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
edge_based_nodes_container = edge_based_nodes_container =
EdgeBasedNodeDataContainer({}, std::move(node_based_graph_factory.GetAnnotationData())); EdgeBasedNodeDataContainer({}, std::move(node_based_graph_factory.GetAnnotationData()));
conditional_turn_restrictions = turn_restrictions = removeInvalidRestrictions(std::move(turn_restrictions), node_based_graph);
removeInvalidRestrictions(std::move(conditional_turn_restrictions), node_based_graph); auto restriction_graph = constructRestrictionGraph(turn_restrictions);
const auto number_of_node_based_nodes = node_based_graph.GetNumberOfNodes(); const auto number_of_node_based_nodes = node_based_graph.GetNumberOfNodes();
@ -294,8 +290,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
node_based_graph_factory.GetCompressedEdges(), node_based_graph_factory.GetCompressedEdges(),
barrier_nodes, barrier_nodes,
traffic_signals, traffic_signals,
turn_restrictions, restriction_graph,
conditional_turn_restrictions,
segregated_edges, segregated_edges,
name_table, name_table,
unresolved_maneuver_overrides, unresolved_maneuver_overrides,
@ -314,8 +309,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
coordinates, coordinates,
node_based_graph_factory.GetCompressedEdges(), node_based_graph_factory.GetCompressedEdges(),
barrier_nodes, barrier_nodes,
turn_restrictions, restriction_graph,
conditional_turn_restrictions,
name_table, name_table,
std::move(turn_lane_map), std::move(turn_lane_map),
scripting_environment); scripting_environment);
@ -374,12 +368,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
return 0; return 0;
} }
std::tuple<LaneDescriptionMap, std::
std::vector<TurnRestriction>, tuple<LaneDescriptionMap, std::vector<TurnRestriction>, std::vector<UnresolvedManeuverOverride>>
std::vector<ConditionalTurnRestriction>, Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
std::vector<UnresolvedManeuverOverride>> const unsigned number_of_threads)
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
const unsigned number_of_threads)
{ {
TIMER_START(extracting); TIMER_START(extracting);
@ -455,7 +447,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
std::vector<std::pair<const osmium::Node &, ExtractionNode>> resulting_nodes; std::vector<std::pair<const osmium::Node &, ExtractionNode>> resulting_nodes;
std::vector<std::pair<const osmium::Way &, ExtractionWay>> resulting_ways; std::vector<std::pair<const osmium::Way &, ExtractionWay>> resulting_ways;
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> resulting_relations; std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> resulting_relations;
std::vector<InputConditionalTurnRestriction> resulting_restrictions; std::vector<InputTurnRestriction> resulting_restrictions;
std::vector<InputManeuverOverride> resulting_maneuver_overrides; std::vector<InputManeuverOverride> resulting_maneuver_overrides;
}; };
@ -638,8 +630,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s"; util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
return std::make_tuple(std::move(turn_lane_map), return std::make_tuple(std::move(turn_lane_map),
std::move(extraction_containers.unconditional_turn_restrictions), std::move(extraction_containers.turn_restrictions),
std::move(extraction_containers.conditional_turn_restrictions),
std::move(extraction_containers.internal_maneuver_overrides)); std::move(extraction_containers.internal_maneuver_overrides));
} }
@ -712,8 +703,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
const CompressedEdgeContainer &compressed_edge_container, const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes, const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_signals, const std::unordered_set<NodeID> &traffic_signals,
const std::vector<TurnRestriction> &turn_restrictions, const RestrictionGraph &restriction_graph,
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
const std::unordered_set<EdgeID> &segregated_edges, const std::unordered_set<EdgeID> &segregated_edges,
const NameTable &name_table, const NameTable &name_table,
const std::vector<UnresolvedManeuverOverride> &maneuver_overrides, const std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
@ -740,21 +730,10 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
turn_lane_map); turn_lane_map);
const auto create_edge_based_edges = [&]() { const auto create_edge_based_edges = [&]() {
// scoped to relase intermediate datastructures right after the call // scoped to release intermediate data structures right after the call
std::vector<TurnRestriction> node_restrictions; RestrictionMap unconditional_node_restriction_map(restriction_graph);
for (auto const &t : turn_restrictions) ConditionalRestrictionMap conditional_node_restriction_map(restriction_graph);
if (t.Type() == RestrictionType::NODE_RESTRICTION) WayRestrictionMap via_way_restriction_map(restriction_graph);
node_restrictions.push_back(t);
std::vector<ConditionalTurnRestriction> conditional_node_restrictions;
for (auto const &t : conditional_turn_restrictions)
if (t.Type() == RestrictionType::NODE_RESTRICTION)
conditional_node_restrictions.push_back(t);
RestrictionMap via_node_restriction_map(node_restrictions, IndexNodeByFromAndVia());
WayRestrictionMap via_way_restriction_map(conditional_turn_restrictions);
ConditionalRestrictionMap conditional_node_restriction_map(conditional_node_restrictions,
IndexNodeByFromAndVia());
edge_based_graph_factory.Run(scripting_environment, edge_based_graph_factory.Run(scripting_environment,
config.GetPath(".osrm.turn_weight_penalties").string(), config.GetPath(".osrm.turn_weight_penalties").string(),
config.GetPath(".osrm.turn_duration_penalties").string(), config.GetPath(".osrm.turn_duration_penalties").string(),
@ -762,7 +741,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
config.GetPath(".osrm.cnbg_to_ebg").string(), config.GetPath(".osrm.cnbg_to_ebg").string(),
config.GetPath(".osrm.restrictions").string(), config.GetPath(".osrm.restrictions").string(),
config.GetPath(".osrm.maneuver_overrides").string(), config.GetPath(".osrm.maneuver_overrides").string(),
via_node_restriction_map, unconditional_node_restriction_map,
conditional_node_restriction_map, conditional_node_restriction_map,
via_way_restriction_map, via_way_restriction_map,
maneuver_overrides); maneuver_overrides);
@ -833,8 +812,7 @@ void Extractor::ProcessGuidanceTurns(
const std::vector<util::Coordinate> &node_coordinates, const std::vector<util::Coordinate> &node_coordinates,
const CompressedEdgeContainer &compressed_edge_container, const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes, const std::unordered_set<NodeID> &barrier_nodes,
const std::vector<TurnRestriction> &turn_restrictions, const RestrictionGraph &restriction_graph,
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
const NameTable &name_table, const NameTable &name_table,
LaneDescriptionMap lane_description_map, LaneDescriptionMap lane_description_map,
ScriptingEnvironment &scripting_environment) ScriptingEnvironment &scripting_environment)
@ -853,20 +831,15 @@ void Extractor::ProcessGuidanceTurns(
SuffixTable street_name_suffix_table(scripting_environment); SuffixTable street_name_suffix_table(scripting_environment);
const auto &turn_lanes_data = transformTurnLaneMapIntoArrays(lane_description_map); const auto &turn_lanes_data = transformTurnLaneMapIntoArrays(lane_description_map);
std::vector<TurnRestriction> node_restrictions; RestrictionMap unconditional_node_restriction_map(restriction_graph);
for (auto const &t : turn_restrictions) WayRestrictionMap way_restriction_map(restriction_graph);
if (t.Type() == RestrictionType::NODE_RESTRICTION)
node_restrictions.push_back(t);
RestrictionMap node_restriction_map(node_restrictions, IndexNodeByFromAndVia());
WayRestrictionMap way_restriction_map(conditional_turn_restrictions);
osrm::guidance::annotateTurns(node_based_graph, osrm::guidance::annotateTurns(node_based_graph,
edge_based_node_container, edge_based_node_container,
node_coordinates, node_coordinates,
compressed_edge_container, compressed_edge_container,
barrier_nodes, barrier_nodes,
node_restriction_map, unconditional_node_restriction_map,
way_restriction_map, way_restriction_map,
name_table, name_table,
street_name_suffix_table, street_name_suffix_table,

View File

@ -11,7 +11,6 @@
#include "util/guidance/turn_lanes.hpp" #include "util/guidance/turn_lanes.hpp"
#include "util/log.hpp" #include "util/log.hpp"
#include <boost/numeric/conversion/cast.hpp>
#include <boost/optional/optional.hpp> #include <boost/optional/optional.hpp>
#include <boost/tokenizer.hpp> #include <boost/tokenizer.hpp>
@ -19,8 +18,6 @@
#include "osrm/coordinate.hpp" #include "osrm/coordinate.hpp"
#include <cstring>
#include <iterator>
#include <limits> #include <limits>
#include <string> #include <string>
#include <vector> #include <vector>
@ -69,10 +66,9 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
} }
} }
void ExtractorCallbacks::ProcessRestriction(const InputConditionalTurnRestriction &restriction) void ExtractorCallbacks::ProcessRestriction(const InputTurnRestriction &restriction)
{ {
external_memory.restrictions_list.push_back(restriction); external_memory.restrictions_list.push_back(restriction);
// util::Log() << restriction.toString();
} }
void ExtractorCallbacks::ProcessManeuverOverride(const InputManeuverOverride &override) void ExtractorCallbacks::ProcessManeuverOverride(const InputManeuverOverride &override)
@ -477,12 +473,9 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
return OSMNodeID{static_cast<std::uint64_t>(ref.ref())}; return OSMNodeID{static_cast<std::uint64_t>(ref.ref())};
}); });
external_memory.way_start_end_id_list.push_back( auto way_id = OSMWayID{static_cast<std::uint64_t>(input_way.id())};
{OSMWayID{static_cast<std::uint32_t>(input_way.id())}, external_memory.ways_list.push_back(way_id);
OSMNodeID{static_cast<std::uint64_t>(nodes[0].ref())}, external_memory.way_node_id_offsets.push_back(external_memory.used_node_id_list.size());
OSMNodeID{static_cast<std::uint64_t>(nodes[1].ref())},
OSMNodeID{static_cast<std::uint64_t>(nodes[nodes.size() - 2].ref())},
OSMNodeID{static_cast<std::uint64_t>(nodes.back().ref())}});
} }
} // namespace extractor } // namespace extractor

View File

@ -20,46 +20,40 @@ namespace osrm
namespace extractor namespace extractor
{ {
void GraphCompressor::Compress( void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &barrier_nodes, const std::unordered_set<NodeID> &traffic_signals,
const std::unordered_set<NodeID> &traffic_signals, ScriptingEnvironment &scripting_environment,
ScriptingEnvironment &scripting_environment, std::vector<TurnRestriction> &turn_restrictions,
std::vector<TurnRestriction> &turn_restrictions, std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions, util::NodeBasedDynamicGraph &graph,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides, const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
util::NodeBasedDynamicGraph &graph, CompressedEdgeContainer &geometry_compressor)
const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
CompressedEdgeContainer &geometry_compressor)
{ {
const unsigned original_number_of_nodes = graph.GetNumberOfNodes(); const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
const unsigned original_number_of_edges = graph.GetNumberOfEdges(); const unsigned original_number_of_edges = graph.GetNumberOfEdges();
RestrictionCompressor restriction_compressor( RestrictionCompressor restriction_compressor(turn_restrictions, maneuver_overrides);
turn_restrictions, conditional_turn_restrictions, maneuver_overrides);
// we do not compress turn restrictions on degree two nodes. These nodes are usually used to // Some degree two nodes are not compressed if they act as entry/exit points into a
// indicated `directed` barriers // restriction path.
std::unordered_set<NodeID> restriction_via_nodes; std::unordered_set<NodeID> restriction_via_nodes;
const auto remember_via_nodes = [&](const auto &restriction) { const auto remember_via_nodes = [&](const auto &restriction) {
if (restriction.Type() == RestrictionType::NODE_RESTRICTION) if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
{ {
const auto &node = restriction.AsNodeRestriction(); restriction_via_nodes.insert(restriction.AsNodeRestriction().via);
restriction_via_nodes.insert(node.via);
} }
else else
{ {
BOOST_ASSERT(restriction.Type() == RestrictionType::WAY_RESTRICTION); BOOST_ASSERT(restriction.Type() == RestrictionType::WAY_RESTRICTION);
const auto &way = restriction.AsWayRestriction(); const auto &way_restriction = restriction.AsWayRestriction();
restriction_via_nodes.insert(way.in_restriction.via); // We do not compress the first and last via nodes so that we know how to enter/exit
restriction_via_nodes.insert(way.out_restriction.via); // a restriction path and apply the restrictions correctly.
restriction_via_nodes.insert(way_restriction.via.front());
restriction_via_nodes.insert(way_restriction.via.back());
} }
}; };
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes); std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes);
std::for_each(conditional_turn_restrictions.begin(),
conditional_turn_restrictions.end(),
remember_via_nodes);
{ {
const auto weight_multiplier = const auto weight_multiplier =
scripting_environment.GetProfileProperties().GetWeightMultiplier(); scripting_environment.GetProfileProperties().GetWeightMultiplier();
@ -82,8 +76,8 @@ void GraphCompressor::Compress(
continue; continue;
} }
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node // check if v is an entry/exit via node for a turn restriction
if (restriction_via_nodes.count(node_v)) if (restriction_via_nodes.count(node_v) > 0)
{ {
continue; continue;
} }
@ -181,7 +175,7 @@ void GraphCompressor::Compress(
* reasonable, since the announcements have to come early anyhow. So there is a * reasonable, since the announcements have to come early anyhow. So there is a
* potential danger in here, but it saves us from adding a lot of additional edges * potential danger in here, but it saves us from adding a lot of additional edges
* for * for
* turn-lanes. Without this,we would have to treat any turn-lane beginning/ending * turn-lanes. Without this, we would have to treat any turn-lane beginning/ending
* just * just
* like a barrier. * like a barrier.
*/ */

View File

@ -428,24 +428,10 @@ double findEdgeLength(const IntersectionEdgeGeometries &geometries, const EdgeID
template <typename RestrictionsRange> template <typename RestrictionsRange>
bool isTurnRestricted(const RestrictionsRange &restrictions, const NodeID to) bool isTurnRestricted(const RestrictionsRange &restrictions, const NodeID to)
{ {
// Check turn restrictions to find a node that is the only allowed target when coming from a // Check if any of the restrictions would prevent a turn to 'to'
// node to an intersection return std::any_of(restrictions.begin(), restrictions.end(), [&to](const auto &restriction) {
// d return restriction->IsTurnRestricted(to);
// | });
// a - b - c and `only_straight_on ab | bc would return `c` for `a,b`
const auto is_only = std::find_if(restrictions.first,
restrictions.second,
[](const auto &pair) { return pair.second->is_only; });
if (is_only != restrictions.second)
return is_only->second->AsNodeRestriction().to != to;
// Check if explicitly forbidden
const auto no_turn =
std::find_if(restrictions.first, restrictions.second, [&to](const auto &restriction) {
return restriction.second->AsNodeRestriction().to == to;
});
return no_turn != restrictions.second;
} }
bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph, bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph,

View File

@ -19,14 +19,10 @@ NodeBasedGraphFactory::NodeBasedGraphFactory(
const boost::filesystem::path &input_file, const boost::filesystem::path &input_file,
ScriptingEnvironment &scripting_environment, ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions, std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides) std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
{ {
LoadDataFromFile(input_file); LoadDataFromFile(input_file);
Compress(scripting_environment, Compress(scripting_environment, turn_restrictions, maneuver_overrides);
turn_restrictions,
conditional_turn_restrictions,
maneuver_overrides);
CompressGeometry(); CompressGeometry();
CompressAnnotationData(); CompressAnnotationData();
} }
@ -82,18 +78,15 @@ void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &inpu
}()); }());
} }
void NodeBasedGraphFactory::Compress( void NodeBasedGraphFactory::Compress(ScriptingEnvironment &scripting_environment,
ScriptingEnvironment &scripting_environment, std::vector<TurnRestriction> &turn_restrictions,
std::vector<TurnRestriction> &turn_restrictions, std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
{ {
GraphCompressor graph_compressor; GraphCompressor graph_compressor;
graph_compressor.Compress(barriers, graph_compressor.Compress(barriers,
traffic_signals, traffic_signals,
scripting_environment, scripting_environment,
turn_restrictions, turn_restrictions,
conditional_turn_restrictions,
maneuver_overrides, maneuver_overrides,
compressed_output_graph, compressed_output_graph,
annotation_data, annotation_data,

View File

@ -3,7 +3,6 @@
#include <algorithm> #include <algorithm>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <utility>
namespace osrm namespace osrm
{ {
@ -12,41 +11,35 @@ namespace extractor
RestrictionCompressor::RestrictionCompressor( RestrictionCompressor::RestrictionCompressor(
std::vector<TurnRestriction> &restrictions, std::vector<TurnRestriction> &restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides) std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
{ {
// add a node restriction ptr to the starts/ends maps, needs to be a reference! // add a turn restriction ptr to the starts/ends maps, needs to be a reference!
auto index = [&](auto &element) { auto index = [&](auto &element) {
starts.insert(std::make_pair(element.from, &element)); starts.insert({element.From(), &element});
ends.insert(std::make_pair(element.to, &element)); ends.insert({element.To(), &element});
if (element.Type() == RestrictionType::WAY_RESTRICTION)
{
const auto &way_via = element.AsWayRestriction().via;
BOOST_ASSERT(way_via.size() >= 2);
// No need to track the first and last via nodes as they will not be compressed.
for (const auto &via_node :
boost::make_iterator_range(way_via.begin() + 1, way_via.end() - 1))
{
vias.insert({via_node, &element});
}
}
}; };
// !needs to be reference, so we can get the correct address // !needs to be reference, so we can get the correct address
const auto index_starts_and_ends = [&](auto &restriction) { const auto index_starts_ends_vias = [&](auto &restriction) { index(restriction); };
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
{
auto &way_restriction = restriction.AsWayRestriction();
index(way_restriction.in_restriction);
index(way_restriction.out_restriction);
}
else
{
BOOST_ASSERT(restriction.Type() == RestrictionType::NODE_RESTRICTION);
auto &node_restriction = restriction.AsNodeRestriction();
index(node_restriction);
}
};
// add all restrictions as their respective startend pointers // add all restrictions as their respective start/via/end pointers
std::for_each(restrictions.begin(), restrictions.end(), index_starts_and_ends); std::for_each(restrictions.begin(), restrictions.end(), index_starts_ends_vias);
std::for_each(conditional_turn_restrictions.begin(),
conditional_turn_restrictions.end(),
index_starts_and_ends);
auto index_maneuver = [&](auto &maneuver) { auto index_maneuver = [&](auto &maneuver) {
for (auto &turn : maneuver.turn_sequence) for (auto &turn : maneuver.turn_sequence)
{ {
maneuver_starts.insert(std::make_pair(turn.from, &turn)); maneuver_starts.insert({turn.from, &turn});
maneuver_ends.insert(std::make_pair(turn.to, &turn)); maneuver_ends.insert({turn.to, &turn});
} }
}; };
// !needs to be reference, so we can get the correct address // !needs to be reference, so we can get the correct address
@ -58,26 +51,48 @@ RestrictionCompressor::RestrictionCompressor(
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to) void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
{ {
// handle turn restrictions // handle turn restrictions
// extract all startptrs and move them from via to from. // extract all start ptrs and move them from via to from.
auto all_starts_range = starts.equal_range(via); auto all_starts_range = starts.equal_range(via);
std::vector<NodeRestriction *> start_ptrs; std::vector<TurnRestriction *> start_ptrs;
std::transform(all_starts_range.first, std::transform(all_starts_range.first,
all_starts_range.second, all_starts_range.second,
std::back_inserter(start_ptrs), std::back_inserter(start_ptrs),
[](const auto pair) { return pair.second; }); [](const auto pair) { return pair.second; });
const auto update_start = [&](auto ptr) { const auto update_start = [&](auto ptr) {
// ____ | from - p.from | via - p.via | to - p.to | ____ if (ptr->Type() == RestrictionType::NODE_RESTRICTION)
BOOST_ASSERT(ptr->from == via);
if (ptr->via == to)
{ {
ptr->from = from;
// ____ | from - p.from | via - p.via | to - p.to | ____
auto &node_ptr = ptr->AsNodeRestriction();
BOOST_ASSERT(node_ptr.from == via);
if (node_ptr.via == to)
{
node_ptr.from = from;
}
// ____ | to - p.from | via - p.via | from - p.to | ____
else
{
BOOST_ASSERT(node_ptr.via == from);
node_ptr.from = to;
}
} }
// ____ | to - p.from | via - p.via | from - p.to | ____
else else
{ {
BOOST_ASSERT(ptr->via == from); BOOST_ASSERT(ptr->Type() == RestrictionType::WAY_RESTRICTION);
ptr->from = to; auto &way_ptr = ptr->AsWayRestriction();
// ____ | from - p.from | via - p.via[0] | to - p[1..],p.to | ____
BOOST_ASSERT(way_ptr.from == via);
if (way_ptr.via.front() == to)
{
way_ptr.from = from;
}
// ____ | to - p.from | via - p.via[0] | from - p[1,..],p.to | ____
else
{
BOOST_ASSERT(way_ptr.via.front() == from);
way_ptr.from = to;
}
} }
}; };
@ -86,29 +101,52 @@ void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const
// update the ptrs in our mapping // update the ptrs in our mapping
starts.erase(via); starts.erase(via);
const auto reinsert_start = [&](auto ptr) { starts.insert(std::make_pair(ptr->from, ptr)); }; const auto reinsert_start = [&](auto ptr) { starts.insert({ptr->From(), ptr}); };
std::for_each(start_ptrs.begin(), start_ptrs.end(), reinsert_start); std::for_each(start_ptrs.begin(), start_ptrs.end(), reinsert_start);
// extract all end ptrs and move them from via to to // extract all end ptrs and move them from via to to
auto all_ends_range = ends.equal_range(via); auto all_ends_range = ends.equal_range(via);
std::vector<NodeRestriction *> end_ptrs; std::vector<TurnRestriction *> end_ptrs;
std::transform(all_ends_range.first, std::transform(all_ends_range.first,
all_ends_range.second, all_ends_range.second,
std::back_inserter(end_ptrs), std::back_inserter(end_ptrs),
[](const auto pair) { return pair.second; }); [](const auto pair) { return pair.second; });
const auto update_end = [&](auto ptr) { const auto update_end = [&](auto ptr) {
BOOST_ASSERT(ptr->to == via); if (ptr->Type() == RestrictionType::NODE_RESTRICTION)
// p.from | ____ - p.via | from - p.to | via - ____ | to
if (ptr->via == from)
{ {
ptr->to = to; auto &node_ptr = ptr->AsNodeRestriction();
BOOST_ASSERT(node_ptr.to == via);
// p.from | ____ - p.via | from - p.to | via - ____ | to
if (node_ptr.via == from)
{
node_ptr.to = to;
}
// p.from | ____ - p.via | to - p.to | via - ____ | from
else
{
BOOST_ASSERT(node_ptr.via == to);
node_ptr.to = from;
}
} }
// p.from | ____ - p.via | to - p.to | via - ____ | from
else else
{ {
BOOST_ASSERT(ptr->via == to); BOOST_ASSERT(ptr->Type() == RestrictionType::WAY_RESTRICTION);
ptr->to = from; auto &way_ptr = ptr->AsWayRestriction();
BOOST_ASSERT(way_ptr.to == via);
// p.from,p.via[..,n-1] | ____ - p.via[n] | from - p.to | via - ____ | to
if (way_ptr.via.back() == from)
{
way_ptr.to = to;
}
// p.from,p.via[..,n-1] | ____ - p.via[n] | to - p.to | via - ____ | from
else
{
BOOST_ASSERT(way_ptr.via.back() == to);
way_ptr.to = from;
}
} }
}; };
std::for_each(end_ptrs.begin(), end_ptrs.end(), update_end); std::for_each(end_ptrs.begin(), end_ptrs.end(), update_end);
@ -116,9 +154,24 @@ void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const
// update end ptrs in mapping // update end ptrs in mapping
ends.erase(via); ends.erase(via);
const auto reinsert_end = [&](auto ptr) { ends.insert(std::make_pair(ptr->to, ptr)); }; const auto reinsert_end = [&](auto ptr) { ends.insert({ptr->To(), ptr}); };
std::for_each(end_ptrs.begin(), end_ptrs.end(), reinsert_end); std::for_each(end_ptrs.begin(), end_ptrs.end(), reinsert_end);
// remove compressed node from all via paths
auto all_vias_range = vias.equal_range(via);
const auto update_via = [&](auto restriction_pair) {
BOOST_ASSERT(restriction_pair.second->Type() == RestrictionType::WAY_RESTRICTION);
auto &way_ptr = restriction_pair.second->AsWayRestriction();
BOOST_ASSERT(std::find(way_ptr.via.begin(), way_ptr.via.end(), via) != way_ptr.via.end());
way_ptr.via.erase(std::remove(way_ptr.via.begin(), way_ptr.via.end(), via),
way_ptr.via.end());
};
std::for_each(all_vias_range.first, all_vias_range.second, update_via);
// update via ptrs in mapping
vias.erase(via);
/**********************************************************************************************/ /**********************************************************************************************/
// handle maneuver overrides from nodes // handle maneuver overrides from nodes
@ -149,9 +202,7 @@ void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const
// update the ptrs in our mapping // update the ptrs in our mapping
maneuver_starts.erase(via); maneuver_starts.erase(via);
const auto reinsert_start_mnv = [&](auto ptr) { const auto reinsert_start_mnv = [&](auto ptr) { maneuver_starts.insert({ptr->from, ptr}); };
maneuver_starts.insert(std::make_pair(ptr->from, ptr));
};
std::for_each(mnv_start_ptrs.begin(), mnv_start_ptrs.end(), reinsert_start_mnv); std::for_each(mnv_start_ptrs.begin(), mnv_start_ptrs.end(), reinsert_start_mnv);
/**********************************************************************************************/ /**********************************************************************************************/
@ -183,9 +234,7 @@ void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const
// update end ptrs in mapping // update end ptrs in mapping
maneuver_ends.erase(via); maneuver_ends.erase(via);
const auto reinsert_end_mnvs = [&](auto ptr) { const auto reinsert_end_mnvs = [&](auto ptr) { maneuver_ends.insert({ptr->to, ptr}); };
maneuver_ends.insert(std::make_pair(ptr->to, ptr));
};
std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), reinsert_end_mnvs); std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), reinsert_end_mnvs);
} }

View File

@ -1,5 +1,6 @@
#include "extractor/restriction_filter.hpp" #include "extractor/restriction_filter.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
#include "util/timing_util.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include <algorithm> #include <algorithm>
@ -10,60 +11,48 @@ namespace osrm
namespace extractor namespace extractor
{ {
std::vector<ConditionalTurnRestriction> std::vector<TurnRestriction>
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction> restrictions, removeInvalidRestrictions(std::vector<TurnRestriction> restrictions,
const util::NodeBasedDynamicGraph &node_based_graph) const util::NodeBasedDynamicGraph &node_based_graph)
{ {
// definition of what we presume to be a valid via-node restriction util::UnbufferedLog log;
const auto is_valid_node = [&node_based_graph](const auto &node_restriction) { log << "Removing invalid restrictions...";
// a valid restriction needs to be connected to both its from and to locations TIMER_START(remove_invalid_restrictions);
bool found_from = false, found_to = false;
for (auto eid : node_based_graph.GetAdjacentEdgeRange(node_restriction.via)) const auto is_valid_edge = [&node_based_graph](const auto from, const auto to) {
const auto eid = node_based_graph.FindEdge(from, to);
if (eid == SPECIAL_EDGEID)
{ {
const auto target = node_based_graph.GetTarget(eid); util::Log(logDEBUG) << "Restriction has invalid edge: " << from << ", " << to;
if (target == node_restriction.from) return false;
found_from = true;
if (target == node_restriction.to)
found_to = true;
} }
if (!found_from || !found_to) const auto &edge_data = node_based_graph.GetEdgeData(eid);
if (edge_data.reversed)
{
util::Log(logDEBUG) << "Restriction has non-traversable edge: " << from << ", " << to;
return false; return false;
}
return true; return true;
}; };
// definition of what we presume to be a valid via-way restriction const auto is_valid_node = [is_valid_edge](const auto &node_restriction) {
const auto is_valid_way = [&node_based_graph, is_valid_node](const auto &way_restriction) { return is_valid_edge(node_restriction.from, node_restriction.via) &&
const auto eid = node_based_graph.FindEdge(way_restriction.in_restriction.via, is_valid_edge(node_restriction.via, node_restriction.to);
way_restriction.out_restriction.via); };
// ability filter, we currently cannot handle restrictions that do not match up in geometry: const auto is_valid_way = [is_valid_edge](const auto &way_restriction) {
// restrictions cannot be interrupted by traffic signals or other similar entities that if (!is_valid_edge(way_restriction.from, way_restriction.via.front()))
// cause node penalties
if ((way_restriction.in_restriction.via != way_restriction.out_restriction.from) ||
(way_restriction.out_restriction.via != way_restriction.in_restriction.to))
return false; return false;
// the edge needs to exit (we cannot handle intermediate stuff, so far) const auto invalid_it = std::adjacent_find(
if (eid == SPECIAL_EDGEID) way_restriction.via.begin(),
way_restriction.via.end(),
[&](auto via_from, auto via_to) { return !is_valid_edge(via_from, via_to); });
if (invalid_it != way_restriction.via.end())
return false; return false;
const auto &data = node_based_graph.GetEdgeData(eid); return is_valid_edge(way_restriction.via.back(), way_restriction.to);
// edge needs to be traversable for a valid restrction
if (data.reversed)
return false;
// is the in restriction referencing the correct nodes
if (!is_valid_node(way_restriction.in_restriction))
return false;
// is the out restriction referencing the correct nodes
if (!is_valid_node(way_restriction.out_restriction))
return false;
return true;
}; };
const auto is_invalid = [is_valid_way, is_valid_node](const auto &restriction) { const auto is_invalid = [is_valid_way, is_valid_node](const auto &restriction) {
@ -80,8 +69,13 @@ removeInvalidRestrictions(std::vector<ConditionalTurnRestriction> restrictions,
const auto end_valid_restrictions = const auto end_valid_restrictions =
std::remove_if(restrictions.begin(), restrictions.end(), is_invalid); std::remove_if(restrictions.begin(), restrictions.end(), is_invalid);
const auto num_removed = std::distance(end_valid_restrictions, restrictions.end());
restrictions.erase(end_valid_restrictions, restrictions.end()); restrictions.erase(end_valid_restrictions, restrictions.end());
TIMER_STOP(remove_invalid_restrictions);
log << "removed " << num_removed << " invalid restrictions, after "
<< TIMER_SEC(remove_invalid_restrictions) << "s";
return restrictions; return restrictions;
} }

View File

@ -0,0 +1,288 @@
#include "extractor/restriction_graph.hpp"
#include "util/node_based_graph.hpp"
#include "util/timing_util.hpp"
#include <util/for_each_pair.hpp>
#include <boost/assign.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace osrm
{
namespace extractor
{
namespace restriction_graph_details
{
void insertEdge(RestrictionGraph &rg, const RestrictionID id, const RestrictionEdge &edge)
{
const auto range = rg.GetEdges(id);
auto &node = rg.nodes[id];
if (node.edges_begin_idx + range.size() != rg.edges.size())
{
// Most nodes will only have one edge, so this copy will be infrequent
node.edges_begin_idx = rg.edges.size();
std::copy(range.begin(), range.end(), std::back_inserter(rg.edges));
}
rg.edges.push_back(edge);
node.num_edges += 1;
}
void insertRestriction(RestrictionGraph &rg,
const RestrictionID id,
const TurnRestriction *restriction)
{
const auto range = rg.GetRestrictions(id);
auto &node = rg.nodes[id];
if (node.restrictions_begin_idx + range.size() != rg.restrictions.size())
{
// Most nodes will only have zero or one restriction, so this copy will be infrequent
node.restrictions_begin_idx = rg.restrictions.size();
std::copy(range.begin(), range.end(), std::back_inserter(rg.restrictions));
}
rg.restrictions.push_back(restriction);
node.num_restrictions += 1;
}
RestrictionID getOrInsertStartNode(RestrictionGraph &rg, NodeID from, NodeID to)
{
auto start_edge = std::make_pair(from, to);
auto start_node_idx_itr = rg.start_edge_to_node.find(start_edge);
if (start_node_idx_itr == rg.start_edge_to_node.end())
{
// First time we have seen a restriction start from this edge.
auto start_node_idx = rg.nodes.size();
rg.nodes.push_back(RestrictionNode{rg.restrictions.size(), 0, rg.edges.size(), 0});
start_node_idx_itr = rg.start_edge_to_node.insert({start_edge, start_node_idx}).first;
}
return start_node_idx_itr->second;
}
RestrictionID insertViaNode(RestrictionGraph &rg, NodeID from, NodeID to)
{
auto new_via_node_idx = rg.nodes.size();
rg.nodes.push_back(RestrictionNode{rg.restrictions.size(), 0, rg.edges.size(), 0});
rg.via_edge_to_node.insert({{from, to}, new_via_node_idx});
return new_via_node_idx;
}
// pathBuilder builds the prefix tree structure that is used to first insert turn restrictions
// into the graph.
struct pathBuilder
{
RestrictionGraph &rg;
RestrictionID cur_node;
pathBuilder(RestrictionGraph &rg_) : rg(rg_) { cur_node = SPECIAL_RESTRICTIONID; }
static std::string name() { return "path builder"; };
void start(NodeID from, NodeID to) { cur_node = getOrInsertStartNode(rg, from, to); }
void next(NodeID from, NodeID to)
{
const auto &edge_range = rg.GetEdges(cur_node);
auto edge_to_itr = std::find_if(edge_range.begin(),
edge_range.end(),
[&](const auto &edge) { return edge.node_based_to == to; });
if (edge_to_itr != edge_range.end())
{
cur_node = edge_to_itr->target;
return;
}
// This is a new restriction path we have not seen before.
// Add a new via node and edge to the tree.
auto new_via_node_idx = insertViaNode(rg, from, to);
insertEdge(rg, cur_node, RestrictionEdge{to, new_via_node_idx, false});
cur_node = new_via_node_idx;
}
void end(const TurnRestriction &restriction) { insertRestriction(rg, cur_node, &restriction); }
};
// transferBuilder adds the transfer edges between overlapping restriction paths. It does this
// by tracking paths in the graph that can be equal to a suffix of a restriction path, and
// attempting to connect the them with a new edge.
struct transferBuilder
{
RestrictionGraph &rg;
std::vector<RestrictionID> suffix_nodes;
RestrictionID cur_node;
transferBuilder(RestrictionGraph &rg_) : rg(rg_) { cur_node = SPECIAL_RESTRICTIONID; }
static std::string name() { return "transfer builder"; };
void start(NodeID from, NodeID to) { cur_node = getOrInsertStartNode(rg, from, to); }
void next_suffixes(NodeID from, NodeID to)
{
// Update the suffix paths to include those that also have this edge
auto new_suffix_it = suffix_nodes.begin();
for (const auto &suffix_node : suffix_nodes)
{
const auto &edges = rg.GetEdges(suffix_node);
const auto edge_it = std::find_if(edges.begin(), edges.end(), [&to](const auto &edge) {
return edge.node_based_to == to && !edge.is_transfer;
});
if (edge_it != edges.end())
{
*(new_suffix_it++) = edge_it->target;
}
}
suffix_nodes.erase(new_suffix_it, suffix_nodes.end());
// Add a start node if it is a trivial suffix
auto start_way_it = rg.start_edge_to_node.find({from, to});
if (start_way_it != rg.start_edge_to_node.end())
{
suffix_nodes.push_back({start_way_it->second});
}
}
// For each edge on path, if there is an edge in the suffix path not on the current
// path, add as a transfer.
void add_suffix_transfer(const RestrictionID &suffix_node)
{
for (const auto &suffix_edge : rg.GetEdges(suffix_node))
{
if (suffix_edge.is_transfer)
continue;
// Check there are no unconditional restrictions at the current node that would prevent
// the transfer
const auto &restrictions = rg.GetRestrictions(cur_node);
const auto is_restricted =
std::any_of(restrictions.begin(), restrictions.end(), [&](const auto &restriction) {
return restriction->IsTurnRestricted(suffix_edge.node_based_to) &&
restriction->IsUnconditional();
});
if (is_restricted)
continue;
const auto &edges = rg.GetEdges(cur_node);
// Check that the suffix edge is not a next edge along the current path.
const auto can_transfer = std::none_of(edges.begin(), edges.end(), [&](auto &edge) {
return edge.node_based_to == suffix_edge.node_based_to;
});
if (can_transfer)
{
insertEdge(rg,
cur_node,
RestrictionEdge{suffix_edge.node_based_to, suffix_edge.target, true});
}
}
};
void next(NodeID from, NodeID to)
{
const auto &edges = rg.GetEdges(cur_node);
auto next_edge_itr = std::find_if(
edges.begin(), edges.end(), [&](const auto edge) { return edge.node_based_to == to; });
// We know this edge exists
cur_node = next_edge_itr->target;
this->next_suffixes(from, to);
std::for_each(suffix_nodes.begin(), suffix_nodes.end(), [&](const auto &suffix_node) {
this->add_suffix_transfer(suffix_node);
});
for (const auto &suffix_node : suffix_nodes)
{
// Also add any restrictions from suffix paths to the current node in the
// restriction graph.
for (const auto &restriction : rg.GetRestrictions(suffix_node))
{
insertRestriction(rg, cur_node, restriction);
}
}
}
void end(const TurnRestriction & /*unused*/) {}
};
template <typename builder_type>
void buildGraph(RestrictionGraph &rg, const std::vector<TurnRestriction> &restrictions)
{
const auto run_builder = [&](const auto &restriction) {
builder_type builder(rg);
builder.start(restriction.From(), restriction.FirstVia());
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
{
const auto &way_restriction = restriction.AsWayRestriction();
util::for_each_pair(way_restriction.via.begin(),
way_restriction.via.end(),
[&](NodeID from, NodeID to) { builder.next(from, to); });
}
builder.end(restriction);
};
std::for_each(restrictions.begin(), restrictions.end(), run_builder);
}
} // namespace restriction_graph_details
RestrictionGraph constructRestrictionGraph(const std::vector<TurnRestriction> &turn_restrictions)
{
util::UnbufferedLog log;
log << "Constructing restriction graph on " << turn_restrictions.size() << " restrictions...";
TIMER_START(construct_restriction_graph);
namespace rgd = restriction_graph_details;
RestrictionGraph rg;
rgd::buildGraph<rgd::pathBuilder>(rg, turn_restrictions);
rgd::buildGraph<rgd::transferBuilder>(rg, turn_restrictions);
// Reorder nodes so that via nodes are at the front. This makes it easier to represent the
// bijection between restriction graph via nodes and edge-based graph duplicate nodes.
std::vector<bool> is_via_node(rg.nodes.size(), false);
for (const auto &entry : rg.via_edge_to_node)
{
is_via_node[entry.second] = true;
}
std::vector<RestrictionID> ordering(rg.nodes.size());
std::iota(ordering.begin(), ordering.end(), 0);
std::partition(ordering.begin(), ordering.end(), [&](const auto i) { return is_via_node[i]; });
// Start renumbering
const auto permutation = util::orderingToPermutation(ordering);
util::inplacePermutation(rg.nodes.begin(), rg.nodes.end(), permutation);
std::for_each(rg.edges.begin(), rg.edges.end(), [&](auto &edge) {
edge.target = permutation[edge.target];
});
rg.num_via_nodes = std::count(is_via_node.begin(), is_via_node.end(), true);
for (auto &entry : rg.via_edge_to_node)
{
entry.second = permutation[entry.second];
}
for (auto &entry : rg.start_edge_to_node)
{
entry.second = permutation[entry.second];
}
TIMER_STOP(construct_restriction_graph);
log << "ok, after " << TIMER_SEC(construct_restriction_graph) << "s";
return rg;
}
RestrictionGraph::RestrictionRange RestrictionGraph::GetRestrictions(RestrictionID id) const
{
const auto &node = nodes[id];
return boost::make_iterator_range(restrictions.begin() + node.restrictions_begin_idx,
restrictions.begin() + node.restrictions_begin_idx +
node.num_restrictions);
}
RestrictionGraph::EdgeRange RestrictionGraph::GetEdges(RestrictionID id) const
{
const auto &node = nodes[id];
return boost::make_iterator_range(edges.begin() + node.edges_begin_idx,
edges.begin() + node.edges_begin_idx + node.num_edges);
}
} // namespace extractor
} // namespace osrm

View File

@ -4,7 +4,6 @@
#include "util/conditional_restrictions.hpp" #include "util/conditional_restrictions.hpp"
#include "util/log.hpp" #include "util/log.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/regex.hpp> #include <boost/algorithm/string/regex.hpp>
#include <boost/optional/optional.hpp> #include <boost/optional/optional.hpp>
@ -15,7 +14,6 @@
#include <osmium/tags/regex_filter.hpp> #include <osmium/tags/regex_filter.hpp>
#include <algorithm> #include <algorithm>
#include <iterator>
namespace osrm namespace osrm
{ {
@ -54,7 +52,7 @@ RestrictionParser::RestrictionParser(bool use_turn_restrictions_,
* in the corresponding profile. We use it for both namespacing restrictions, as in * in the corresponding profile. We use it for both namespacing restrictions, as in
* restriction:motorcar as well as whitelisting if its in except:motorcar. * restriction:motorcar as well as whitelisting if its in except:motorcar.
*/ */
boost::optional<InputConditionalTurnRestriction> boost::optional<InputTurnRestriction>
RestrictionParser::TryParse(const osmium::Relation &relation) const RestrictionParser::TryParse(const osmium::Relation &relation) const
{ {
// return if turn restrictions should be ignored // return if turn restrictions should be ignored
@ -122,14 +120,13 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
} }
} }
// we pretend every restriction is a conditional restriction. If we do not find any restriction, InputTurnRestriction restriction_container;
// we can trim away the vector after parsing
InputConditionalTurnRestriction restriction_container;
restriction_container.is_only = is_only_restriction; restriction_container.is_only = is_only_restriction;
constexpr auto INVALID_OSM_ID = std::numeric_limits<std::uint64_t>::max(); constexpr auto INVALID_OSM_ID = std::numeric_limits<std::uint64_t>::max();
auto from = INVALID_OSM_ID; auto from = INVALID_OSM_ID;
auto via = INVALID_OSM_ID; auto via_node = INVALID_OSM_ID;
std::vector<OSMWayID> via_ways;
auto to = INVALID_OSM_ID; auto to = INVALID_OSM_ID;
bool is_node_restriction = true; bool is_node_restriction = true;
@ -152,7 +149,7 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
continue; continue;
} }
BOOST_ASSERT(0 == strcmp("via", role)); BOOST_ASSERT(0 == strcmp("via", role));
via = static_cast<std::uint64_t>(member.ref()); via_node = static_cast<std::uint64_t>(member.ref());
is_node_restriction = true; is_node_restriction = true;
// set via node id // set via node id
break; break;
@ -170,7 +167,7 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
} }
else if (0 == strcmp("via", role)) else if (0 == strcmp("via", role))
{ {
via = static_cast<std::uint64_t>(member.ref()); via_ways.push_back({static_cast<std::uint64_t>(member.ref())});
is_node_restriction = false; is_node_restriction = false;
} }
break; break;
@ -211,17 +208,18 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
} }
} }
if (from != INVALID_OSM_ID && via != INVALID_OSM_ID && to != INVALID_OSM_ID) if (from != INVALID_OSM_ID && (via_node != INVALID_OSM_ID || !via_ways.empty()) &&
to != INVALID_OSM_ID)
{ {
if (is_node_restriction) if (is_node_restriction)
{ {
// template struct requires bracket for ID initialisation :( // template struct requires bracket for ID initialisation :(
restriction_container.node_or_way = InputNodeRestriction{{from}, {via}, {to}}; restriction_container.node_or_way = InputNodeRestriction{{from}, {via_node}, {to}};
} }
else else
{ {
// template struct requires bracket for ID initialisation :( // template struct requires bracket for ID initialisation :(
restriction_container.node_or_way = InputWayRestriction{{from}, {via}, {to}}; restriction_container.node_or_way = InputWayRestriction{{from}, via_ways, {to}};
} }
return restriction_container; return restriction_container;
} }

View File

@ -870,7 +870,7 @@ void Sol2ScriptingEnvironment::ProcessElements(
const ExtractionRelationContainer &relations, const ExtractionRelationContainer &relations,
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes, std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways, std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
std::vector<InputConditionalTurnRestriction> &resulting_restrictions, std::vector<InputTurnRestriction> &resulting_restrictions,
std::vector<InputManeuverOverride> &resulting_maneuver_overrides) std::vector<InputManeuverOverride> &resulting_maneuver_overrides)
{ {
ExtractionNode result_node; ExtractionNode result_node;

View File

@ -1,8 +1,5 @@
#include "extractor/way_restriction_map.hpp" #include "extractor/way_restriction_map.hpp"
#include "util/for_each_pair.hpp"
#include <functional>
#include <iterator>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
@ -11,247 +8,117 @@ namespace osrm
namespace extractor namespace extractor
{ {
namespace WayRestrictionMap::WayRestrictionMap(const RestrictionGraph &restriction_graph)
: restriction_graph(restriction_graph)
{ {
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;
}
};
template <typename restriction_type> auto asDuplicatedNode(const restriction_type &restriction)
{
auto &way = restriction.AsWayRestriction();
// group restrictions by the via-way. On same via-ways group by from
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
}
template <typename restriction_type> struct CompareByDuplicatedNode
{
bool operator()(const ConditionalTurnRestriction &lhs, const ConditionalTurnRestriction &rhs)
{
if (asDuplicatedNode(lhs) < asDuplicatedNode(rhs))
{
return true;
}
else if (asDuplicatedNode(rhs) < asDuplicatedNode(lhs))
{
return false;
}
else
{
const auto lhs_to = lhs.AsWayRestriction().out_restriction.to;
const auto rhs_to = rhs.AsWayRestriction().out_restriction.to;
const bool has_conditions_lhs = !lhs.condition.empty();
const bool has_conditions_rhs = !rhs.condition.empty();
return std::tie(lhs_to, lhs.is_only, has_conditions_lhs) <
std::tie(rhs_to, rhs.is_only, has_conditions_rhs);
}
}
};
template <typename restriction_type>
std::vector<restriction_type>
extractRestrictions(const std::vector<restriction_type> &turn_restrictions)
{
std::vector<restriction_type> result;
for (const auto &turn_restriction : turn_restrictions)
{
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)
result.push_back(turn_restriction);
}
}
std::sort(result.begin(), result.end(), CompareByDuplicatedNode<restriction_type>());
auto new_end = std::unique(result.begin(), result.end());
result.erase(new_end, result.end());
return result;
}
template <typename restriction_type> struct ByInFromAndVia
{
std::pair<NodeID, NodeID> operator()(const restriction_type &restriction)
{
const auto &way = restriction.AsWayRestriction();
return std::make_pair(way.in_restriction.from, way.in_restriction.via);
}
};
} // namespace
// get all way restrictions
WayRestrictionMap::WayRestrictionMap(
const std::vector<ConditionalTurnRestriction> &turn_restrictions_)
: restriction_data(extractRestrictions(turn_restrictions_)),
restriction_starts(restriction_data, ByInFromAndVia<ConditionalTurnRestriction>())
{
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]);
BOOST_ASSERT(lhs.Type() == RestrictionType::WAY_RESTRICTION);
BOOST_ASSERT(rhs.Type() == RestrictionType::WAY_RESTRICTION);
// add a new lower bound for rhs
if (asDuplicatedNode(lhs) != asDuplicatedNode(rhs))
duplicated_node_groups.push_back(offset);
++offset;
};
util::for_each_pair(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 std::size_t WayRestrictionMap::NumberOfDuplicatedNodes() const
{ {
return duplicated_node_groups.size() - 1; return restriction_graph.num_via_nodes;
} }
bool WayRestrictionMap::IsViaWay(const NodeID from, const NodeID to) const bool WayRestrictionMap::IsViaWayEdge(const NodeID from, const NodeID to) const
{ {
// safe-guards return restriction_graph.via_edge_to_node.count({from, to}) > 0;
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;
}
DuplicatedNodeID WayRestrictionMap::AsDuplicatedNodeID(const RestrictionID restriction_id) const
{
const auto upper_bound_restriction = std::upper_bound(
duplicated_node_groups.begin(), duplicated_node_groups.end(), restriction_id);
const auto distance_to_upper_bound =
std::distance(duplicated_node_groups.begin(), upper_bound_restriction);
return distance_to_upper_bound - 1;
} }
std::vector<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from, std::vector<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
const NodeID to) const const NodeID to) const
{ {
const auto duplicated_node_range_itr = std::equal_range( const auto restriction_ways = restriction_graph.via_edge_to_node.equal_range({from, to});
restriction_data.begin(), restriction_data.end(), std::make_tuple(from, to), FindViaWay()); std::vector<DuplicatedNodeID> result;
std::transform(restriction_ways.first,
const auto as_restriction_id = [this](const auto itr) { restriction_ways.second,
return std::distance(restriction_data.begin(), itr); std::back_inserter(result),
}; [](const auto &range_val) { return DuplicatedNodeID(range_val.second); });
auto first = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first));
auto end = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second));
std::vector<DuplicatedNodeID> result(end - first);
std::iota(result.begin(), result.end(), first);
return result; return result;
} }
bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const
{ {
// loop over all restrictions associated with the node. Mark as restricted based on // Checks if a turn to 'to' is restricted
// is_only/restricted targets BOOST_ASSERT(duplicated_node < restriction_graph.num_via_nodes);
for (RestrictionID restriction_index = duplicated_node_groups[duplicated_node]; const auto &restrictions = restriction_graph.GetRestrictions(duplicated_node);
restriction_index != duplicated_node_groups[duplicated_node + 1]; return std::any_of(restrictions.begin(), restrictions.end(), [&to](const auto &restriction) {
++restriction_index) return restriction->IsTurnRestricted(to);
{ });
BOOST_ASSERT(restriction_index < restriction_data.size());
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;
} }
ConditionalTurnRestriction const & std::vector<const TurnRestriction *>
WayRestrictionMap::GetRestriction(DuplicatedNodeID duplicated_node, const NodeID to) const WayRestrictionMap::GetRestrictions(DuplicatedNodeID duplicated_node, const NodeID to) const
{ {
// loop over all restrictions associated with the node. Mark as restricted based on std::vector<const TurnRestriction *> result;
// is_only/restricted targets // Fetch all restrictions that will restrict a turn to 'to'.
for (RestrictionID restriction_index = duplicated_node_groups[duplicated_node]; BOOST_ASSERT(duplicated_node < restriction_graph.num_via_nodes);
restriction_index != duplicated_node_groups[duplicated_node + 1]; const auto &restrictions = restriction_graph.GetRestrictions(duplicated_node);
++restriction_index) std::copy_if(restrictions.begin(),
restrictions.end(),
std::back_inserter(result),
[&to](const auto &restriction) { return restriction->IsTurnRestricted(to); });
if (result.empty())
{ {
BOOST_ASSERT(restriction_index < restriction_data.size()); throw(
const auto &restriction = restriction_data[restriction_index]; "Asking for the restriction of an unrestricted turn. Check with `IsRestricted` before "
const auto &way = restriction.AsWayRestriction(); "calling GetRestriction");
if (restriction.is_only && (way.out_restriction.to != to))
{
return restriction;
}
else if (!restriction.is_only && (to == way.out_restriction.to))
{
return restriction;
}
} }
throw("Asking for the restriction of an unrestricted turn. Check with `IsRestricted` before "
"calling GetRestriction");
}
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 {way.in_restriction.via, way.out_restriction.via};
});
return result; return result;
} }
NodeID WayRestrictionMap::RemapIfRestricted(const NodeID edge_based_node, std::vector<WayRestrictionMap::ViaEdge> WayRestrictionMap::DuplicatedViaEdges() const
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.Restrictions(node_based_from, node_based_via); std::vector<ViaEdge> result;
result.resize(NumberOfDuplicatedNodes());
// returns true if the ID saved in an iterator belongs to a turn restriction that references // We use the node id from the restriction graph to enumerate all
// node_based_to as destination of the `in_restriction` // duplicate nodes, and map them to their node based edge representation.
const auto restriction_targets_to = [node_based_to](const auto &pair) { // This means an node based edge (from,to) can have many duplicate nodes.
return pair.second->AsWayRestriction().in_restriction.to == node_based_to; for (auto entry : restriction_graph.via_edge_to_node)
}; {
const auto itr = std::find_if(range.first, range.second, restriction_targets_to); result[entry.second] = {entry.first.first, entry.first.second};
}
return result;
}
// in case we found a matching restriction, we can remap the edge_based_node NodeID WayRestrictionMap::RemapIfRestrictionStart(const NodeID edge_based_node,
if (itr != range.second) const NodeID node_based_from,
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() + const NodeID node_based_via,
AsDuplicatedNodeID(itr->second - &restriction_data[0]); const NodeID node_based_to,
else const NodeID number_of_edge_based_nodes) const
return edge_based_node; {
auto restriction_it =
restriction_graph.start_edge_to_node.find({node_based_from, node_based_via});
if (restriction_it != restriction_graph.start_edge_to_node.end())
{
for (const auto &edge : restriction_graph.GetEdges(restriction_it->second))
{
if (edge.node_based_to == node_based_to)
{
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() + edge.target;
}
}
}
return edge_based_node;
}
NodeID WayRestrictionMap::RemapIfRestrictionVia(const NodeID edge_based_target_node,
const NodeID edge_based_via_node,
const NodeID node_based_to,
const NodeID number_of_edge_based_nodes) const
{
auto duplicated_node_id =
edge_based_via_node + NumberOfDuplicatedNodes() - number_of_edge_based_nodes;
BOOST_ASSERT(duplicated_node_id < restriction_graph.num_via_nodes);
for (const auto &edge : restriction_graph.GetEdges(duplicated_node_id))
{
if (edge.node_based_to == node_based_to)
{
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() + edge.target;
}
}
return edge_based_target_node;
} }
} // namespace extractor } // namespace extractor

View File

@ -201,9 +201,9 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
// be fine. // be fine.
bearing_class_by_node_based_node[intersection_node] = bearing_class_id; bearing_class_by_node_based_node[intersection_node] = bearing_class_id;
// check if we are turning off a via way // check if we on a restriction via edge
const auto turning_off_via_way = const auto is_restriction_via_edge =
way_restriction_map.IsViaWay(incoming_edge.node, intersection_node); way_restriction_map.IsViaWayEdge(incoming_edge.node, intersection_node);
for (const auto &outgoing_edge : outgoing_edges) for (const auto &outgoing_edge : outgoing_edges)
{ {
@ -239,11 +239,11 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
guidance::TurnBearing(intersection[0].perceived_bearing), guidance::TurnBearing(intersection[0].perceived_bearing),
guidance::TurnBearing(turn->perceived_bearing)}); guidance::TurnBearing(turn->perceived_bearing)});
// when turning off a a via-way turn restriction, we need to not only // When on the edge of a via-way turn restriction, we need to not only
// handle the normal edges for the way, but also add turns for every // handle the normal edges for the way, but also add turns for every
// duplicated node. This process is integrated here to avoid doing the // duplicated node. This process is integrated here to avoid doing the
// turn analysis multiple times. // turn analysis multiple times.
if (turning_off_via_way) if (is_restriction_via_edge)
{ {
const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs( const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs(
incoming_edge.node, intersection_node); incoming_edge.node, intersection_node);
@ -261,10 +261,18 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
if (is_way_restricted) if (is_way_restricted)
{ {
auto const restriction = way_restriction_map.GetRestriction( auto const restrictions =
duplicated_node_id, node_at_end_of_turn); way_restriction_map.GetRestrictions(
duplicated_node_id, node_at_end_of_turn);
if (restriction.condition.empty()) auto has_unconditional =
std::any_of(restrictions.begin(),
restrictions.end(),
[](const auto &restriction) {
return restriction->IsUnconditional();
});
if (has_unconditional)
continue; continue;
buffer->delayed_turn_data.push_back(guidance::TurnData{ buffer->delayed_turn_data.push_back(guidance::TurnData{

View File

@ -68,7 +68,6 @@ BOOST_AUTO_TEST_CASE(long_road_test)
std::unordered_set<NodeID> barrier_nodes; std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights; std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions; std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
std::vector<NodeBasedEdgeAnnotation> annotations(1); std::vector<NodeBasedEdgeAnnotation> annotations(1);
CompressedEdgeContainer container; CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment; test::MockScriptingEnvironment scripting_environment;
@ -92,7 +91,6 @@ BOOST_AUTO_TEST_CASE(long_road_test)
traffic_lights, traffic_lights,
scripting_environment, scripting_environment,
restrictions, restrictions,
conditional_restrictions,
maneuver_overrides, maneuver_overrides,
graph, graph,
annotations, annotations,
@ -116,7 +114,6 @@ BOOST_AUTO_TEST_CASE(loop_test)
std::unordered_set<NodeID> barrier_nodes; std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights; std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions; std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container; CompressedEdgeContainer container;
std::vector<NodeBasedEdgeAnnotation> annotations(1); std::vector<NodeBasedEdgeAnnotation> annotations(1);
test::MockScriptingEnvironment scripting_environment; test::MockScriptingEnvironment scripting_environment;
@ -154,7 +151,6 @@ BOOST_AUTO_TEST_CASE(loop_test)
traffic_lights, traffic_lights,
scripting_environment, scripting_environment,
restrictions, restrictions,
conditional_restrictions,
maneuver_overrides, maneuver_overrides,
graph, graph,
annotations, annotations,
@ -182,7 +178,6 @@ BOOST_AUTO_TEST_CASE(t_intersection)
std::unordered_set<NodeID> traffic_lights; std::unordered_set<NodeID> traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations(1); std::vector<NodeBasedEdgeAnnotation> annotations(1);
std::vector<TurnRestriction> restrictions; std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container; CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment; test::MockScriptingEnvironment scripting_environment;
std::vector<UnresolvedManeuverOverride> maneuver_overrides; std::vector<UnresolvedManeuverOverride> maneuver_overrides;
@ -205,7 +200,6 @@ BOOST_AUTO_TEST_CASE(t_intersection)
traffic_lights, traffic_lights,
scripting_environment, scripting_environment,
restrictions, restrictions,
conditional_restrictions,
maneuver_overrides, maneuver_overrides,
graph, graph,
annotations, annotations,
@ -227,7 +221,6 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
std::unordered_set<NodeID> traffic_lights; std::unordered_set<NodeID> traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations(2); std::vector<NodeBasedEdgeAnnotation> annotations(2);
std::vector<TurnRestriction> restrictions; std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container; CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment; test::MockScriptingEnvironment scripting_environment;
std::vector<UnresolvedManeuverOverride> maneuver_overrides; std::vector<UnresolvedManeuverOverride> maneuver_overrides;
@ -246,7 +239,6 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
traffic_lights, traffic_lights,
scripting_environment, scripting_environment,
restrictions, restrictions,
conditional_restrictions,
maneuver_overrides, maneuver_overrides,
graph, graph,
annotations, annotations,
@ -267,7 +259,6 @@ BOOST_AUTO_TEST_CASE(direction_changes)
std::unordered_set<NodeID> traffic_lights; std::unordered_set<NodeID> traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations(1); std::vector<NodeBasedEdgeAnnotation> annotations(1);
std::vector<TurnRestriction> restrictions; std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container; CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment; test::MockScriptingEnvironment scripting_environment;
std::vector<UnresolvedManeuverOverride> maneuver_overrides; std::vector<UnresolvedManeuverOverride> maneuver_overrides;
@ -282,7 +273,6 @@ BOOST_AUTO_TEST_CASE(direction_changes)
traffic_lights, traffic_lights,
scripting_environment, scripting_environment,
restrictions, restrictions,
conditional_restrictions,
maneuver_overrides, maneuver_overrides,
graph, graph,
annotations, annotations,

View File

@ -24,7 +24,6 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
{EMPTY_NAMEID, 0, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false}, {EMPTY_NAMEID, 0, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false},
{EMPTY_NAMEID, 1, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false}}; {EMPTY_NAMEID, 1, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false}};
std::vector<TurnRestriction> restrictions{TurnRestriction{NodeRestriction{0, 2, 1}, false}}; std::vector<TurnRestriction> restrictions{TurnRestriction{NodeRestriction{0, 2, 1}, false}};
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container; CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment; test::MockScriptingEnvironment scripting_environment;
std::vector<UnresolvedManeuverOverride> maneuver_overrides; std::vector<UnresolvedManeuverOverride> maneuver_overrides;
@ -90,7 +89,6 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
traffic_lights, traffic_lights,
scripting_environment, scripting_environment,
restrictions, restrictions,
conditional_restrictions,
maneuver_overrides, maneuver_overrides,
graph, graph,
annotations, annotations,
@ -101,7 +99,8 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
EdgeBasedNodeDataContainer node_data_container( EdgeBasedNodeDataContainer node_data_container(
std::vector<EdgeBasedNode>(graph.GetNumberOfEdges()), annotations); std::vector<EdgeBasedNode>(graph.GetNumberOfEdges()), annotations);
RestrictionMap restriction_map(restrictions, IndexNodeByFromAndVia()); RestrictionGraph restriction_graph = constructRestrictionGraph(restrictions);
RestrictionMap restriction_map(restriction_graph);
const auto connectivity_matrix = [&](NodeID node) { const auto connectivity_matrix = [&](NodeID node) {
std::vector<bool> result; std::vector<bool> result;
@ -156,7 +155,6 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
std::unordered_set<NodeID> traffic_lights; std::unordered_set<NodeID> traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations; std::vector<NodeBasedEdgeAnnotation> annotations;
std::vector<TurnRestriction> restrictions; std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container; CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment; test::MockScriptingEnvironment scripting_environment;
std::vector<UnresolvedManeuverOverride> maneuver_overrides; std::vector<UnresolvedManeuverOverride> maneuver_overrides;
@ -214,7 +212,6 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
traffic_lights, traffic_lights,
scripting_environment, scripting_environment,
restrictions, restrictions,
conditional_restrictions,
maneuver_overrides, maneuver_overrides,
graph, graph,
annotations, annotations,
@ -225,7 +222,9 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
EdgeBasedNodeDataContainer node_data_container( EdgeBasedNodeDataContainer node_data_container(
std::vector<EdgeBasedNode>(graph.GetNumberOfEdges()), annotations); std::vector<EdgeBasedNode>(graph.GetNumberOfEdges()), annotations);
RestrictionMap restriction_map(restrictions, IndexNodeByFromAndVia());
RestrictionGraph restriction_graph = constructRestrictionGraph(restrictions);
RestrictionMap restriction_map(restriction_graph);
const auto connectivity_matrix = [&](NodeID node) { const auto connectivity_matrix = [&](NodeID node) {
std::vector<bool> result; std::vector<bool> result;
@ -263,7 +262,6 @@ BOOST_AUTO_TEST_CASE(skip_degree_two_nodes)
std::unordered_set<NodeID> traffic_lights{2}; std::unordered_set<NodeID> traffic_lights{2};
std::vector<NodeBasedEdgeAnnotation> annotations(1); std::vector<NodeBasedEdgeAnnotation> annotations(1);
std::vector<TurnRestriction> restrictions; std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container; CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment; test::MockScriptingEnvironment scripting_environment;
std::vector<UnresolvedManeuverOverride> maneuver_overrides; std::vector<UnresolvedManeuverOverride> maneuver_overrides;
@ -306,7 +304,6 @@ BOOST_AUTO_TEST_CASE(skip_degree_two_nodes)
traffic_lights, traffic_lights,
scripting_environment, scripting_environment,
restrictions, restrictions,
conditional_restrictions,
maneuver_overrides, maneuver_overrides,
graph, graph,
annotations, annotations,

View File

@ -0,0 +1,597 @@
#include "extractor/restriction_graph.hpp"
#include "extractor/maneuver_override.hpp"
#include "extractor/restriction.hpp"
#include "util/typedefs.hpp"
#include <boost/test/unit_test.hpp>
#include <iostream>
#include <vector>
BOOST_AUTO_TEST_SUITE(restriction_graph)
using namespace osrm;
using namespace osrm::extractor;
TurnRestriction makeWayRestriction(NodeID from, std::vector<NodeID> via, NodeID to, bool is_only)
{
WayRestriction wr{from, via, to};
return TurnRestriction(wr, is_only);
}
TurnRestriction makeNodeRestriction(NodeID from, NodeID via, NodeID to, bool is_only)
{
NodeRestriction nr{from, via, to};
return TurnRestriction(nr, is_only);
}
struct instruction
{
NodeID to;
bool is_only;
};
std::ostream &operator<<(std::ostream &os, const instruction &in)
{
os << std::boolalpha << in.to << ':' << in.is_only;
return os;
}
bool operator==(const instruction &lhs, const instruction &rhs) noexcept
{
return lhs.to == rhs.to && lhs.is_only == rhs.is_only;
}
bool operator!=(const instruction &lhs, const instruction &rhs) noexcept { return !(lhs == rhs); }
void checkInstructions(RestrictionGraph::RestrictionRange restrictions,
std::vector<instruction> expected_instructions)
{
std::vector<instruction> actual_instructions;
std::transform(restrictions.begin(),
restrictions.end(),
std::back_inserter(actual_instructions),
[](const auto &restriction) {
return instruction{restriction->To(), bool(restriction->is_only)};
});
std::sort(actual_instructions.begin(),
actual_instructions.end(),
[](const auto &lhs, const auto &rhs) {
return (lhs.to < rhs.to) || (lhs.to == rhs.to && lhs.is_only);
});
std::sort(expected_instructions.begin(),
expected_instructions.end(),
[](const auto &lhs, const auto &rhs) {
return (lhs.to < rhs.to) || (lhs.to == rhs.to && lhs.is_only);
});
BOOST_REQUIRE_EQUAL_COLLECTIONS(actual_instructions.begin(),
actual_instructions.end(),
expected_instructions.begin(),
expected_instructions.end());
}
void checkEdges(RestrictionGraph::EdgeRange edges, std::vector<NodeID> expected_edges)
{
std::vector<NodeID> actual_edges;
std::transform(edges.begin(),
edges.end(),
std::back_inserter(actual_edges),
[&](const auto &edge) { return edge.node_based_to; });
std::sort(actual_edges.begin(), actual_edges.end(), std::less<NodeID>());
std::sort(expected_edges.begin(), expected_edges.end(), std::less<NodeID>());
BOOST_REQUIRE_EQUAL_COLLECTIONS(
actual_edges.begin(), actual_edges.end(), expected_edges.begin(), expected_edges.end());
}
std::map<NodeID, size_t> nextEdges(RestrictionGraph::EdgeRange edges)
{
std::map<NodeID, size_t> res;
std::transform(
edges.begin(), edges.end(), std::inserter(res, res.end()), [&](const auto &edge) {
return std::make_pair(edge.node_based_to, edge.target);
});
return res;
}
std::map<NodeID, size_t> checkNode(const RestrictionGraph &graph,
const RestrictionID node_id,
std::vector<instruction> expected_instructions,
std::vector<NodeID> expected_edges)
{
checkInstructions(graph.GetRestrictions(node_id), expected_instructions);
checkEdges(graph.GetEdges(node_id), expected_edges);
return nextEdges(graph.GetEdges(node_id));
}
std::map<NodeID, size_t>
validateStartRestrictionNode(RestrictionGraph &graph,
NodeID from,
NodeID to,
std::vector<instruction> restriction_instructions,
std::vector<NodeID> restriction_edges)
{
BOOST_REQUIRE_EQUAL(graph.start_edge_to_node.count({from, to}), 1);
const auto node_id = graph.start_edge_to_node[{from, to}];
BOOST_REQUIRE_GE(node_id, graph.num_via_nodes);
BOOST_REQUIRE_LT(node_id, graph.nodes.size());
return checkNode(graph, node_id, restriction_instructions, restriction_edges);
}
std::map<NodeID, size_t>
validateViaRestrictionNode(RestrictionGraph &graph,
size_t via_node_idx,
NodeID from,
NodeID to,
std::vector<instruction> restriction_instructions,
std::vector<NodeID> restriction_edges)
{
BOOST_REQUIRE_GE(graph.via_edge_to_node.count({from, to}), 1);
auto node_match_it = graph.via_edge_to_node.equal_range({from, to});
BOOST_REQUIRE_MESSAGE(
std::any_of(node_match_it.first,
node_match_it.second,
[&](const auto node_match) { return node_match.second == via_node_idx; }),
"Could not find expected via_node_idx " << via_node_idx << " for graph edge " << from << ","
<< to);
BOOST_REQUIRE_LT(via_node_idx, graph.num_via_nodes);
return checkNode(graph, via_node_idx, restriction_instructions, restriction_edges);
}
BOOST_AUTO_TEST_CASE(empty_restrictions)
{
//
// Input
//
// Output
//
std::vector<TurnRestriction> empty;
auto graph = constructRestrictionGraph(empty);
BOOST_CHECK(graph.nodes.empty());
BOOST_CHECK_EQUAL(graph.num_via_nodes, 0);
BOOST_CHECK(graph.edges.empty());
BOOST_CHECK(graph.start_edge_to_node.empty());
BOOST_CHECK(graph.via_edge_to_node.empty());
}
BOOST_AUTO_TEST_CASE(node_restriction)
{
//
// Input
// 0 -> 1: only_2
//
// Output
// s(0,1,[only_2])
//
std::vector<TurnRestriction> input{
makeNodeRestriction(0, 1, 2, true),
};
std::cout << "Construct graph" << std::endl;
auto graph = constructRestrictionGraph(input);
std::cout << "Constructed graph" << std::endl;
BOOST_CHECK_EQUAL(graph.nodes.size(), 1);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 0);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 1);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 0);
BOOST_CHECK_EQUAL(graph.edges.size(), 0);
validateStartRestrictionNode(graph, 0, 1, {{2, true}}, {});
}
BOOST_AUTO_TEST_CASE(way_restriction)
{
//
// Input
// 0 -> 1 -> 2 -> 3: only_4
//
// Output
// s(0,1) -> v(1,2) -> v(2,3,[only_4])
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
2,
3,
},
4,
true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 3);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 2);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 1);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 2);
BOOST_CHECK_EQUAL(graph.edges.size(), 2);
auto start_edges = validateStartRestrictionNode(graph, 0, 1, {}, {2});
auto via_edges = validateViaRestrictionNode(graph, start_edges[2], 1, 2, {}, {3});
validateViaRestrictionNode(graph, via_edges[3], 2, 3, {{4, true}}, {});
}
BOOST_AUTO_TEST_CASE(disconnected_restrictions)
{
//
// Input
// 0 -> 1 -> 2 -> 3: only_4
// 5 -> 6 -> 7 -> 8: only_9
//
// Output
// s(0,1) -> v(1,2) -> v(2,3,[only_4])
// s(5,6) -> v(6,7) -> v(7,8,[only_9])
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
2,
3,
},
4,
true),
makeWayRestriction(5,
{
6,
7,
8,
},
9,
true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 6);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 4);
BOOST_CHECK_EQUAL(graph.edges.size(), 4);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 2);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 4);
auto start_edges_1 = validateStartRestrictionNode(graph, 0, 1, {}, {2});
auto start_edges_2 = validateStartRestrictionNode(graph, 5, 6, {}, {7});
auto via_edges_1 = validateViaRestrictionNode(graph, start_edges_1[2], 1, 2, {}, {3});
validateViaRestrictionNode(graph, via_edges_1[3], 2, 3, {{4, true}}, {});
auto via_edges_2 = validateViaRestrictionNode(graph, start_edges_2[7], 6, 7, {}, {8});
validateViaRestrictionNode(graph, via_edges_2[8], 7, 8, {{9, true}}, {});
}
BOOST_AUTO_TEST_CASE(same_prefix_restrictions)
{
//
// Input
// 0 -> 1 -> 2 -> 3: only_4
// 0 -> 1 -> 2 -> 5: only_6
//
// Output
// s(0,1) -> v(1,2) -> v(2,3,[only_4])
// \_>v(2,5,[only_6])
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
2,
3,
},
4,
true),
makeWayRestriction(0,
{
1,
2,
5,
},
6,
true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 4);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 3);
BOOST_CHECK_EQUAL(graph.edges.size(), 3);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 1);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 3);
auto start_edges = validateStartRestrictionNode(graph, 0, 1, {}, {2});
auto via_edges = validateViaRestrictionNode(graph, start_edges[2], 1, 2, {}, {3, 5});
validateViaRestrictionNode(graph, via_edges[3], 2, 3, {{4, true}}, {});
validateViaRestrictionNode(graph, via_edges[5], 2, 5, {{6, true}}, {});
}
BOOST_AUTO_TEST_CASE(duplicate_edges)
{
//
// Input
// 0 -> 1 -> 2 -> 3: only_4
// 5 -> 1 -> 2 -> 3: only_6
//
// Output
// s(0,1) -> v(1,2) -> v(2,3,[only_4])
// s(5,1) -> v(1,2) -> v(2,3,[only_6])
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
2,
3,
},
4,
true),
makeWayRestriction(5,
{
1,
2,
3,
},
6,
true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 6);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 4);
BOOST_CHECK_EQUAL(graph.edges.size(), 4);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 2);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 4);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.count({1, 2}), 2);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.count({2, 3}), 2);
auto start_edges_1 = validateStartRestrictionNode(graph, 0, 1, {}, {2});
auto start_edges_2 = validateStartRestrictionNode(graph, 5, 1, {}, {2});
auto via_edges_1 = validateViaRestrictionNode(graph, start_edges_1[2], 1, 2, {}, {3});
validateViaRestrictionNode(graph, via_edges_1[3], 2, 3, {{4, true}}, {});
auto via_edges_2 = validateViaRestrictionNode(graph, start_edges_2[2], 1, 2, {}, {3});
validateViaRestrictionNode(graph, via_edges_2[3], 2, 3, {{6, true}}, {});
}
BOOST_AUTO_TEST_CASE(nested_restriction)
{
//
// Input
// 0 -> 1 -> 2 -> 3: [only_4]
// 1 -> 2: [only_4]
//
// Output
// s(0,1) -> v(1,2,[only_4]) -> v(2,3,[only_4])
// s(1,2,[only_4])
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
2,
3,
},
4,
true),
makeNodeRestriction(1, 2, 4, true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 4);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 2);
BOOST_CHECK_EQUAL(graph.edges.size(), 2);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 2);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 2);
auto start_edges_1 = validateStartRestrictionNode(graph, 0, 1, {}, {2});
validateStartRestrictionNode(graph, 1, 2, {{4, true}}, {});
auto via_edges_1 = validateViaRestrictionNode(graph, start_edges_1[2], 1, 2, {{4, true}}, {3});
validateViaRestrictionNode(graph, via_edges_1[3], 2, 3, {{4, true}}, {});
}
BOOST_AUTO_TEST_CASE(partially_nested_restriction)
{
//
// Input
// 0 -> 1 -> 2 -> 3: only_4
// 2 -> 3 -> 4: only_5
//
// Output
// s(0,1) -> v(1,2) -> v(2,3,[only_4])
// |
// t
// |
// s(2,3) -> v(3,4,[only_5])
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
2,
3,
},
4,
true),
makeWayRestriction(2, {3, 4}, 5, true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 5);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 3);
BOOST_CHECK_EQUAL(graph.edges.size(), 4);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 2);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 3);
auto start_edges_1 = validateStartRestrictionNode(graph, 0, 1, {}, {2});
auto start_edges_2 = validateStartRestrictionNode(graph, 2, 3, {}, {4});
auto via_edges_1 = validateViaRestrictionNode(graph, start_edges_1[2], 1, 2, {}, {3});
validateViaRestrictionNode(graph, via_edges_1[3], 2, 3, {{4, true}}, {4});
validateViaRestrictionNode(graph, start_edges_2[4], 3, 4, {{5, true}}, {});
}
BOOST_AUTO_TEST_CASE(conflicting_nested_restriction)
{
//
// Input
// 0 -> 1 -> 2 -> 3: no_4
// 2 -> 3 -> 4: only_5
//
// Output
// s(0,1) -> v(1,2) -> v(2,3,[no_4])
// s(2,3) -> v(3,4,[only_5])
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
2,
3,
},
4,
false),
makeWayRestriction(2, {3, 4}, 5, true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 5);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 3);
BOOST_CHECK_EQUAL(graph.edges.size(), 3);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 2);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 3);
auto start_edges_1 = validateStartRestrictionNode(graph, 0, 1, {}, {2});
auto start_edges_2 = validateStartRestrictionNode(graph, 2, 3, {}, {4});
auto via_edges_1 = validateViaRestrictionNode(graph, start_edges_1[2], 1, 2, {}, {3});
validateViaRestrictionNode(graph, via_edges_1[3], 2, 3, {{4, false}}, {});
validateViaRestrictionNode(graph, start_edges_2[4], 3, 4, {{5, true}}, {});
}
BOOST_AUTO_TEST_CASE(restriction_edge_matches_start)
{
//
// Input
// 0 -> 1 -> 2 -> 3: only_4
// 3 -> 4 -> 5: only_6
//
// Output
// s(0,1) -> v(1,2) -> v(2,3,[only_4])
// s(3,4) -> v(4,5,[only_6])
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
2,
3,
},
4,
true),
makeWayRestriction(3, {4, 5}, 6, true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 5);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 3);
BOOST_CHECK_EQUAL(graph.edges.size(), 3);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 2);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 3);
auto start_edges_1 = validateStartRestrictionNode(graph, 0, 1, {}, {2});
auto start_edges_2 = validateStartRestrictionNode(graph, 3, 4, {}, {5});
auto via_edges_1 = validateViaRestrictionNode(graph, start_edges_1[2], 1, 2, {}, {3});
validateViaRestrictionNode(graph, via_edges_1[3], 2, 3, {{4, true}}, {});
validateViaRestrictionNode(graph, start_edges_2[5], 4, 5, {{6, true}}, {});
}
BOOST_AUTO_TEST_CASE(self_nested_restriction)
{
//
// Input
// 0 -> 1 -> 0 -> 1 -> 2: only_3
//
// Output
// s(0,1) -> v(1,0) -> v(0,1) -> v(1,2,[only_3])
// \___t___/
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
1,
0,
1,
2,
},
3,
true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 4);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 3);
BOOST_CHECK_EQUAL(graph.edges.size(), 4);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 1);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 3);
auto start_edges_1 = validateStartRestrictionNode(graph, 0, 1, {}, {0});
auto via_edges_1 = validateViaRestrictionNode(graph, start_edges_1[0], 1, 0, {}, {1});
auto via_edges_2 = validateViaRestrictionNode(graph, via_edges_1[1], 0, 1, {}, {0, 2});
validateViaRestrictionNode(graph, via_edges_2[2], 1, 2, {{3, true}}, {});
}
BOOST_AUTO_TEST_CASE(single_node_restriction)
{
//
// Input
// 0 -> 0 -> 0 -> 0 -> 0: only_0
//
// Output
// s(0,0) -> v(0,0) -> v(0,0) -> v(0,0,[only_0])
// \t/
//
std::vector<TurnRestriction> input{
makeWayRestriction(0,
{
0,
0,
0,
0,
},
0,
true),
};
auto graph = constructRestrictionGraph(input);
BOOST_CHECK_EQUAL(graph.nodes.size(), 4);
BOOST_CHECK_EQUAL(graph.num_via_nodes, 3);
BOOST_CHECK_EQUAL(graph.edges.size(), 4);
BOOST_CHECK_EQUAL(graph.start_edge_to_node.size(), 1);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.size(), 3);
BOOST_CHECK_EQUAL(graph.via_edge_to_node.count({0, 0}), 3);
auto start_edges_1 = validateStartRestrictionNode(graph, 0, 0, {}, {0});
auto via_edges_1 = validateViaRestrictionNode(graph, start_edges_1[0], 0, 0, {}, {0});
auto via_edges_2 = validateViaRestrictionNode(graph, via_edges_1[0], 0, 0, {}, {0});
validateViaRestrictionNode(graph, via_edges_2[0], 0, 0, {{0, true}}, {0});
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -42,7 +42,7 @@ class MockScriptingEnvironment : public extractor::ScriptingEnvironment
const extractor::ExtractionRelationContainer &, const extractor::ExtractionRelationContainer &,
std::vector<std::pair<const osmium::Node &, extractor::ExtractionNode>> &, std::vector<std::pair<const osmium::Node &, extractor::ExtractionNode>> &,
std::vector<std::pair<const osmium::Way &, extractor::ExtractionWay>> &, std::vector<std::pair<const osmium::Way &, extractor::ExtractionWay>> &,
std::vector<extractor::InputConditionalTurnRestriction> &, std::vector<extractor::InputTurnRestriction> &,
std::vector<extractor::InputManeuverOverride> &) override final std::vector<extractor::InputManeuverOverride> &) override final
{ {
} }