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:
parent
eb1d399f3b
commit
5266ac1635
@ -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:
|
||||||
|
@ -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
|
|
||||||
"""
|
|
||||||
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 | only_right_turn @ (Mo-Su 07:00-14:00) |
|
|
||||||
|
|
||||||
When I route I should get
|
|
||||||
| from | to | route |
|
|
||||||
| b | c | bj,aj,aj,jc,jc |
|
|
||||||
| 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
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a
|
|
||||||
p |
|
|
||||||
\ |
|
|
||||||
j
|
j
|
||||||
| \
|
|
|
||||||
c m
|
k - l - m
|
||||||
|
|
|
||||||
|
n
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
| nodes | oneway |
|
| nodes |
|
||||||
| aj | no |
|
| kl |
|
||||||
| jc | no |
|
| jl |
|
||||||
| jp | yes |
|
| ln |
|
||||||
| mj | 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 | aj | jp | j | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
|
| 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 |
|
||||||
| a | p | aj,jc,jc,jp,jp |
|
| k | m | kl,ln,ln,lm,lm |
|
||||||
| m | p | mj,jp,jp |
|
|
||||||
|
|
||||||
@restriction-way
|
@restriction-way
|
||||||
Scenario: Car - prohibit turn
|
Scenario: Car - prohibit turn
|
||||||
@ -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 |
|
||||||
|
1033
features/car/multi_via_restrictions.feature
Normal file
1033
features/car/multi_via_restrictions.feature
Normal file
File diff suppressed because it is too large
Load Diff
@ -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 |
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,20 +96,13 @@ 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,
|
|
||||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
|
||||||
|
|
||||||
void ProcessGuidanceTurns(
|
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &edge_based_node_container,
|
const EdgeBasedNodeDataContainer &edge_based_node_container,
|
||||||
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);
|
||||||
|
@ -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 ¤t_node, const ExtractionNode &result_node);
|
void ProcessNode(const osmium::Node ¤t_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 ¤t_way, const ExtractionWay &result_way);
|
void ProcessWay(const osmium::Way ¤t_way, const ExtractionWay &result_way);
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
#ifndef FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
|
|
||||||
#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
|
|
||||||
|
|
||||||
#include "util/typedefs.hpp"
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace extractor
|
|
||||||
{
|
|
||||||
|
|
||||||
struct FirstAndLastSegmentOfWay
|
|
||||||
{
|
|
||||||
OSMWayID way_id;
|
|
||||||
OSMNodeID first_segment_source_id;
|
|
||||||
OSMNodeID first_segment_target_id;
|
|
||||||
OSMNodeID last_segment_source_id;
|
|
||||||
OSMNodeID last_segment_target_id;
|
|
||||||
|
|
||||||
FirstAndLastSegmentOfWay()
|
|
||||||
: way_id(SPECIAL_OSM_WAYID), first_segment_source_id(SPECIAL_OSM_NODEID),
|
|
||||||
first_segment_target_id(SPECIAL_OSM_NODEID), last_segment_source_id(SPECIAL_OSM_NODEID),
|
|
||||||
last_segment_target_id(SPECIAL_OSM_NODEID)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
FirstAndLastSegmentOfWay(OSMWayID w, OSMNodeID fs, OSMNodeID ft, OSMNodeID ls, OSMNodeID lt)
|
|
||||||
: way_id(std::move(w)), first_segment_source_id(std::move(fs)),
|
|
||||||
first_segment_target_id(std::move(ft)), last_segment_source_id(std::move(ls)),
|
|
||||||
last_segment_target_id(std::move(lt))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static FirstAndLastSegmentOfWay min_value()
|
|
||||||
{
|
|
||||||
return {MIN_OSM_WAYID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID};
|
|
||||||
}
|
|
||||||
static FirstAndLastSegmentOfWay max_value()
|
|
||||||
{
|
|
||||||
return {MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FirstAndLastSegmentOfWayCompare
|
|
||||||
{
|
|
||||||
using value_type = FirstAndLastSegmentOfWay;
|
|
||||||
bool operator()(const FirstAndLastSegmentOfWay &a, const FirstAndLastSegmentOfWay &b) const
|
|
||||||
{
|
|
||||||
return a.way_id < b.way_id;
|
|
||||||
}
|
|
||||||
value_type max_value() { return FirstAndLastSegmentOfWay::max_value(); }
|
|
||||||
value_type min_value() { return FirstAndLastSegmentOfWay::min_value(); }
|
|
||||||
};
|
|
||||||
} // namespace extractor
|
|
||||||
} // namespace osrm
|
|
||||||
|
|
||||||
#endif /* FIRST_AND_LAST_SEGMENT_OF_WAY_HPP */
|
|
@ -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,
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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,
|
||||||
|
80
include/extractor/node_restriction_map.hpp
Normal file
80
include/extractor/node_restriction_map.hpp
Normal 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_
|
56
include/extractor/nodes_of_way.hpp
Normal file
56
include/extractor/nodes_of_way.hpp
Normal 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 */
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
134
include/extractor/restriction_graph.hpp
Normal file
134
include/extractor/restriction_graph.hpp
Normal 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_
|
@ -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_
|
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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(); }
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
31
include/util/for_each_indexed.hpp
Normal file
31
include/util/for_each_indexed.hpp
Normal 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 */
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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,21 +932,40 @@ 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 =
|
||||||
|
way_restriction_map.GetRestrictions(
|
||||||
duplicated_node_id, node_at_end_of_turn);
|
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.
|
||||||
|
// b) take a conditional turn to exit the restriction.
|
||||||
|
// If a) is applicable here, we change the target to be
|
||||||
|
// the duplicate restriction node.
|
||||||
|
auto const via_target_id =
|
||||||
|
way_restriction_map.RemapIfRestrictionVia(
|
||||||
nbe_to_ebn_mapping[outgoing_edge.edge],
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||||
|
from_id,
|
||||||
|
m_node_based_graph.GetTarget(outgoing_edge.edge),
|
||||||
|
m_number_of_edge_based_nodes);
|
||||||
|
|
||||||
|
// add into delayed data
|
||||||
|
auto edge_with_data = generate_edge(from_id,
|
||||||
|
via_target_id,
|
||||||
incoming_edge.node,
|
incoming_edge.node,
|
||||||
incoming_edge.edge,
|
incoming_edge.edge,
|
||||||
outgoing_edge.node,
|
outgoing_edge.node,
|
||||||
@ -967,31 +975,38 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
road_legs_on_the_left,
|
road_legs_on_the_left,
|
||||||
edge_geometries);
|
edge_geometries);
|
||||||
|
|
||||||
buffer->delayed_data.push_back(
|
buffer->delayed_data.push_back(edge_with_data);
|
||||||
edge_with_data_and_condition.first);
|
|
||||||
if (edge_with_data_and_condition.second)
|
|
||||||
{
|
|
||||||
buffer->conditionals.push_back(
|
|
||||||
*edge_with_data_and_condition.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
|
// b) transfer to a via path of an overlapping restriction.
|
||||||
|
// c) exit the restriction
|
||||||
|
// If a) or b) are applicable here, we change the target to
|
||||||
|
// be the duplicate restriction node.
|
||||||
|
auto const via_target_id =
|
||||||
|
way_restriction_map.RemapIfRestrictionVia(
|
||||||
nbe_to_ebn_mapping[outgoing_edge.edge],
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||||
|
from_id,
|
||||||
|
m_node_based_graph.GetTarget(outgoing_edge.edge),
|
||||||
|
m_number_of_edge_based_nodes);
|
||||||
|
|
||||||
|
auto edge_with_data = generate_edge(from_id,
|
||||||
|
via_target_id,
|
||||||
incoming_edge.node,
|
incoming_edge.node,
|
||||||
incoming_edge.edge,
|
incoming_edge.edge,
|
||||||
outgoing_edge.node,
|
outgoing_edge.node,
|
||||||
@ -1001,13 +1016,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
road_legs_on_the_left,
|
road_legs_on_the_left,
|
||||||
edge_geometries);
|
edge_geometries);
|
||||||
|
|
||||||
buffer->delayed_data.push_back(
|
buffer->delayed_data.push_back(edge_with_data);
|
||||||
edge_with_data_and_condition.first);
|
|
||||||
if (edge_with_data_and_condition.second)
|
|
||||||
{
|
|
||||||
buffer->conditionals.push_back(
|
|
||||||
*edge_with_data_and_condition.second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 start/end information on " << external_maneuver_overrides_list.size()
|
log << "Collecting way information on " << external_maneuver_overrides_list.size()
|
||||||
<< " maneuver overrides...";
|
<< " maneuver overrides...";
|
||||||
TIMER_START(prepare_maneuver_overrides);
|
TIMER_START(identify_maneuver_override_ways);
|
||||||
|
|
||||||
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(),
|
||||||
[&referenced_ways, dummy_segment](const auto &element) {
|
[&maneuver_override_ways, dummy_segment](const auto &element) {
|
||||||
referenced_ways[element] = dummy_segment;
|
maneuver_override_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;
|
|
||||||
|
|
||||||
// prepare for extracting source/destination nodes for all restrictions
|
|
||||||
{
|
|
||||||
util::UnbufferedLog log;
|
util::UnbufferedLog log;
|
||||||
log << "Collecting start/end information on " << restrictions_list.size()
|
log << "Collecting way information on " << restrictions_list.size() << " restrictions...";
|
||||||
<< " restrictions...";
|
TIMER_START(identify_restriction_ways);
|
||||||
TIMER_START(prepare_restrictions);
|
|
||||||
|
|
||||||
|
// Enter invalid IDs into the map to indicate that we want to find out about
|
||||||
|
// nodes of these ways.
|
||||||
const auto mark_ids = [&](auto const &turn_restriction) {
|
const auto mark_ids = [&](auto const &turn_restriction) {
|
||||||
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};
|
|
||||||
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||||
{
|
{
|
||||||
const auto &way = turn_restriction.AsWayRestriction();
|
const auto &way = turn_restriction.AsWayRestriction();
|
||||||
referenced_ways[way.from] = dummy_segment;
|
restriction_ways[way.from] = dummy_segment;
|
||||||
referenced_ways[way.to] = dummy_segment;
|
restriction_ways[way.to] = dummy_segment;
|
||||||
referenced_ways[way.via] = dummy_segment;
|
for (const auto &v : way.via)
|
||||||
|
{
|
||||||
|
restriction_ways[v] = dummy_segment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||||
const auto &node = turn_restriction.AsNodeRestriction();
|
const auto &node = turn_restriction.AsNodeRestriction();
|
||||||
referenced_ways[node.from] = dummy_segment;
|
restriction_ways[node.from] = dummy_segment;
|
||||||
referenced_ways[node.to] = 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)
|
||||||
{
|
{
|
||||||
if (segment.first_segment_source_id == via_segment.first_segment_source_id)
|
util::Log(logDEBUG) << "Restriction has unconnected from and via ways: "
|
||||||
{
|
<< from_way.way_id << ", " << via_ways.front().way_id;
|
||||||
return NodeRestriction{to_internal(segment.first_segment_target_id),
|
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||||
to_internal(segment.first_segment_source_id),
|
|
||||||
to_internal(via_segment.first_segment_target_id)};
|
|
||||||
}
|
}
|
||||||
else if (segment.first_segment_source_id == via_segment.last_segment_target_id)
|
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)
|
||||||
{
|
{
|
||||||
return NodeRestriction{to_internal(segment.first_segment_target_id),
|
if (next_connection == via_way.first_segment_source_id())
|
||||||
to_internal(segment.first_segment_source_id),
|
{
|
||||||
to_internal(via_segment.last_segment_source_id)};
|
std::transform(std::next(via_way.node_ids.begin()),
|
||||||
|
via_way.node_ids.end(),
|
||||||
|
std::back_inserter(restriction.via),
|
||||||
|
to_internal);
|
||||||
|
next_connection = via_way.last_segment_target_id();
|
||||||
|
}
|
||||||
|
else if (next_connection == via_way.last_segment_target_id())
|
||||||
|
{
|
||||||
|
std::transform(std::next(via_way.node_ids.rbegin()),
|
||||||
|
via_way.node_ids.rend(),
|
||||||
|
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};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// connected at the end of the segment
|
// Add the final to node after the via-to intersection.
|
||||||
if (via_node == MAX_OSM_NODEID || segment.last_segment_target_id == via_node)
|
if (next_connection == to_way.first_segment_source_id())
|
||||||
{
|
{
|
||||||
if (segment.last_segment_target_id == via_segment.first_segment_source_id)
|
restriction.to = to_internal(to_way.first_segment_target_id());
|
||||||
|
}
|
||||||
|
else if (next_connection == to_way.last_segment_target_id())
|
||||||
{
|
{
|
||||||
return NodeRestriction{to_internal(segment.last_segment_source_id),
|
restriction.to = to_internal(to_way.last_segment_source_id());
|
||||||
to_internal(segment.last_segment_target_id),
|
|
||||||
to_internal(via_segment.first_segment_target_id)};
|
|
||||||
}
|
}
|
||||||
else if (segment.last_segment_target_id == via_segment.last_segment_target_id)
|
else
|
||||||
{
|
{
|
||||||
return NodeRestriction{to_internal(segment.last_segment_source_id),
|
util::Log(logDEBUG) << "Restriction has unconnected via and to ways: "
|
||||||
to_internal(segment.last_segment_target_id),
|
<< via_ways.back().way_id << ", " << to_way.way_id;
|
||||||
to_internal(via_segment.last_segment_source_id)};
|
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||||
}
|
}
|
||||||
}
|
return restriction;
|
||||||
|
|
||||||
// unconnected
|
|
||||||
util::Log(logDEBUG) << "Restriction references unconnected way: " << segment.way_id;
|
|
||||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// translate the turn from one segment onto another into a node restriction (the ways can
|
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||||
// only
|
// internal restriction
|
||||||
// be connected at a single location)
|
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};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<NodesOfWay> via_ways;
|
||||||
|
for (const auto &via_id : via_ids)
|
||||||
|
{
|
||||||
|
auto const via_segment_itr = restriction_ways.find(via_id);
|
||||||
|
if (via_segment_itr->second.way_id != via_id)
|
||||||
|
{
|
||||||
|
util::Log(logDEBUG) << "Restriction references invalid via way: " << via_id;
|
||||||
|
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||||
|
}
|
||||||
|
via_ways.push_back(via_segment_itr->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const to_way_itr = restriction_ways.find(to_id);
|
||||||
|
if (to_way_itr->second.way_id != to_id)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node restrictions are described as a restriction between the two segments closest
|
||||||
|
// to the shared via-node on the from and to ways.
|
||||||
|
// 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
|
|
||||||
const auto transform_into_internal_types =
|
|
||||||
[&](const InputConditionalTurnRestriction &external_restriction) {
|
|
||||||
// unconditional restriction
|
|
||||||
if (external_restriction.condition.empty() &&
|
|
||||||
external_restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
|
||||||
{
|
|
||||||
TurnRestriction restriction;
|
TurnRestriction restriction;
|
||||||
restriction.is_only = external_restriction.is_only;
|
|
||||||
if (transform(external_restriction, restriction))
|
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.is_only = external_restriction.is_only;
|
||||||
restriction.condition = std::move(external_restriction.condition);
|
restriction.condition = std::move(external_restriction.condition);
|
||||||
if (transform(external_restriction, restriction))
|
turn_restrictions.push_back(std::move(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);
|
||||||
|
@ -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,11 +368,9 @@ 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>>
|
|
||||||
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|
||||||
const unsigned number_of_threads)
|
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,
|
||||||
|
@ -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
|
||||||
|
@ -20,12 +20,10 @@ 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<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,
|
||||||
@ -34,32 +32,28 @@ void GraphCompressor::Compress(
|
|||||||
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.
|
||||||
*/
|
*/
|
||||||
|
@ -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,
|
||||||
|
@ -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,10 +78,8 @@ 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<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
|
||||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
||||||
{
|
{
|
||||||
GraphCompressor graph_compressor;
|
GraphCompressor graph_compressor;
|
||||||
@ -93,7 +87,6 @@ void NodeBasedGraphFactory::Compress(
|
|||||||
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,
|
||||||
|
@ -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 | ____
|
// ____ | to - p.from | via - p.via | from - p.to | ____
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(ptr->via == from);
|
BOOST_ASSERT(node_ptr.via == from);
|
||||||
ptr->from = to;
|
node_ptr.from = to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(ptr->Type() == RestrictionType::WAY_RESTRICTION);
|
||||||
|
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
|
// p.from | ____ - p.via | to - p.to | via - ____ | from
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(ptr->via == to);
|
BOOST_ASSERT(node_ptr.via == to);
|
||||||
ptr->to = from;
|
node_ptr.to = from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(ptr->Type() == RestrictionType::WAY_RESTRICTION);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
288
src/extractor/restriction_graph.cpp
Normal file
288
src/extractor/restriction_graph.cpp
Normal 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
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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,248 +8,118 @@ 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 &
|
|
||||||
WayRestrictionMap::GetRestriction(DuplicatedNodeID duplicated_node, const NodeID to) const
|
|
||||||
{
|
|
||||||
// loop over all restrictions associated with the node. Mark as restricted based on
|
|
||||||
// is_only/restricted targets
|
|
||||||
for (RestrictionID restriction_index = duplicated_node_groups[duplicated_node];
|
|
||||||
restriction_index != duplicated_node_groups[duplicated_node + 1];
|
|
||||||
++restriction_index)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(restriction_index < restriction_data.size());
|
|
||||||
const auto &restriction = restriction_data[restriction_index];
|
|
||||||
const auto &way = restriction.AsWayRestriction();
|
|
||||||
|
|
||||||
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};
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const TurnRestriction *>
|
||||||
|
WayRestrictionMap::GetRestrictions(DuplicatedNodeID duplicated_node, const NodeID to) const
|
||||||
|
{
|
||||||
|
std::vector<const TurnRestriction *> result;
|
||||||
|
// Fetch all restrictions that will restrict a turn to 'to'.
|
||||||
|
BOOST_ASSERT(duplicated_node < restriction_graph.num_via_nodes);
|
||||||
|
const auto &restrictions = restriction_graph.GetRestrictions(duplicated_node);
|
||||||
|
std::copy_if(restrictions.begin(),
|
||||||
|
restrictions.end(),
|
||||||
|
std::back_inserter(result),
|
||||||
|
[&to](const auto &restriction) { return restriction->IsTurnRestricted(to); });
|
||||||
|
if (result.empty())
|
||||||
|
{
|
||||||
|
throw(
|
||||||
|
"Asking for the restriction of an unrestricted turn. Check with `IsRestricted` before "
|
||||||
|
"calling GetRestriction");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeID WayRestrictionMap::RemapIfRestricted(const NodeID edge_based_node,
|
std::vector<WayRestrictionMap::ViaEdge> WayRestrictionMap::DuplicatedViaEdges() const
|
||||||
|
{
|
||||||
|
std::vector<ViaEdge> result;
|
||||||
|
result.resize(NumberOfDuplicatedNodes());
|
||||||
|
|
||||||
|
// We use the node id from the restriction graph to enumerate all
|
||||||
|
// duplicate nodes, and map them to their node based edge representation.
|
||||||
|
// This means an node based edge (from,to) can have many duplicate nodes.
|
||||||
|
for (auto entry : restriction_graph.via_edge_to_node)
|
||||||
|
{
|
||||||
|
result[entry.second] = {entry.first.first, entry.first.second};
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeID WayRestrictionMap::RemapIfRestrictionStart(const NodeID edge_based_node,
|
||||||
const NodeID node_based_from,
|
const NodeID node_based_from,
|
||||||
const NodeID node_based_via,
|
const NodeID node_based_via,
|
||||||
const NodeID node_based_to,
|
const NodeID node_based_to,
|
||||||
const NodeID number_of_edge_based_nodes) const
|
const NodeID number_of_edge_based_nodes) const
|
||||||
{
|
{
|
||||||
auto range = restriction_starts.Restrictions(node_based_from, node_based_via);
|
|
||||||
|
|
||||||
// returns true if the ID saved in an iterator belongs to a turn restriction that references
|
auto restriction_it =
|
||||||
// node_based_to as destination of the `in_restriction`
|
restriction_graph.start_edge_to_node.find({node_based_from, node_based_via});
|
||||||
const auto restriction_targets_to = [node_based_to](const auto &pair) {
|
if (restriction_it != restriction_graph.start_edge_to_node.end())
|
||||||
return pair.second->AsWayRestriction().in_restriction.to == node_based_to;
|
{
|
||||||
};
|
for (const auto &edge : restriction_graph.GetEdges(restriction_it->second))
|
||||||
const auto itr = std::find_if(range.first, range.second, restriction_targets_to);
|
{
|
||||||
|
if (edge.node_based_to == node_based_to)
|
||||||
// in case we found a matching restriction, we can remap the edge_based_node
|
{
|
||||||
if (itr != range.second)
|
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() + edge.target;
|
||||||
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() +
|
}
|
||||||
AsDuplicatedNodeID(itr->second - &restriction_data[0]);
|
}
|
||||||
else
|
}
|
||||||
return edge_based_node;
|
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
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
@ -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 =
|
||||||
|
way_restriction_map.GetRestrictions(
|
||||||
duplicated_node_id, node_at_end_of_turn);
|
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{
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
597
unit_tests/extractor/restriction_graph.cpp
Normal file
597
unit_tests/extractor/restriction_graph.cpp
Normal 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()
|
@ -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
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user