Compare commits

..

9 Commits

Author SHA1 Message Date
Daniel Patterson 1687a9d848 Update package.json for 5.14 release. 2017-11-27 15:23:48 -08:00
Daniel Patterson 531b281b73 Use the correct driving_side property on the arrive step. (#4708)
Use the correct driving_side property on the arrive step.
2017-11-27 13:17:03 -08:00
Daniel J. Hofmann 7137459fb0 Makes MLD default algorithm in example to avoid confusion, see #4702 2017-11-27 12:37:13 -08:00
brian lewis f57fd4ffc3 Refer to Lua scripting language by its correct name 2017-11-27 12:37:04 -08:00
brian lewis 275f71a7d7 Fix typos in profiles documentation 2017-11-27 12:36:58 -08:00
Daniel Patterson 2c7d1ed48c Add Macau and Hong Kong to the left-side driving polygon file. 2017-11-27 12:36:48 -08:00
Daniel Patterson d67cd34edd Enable building release candidate branch 2017-11-22 12:54:12 -08:00
Daniel Patterson c8c3a49fb5 Set changelog to 5.14 2017-11-22 12:36:01 -08:00
Daniel Patterson 3ae313d35d Make 5.14.0-rc.1 2017-11-22 12:35:30 -08:00
125 changed files with 2352 additions and 4154 deletions
-1
View File
@@ -4,7 +4,6 @@ What issue is this PR targeting? If there is no issue that addresses the problem
## Tasklist
- [ ] ADD OWN TASKS HERE
- [ ] CHANGELOG.md entry ([How to write a changelog entry](http://keepachangelog.com/en/1.0.0/#how))
- [ ] update relevant [Wiki pages](https://github.com/Project-OSRM/osrm-backend/wiki)
- [ ] add regression / cucumber cases (see docs/testing.md)
- [ ] review
+2 -1
View File
@@ -12,9 +12,10 @@ notifications:
branches:
only:
- 5.15
- master
# enable building tags
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
- 5.14
cache:
yarn: true
-56
View File
@@ -1,59 +1,3 @@
# 5.15.2
- Changes from 5.15.1:
- Features:
- Exposed the waypoints parameter in the node bindings interface
- Bugfixes:
- Segfault causing bug in leg collapsing map matching when traversing edges in reverse
# 5.15.1
- Changes from 5.15.0:
- Bugfixes:
- FIXED: Segfault in map matching when RouteLeg collapsing code is run on a match with multiple submatches
- Guidance:
- Set type of trivial intersections where classes change to Suppressed instead of NoTurn
# 5.15.0
- Changes from 5.14.3:
- Bugfixes:
- FIXED #4704: Fixed regression in bearings reordering introduced in 5.13 [#4704](https://github.com/Project-OSRM/osrm-backend/issues/4704)
- FIXED #4781: Fixed overflow exceptions in percent-encoding parsing
- FIXED #4770: Fixed exclude flags for single toll road scenario
- FIXED #4283: Fix overflow on zero duration segments
- FIXED #4804: Ignore no_*_on_red turn restrictions
- Guidance:
- CHANGED #4706: Guidance refactoring step to decouple intersection connectivity analysis and turn instructions generation [#4706](https://github.com/Project-OSRM/osrm-backend/pull/4706)
- CHANGED #3491: Refactor `isThroughStreet`/Intersection options
- Profile:
- ADDED: `tunnel` as a new class in car profile so that sections of the route with tunnel tags will be marked as such
# 5.14.3
- Changes from 5.14.2:
- Features:
- Added a `waypoints` parameter to the match service plugin that accepts indices to input coordinates and treats only those points as waypoints in the response format.
- Bugfixes:
- FIXED #4754: U-Turn penalties are applied to straight turns.
- FIXED #4756: Removed too restrictive road name check in the sliproad handler
- FIXED #4731: Use correct weights for edge-based graph duplicated via nodes.
- Profile:
- CHANGED: added Belarus speed limits
- CHANGED: set default urban speed in Ukraine to 50kmh
# 5.14.2
- Changes from 5.14.1:
- Bugfixes:
- FIXED #4727: Erroring when a old .core file is present.
- FIXED #4642: Update checks for EMPTY_NAMEID to check for empty name strings
- FIXED #4738: Fix potential segmentation fault
- Node.js Bindings:
- ADDED: Exposed new `max_radiuses_map_matching` option from `EngingConfig` options
- Tools:
- ADDED: New osrm-routed `max_radiuses_map_matching` command line flag to optionally set a maximum radius for map matching
# 5.14.1
- Changes from 5.14.0
- Bugfixes:
- FIXED: don't use removed alternative candidates in `filterPackedPathsByCellSharing`
# 5.14.0
- Changes from 5.13
- API:
+2 -2
View File
@@ -61,8 +61,8 @@ if (POLICY CMP0048)
endif()
project(OSRM C CXX)
set(OSRM_VERSION_MAJOR 5)
set(OSRM_VERSION_MINOR 15)
set(OSRM_VERSION_PATCH 2)
set(OSRM_VERSION_MINOR 14)
set(OSRM_VERSION_PATCH 0)
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
+1 -2
View File
@@ -114,8 +114,7 @@ sudo cmake --build . --target install
### Request Against the Demo Server
Read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Demo-server).
Read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Api-usage-policy).
Simple query with instructions and alternatives on Berlin:
```
+1 -2
View File
@@ -288,7 +288,6 @@ In addition to the [general options](#general-options) the following options are
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
|gaps |`split` (default), `ignore` |Allows the input track splitting based on huge timestamp gaps between points. |
|tidy |`true`, `false` (default) |Allows the input track modification to obtain better matching quality for noisy tracks. |
|waypoints | `{index};{index};{index}...` |Treats input coordinates indicated by given indices as waypoints in returned Match object. Default is to treat all input coordinates as waypoints. |
|Parameter |Values |
|------------|-----------------------------------|
@@ -587,7 +586,7 @@ step.
- `name`: The name of the way along which travel proceeds.
- `ref`: A reference number or code for the way. Optionally included, if ref data is available for the given way.
- `pronunciation`: A string containing an [IPA](https://en.wikipedia.org/wiki/International_Phonetic_Alphabet) phonetic transcription indicating how to pronounce the name in the `name` property. This property is omitted if pronunciation data is unavailable for the step.
- `pronunciation`: The pronunciation hint of the way name. Will be `undefined` if there is no pronunciation hit.
- `destinations`: The destinations of the way. Will be `undefined` if there are no destinations.
- `exits`: The exit numbers or names of the way. Will be `undefined` if there are no exit numbers or names.
- `mode`: A string signifying the mode of transportation.
+10 -13
View File
@@ -208,19 +208,16 @@ The `process_turn` function is called for every possible turn in the network. Ba
The following attributes can be read and set on the result in `process_turn`:
Attribute | Read/write? | Type | Notes
---------------------|-------------|---------|------------------------------------------------------
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
number_of_roads | Read | Integer | Number of ways at the intersection of the turn
is_u_turn | Read | Boolean | Is the turn a u-turn?
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`)
is_left_hand_driving | Read | Boolean | Is left-hand traffic?
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
source_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
target_mode | Read | Enum | Travel mode after the turn. Defined in `include/extractor/travel_mode.hpp`
Attribute | Read/write? | Type | Notes
-------------------|-------------|---------|------------------------------------------------------
direction_modifier | Read | Enum | Geometry of turn. Defined in `include/extractor/guidance/turn_instruction.hpp`
turn_type | Read | Enum | Priority of turn. Defined in `include/extractor/guidance/turn_instruction.hpp`
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`)
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
## Guidance
The guidance parameters in profiles are currently a work in progress. They can and will change.
-23
View File
@@ -1,23 +0,0 @@
@routing @car @way
Feature: Car - Avoid defined areas
Background:
Given the profile file "car" initialized with
"""
profile.avoid = Set { 'motorway', 'motorway_link' }
profile.speeds = Sequence {
highway = {
motorway = 90,
motorway_link = 45,
primary = 50
}
}
"""
Scenario: Car - Avoid motorways
Then routability should be
| highway | bothw |
| motorway | |
| motorway_link | |
| primary | x |
+2 -40
View File
@@ -82,7 +82,7 @@ Feature: Car - Mode flag
| from | to | route | turns | classes |
| a | d | ab,cd | depart,arrive| [(restricted),(motorway,restricted),()],[()] |
Scenario: Car - We tag toll with a class
Scenario: Car - We toll restricted with a class
Given the node map
"""
a b
@@ -99,45 +99,6 @@ Feature: Car - Mode flag
| from | to | route | turns | classes |
| a | d | ab,cd | depart,arrive | [(toll),(motorway,toll),()],[()] |
Scenario: Car - We tag tunnel with a class
Background:
Given a grid size of 200 meters
Given the node map
"""
a b
c d
"""
And the ways
| nodes | tunnel |
| ab | no |
| bc | yes |
| cd | |
When I route I should get
| from | to | route | turns | classes |
| a | d | ab,bc,cd,cd | depart,new name right,new name left,arrive | [()],[(tunnel)],[()],[()] |
Scenario: Car - We tag classes without intersections
Background:
Given a grid size of 200 meters
Given the node map
"""
a b c d
"""
And the ways
| nodes | name | tunnel |
| ab | road | |
| bc | road | yes |
| cd | road | |
When I route I should get
| from | to | route | turns | classes |
| a | d | road,road | depart,arrive | [(),(tunnel),()],[()] |
Scenario: Car - From roundabout on toll road
Given the node map
"""
@@ -163,3 +124,4 @@ Feature: Car - Mode flag
When I route I should get
| from | to | route | turns | classes |
| a | f | ab,df,df,df | depart,roundabout-exit-2,exit roundabout slight right,arrive | [()],[(),(motorway)],[(toll,motorway)],[()] |
@@ -884,7 +884,7 @@ Feature: Car - Turn restrictions
| a | c | albic,dobe,dobe,albic,albic | depart,turn left,continue uturn,turn left,arrive |
| a | e | albic,dobe,dobe | depart,turn left,arrive |
@no_turning @conditionals @restriction-way
@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
@@ -1054,3 +1054,4 @@ Feature: Car - Turn restrictions
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
-45
View File
@@ -1,45 +0,0 @@
@routing @car
Feature: Car - Handle physical limitation
Background:
Given the profile "car"
Scenario: Car - Use a narrow way
Then routability should be
| highway | width | narrow | bothw |
| primary | | | x |
| primary | narrow | | x |
| primary | | yes | x |
| primary | 1.8 | | |
| primary | 1.9 | | |
| primary | 2.0 | | x |
| primary | 2.1 | | x |
| primary | 1m | | |
| primary | 1 m | | |
| primary | 3 m | | x |
| primary | 6' | | |
| primary | 6'0" | | |
| primary | 6'2" | | |
| primary | 6'3" | | x |
| primary | 7' | | x |
| primary | 7'0" | | x |
Scenario: Car - Limited by width
Then routability should be
| highway | maxwidth:physical | maxwidth | width | est_width | bothw |
| primary | 1 | | | | |
| primary | 3 | | | | x |
| primary | | 1 | | | |
| primary | | 3 | | | x |
| primary | | | 1 | | |
| primary | | | 3 | | x |
| primary | | | | 1 | |
| primary | | | | 3 | x |
Scenario: Car - Limited by height
Then routability should be
| highway | maxheight:physical | maxheight | bothw |
| primary | 1 | | |
| primary | 3 | | x |
| primary | | 1 | |
| primary | | 3 | x |
+10 -37
View File
@@ -141,33 +141,6 @@ Feature: Car - Turn restrictions
| c | a | cj,aj,aj |
| c | b | cj,bj,bj |
@no_turning
Scenario: Car - Ignore no_*_on_red relations
Given the node map
"""
a
d j b
c
"""
And the ways
| nodes | oneway |
| cj | yes |
| aj | -1 |
| dj | -1 |
| bj | -1 |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | cj | dj | j | no_turn_on_red |
| restriction | cj | bj | j | no_right_turn_on_red |
When I route I should get
| from | to | route |
| c | d | cj,dj,dj |
| c | a | cj,aj,aj |
| c | b | cj,bj,bj |
@only_turning
Scenario: Car - Only left turn
Given the node map
@@ -602,7 +575,7 @@ Feature: Car - Turn restrictions
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
@restriction-way @overlap
@restriction @overlap
Scenario: Car - prohibit turn
Given the node map
"""
@@ -737,7 +710,7 @@ Feature: Car - Turn restrictions
| a | j | left,first,right,right |
| f | e | right,third,left,left |
@restriction-way
@restriction
Scenario: Car - allow only turn
Given the node map
"""
@@ -769,7 +742,7 @@ Feature: Car - Turn restrictions
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
@restriction-way
@restriction
Scenario: Car - allow only turn
Given the node map
"""
@@ -798,7 +771,7 @@ Feature: Car - Turn restrictions
| from | to | route |
| a | d | ab,be,de,de |
@restriction-way
@restriction
Scenario: Multi Way restriction
Given the node map
"""
@@ -835,7 +808,7 @@ Feature: Car - Turn restrictions
| from | to | route |
| a | h | horiz,vert,horiz,horiz |
@restriction-way
@restriction
Scenario: Multi-Way overlapping single-way
Given the node map
"""
@@ -874,7 +847,7 @@ Feature: Car - Turn restrictions
| h | d | hfb,abcd,abcd | depart,end of road right,arrive | h,b,d |
@restriction-way
@restriction
Scenario: Car - prohibit turn, traffic lights
Given the node map
"""
@@ -917,7 +890,7 @@ Feature: Car - Turn restrictions
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
@restriction-way @overlap @geometry
@restriction @overlap @geometry
Scenario: Geometry
Given the node map
"""
@@ -952,7 +925,7 @@ Feature: Car - Turn restrictions
| c | d | bc,bge,de,de |
| c | f | bc,bge,de,de,ef,ef |
@restriction-way @overlap @geometry @traffic-signals
@restriction @overlap @geometry @traffic-signals
Scenario: Geometry
Given the node map
"""
@@ -994,7 +967,7 @@ Feature: Car - Turn restrictions
| c | f | bc,bge,de,de,ef,ef |
# don't crash hard on invalid restrictions
@restriction-way @invalid
@restriction @invalid
Scenario: Geometry
Given the node map
"""
@@ -1026,7 +999,7 @@ Feature: Car - Turn restrictions
| a | f | ab,be,ef,ef |
@restriction @restriction-way @overlap @geometry
@restriction @overlap @geometry
Scenario: Duplicated restriction
Given the node map
"""
@@ -98,11 +98,11 @@ Feature: Car - Guidance - Bridges and Tunnels
| dce | primary | | Nebenstraße |
When I route I should get
| from | to | route | turns |
| a | d | Hauptstraße,Nebenstraße,Nebenstraße | depart,end of road left,arrive |
| a | e | Hauptstraße,Nebenstraße,Nebenstraße | depart,end of road right,arrive |
| e | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn left,arrive |
| d | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn right,arrive |
| from | to | route | turns |
| a | d | Hauptstraße,Nebenstraße,Nebenstraße | depart,turn left,arrive |
| a | e | Hauptstraße,Nebenstraße,Nebenstraße | depart,turn right,arrive |
| e | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn left,arrive |
| d | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn right,arrive |
Scenario: Tunnel with Immediate Turn Front and Back
Given the node map
@@ -129,3 +129,4 @@ Feature: Car - Guidance - Bridges and Tunnels
| e | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn left,turn left,arrive |
| d | f | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn right,arrive |
| d | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn left,arrive |
+3 -49
View File
@@ -992,6 +992,7 @@ Feature: Slipways and Dedicated Turn Lanes
| dbef | primary | dbef | |
| ae | primary_link | ae | yes |
When I route I should get
| waypoints | route | turns | locations |
| s,f | sabc,dbef,dbef | depart,turn right,arrive | s,a,f |
@@ -1018,6 +1019,7 @@ Feature: Slipways and Dedicated Turn Lanes
| dbcf | primary | dbcf | |
| ac | primary_link | ae | yes |
When I route I should get
| waypoints | route | turns | locations |
| s,f | sab,dbcf,dbcf | depart,turn right,arrive | s,a,f |
@@ -1045,55 +1047,7 @@ Feature: Slipways and Dedicated Turn Lanes
| ae | primary_link | sab | yes |
| cg | primary | cg | |
When I route I should get
| waypoints | route | turns | locations |
| s,f | sab,dbcef,dbcef | depart,turn right,arrive | s,a,f |
@sliproads
Scenario: Sliproad converted from a fork
Given the node map
"""
d
.
b
s . a '.
`c
.
f
"""
And the ways
| nodes | highway | name | ref | oneway |
| sa | tertiary | | D 60A | yes |
| ab | tertiary | ab | D 60A | yes |
| ac | tertiary | | D 60A | yes |
| dbcf | tertiary | dbcf | D 543 | yes |
When I route I should get
| waypoints | route | turns | locations |
| s,f | ,dbcf,dbcf | depart,turn right,arrive | s,a,f |
@sliproads
Scenario: Sliproad to a road with a reference only
Given the node map
"""
s . a . b . d
` .
' .
..
c
.
f
"""
And the ways
| nodes | highway | name | ref | oneway |
| sabd | primary | road | | |
| bcf | primary | | K108 | |
| ac | primary_link | | | yes |
When I route I should get
| waypoints | route | turns | locations |
| s,f | road,, | depart,turn right,arrive | s,a,f |
@@ -393,44 +393,31 @@ Feature: Merge Segregated Roads
"""
a
|
b-----z
/ \
b
c h
| |
| |
| |
| |
| |
| |
| |
| |
| |
d g
\ /
e
|
f
"""
And the ways
| nodes | name | oneway |
| ab | road | no |
| ef | road | no |
| bcde | road | yes |
| eghb | road | yes |
| bz | cross | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bz | bcde | b | no_left_turn |
| nodes | name | oneway |
| ab | road | no |
| ef | road | no |
| bcde | road | yes |
| eghb | road | yes |
When I route I should get
| waypoints | turns | route |
| a,f | depart,arrive | road,road |
| c,f | depart,arrive | road,road |
| f,a | depart,arrive | road,road |
| g,a | depart,arrive | road,road |
| z,a | depart,turn right,arrive | cross,road,road |
| waypoints | turns | route |
| a,f | depart,arrive | road,road |
| c,f | depart,arrive | road,road |
| f,a | depart,arrive | road,road |
| g,a | depart,arrive | road,road |
Scenario: Traffic Island
Given the node map
@@ -601,10 +588,10 @@ Feature: Merge Segregated Roads
When I route I should get
| waypoints | route | turns |
| a,c | germ,ober | depart,arrive |
| a,g | germ,germ,germ | depart,continue right,arrive |
| a,1 | germ,germ,germ | depart,continue left,arrive |
| d,g | ober,germ,germ | depart,turn left,arrive |
| a,c | germ,ober | depart,arrive |
| a,g | germ,germ,germ | depart,continue right,arrive |
| a,1 | germ,germ,germ | depart,continue left,arrive |
| d,g | ober,germ,germ | depart,turn left,arrive |
# https://www.openstreetmap.org/#map=19/51.32888/6.57059
Scenario: Places in presence of oneways
@@ -636,16 +623,16 @@ Feature: Merge Segregated Roads
| cf | albrecht | yes |
When I route I should get
| waypoints | route | turns |
| a,l | schwert,albrecht,marianne,marianne | depart,new name straight,turn left,arrive |
| a,j | schwert,luise,luise | depart,turn right,arrive |
| a,1 | schwert,albrecht,albrecht,albrecht | depart,new name straight,continue uturn,arrive |
| k,l | marianne,marianne | depart,arrive |
| k,j | marianne,albrecht,luise,luise | depart,turn left,turn left,arrive |
| k,d | marianne,schwert,schwert | depart,turn right,arrive |
| i,j | luise,luise | depart,arrive |
| i,d | luise,albrecht,schwert,schwert | depart,turn left,turn straight,arrive |
| i,l | luise,albrecht,marianne,marianne | depart,turn left,turn left,arrive |
| waypoints | route | turns |
| a,l | schwert,albrecht,marianne,marianne | depart,new name straight,turn left,arrive |
| a,j | schwert,luise,luise | depart,turn right,arrive |
| a,1 | schwert,albrecht,albrecht,albrecht | depart,new name straight,continue uturn,arrive |
| k,l | marianne,marianne | depart,arrive |
| k,j | marianne,albrecht,luise,luise | depart,turn left,turn left,arrive |
| k,d | marianne,schwert,schwert | depart,turn right,arrive |
| i,j | luise,luise | depart,arrive |
| i,d | luise,albrecht,schwert,schwert | depart,turn left,turn straight,arrive |
| i,l | luise,albrecht,marianne,marianne | depart,turn left,turn left,arrive |
# https://www.openstreetmap.org/#map=19/52.46339/13.40272
Scenario: Do not merge links between segregated roads
+10 -13
View File
@@ -745,15 +745,12 @@ Feature: Basic Roundabout
Scenario: Drive through roundabout
Given a grid size of 5 meters
Given the node map
"""
. a .
. .
b e --- d ---- f
. .
.c.
g h
a
b e d f
c
g h
"""
And the ways
@@ -763,12 +760,12 @@ Feature: Basic Roundabout
| gch | | yes |
When I route I should get
| waypoints | bearings | route | turns |
| e,f | 90 90 | edf,edf | depart,arrive |
| e,h | 90 130 | edf,gch,gch,gch | depart,roundabout-exit-2,exit roundabout straight,arrive |
| g,f | 50 90 | gch,edf,edf,edf | depart,roundabout-exit-2,exit roundabout slight right,arrive |
| g,h | 50 130 | gch,gch,gch | depart,exit roundabout right,arrive |
| e,e | 90 270 | edf,edf,edf,edf | depart,roundabout-exit-3,exit roundabout sharp left,arrive |
| waypoints | bearings | route | turns |
| e,f | 90 90 | edf,edf | depart,arrive |
| e,h | 90 135 | edf,gch,gch,gch | depart,roundabout-exit-2,exit roundabout straight,arrive |
| g,f | 45 90 | gch,edf,edf,edf | depart,roundabout-exit-2,exit roundabout right,arrive |
| g,h | 45 135 | gch,gch,gch | depart,exit roundabout right,arrive |
| e,e | 90 270 | edf,edf,edf | depart,continue uturn,arrive |
Scenario: CCW and CW roundabouts with overlaps
Given the node map
+6 -6
View File
@@ -961,12 +961,12 @@ Feature: Simple Turns
g
.
.
.
.
h f
.
. .
. j
.
.
f
h .
. .
. j
. .
c
. . .
-61
View File
@@ -1372,64 +1372,3 @@ Feature: Simple Turns
| waypoints | route | turns |
| a,d | ab,bcd,bcd | depart,fork slight right,arrive |
| a,g | ab,befg,befg | depart,fork slight left,arrive |
# https://www.openstreetmap.org/#map=18/52.25130/10.42545
Scenario: Turn for roads with no name, ref changes
Given the node map
"""
d
.
.
e c . . f
.
.
b
.
.
a
"""
And the ways
| nodes | highway | ref | name |
| abc | tertiary | K 57 | |
| cd | tertiary | K 56 | |
| cf | tertiary | K 56 | |
| ce | residential | | Heinrichshöhe |
When I route I should get
| waypoints | route | turns |
| a,f | ,, | depart,turn right,arrive |
# https://www.openstreetmap.org/#map=18/52.24071/10.29066
Scenario: Turn for roads with no name, ref changes
Given the node map
"""
x
.
.
d
. .
. .
. .
e. . t . c . p. .f
. .
. .
. .
b
.
.
a
"""
And the ways
| nodes | highway | ref | name | oneway |
| abp | tertiary | K 23 | | yes |
| pdx | tertiary | K 23 | | yes |
| xdt | tertiary | K 23 | | yes |
| tba | tertiary | K 23 | | yes |
| etcpf | primary | B 1 | | no |
When I route I should get
| waypoints | route | turns |
| e,x | ,,, | depart,turn sharp left,turn right,arrive |
| f,a | ,, | depart,turn left,arrive |
+1 -30
View File
@@ -150,8 +150,7 @@ module.exports = function () {
}
var ok = true;
var encodedResult = '',
extendedTarget = '',
resultWaypoints = [];
extendedTarget = '';
var testSubMatching = (sub, si) => {
var testSubNode = (ni) => {
@@ -187,29 +186,6 @@ module.exports = function () {
});
}
if (headers.has('waypoints')) {
var got_loc = [];
for (let i = 0; i < json.tracepoints.length; i++) {
if (!json.tracepoints[i]) continue;
if (json.tracepoints[i].waypoint_index != null)
got_loc.push(json.tracepoints[i].location);
}
if (row.waypoints.length != got_loc.length)
return cb(new Error(`Expected ${row.waypoints.length} waypoints, got ${got_loc.length}`));
for (i = 0; i < row.waypoints.length; i++)
{
var want_node = this.findNodeByName(row.waypoints[i]);
if (!this.FuzzyMatch.matchLocation(got_loc[i], want_node)) {
resultWaypoints.push(util.format('? [%s,%s]', got_loc[i][0], got_loc[i][1]));
ok = false;
} else {
resultWaypoints.push(row.waypoints[i]);
}
}
}
if (ok) {
if (headers.has('matchings')) {
got.matchings = row.matchings;
@@ -218,12 +194,7 @@ module.exports = function () {
if (headers.has('timestamps')) {
got.timestamps = row.timestamps;
}
if (headers.has('waypoints')) {
got.waypoints = row.waypoints;
}
} else {
got.waypoints = resultWaypoints.join(';');
got.matchings = encodedResult;
row.matchings = extendedTarget;
}
-4
View File
@@ -12,10 +12,6 @@ module.exports = {
FuzzyMatch: class {
match (got, want) {
// don't fail if bearings input and extected string is empty and actual result is undefined
if (want === '' && (got === '' || got === undefined))
return true;
var matchPercent = want.match(/(.*)\s+~(.+)%$/),
matchAbs = want.match(/(.*)\s+\+\-(.+)$/),
matchRe = want.match(/^\/(.*)\/$/),
-24
View File
@@ -59,27 +59,3 @@ Feature: Annotations
| from | to | route | a:datasources | a:speed |
| a | i | abcdefghi,abcdefghi | 1:0:1:0:1:0:0:0 | 50:10:50:10:50:10:10:10 |
| i | a | abcdefghi,abcdefghi | 0:1:0:0:0:0:0:1 | 10:50:10:10:10:10:10:50 |
Scenario: Speed annotations should handle zero segments
Given the profile "testbot"
Given the node map
"""
a -- b --- c
|
d
"""
And the ways
| nodes |
| abc |
| cd |
# This test relies on the snapping to the EBN cd to introduce a zero segment after the turn
And the query options
| annotations | speed,distance,duration,nodes |
| bearings | 90,5;180,5 |
When I route I should get
| from | to | route | a:speed | a:distance | a:duration | a:nodes |
| a | c | abc,abc | 10:10:10 | 249.998641:299.931643:0 | 25:30:0 | 1:2:3 |
@@ -1,68 +0,0 @@
@routing @testbot @exclude
Feature: Testbot - Exclude flags regression tests
Background:
Given the profile "testbot"
Scenario: Testbot - Exclude toll regression 1
Given the node map
"""
a g
. .
b....d-$-$-e....f
. .
c h
"""
And the ways
| nodes | highway | toll | # |
| ab | primary | | always drivable |
| cb | primary | | always drivable |
| bd | primary | | always drivable |
| de | motorway | yes | not drivable for exclude=toll |
| ef | primary | | always drivable |
| fg | primary | | always drivable |
| fh | primary | | always drivable |
Given the query options
| exclude | toll |
When I route I should get
| from | to | route |
| a | h | |
| a | g | |
| g | a | |
| d | e | |
Scenario: Testbot - Exclude toll regression 2
Given the profile "testbot"
Given the node map
"""
a g
. .
b....d-$-$-e....f
. .
c h..i
"""
And the ways
| nodes | highway | toll | # |
| ab | primary | | always drivable |
| cb | primary | | always drivable |
| bd | primary | | always drivable |
| de | motorway | yes | not drivable for exclude=toll |
| ef | primary | | always drivable |
| fg | primary | | always drivable |
| fh | primary | | always drivable |
| hi | primary | | always drivable |
Given the query options
| exclude | toll |
When I route I should get
| from | to | route |
| a | h | |
| a | g | |
| g | a | |
| d | e | |
| d | i | |
-146
View File
@@ -480,149 +480,3 @@ Feature: Basic Map Matching
| trace | a:nodes |
| 12 | 1:2:3:4:5:6 |
| 21 | 6:5:4:3:2:1 |
Scenario: Matching with waypoints param for start/end
Given the node map
"""
a-----b---c
|
|
d
|
|
e
"""
And the ways
| nodes | oneway |
| abc | no |
| bde | no |
Given the query options
| waypoints | 0;3 |
When I match I should get
| trace | code | matchings | waypoints |
| abde | Ok | abde | ae |
Scenario: Matching with waypoints param that were tidied away
Given the node map
"""
a - b - c - e
|
f
|
g
"""
And the ways
| nodes | oneway |
| abce | no |
| cfg | no |
Given the query options
| tidy | true |
| waypoints | 0;2;5 |
When I match I should get
| trace | code | matchings | waypoints |
| abccfg | Ok | abcfg | acg |
Scenario: Testbot - Map matching refuses to use waypoints with trace splitting
Given the node map
"""
a b c d
e
"""
Given the query options
| waypoints | 0;3 |
And the ways
| nodes | oneway |
| abcd | no |
When I match I should get
| trace | timestamps | code |
| abcd | 0 1 62 63 | NoMatch |
Scenario: Testbot - Map matching invalid waypoints
Given the node map
"""
a b c d
e
"""
Given the query options
| waypoints | 0;4 |
And the ways
| nodes | oneway |
| abcd | no |
When I match I should get
| trace | code |
| abcd | InvalidOptions |
Scenario: Matching fail with waypoints param missing start/end
Given the node map
"""
a-----b---c
|
|
d
|
|
e
"""
And the ways
| nodes | oneway |
| abc | no |
| bde | no |
Given the query options
| waypoints | 1;3 |
When I match I should get
| trace | code |
| abde | InvalidValue |
Scenario: Testbot - Map matching with outlier that has no candidate and waypoint parameter
Given a grid size of 100 meters
Given the node map
"""
a b c d
1
"""
And the ways
| nodes | oneway |
| abcd | no |
Given the query options
| waypoints | 0;2;3 |
When I match I should get
| trace | timestamps | code |
| ab1d | 0 1 2 3 | NoMatch |
Scenario: Regression test - avoid collapsing legs of a tidied split trace
Given a grid size of 20 meters
Given the node map
"""
a--b--f
|
|
e--c---d--g
"""
Given the query options
| tidy | true |
And the ways
| nodes | oneway |
| abf | no |
| be | no |
| ecdg | no |
When I match I should get
| trace | timestamps | matchings | code |
| abbecd | 10 11 27 1516914902 1516914913 1516914952 | ab,ecd | Ok |
+1 -1
View File
@@ -309,7 +309,7 @@ Feature: Via points
| waypoints | route |
| a,b,e | |
@3359
@todo @3359
Scenario: U-Turn In Bearings
Given the node map
"""
@@ -69,11 +69,6 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_,
});
non_core_edges.resize(new_end - non_core_edges.begin());
edge_container.Insert(std::move(non_core_edges));
for (const auto filter_index : util::irange<std::size_t>(0, filters.size()))
{
edge_container.Filter(filters[filter_index], filter_index);
}
}
// Extract core graph for further contraction
@@ -60,25 +60,6 @@ struct ContractedEdgeContainer
flags.resize(edges.size(), ALL_FLAGS);
}
void Filter(const std::vector<bool> &filter, std::size_t index)
{
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
const MergedFlags flag = 1 << index;
for (auto edge_index : util::irange<std::size_t>(0, edges.size()))
{
auto allowed = filter[edges[edge_index].source] && filter[edges[edge_index].target];
if (allowed)
{
flags[edge_index] |= flag;
}
else
{
flags[edge_index] &= ~flag;
}
}
}
void Merge(std::vector<QueryEdge> new_edges)
{
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
@@ -127,7 +108,7 @@ struct ContractedEdgeContainer
edges.insert(edges.end(), new_edges.begin(), new_end);
auto edges_size = edges.size();
auto new_edges_size = std::distance(new_edges.begin(), new_end);
BOOST_ASSERT(static_cast<int>(edges_size) >= new_edges_size);
BOOST_ASSERT(edges_size >= new_edges_size);
flags.resize(edges_size);
std::fill(flags.begin() + edges_size - new_edges_size, flags.end(), flag);
-1
View File
@@ -6,7 +6,6 @@
#include "util/query_heap.hpp"
#include <tbb/enumerable_thread_specific.h>
#include <tbb/parallel_for.h>
#include <unordered_set>
-21
View File
@@ -86,10 +86,6 @@ class MatchAPI final : public RouteAPI
for (auto point_index : util::irange(
0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
{
// tidied_to_original: index of the input coordinate that a tidied coordinate
// corresponds to.
// sub_matching indices: index of the coordinate passed to map matching plugin that
// a matched node corresponds to.
trace_idx_to_matching_idx[tidy_result
.tidied_to_original[sub_matchings[sub_matching_index]
.indices[point_index]]] =
@@ -97,9 +93,6 @@ class MatchAPI final : public RouteAPI
}
}
BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1);
std::size_t was_waypoint_idx = 0;
for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
if (tidy_result.can_be_removed[trace_index])
@@ -121,20 +114,6 @@ class MatchAPI final : public RouteAPI
waypoint.values["alternatives_count"] =
sub_matchings[matching_index.sub_matching_index]
.alternatives_count[matching_index.point_index];
// waypoint indices need to be adjusted if route legs were collapsed
// waypoint parameter assumes there is only one match object
if (!parameters.waypoints.empty())
{
if (tidy_result.was_waypoint[trace_index])
{
waypoint.values["waypoint_index"] = was_waypoint_idx;
was_waypoint_idx++;
}
else
{
waypoint.values["waypoint_index"] = util::json::Null();
}
}
waypoints.values.push_back(std::move(waypoint));
}
+3 -18
View File
@@ -63,40 +63,25 @@ struct MatchParameters : public RouteParameters
RouteParameters::GeometriesType::Polyline,
RouteParameters::OverviewType::Simplified,
{}),
gaps(GapsType::Split), tidy(false), waypoints()
gaps(GapsType::Split), tidy(false)
{
}
template <typename... Args>
MatchParameters(std::vector<unsigned> timestamps_, GapsType gaps_, bool tidy_, Args... args_)
: MatchParameters(std::move(timestamps_), gaps_, tidy_, {}, std::forward<Args>(args_)...)
{
}
template <typename... Args>
MatchParameters(std::vector<unsigned> timestamps_,
GapsType gaps_,
bool tidy_,
std::vector<std::size_t> waypoints_,
Args... args_)
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)},
gaps(gaps_), tidy(tidy_), waypoints{std::move(waypoints_)}
gaps(gaps_), tidy(tidy_)
{
}
std::vector<unsigned> timestamps;
GapsType gaps;
bool tidy;
std::vector<std::size_t> waypoints;
bool IsValid() const
{
const auto valid_waypoints =
std::all_of(waypoints.begin(), waypoints.end(), [this](const auto &w) {
return w < coordinates.size();
});
return RouteParameters::IsValid() &&
(timestamps.empty() || timestamps.size() == coordinates.size()) && valid_waypoints;
(timestamps.empty() || timestamps.size() == coordinates.size());
}
};
}
+2 -39
View File
@@ -37,9 +37,6 @@ struct Result
Mask can_be_removed;
// Maps the MatchParameter's original items to items which should not be removed.
Mapping tidied_to_original;
// Masking the MatchParameter coordinates for items whose indices were present in the
// `waypoints` parameter.
Mask was_waypoint;
};
inline Result keep_all(const MatchParameters &params)
@@ -47,17 +44,6 @@ inline Result keep_all(const MatchParameters &params)
Result result;
result.can_be_removed.resize(params.coordinates.size(), false);
result.was_waypoint.resize(params.coordinates.size(), true);
// by default all input coordinates are treated as waypoints
if (!params.waypoints.empty())
{
for (const auto p : params.waypoints)
{
result.was_waypoint.set(p, false);
}
// logic is a little funny, uses inversion to set the bitfield
result.was_waypoint.flip();
}
result.tidied_to_original.reserve(params.coordinates.size());
for (std::size_t current = 0; current < params.coordinates.size(); ++current)
{
@@ -75,8 +61,6 @@ inline Result keep_all(const MatchParameters &params)
{
result.parameters.coordinates.push_back(params.coordinates[i]);
if (result.was_waypoint[i])
result.parameters.waypoints.push_back(result.parameters.coordinates.size() - 1);
if (!params.hints.empty())
result.parameters.hints.push_back(params.hints[i]);
@@ -90,8 +74,6 @@ inline Result keep_all(const MatchParameters &params)
result.parameters.timestamps.push_back(params.timestamps[i]);
}
}
if (params.waypoints.empty())
result.parameters.waypoints.clear();
return result;
}
@@ -103,15 +85,6 @@ inline Result tidy(const MatchParameters &params, Thresholds cfg = {15., 5})
Result result;
result.can_be_removed.resize(params.coordinates.size(), false);
result.was_waypoint.resize(params.coordinates.size(), true);
if (!params.waypoints.empty())
{
for (const auto p : params.waypoints)
{
result.was_waypoint.set(p, false);
}
result.was_waypoint.flip();
}
result.tidied_to_original.push_back(0);
@@ -165,14 +138,13 @@ inline Result tidy(const MatchParameters &params, Thresholds cfg = {15., 5})
// We have to filter parallel arrays that may be empty or the exact same size.
// result.parameters contains an empty MatchParameters at this point: conditionally fill.
for (std::size_t i = 0; i < result.can_be_removed.size(); ++i)
{
if (!result.can_be_removed[i])
{
result.parameters.coordinates.push_back(params.coordinates[i]);
if (result.was_waypoint[i])
result.parameters.waypoints.push_back(result.parameters.coordinates.size() - 1);
if (!params.hints.empty())
result.parameters.hints.push_back(params.hints[i]);
@@ -185,17 +157,8 @@ inline Result tidy(const MatchParameters &params, Thresholds cfg = {15., 5})
if (!params.timestamps.empty())
result.parameters.timestamps.push_back(params.timestamps[i]);
}
else
{
// one of the coordinates meant to be used as a waypoint was marked for removal
// update the original waypoint index to the new representative coordinate
const auto last_idx = result.parameters.coordinates.size() - 1;
if (result.was_waypoint[i] && (result.parameters.waypoints.back() != last_idx))
{
result.parameters.waypoints.push_back(last_idx);
}
}
}
BOOST_ASSERT(result.tidied_to_original.size() == result.parameters.coordinates.size());
return result;
}
+13 -22
View File
@@ -88,12 +88,11 @@ class RouteAPI : public BaseAPI
{
util::json::Array annotations_store;
annotations_store.values.reserve(leg.annotations.size());
for (const auto &step : leg.annotations)
{
annotations_store.values.push_back(Get(step));
}
std::for_each(leg.annotations.begin(),
leg.annotations.end(),
[Get, &annotations_store](const auto &step) {
annotations_store.values.push_back(Get(step));
});
return annotations_store;
}
@@ -256,19 +255,10 @@ class RouteAPI : public BaseAPI
// AnnotationsType uses bit flags, & operator checks if a property is set
if (parameters.annotations_type & RouteParameters::AnnotationsType::Speed)
{
double prev_speed = 0;
annotation.values["speed"] = GetAnnotations(
leg_geometry, [&prev_speed](const guidance::LegGeometry::Annotation &anno) {
if (anno.duration < std::numeric_limits<double>::min())
{
return prev_speed;
}
else
{
auto speed = std::round(anno.distance / anno.duration * 10.) / 10.;
prev_speed = speed;
return util::json::clamp_float(speed);
}
leg_geometry, [](const guidance::LegGeometry::Annotation &anno) {
auto val = std::round(anno.distance / anno.duration * 10.) / 10.;
return util::json::clamp_float(val);
});
}
@@ -303,10 +293,11 @@ class RouteAPI : public BaseAPI
{
util::json::Array nodes;
nodes.values.reserve(leg_geometry.osm_node_ids.size());
for (const auto node_id : leg_geometry.osm_node_ids)
{
nodes.values.push_back(static_cast<std::uint64_t>(node_id));
}
std::for_each(leg_geometry.osm_node_ids.begin(),
leg_geometry.osm_node_ids.end(),
[this, &nodes](const OSMNodeID &node_id) {
nodes.values.push_back(static_cast<std::uint64_t>(node_id));
});
annotation.values["nodes"] = std::move(nodes);
}
+6 -6
View File
@@ -53,12 +53,12 @@ template <typename Algorithm> class Engine final : public EngineInterface
{
public:
explicit Engine(const EngineConfig &config)
: route_plugin(config.max_locations_viaroute, config.max_alternatives), //
table_plugin(config.max_locations_distance_table), //
nearest_plugin(config.max_results_nearest), //
trip_plugin(config.max_locations_trip), //
match_plugin(config.max_locations_map_matching, config.max_radius_map_matching), //
tile_plugin() //
: route_plugin(config.max_locations_viaroute, config.max_alternatives), //
table_plugin(config.max_locations_distance_table), //
nearest_plugin(config.max_results_nearest), //
trip_plugin(config.max_locations_trip), //
match_plugin(config.max_locations_map_matching), //
tile_plugin() //
{
if (config.use_shared_memory)
-1
View File
@@ -84,7 +84,6 @@ struct EngineConfig final
int max_locations_viaroute = -1;
int max_locations_distance_table = -1;
int max_locations_map_matching = -1;
double max_radius_map_matching = -1.0;
int max_results_nearest = -1;
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
bool use_shared_memory = true;
+2 -54
View File
@@ -7,11 +7,11 @@
#include "engine/phantom_node.hpp"
#include "util/coordinate.hpp"
#include "osrm/coordinate.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/guidance/turn_bearing.hpp"
#include "util/guidance/turn_lanes.hpp"
#include "util/integer_range.hpp"
#include "util/typedefs.hpp"
#include <vector>
@@ -102,58 +102,6 @@ struct InternalManyRoutesResult
std::vector<InternalRouteResult> routes;
};
inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult &leggy_result,
const std::vector<bool> &is_waypoint)
{
BOOST_ASSERT(leggy_result.is_valid());
BOOST_ASSERT(is_waypoint[0]); // first and last coords
BOOST_ASSERT(is_waypoint.back()); // should always be waypoints
// Nothing to collapse! return result as is
if (leggy_result.unpacked_path_segments.size() == 1)
return leggy_result;
BOOST_ASSERT(leggy_result.segment_end_coordinates.size() > 1);
InternalRouteResult collapsed;
collapsed.shortest_path_weight = leggy_result.shortest_path_weight;
for (auto i : util::irange<std::size_t>(0, leggy_result.unpacked_path_segments.size()))
{
if (is_waypoint[i])
{
// start another leg vector
collapsed.unpacked_path_segments.push_back(leggy_result.unpacked_path_segments[i]);
// save new phantom node pair
collapsed.segment_end_coordinates.push_back(leggy_result.segment_end_coordinates[i]);
// save data about phantom nodes
collapsed.source_traversed_in_reverse.push_back(
leggy_result.source_traversed_in_reverse[i]);
collapsed.target_traversed_in_reverse.push_back(
leggy_result.target_traversed_in_reverse[i]);
}
else
// no new leg, collapse the next segment into the last leg
{
BOOST_ASSERT(!collapsed.unpacked_path_segments.empty());
auto &last_segment = collapsed.unpacked_path_segments.back();
// deduplicate last segment (needs to be checked for empty for the same node query edge
// case)
if (!last_segment.empty())
last_segment.pop_back();
// update target phantom node of leg
BOOST_ASSERT(!collapsed.segment_end_coordinates.empty());
collapsed.segment_end_coordinates.back().target_phantom =
leggy_result.segment_end_coordinates[i].target_phantom;
collapsed.target_traversed_in_reverse.back() =
leggy_result.target_traversed_in_reverse[i];
// copy path segments into current leg
last_segment.insert(last_segment.end(),
leggy_result.unpacked_path_segments[i].begin(),
leggy_result.unpacked_path_segments[i].end());
}
}
return collapsed;
}
}
}
+2 -4
View File
@@ -24,9 +24,8 @@ class MatchPlugin : public BasePlugin
using CandidateLists = routing_algorithms::CandidateLists;
static const constexpr double RADIUS_MULTIPLIER = 3;
MatchPlugin(const int max_locations_map_matching, const double max_radius_map_matching)
: max_locations_map_matching(max_locations_map_matching),
max_radius_map_matching(max_radius_map_matching)
MatchPlugin(const int max_locations_map_matching)
: max_locations_map_matching(max_locations_map_matching)
{
}
@@ -36,7 +35,6 @@ class MatchPlugin : public BasePlugin
private:
const int max_locations_map_matching;
const double max_radius_map_matching;
};
}
}
+2 -2
View File
@@ -39,8 +39,8 @@ struct ExtractionTurn
const bool is_left_hand_driving;
double weight;
double duration;
const TravelMode source_mode;
const TravelMode target_mode;
TravelMode source_mode;
TravelMode target_mode;
};
}
}
+8
View File
@@ -47,6 +47,7 @@ namespace extractor
class ScriptingEnvironment;
struct ProfileProperties;
class NodeBasedGraphFactory;
class Extractor
{
@@ -101,6 +102,13 @@ class Extractor
void WriteConditionalRestrictions(
const std::string &path,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
// Find all "segregated" edges, e.g. edges that can be skipped in turn instructions.
// The main cases are:
// - middle edges between two osm ways in one logic road (U-turn)
// - staggered intersections (X-cross)
// - square/circle intersections
std::unordered_set<EdgeID> FindSegregatedNodes(NodeBasedGraphFactory &factory);
};
}
}
+1 -1
View File
@@ -60,7 +60,7 @@ operator()(const NodeID intersection_node,
const boost::optional<util::json::Object> &way_style) const
{
// request the number of lanes. This process needs to be in sync with what happens over at
// intersection analysis
// intersection_generator
const auto intersection_lanes =
intersection.FindMaximum(guidance::makeExtractLanesForRoad(node_based_graph));
@@ -14,13 +14,10 @@ namespace guidance
class DrivewayHandler final : public IntersectionHandler
{
public:
DrivewayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
DrivewayHandler(const IntersectionGenerator &intersection_generator,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
@@ -1,27 +0,0 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
#include "extractor/guidance/constants.hpp"
#include "extractor/suffix_table.hpp"
#include "util/name_table.hpp"
namespace osrm
{
namespace extractor
{
namespace guidance
{
// check if two name ids can be seen as identical (in presence of refs/others)
// in our case this translates into no name announcement in either direction (lhs->rhs and
// rhs->lhs)
bool HaveIdenticalNames(const NameID lhs,
const NameID rhs,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_*/
+10 -3
View File
@@ -44,6 +44,14 @@ inline auto makeCompareShapeDataByBearing(const double base_bearing)
};
}
inline auto makeCompareShapeDataAngleToBearing(const double base_bearing)
{
return [base_bearing](const auto &lhs, const auto &rhs) {
return util::bearing::angleBetween(lhs.bearing, base_bearing) <
util::bearing::angleBetween(rhs.bearing, base_bearing);
};
}
inline auto makeCompareAngularDeviation(const double angle)
{
return [angle](const auto &lhs, const auto &rhs) {
@@ -293,11 +301,10 @@ struct IntersectionView final : std::vector<IntersectionViewData>, //
};
// `Intersection` is a relative view of an intersection by an incoming edge.
// `Intersection` are streets at an intersection stored as an ordered list of connected roads
// ordered from sharp right counter-clockwise to
// `Intersection` are streets at an intersection ordered from from sharp right counter-clockwise to
// sharp left where `intersection[0]` is _always_ a u-turn
// An intersection is an ordered list of connected roads ordered from sharp right
// An intersection is an ordered list of connected roads ordered from from sharp right
// counter-clockwise to sharp left where `intersection[0]` is always a u-turn
//
// |
@@ -0,0 +1,127 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_normalization_operation.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_index.hpp"
#include "util/attributes.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include <unordered_set>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
namespace osrm
{
namespace extractor
{
namespace guidance
{
struct IntersectionGenerationParameters
{
NodeID nid;
EdgeID via_eid;
};
// The Intersection Generator is given a turn location and generates an intersection representation
// from it. For this all turn possibilities are analysed.
// We consider turn restrictions to indicate possible turns. U-turns are generated based on profile
// decisions.
class IntersectionGenerator
{
public:
IntersectionGenerator(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const std::vector<util::Coordinate> &coordinates,
const CompressedEdgeContainer &compressed_edge_container);
// For a source node `a` and a via edge `ab` creates an intersection at target `b`.
//
// a . . . b . .
// .
// .
//
IntersectionView operator()(const NodeID nid, const EdgeID via_eid) const;
/*
* Compute the shape of an intersection, returning a set of connected roads, without any further
* concern for which of the entries are actually allowed.
* The shape also only comes with turn bearings, not with turn angles. All turn angles will be
* set to zero
*/
OSRM_ATTR_WARN_UNUSED
IntersectionShape
ComputeIntersectionShape(const NodeID center_node,
const boost::optional<NodeID> sorting_base = boost::none,
bool use_low_precision_angles = false) const;
// Graph Compression cannot compress every setting. For example any barrier/traffic light cannot
// be compressed. As a result, a simple road of the form `a ----- b` might end up as having an
// intermediate intersection, if there is a traffic light in between. If we want to look farther
// down a road, finding the next actual decision requires the look at multiple intersections.
// Here we follow the road until we either reach a dead end or find the next intersection with
// more than a single next road. This function skips over degree two nodes to find coorect input
// for GetConnectedRoads.
OSRM_ATTR_WARN_UNUSED
IntersectionGenerationParameters SkipDegreeTwoNodes(const NodeID starting_node,
const EdgeID via_edge) const;
// Allow access to the coordinate extractor for all owners
const CoordinateExtractor &GetCoordinateExtractor() const;
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
// the node reached from `from_node` via `via_eid`. The resulting candidates have to be analysed
// for their actual instructions later on.
// The switch for `use_low_precision_angles` enables a faster mode that will procude less
// accurate coordinates. It should be good enough to check order of turns, find straightmost
// turns. Even good enough to do some simple angle verifications. It is mostly available to
// allow for faster graph traversal in the extraction phase.
OSRM_ATTR_WARN_UNUSED
IntersectionView GetConnectedRoads(const NodeID from_node,
const EdgeID via_eid,
const bool use_low_precision_angles = false) const;
/*
* To be used in the road network, we need to check for valid/restricted turns. These two
* functions transform a basic intersection / a normalised intersection into the
* correct view when entering via a given edge.
*/
OSRM_ATTR_WARN_UNUSED
IntersectionView
TransformIntersectionShapeIntoView(const NodeID previous_node,
const EdgeID entering_via_edge,
const IntersectionShape &intersection) const;
// version for normalised intersection
OSRM_ATTR_WARN_UNUSED
IntersectionView TransformIntersectionShapeIntoView(
const NodeID previous_node,
const EdgeID entering_via_edge,
const IntersectionShape &normalised_intersection,
const IntersectionShape &intersection,
const std::vector<IntersectionNormalizationOperation> &merging_map) const;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const EdgeBasedNodeDataContainer &node_data_container;
const RestrictionMap &restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const std::vector<util::Coordinate> &coordinates;
// own state, used to find the correct coordinates along a road
const CoordinateExtractor coordinate_extractor;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_ */
@@ -2,8 +2,8 @@
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/node_based_graph_walker.hpp"
#include "extractor/intersection/intersection_analysis.hpp"
#include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp"
@@ -34,13 +34,10 @@ class IntersectionHandler
public:
IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const std::vector<util::Coordinate> &coordinates,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator);
virtual ~IntersectionHandler() = default;
@@ -55,20 +52,15 @@ class IntersectionHandler
protected:
const util::NodeBasedDynamicGraph &node_based_graph;
const EdgeBasedNodeDataContainer &node_data_container;
const std::vector<util::Coordinate> &node_coordinates;
const extractor::CompressedEdgeContainer &compressed_geometries;
const RestrictionMap &node_restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const guidance::TurnLanesIndexedArray &turn_lanes_data;
const std::vector<util::Coordinate> &coordinates;
const util::NameTable &name_table;
const SuffixTable &street_name_suffix_table;
const IntersectionGenerator &intersection_generator;
const NodeBasedGraphWalker graph_walker; // for skipping traffic signal, distances etc.
// Decide on a basic turn types
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
TurnType::Enum areSameClasses(const EdgeID via_edge, const ConnectedRoad &road) const;
// Find the most obvious turn to follow. The function returns an index into the intersection
// determining whether there is a road that can be seen as obvious turn in the presence of many
// other possible turns. The function will consider road categories and other inputs like the
@@ -98,6 +90,9 @@ class IntersectionHandler
const std::size_t begin,
const std::size_t end) const;
// Checks the intersection for a through street connected to `intersection[index]`
bool isThroughStreet(const std::size_t index, const Intersection &intersection) const;
// See `getNextIntersection`
struct IntersectionViewAndNode final
{
@@ -572,19 +567,11 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
// try to find whether there is a turn going to the opposite direction of our obvious
// turn, this should be alright.
const auto previous_intersection = [&]() -> IntersectionView {
const auto parameters = intersection::skipDegreeTwoNodes(
node_based_graph, {node_at_intersection, intersection[0].eid});
if (node_based_graph.GetTarget(parameters.edge) == node_at_intersection)
const auto parameters = intersection_generator.SkipDegreeTwoNodes(
node_at_intersection, intersection[0].eid);
if (node_based_graph.GetTarget(parameters.via_eid) == node_at_intersection)
return {};
return intersection::getConnectedRoads<false>(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
parameters);
return intersection_generator.GetConnectedRoads(parameters.nid, parameters.via_eid);
}();
if (!previous_intersection.empty())
@@ -0,0 +1,25 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZATION_OPERATION_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZATION_OPERATION_HPP_
#include "util/typedefs.hpp"
namespace osrm
{
namespace extractor
{
namespace guidance
{
struct IntersectionNormalizationOperation
{
// the source of the merge, not part of the intersection after the merge is performed.
EdgeID merged_eid;
// the edge that is covering the `merged_eid`
EdgeID into_eid;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZATION_OPERATION_HPP_*/
@@ -0,0 +1,125 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
#include "util/attributes.hpp"
#include "util/name_table.hpp"
#include "util/typedefs.hpp"
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/intersection_normalization_operation.hpp"
#include "extractor/guidance/mergable_road_detector.hpp"
#include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp"
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
namespace guidance
{
/*
* An intersection is a central part in computing guidance decisions. However the model in OSM and
* the view we want to use in guidance are not necessarily the same thing. We have to account for
* some models that are chosen explicitly in OSM and that don't actually describe how a human would
* experience an intersection.
*
* For example, if a small pedestrian island is located at a traffic light right in the middle of a
* road, OSM tends to model the road as two separate ways. A human would consider these two ways a
* single road, though. In this normalizer, we try to account for these subtle differences between
* OSM data and human perception to improve our decision base for guidance later on.
*/
class IntersectionNormalizer
{
public:
struct NormalizationResult
{
IntersectionShape normalized_shape;
std::vector<IntersectionNormalizationOperation> performed_merges;
};
IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator);
// The function takes an intersection an converts it to a `perceived` intersection which closer
// represents how a human might experience the intersection
OSRM_ATTR_WARN_UNUSED
NormalizationResult operator()(const NodeID node_at_intersection,
IntersectionShape intersection) const;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const IntersectionGenerator &intersection_generator;
const MergableRoadDetector mergable_road_detector;
/* check if two indices in an intersection can be seen as a single road in the perceived
* intersection representation. See below for an example. Utility function for
* MergeSegregatedRoads. It also checks for neighboring merges.
* This is due possible segments where multiple roads could end up being merged into one.
* We only support merging two roads, not three or more, though.
* c c
* / /
* a - b -> a - b - (c,d) but not a - b d -> a,b,(cde)
* \ \
* d e
*/
bool CanMerge(const NodeID intersection_node,
const IntersectionShape &intersection,
std::size_t first_index,
std::size_t second_index) const;
// Perform an Actual Merge
IntersectionNormalizationOperation
DetermineMergeDirection(const IntersectionShapeData &lhs,
const IntersectionShapeData &rhs) const;
IntersectionShapeData MergeRoads(const IntersectionShapeData &destination,
const IntersectionShapeData &source) const;
IntersectionShapeData MergeRoads(const IntersectionNormalizationOperation direction,
const IntersectionShapeData &lhs,
const IntersectionShapeData &rhs,
const double opposite_bearing) const;
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
// one.
// This function combines roads the following way:
//
// * *
// * is converted to *
// v ^ +
// v ^ +
//
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
// 160
OSRM_ATTR_WARN_UNUSED
NormalizationResult MergeSegregatedRoads(const NodeID intersection_node,
IntersectionShape intersection) const;
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
// intersection itself, it can also happen that intersections are connected to joining roads.
//
// * *
// * is converted to *
// v a --- a ---
// v ^ +
// v ^ +
// b
//
// for the local view of b at a.
OSRM_ATTR_WARN_UNUSED
IntersectionShape AdjustBearingsForMergeAtDestination(const NodeID node_at_intersection,
IntersectionShape intersection) const;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_ */
@@ -1,63 +0,0 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_
#include "extractor/guidance/constants.hpp"
#include "extractor/suffix_table.hpp"
#include "util/guidance/name_announcements.hpp"
using osrm::util::angularDeviation;
namespace osrm
{
namespace extractor
{
namespace guidance
{
template <typename IntersectionType>
inline bool isThroughStreet(const std::size_t index,
const IntersectionType &intersection,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
{
const auto &data_at_index = node_data_container.GetAnnotation(
node_based_graph.GetEdgeData(intersection[index].eid).annotation_data);
if (data_at_index.name_id == EMPTY_NAMEID)
return false;
// a through street cannot start at our own position -> index 1
for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index)
{
if (road_index == index)
continue;
const auto &road = intersection[road_index];
const auto &road_data = node_data_container.GetAnnotation(
node_based_graph.GetEdgeData(road.eid).annotation_data);
// roads have a near straight angle (180 degree)
const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
const bool have_same_name = HaveIdenticalNames(
data_at_index.name_id, road_data.name_id, name_table, street_name_suffix_table);
const bool have_same_category =
node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification ==
node_based_graph.GetEdgeData(road.eid).flags.road_classification;
if (is_nearly_straight && have_same_name && have_same_category)
return true;
}
return false;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_*/
@@ -1,12 +1,7 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_MERGEABLE_ROADS
#define OSRM_EXTRACTOR_GUIDANCE_MERGEABLE_ROADS
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/have_identical_names.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/turn_lane_types.hpp"
#include "extractor/restriction_index.hpp"
#include "util/coordinate.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
@@ -14,7 +9,6 @@
#include <cstdint>
#include <functional>
#include <limits>
#include <unordered_set>
#include <vector>
namespace osrm
@@ -45,10 +39,8 @@ class MergableRoadDetector
MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const IntersectionGenerator &intersection_generator,
const CoordinateExtractor &coordinate_extractor,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
@@ -79,6 +71,11 @@ class MergableRoadDetector
bool IsDistinctFrom(const MergableRoadData &lhs, const MergableRoadData &rhs) const;
private:
// check if two name ids can be seen as identical (in presence of refs/others)
// in our case this translates into no name announcement in either direction (lhs->rhs and
// rhs->lhs)
bool HaveIdenticalNames(const NameID lhs, const NameID rhs) const;
// When it comes to merging roads, we need to find out if two ways actually represent the
// same road. This check tries to identify roads which are the same road in opposite directions
bool EdgeDataSupportsMerge(const NodeBasedEdgeClassification &lhs_flags,
@@ -162,19 +159,15 @@ class MergableRoadDetector
const util::NodeBasedDynamicGraph &node_based_graph;
const EdgeBasedNodeDataContainer &node_data_container;
const std::vector<util::Coordinate> &node_coordinates;
const extractor::CompressedEdgeContainer &compressed_geometries;
const RestrictionMap &node_restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const guidance::TurnLanesIndexedArray &turn_lanes_data;
const IntersectionGenerator &intersection_generator;
const CoordinateExtractor &coordinate_extractor;
// name detection
const util::NameTable &name_table;
const SuffixTable &street_name_suffix_table;
const CoordinateExtractor coordinate_extractor;
// limit for detecting circles / parallel roads
const static double constexpr distance_to_extract = 120;
const static double constexpr distance_to_extract = 150;
};
} // namespace guidance
@@ -2,8 +2,8 @@
#define OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/is_through_street.hpp"
#include "extractor/query_node.hpp"
#include "util/attributes.hpp"
@@ -26,12 +26,9 @@ class MotorwayHandler : public IntersectionHandler
MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator);
~MotorwayHandler() override final = default;
@@ -2,9 +2,7 @@
#define OSRM_EXTRACTOR_GUIDANCE_NODE_BASED_GRAPH_WALKER
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/turn_lane_data.hpp"
#include "extractor/intersection/intersection_analysis.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/node_based_graph.hpp"
@@ -31,11 +29,7 @@ class NodeBasedGraphWalker
public:
NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data);
const IntersectionGenerator &intersection_generator);
/*
* the returned node-id, edge-id are either the last ones used, just prior accumulator
@@ -54,11 +48,7 @@ class NodeBasedGraphWalker
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const EdgeBasedNodeDataContainer &node_data_container;
const std::vector<util::Coordinate> &node_coordinates;
const extractor::CompressedEdgeContainer &compressed_geometries;
const RestrictionMap &node_restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const guidance::TurnLanesIndexedArray &turn_lanes_data;
const IntersectionGenerator &intersection_generator;
};
/*
@@ -159,13 +149,7 @@ struct SelectStraightmostRoadByNameAndOnlyChoice
struct IntersectionFinderAccumulator
{
IntersectionFinderAccumulator(const std::uint8_t hop_limit,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data);
const IntersectionGenerator &intersection_generator);
// true if the path has traversed enough distance
bool terminate();
@@ -175,19 +159,13 @@ struct IntersectionFinderAccumulator
std::uint8_t hops;
const std::uint8_t hop_limit;
// we need to be able to look-up the intersection
const IntersectionGenerator &intersection_generator;
// the result we are looking for
NodeID nid;
EdgeID via_edge_id;
IntersectionView intersection;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const EdgeBasedNodeDataContainer &node_data_container;
const std::vector<util::Coordinate> &node_coordinates;
const extractor::CompressedEdgeContainer &compressed_geometries;
const RestrictionMap &node_restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const guidance::TurnLanesIndexedArray &turn_lanes_data;
};
template <class accumulator_type, class selector_type>
@@ -221,15 +199,9 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
return {};
// look at the next intersection
const auto next_intersection =
intersection::getConnectedRoads<true>(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
{current_node_id, current_edge_id});
const constexpr auto LOW_PRECISION = true;
const auto next_intersection = intersection_generator.GetConnectedRoads(
current_node_id, current_edge_id, LOW_PRECISION);
// don't follow u-turns or go past our initial intersection
if (next_intersection.size() <= 1)
@@ -4,8 +4,8 @@
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/is_through_street.hpp"
#include "extractor/guidance/roundabout_type.hpp"
#include "extractor/query_node.hpp"
@@ -42,12 +42,10 @@ class RoundaboutHandler : public IntersectionHandler
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const CompressedEdgeContainer &compressed_edge_container,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator);
~RoundaboutHandler() override final = default;
@@ -66,6 +64,10 @@ class RoundaboutHandler : public IntersectionHandler
const EdgeID via_eid,
const Intersection &intersection) const;
void invalidateExitAgainstDirection(const NodeID from_nid,
const EdgeID via_eid,
Intersection &intersection) const;
// decide whether we lookk at a roundabout or a rotary
RoundaboutType getRoundaboutType(const NodeID nid) const;
@@ -82,6 +84,7 @@ class RoundaboutHandler : public IntersectionHandler
bool
qualifiesAsRoundaboutIntersection(const std::unordered_set<NodeID> &roundabout_nodes) const;
const CompressedEdgeContainer &compressed_edge_container;
const CoordinateExtractor coordinate_extractor;
};
@@ -1,27 +0,0 @@
#include "util/typedefs.hpp"
#include <unordered_set>
namespace osrm
{
namespace util
{
class NameTable;
}
namespace extractor
{
class NodeBasedGraphFactory;
namespace guidance
{
// Find all "segregated" edges, e.g. edges that can be skipped in turn instructions.
// The main cases are:
// - middle edges between two osm ways in one logic road (U-turn)
// - staggered intersections (X-cross)
// - square/circle intersections
std::unordered_set<EdgeID> findSegregatedNodes(const NodeBasedGraphFactory &factory,
const util::NameTable &names);
}
}
}
@@ -2,8 +2,8 @@
#define OSRM_EXTRACTOR_GUIDANCE_SLIPROAD_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/is_through_street.hpp"
#include "extractor/query_node.hpp"
#include "util/name_table.hpp"
@@ -24,13 +24,10 @@ namespace guidance
class SliproadHandler final : public IntersectionHandler
{
public:
SliproadHandler(const util::NodeBasedDynamicGraph &node_based_graph,
SliproadHandler(const IntersectionGenerator &intersection_generator,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
@@ -54,6 +51,9 @@ class SliproadHandler final : public IntersectionHandler
// Next intersection from `start` onto `onto` is too far away for a Siproad scenario
bool nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const;
// Through street: does a road continue with from's name at the intersection
bool isThroughStreet(const EdgeID from, const IntersectionView &intersection) const;
// Does the road from `current` to `next` continue
bool roadContinues(const EdgeID current, const EdgeID next) const;
@@ -78,8 +78,6 @@ class SliproadHandler final : public IntersectionHandler
// The return value is guaranteed to not be larger than `threshold`.
static double scaledThresholdByRoadClass(const double max_threshold,
const RoadClassification &classification);
const CoordinateExtractor coordinate_extractor;
};
} // namespace guidance
@@ -10,8 +10,8 @@
#include <algorithm>
#include <iomanip>
#include <iterator>
#include <map>
#include <mutex>
#include <unordered_map>
#include <cstdint>
@@ -27,24 +27,18 @@ namespace guidance
class StatisticsHandler final : public IntersectionHandler
{
public:
StatisticsHandler(const util::NodeBasedDynamicGraph &node_based_graph,
StatisticsHandler(const IntersectionGenerator &intersection_generator,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
: IntersectionHandler(node_based_graph,
node_data_container,
coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
name_table,
street_name_suffix_table)
street_name_suffix_table,
intersection_generator)
{
}
@@ -61,7 +55,7 @@ class StatisticsHandler final : public IntersectionHandler
for (const auto &kv : type_hist)
if (kv.second > 0)
util::Log() << " " << std::fixed << std::setprecision(2)
util::Log() << std::fixed << std::setprecision(2)
<< internalInstructionTypeToString(kv.first) << ": " << kv.second
<< " (" << (kv.second / static_cast<float>(num_types) * 100.) << "%)";
@@ -69,7 +63,7 @@ class StatisticsHandler final : public IntersectionHandler
for (const auto &kv : modifier_hist)
if (kv.second > 0)
util::Log() << " " << std::fixed << std::setprecision(2)
util::Log() << std::fixed << std::setprecision(2)
<< instructionModifierToString(kv.first) << ": " << kv.second << " ("
<< (kv.second / static_cast<float>(num_modifiers) * 100.) << "%)";
}
@@ -90,14 +84,12 @@ class StatisticsHandler final : public IntersectionHandler
// numbers closer to the handlers and see how often handlers ran.
for (const auto &road : intersection)
{
if (road.entry_allowed)
{
const auto type = road.instruction.type;
const auto modifier = road.instruction.direction_modifier;
type_hist[type] += 1;
modifier_hist[modifier] += 1;
}
const auto type = road.instruction.type;
const auto modifier = road.instruction.direction_modifier;
type_hist[type] += 1;
modifier_hist[modifier] += 1;
}
return intersection;
@@ -105,8 +97,8 @@ class StatisticsHandler final : public IntersectionHandler
private:
mutable std::mutex lock;
mutable std::map<TurnType::Enum, std::uint64_t> type_hist;
mutable std::map<DirectionModifier::Enum, std::uint64_t> modifier_hist;
mutable std::unordered_map<TurnType::Enum, std::uint64_t> type_hist;
mutable std::unordered_map<DirectionModifier::Enum, std::uint64_t> modifier_hist;
};
} // namespace guidance
@@ -3,6 +3,7 @@
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/travel_mode.hpp"
#include "util/node_based_graph.hpp"
@@ -20,13 +21,10 @@ namespace guidance
class SuppressModeHandler final : public IntersectionHandler
{
public:
SuppressModeHandler(const util::NodeBasedDynamicGraph &node_based_graph,
SuppressModeHandler(const IntersectionGenerator &intersection_generator,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
+25 -3
View File
@@ -4,6 +4,9 @@
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/driveway_handler.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/intersection_normalization_operation.hpp"
#include "extractor/guidance/intersection_normalizer.hpp"
#include "extractor/guidance/motorway_handler.hpp"
#include "extractor/guidance/roundabout_handler.hpp"
#include "extractor/guidance/sliproad_handler.hpp"
@@ -40,11 +43,10 @@ class TurnAnalysis
public:
TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const CompressedEdgeContainer &compressed_edge_container,
const std::vector<util::Coordinate> &coordinates,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const CompressedEdgeContainer &compressed_edge_container,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
@@ -54,14 +56,34 @@ class TurnAnalysis
Intersection operator()(const NodeID node_prior_to_intersection,
const EdgeID entering_via_edge) const;
/*
* Returns a normalized intersection without any assigned turn types.
* This intersection can be used as input for intersection classification, turn lane assignment
* and similar.
*/
struct ShapeResult
{
// the basic shape, containing all turns
IntersectionShape intersection_shape;
// normalized shape, merged some roads into others, adjusted bearings
// see intersection_normalizer for further explanations
IntersectionNormalizer::NormalizationResult annotated_normalized_shape;
};
OSRM_ATTR_WARN_UNUSED
ShapeResult ComputeIntersectionShapes(const NodeID node_at_center_of_intersection) const;
// Select turn types based on the intersection shape
OSRM_ATTR_WARN_UNUSED
Intersection AssignTurnTypes(const NodeID from_node,
const EdgeID via_eid,
const IntersectionView &intersection) const;
const IntersectionGenerator &GetIntersectionGenerator() const;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const IntersectionGenerator intersection_generator;
const IntersectionNormalizer intersection_normalizer;
const RoundaboutHandler roundabout_handler;
const MotorwayHandler motorway_handler;
const TurnHandler turn_handler;
+2 -19
View File
@@ -2,27 +2,15 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_DISCOVERY_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/turn_lane_data.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "util/typedefs.hpp"
#include <unordered_set>
namespace osrm
{
namespace util
{
struct Coordinate;
}
namespace extractor
{
class CompressedEdgeContainer;
namespace guidance
{
namespace lanes
{
@@ -33,13 +21,8 @@ bool findPreviousIntersection(
const NodeID node,
const EdgeID via_edge,
const Intersection &intersection,
const IntersectionGenerator &intersection_generator,
const util::NodeBasedDynamicGraph &node_based_graph, // query edge data
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
// output parameters, will be in an arbitrary state on failure
NodeID &result_node,
EdgeID &result_via_edge,
+3 -6
View File
@@ -2,8 +2,8 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/is_through_street.hpp"
#include "extractor/query_node.hpp"
#include "util/attributes.hpp"
@@ -30,12 +30,9 @@ class TurnHandler : public IntersectionHandler
TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator);
~TurnHandler() override final = default;
@@ -77,11 +77,7 @@ struct TurnInstruction
TurnType::Enum type : 5;
DirectionModifier::Enum direction_modifier : 3;
bool IsUTurn() const
{
return type != TurnType::NoTurn && direction_modifier == DirectionModifier::UTurn;
}
// the lane tupel that is used for the turn
static TurnInstruction INVALID() { return {TurnType::Invalid, DirectionModifier::UTurn}; }
@@ -74,11 +74,6 @@ class TurnLaneHandler
TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
LaneDescriptionMap &lane_description_map,
const TurnAnalysis &turn_analysis,
util::guidance::LaneDataIdMap &id_map);
@@ -95,12 +90,6 @@ class TurnLaneHandler
// lanes for a turn
const util::NodeBasedDynamicGraph &node_based_graph;
const EdgeBasedNodeDataContainer &node_data_container;
const std::vector<util::Coordinate> &node_coordinates;
const extractor::CompressedEdgeContainer &compressed_geometries;
const RestrictionMap &node_restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const guidance::TurnLanesIndexedArray &turn_lanes_data;
std::vector<std::uint32_t> turn_lane_offsets;
std::vector<TurnLaneType::Mask> turn_lane_masks;
LaneDescriptionMap &lane_description_map;
@@ -100,10 +100,8 @@ typedef util::ConcurrentIDMap<guidance::TurnLaneDescription,
guidance::TurnLaneDescription_hash>
LaneDescriptionMap;
using TurnLanesIndexedArray =
std::tuple<std::vector<std::uint32_t>, std::vector<TurnLaneType::Mask>>;
inline TurnLanesIndexedArray transformTurnLaneMapIntoArrays(const LaneDescriptionMap &turn_lane_map)
inline std::tuple<std::vector<std::uint32_t>, std::vector<TurnLaneType::Mask>>
transformTurnLaneMapIntoArrays(const LaneDescriptionMap &turn_lane_map)
{
// could use some additional capacity? To avoid a copy during processing, though small data so
// probably not that important.
@@ -113,7 +111,8 @@ inline TurnLanesIndexedArray transformTurnLaneMapIntoArrays(const LaneDescriptio
//
// turn lane offsets points into the locations of the turn_lane_masks array. We use a standard
// adjacency array like structure to store the turn lane masks.
std::vector<std::uint32_t> turn_lane_offsets(turn_lane_map.data.size() + 1); // + sentinel
std::vector<std::uint32_t> turn_lane_offsets(turn_lane_map.data.size() +
2); // empty ID + sentinel
for (auto entry = turn_lane_map.data.begin(); entry != turn_lane_map.data.end(); ++entry)
turn_lane_offsets[entry->second + 1] = entry->first.size();
@@ -126,7 +125,6 @@ inline TurnLanesIndexedArray transformTurnLaneMapIntoArrays(const LaneDescriptio
std::copy(entry->first.begin(),
entry->first.end(),
turn_lane_masks.begin() + turn_lane_offsets[entry->second]);
return std::make_tuple(std::move(turn_lane_offsets), std::move(turn_lane_masks));
}
@@ -1,87 +0,0 @@
#ifndef OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_ANALYSIS_HPP
#define OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_ANALYSIS_HPP
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/mergable_road_detector.hpp"
#include "extractor/guidance/turn_lane_types.hpp"
#include "extractor/intersection/intersection_edge.hpp"
#include "extractor/restriction_index.hpp"
#include "util/coordinate.hpp"
#include "util/node_based_graph.hpp"
#include <unordered_set>
#include <vector>
namespace osrm
{
namespace extractor
{
namespace intersection
{
IntersectionEdges getIncomingEdges(const util::NodeBasedDynamicGraph &graph,
const NodeID intersection);
IntersectionEdges getOutgoingEdges(const util::NodeBasedDynamicGraph &graph,
const NodeID intersection);
bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph,
const EdgeBasedNodeDataContainer &node_data_container,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const IntersectionEdgeGeometries &geometries,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const IntersectionEdge &from,
const IntersectionEdge &to);
double findEdgeBearing(const IntersectionEdgeGeometries &geometries, const EdgeID &edge);
double findEdgeLength(const IntersectionEdgeGeometries &geometries, const EdgeID &edge);
std::pair<IntersectionEdgeGeometries, std::unordered_set<EdgeID>>
getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
const extractor::CompressedEdgeContainer &compressed_geometries,
const std::vector<util::Coordinate> &node_coordinates,
const guidance::MergableRoadDetector &detector,
const NodeID intersection);
guidance::IntersectionView
convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
const EdgeBasedNodeDataContainer &node_data_container,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const IntersectionEdgeGeometries &edge_geometries,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const IntersectionEdge &incoming_edge,
const IntersectionEdges &outgoing_edges,
const std::unordered_set<EdgeID> &merged_edges);
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
// the node reached from `incoming_edge`. The resulting candidates have to be analyzed
// for their actual instructions later on.
template <bool USE_CLOSE_COORDINATE>
guidance::IntersectionView
getConnectedRoads(const util::NodeBasedDynamicGraph &graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const IntersectionEdge &incoming_edge);
// Graph Compression cannot compress every setting. For example any barrier/traffic light cannot
// be compressed. As a result, a simple road of the form `a ----- b` might end up as having an
// intermediate intersection, if there is a traffic light in between. If we want to look farther
// down a road, finding the next actual decision requires the look at multiple intersections.
// Here we follow the road until we either reach a dead end or find the next intersection with
// more than a single next road. This function skips over degree two nodes to find correct input
// for getConnectedRoads.
IntersectionEdge skipDegreeTwoNodes(const util::NodeBasedDynamicGraph &graph,
IntersectionEdge road);
}
}
}
#endif
@@ -1,44 +0,0 @@
#ifndef OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_EDGE_HPP
#define OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_EDGE_HPP
#include "util/typedefs.hpp"
#include <vector>
namespace osrm
{
namespace extractor
{
namespace intersection
{
// IntersectionEdge is an alias for incoming and outgoing node-based graph edges of an intersection
struct IntersectionEdge
{
NodeID node;
EdgeID edge;
bool operator<(const IntersectionEdge &other) const
{
return std::tie(node, edge) < std::tie(other.node, other.edge);
}
};
using IntersectionEdges = std::vector<IntersectionEdge>;
struct IntersectionEdgeGeometry
{
EdgeID edge;
double initial_bearing;
double perceived_bearing;
double length;
bool operator<(const IntersectionEdgeGeometry &other) const { return edge < other.edge; }
};
using IntersectionEdgeGeometries = std::vector<IntersectionEdgeGeometry>;
}
}
}
#endif
@@ -41,13 +41,9 @@ class NodeBasedGraphFactory
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
auto const &GetGraph() const { return compressed_output_graph; }
auto const &GetGraph() { return compressed_output_graph; }
auto const &GetBarriers() const { return barriers; }
auto const &GetTrafficSignals() const { return traffic_signals; }
auto const &GetCompressedEdges() const { return compressed_edge_container; }
auto const &GetCoordinates() const { return coordinates; }
auto const &GetAnnotationData() const { return annotation_data; }
auto const &GetOsmNodes() const { return osm_node_ids; }
auto &GetCompressedEdges() { return compressed_edge_container; }
auto &GetCoordinates() { return coordinates; }
auto &GetAnnotationData() { return annotation_data; }
@@ -10,6 +10,8 @@
#include <boost/optional/optional.hpp>
#include <tbb/concurrent_vector.h>
#include <string>
#include <vector>
+1 -60
View File
@@ -186,8 +186,6 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
params->Get(Nan::New("max_locations_map_matching").ToLocalChecked());
auto max_results_nearest = params->Get(Nan::New("max_results_nearest").ToLocalChecked());
auto max_alternatives = params->Get(Nan::New("max_alternatives").ToLocalChecked());
auto max_radius_map_matching =
params->Get(Nan::New("max_radius_map_matching").ToLocalChecked());
if (!max_locations_trip->IsUndefined() && !max_locations_trip->IsNumber())
{
@@ -235,9 +233,6 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
engine_config->max_results_nearest = static_cast<int>(max_results_nearest->NumberValue());
if (max_alternatives->IsNumber())
engine_config->max_alternatives = static_cast<int>(max_alternatives->NumberValue());
if (max_radius_map_matching->IsNumber())
engine_config->max_radius_map_matching =
static_cast<double>(max_radius_map_matching->NumberValue());
return engine_config;
}
@@ -1171,7 +1166,7 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
Nan::ThrowError("Timestamps array items must be numbers");
return match_parameters_ptr();
}
params->timestamps.emplace_back(static_cast<std::size_t>(timestamp->NumberValue()));
params->timestamps.emplace_back(static_cast<unsigned>(timestamp->NumberValue()));
}
}
@@ -1220,60 +1215,6 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
params->tidy = tidy->BooleanValue();
}
if (obj->Has(Nan::New("waypoints").ToLocalChecked()))
{
v8::Local<v8::Value> waypoints = obj->Get(Nan::New("waypoints").ToLocalChecked());
if (waypoints.IsEmpty())
return match_parameters_ptr();
// must be array
if (!waypoints->IsArray())
{
Nan::ThrowError(
"Waypoints must be an array of integers corresponding to the input coordinates.");
return match_parameters_ptr();
}
auto waypoints_array = v8::Local<v8::Array>::Cast(waypoints);
// must have at least two elements
if (waypoints_array->Length() < 2)
{
Nan::ThrowError("At least two waypoints must be provided");
return match_parameters_ptr();
}
auto coords_size = params->coordinates.size();
auto waypoints_array_size = waypoints_array->Length();
const auto first_index = Nan::To<std::uint32_t>(waypoints_array->Get(0)).FromJust();
const auto last_index =
Nan::To<std::uint32_t>(waypoints_array->Get(waypoints_array_size - 1)).FromJust();
if (first_index != 0 || last_index != coords_size - 1)
{
Nan::ThrowError("First and last waypoints values must correspond to first and last "
"coordinate indices");
return match_parameters_ptr();
}
for (uint32_t i = 0; i < waypoints_array_size; ++i)
{
v8::Local<v8::Value> waypoint_value = waypoints_array->Get(i);
// all elements must be numbers
if (!waypoint_value->IsNumber())
{
Nan::ThrowError("Waypoint values must be an array of integers");
return match_parameters_ptr();
}
// check that the waypoint index corresponds with an inpute coordinate
const auto index = Nan::To<std::uint32_t>(waypoint_value).FromJust();
if (index >= coords_size)
{
Nan::ThrowError("Waypoints must correspond with the index of an input coordinate");
return match_parameters_ptr();
}
params->waypoints.emplace_back(static_cast<unsigned>(waypoint_value->NumberValue()));
}
}
bool parsedSuccessfully = parseCommonParameters(obj, params);
if (!parsedSuccessfully)
{
-1
View File
@@ -16,7 +16,6 @@
#include <boost/iterator/iterator_facade.hpp>
#include <boost/range/iterator_range.hpp>
#include <tbb/parallel_sort.h>
#include <algorithm>
@@ -10,9 +10,8 @@
#include "util/dynamic_graph.hpp"
#include "util/typedefs.hpp"
#include <tbb/blocked_range.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_reduce.h>
#include <tbb/parallel_sort.h>
#include <cstdint>
@@ -28,31 +28,17 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
MatchParametersGrammar() : BaseGrammar(root_rule)
{
#ifdef BOOST_HAS_LONG_LONG
if (std::is_same<std::size_t, unsigned long long>::value)
size_t_ = qi::ulong_long;
else
size_t_ = qi::ulong_;
#else
size_t_ = qi::ulong_;
#endif
timestamps_rule =
qi::lit("timestamps=") >
(qi::uint_ %
';')[ph::bind(&engine::api::MatchParameters::timestamps, qi::_r1) = qi::_1];
waypoints_rule =
qi::lit("waypoints=") >
(size_t_ % ';')[ph::bind(&engine::api::MatchParameters::waypoints, qi::_r1) = qi::_1];
gaps_type.add("split", engine::api::MatchParameters::GapsType::Split)(
"ignore", engine::api::MatchParameters::GapsType::Ignore);
root_rule =
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) |
waypoints_rule(qi::_r1) |
(qi::lit("gaps=") >
gaps_type[ph::bind(&engine::api::MatchParameters::gaps, qi::_r1) = qi::_1]) |
(qi::lit("tidy=") >
@@ -63,8 +49,6 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
private:
qi::rule<Iterator, Signature> root_rule;
qi::rule<Iterator, Signature> timestamps_rule;
qi::rule<Iterator, Signature> waypoints_rule;
qi::rule<Iterator, std::size_t()> size_t_;
qi::symbols<char, engine::api::MatchParameters::GapsType> gaps_type;
};
+25 -1
View File
@@ -48,6 +48,14 @@ const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA",
"HSGR_CHECKSUM",
"TIMESTAMP",
"FILE_INDEX_PATH",
"CH_CORE_MARKER_0",
"CH_CORE_MARKER_1",
"CH_CORE_MARKER_2",
"CH_CORE_MARKER_3",
"CH_CORE_MARKER_4",
"CH_CORE_MARKER_5",
"CH_CORE_MARKER_6",
"CH_CORE_MARKER_7",
"DATASOURCES_NAMES",
"PROPERTIES",
"BEARING_CLASSID",
@@ -124,6 +132,14 @@ struct DataLayout
HSGR_CHECKSUM,
TIMESTAMP,
FILE_INDEX_PATH,
CH_CORE_MARKER_0,
CH_CORE_MARKER_1,
CH_CORE_MARKER_2,
CH_CORE_MARKER_3,
CH_CORE_MARKER_4,
CH_CORE_MARKER_5,
CH_CORE_MARKER_6,
CH_CORE_MARKER_7,
DATASOURCES_NAMES,
PROPERTIES,
BEARING_CLASSID,
@@ -184,7 +200,15 @@ struct DataLayout
inline uint64_t GetBlockEntries(BlockID bid) const { return num_entries[bid]; }
inline uint64_t GetBlockSize(BlockID bid) const { return num_entries[bid] * entry_size[bid]; }
inline uint64_t GetBlockSize(BlockID bid) const
{
// special bit encoding
if (bid >= CH_CORE_MARKER_0 && bid <= CH_CORE_MARKER_7)
{
return (num_entries[bid] / 32 + 1) * entry_size[bid];
}
return num_entries[bid] * entry_size[bid];
}
inline uint64_t GetSizeOfLayout() const
{
+1
View File
@@ -64,6 +64,7 @@ struct StorageConfig final : IOConfig
{".osrm.hsgr",
".osrm.nbg_nodes",
".osrm.ebg_nodes",
".osrm.core",
".osrm.cells",
".osrm.cell_metrics",
".osrm.mldgr",
+12
View File
@@ -144,6 +144,18 @@ inline double restrictAngleToValidRange(const double angle)
return angle;
}
// finds the angle between two angles, based on the minum difference between the two
inline double angleBetween(const double lhs, const double rhs)
{
const auto difference = std::abs(lhs - rhs);
const auto is_clockwise_difference = difference <= 180;
const auto angle_between_candidate = .5 * (lhs + rhs);
if (is_clockwise_difference)
return angle_between_candidate;
else
return restrictAngleToValidRange(angle_between_candidate + 180);
}
} // namespace util
} // namespace osrm
+3 -8
View File
@@ -115,7 +115,7 @@ template <typename EdgeDataT> class DynamicGraph
number_of_nodes = nodes;
number_of_edges = static_cast<EdgeIterator>(graph.size());
node_array.resize(number_of_nodes);
node_array.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
for (const auto node : irange(0u, number_of_nodes))
@@ -129,6 +129,7 @@ template <typename EdgeDataT> class DynamicGraph
node_array[node].edges = edge - last_edge;
position += node_array[node].edges;
}
node_array.back().first_edge = position;
edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
edge_list.resize(position);
edge = 0;
@@ -143,8 +144,6 @@ template <typename EdgeDataT> class DynamicGraph
++edge;
}
}
BOOST_ASSERT(node_array.size() == number_of_nodes);
}
// Copy&move for the same data
@@ -192,8 +191,6 @@ template <typename EdgeDataT> class DynamicGraph
// Removes all edges to and from nodes for which filter(node_id) returns false
template <typename Pred> auto Filter(Pred filter) const &
{
BOOST_ASSERT(node_array.size() == number_of_nodes);
DynamicGraph other;
other.number_of_nodes = number_of_nodes;
@@ -205,8 +202,6 @@ template <typename EdgeDataT> class DynamicGraph
std::transform(
node_array.begin(), node_array.end(), other.node_array.begin(), [&](const Node &node) {
const EdgeIterator first_edge = other.edge_list.size();
BOOST_ASSERT(node_id < number_of_nodes);
if (filter(node_id++))
{
std::copy_if(edge_list.begin() + node.first_edge,
@@ -421,7 +416,7 @@ template <typename EdgeDataT> class DynamicGraph
void Renumber(const std::vector<NodeID> &old_to_new_node)
{
// permutate everything but the sentinel
util::inplacePermutation(node_array.begin(), node_array.end(), old_to_new_node);
util::inplacePermutation(node_array.begin(), std::prev(node_array.end()), old_to_new_node);
// Build up edge permutation
auto new_edge_index = 0;
+63 -38
View File
@@ -26,8 +26,7 @@ namespace guidance
// Name Change Logic
// Used both during Extraction as well as during Post-Processing
inline util::StringView longest_common_substring(const util::StringView &lhs,
const util::StringView &rhs)
inline std::string longest_common_substring(const std::string &lhs, const std::string &rhs)
{
if (lhs.empty() || rhs.empty())
return "";
@@ -61,15 +60,15 @@ inline util::StringView longest_common_substring(const util::StringView &lhs,
// TODO US-ASCII support only, no UTF-8 support
// While UTF-8 might work in some cases, we do not guarantee full functionality
template <typename StringView> inline auto decompose(const StringView &lhs, const StringView &rhs)
inline auto decompose(const std::string &lhs, const std::string &rhs)
{
auto const lcs = longest_common_substring(lhs, rhs);
// trim spaces, transform to lower
const auto trim = [](StringView view) {
const auto trim = [](auto str) {
// we compare suffixes based on this value, it might break UTF chars, but as long as we are
// consistent in handling, we do not create bad results
std::string str = boost::to_lower_copy(view.to_string());
boost::to_lower(str);
auto front = str.find_first_not_of(" ");
if (front == std::string::npos)
@@ -81,7 +80,8 @@ template <typename StringView> inline auto decompose(const StringView &lhs, cons
if (lcs.empty())
{
return std::make_tuple(trim(lhs), trim(rhs), std::string(), std::string());
std::string empty = "";
return std::make_tuple(trim(lhs), trim(rhs), empty, empty);
}
// find the common substring in both
@@ -92,27 +92,32 @@ template <typename StringView> inline auto decompose(const StringView &lhs, cons
BOOST_ASSERT(rhs_pos + lcs.size() <= rhs.size());
// prefixes
auto lhs_prefix = (lhs_pos > 0) ? lhs.substr(0, lhs_pos) : StringView();
auto rhs_prefix = (rhs_pos > 0) ? rhs.substr(0, rhs_pos) : StringView();
std::string lhs_prefix = (lhs_pos > 0) ? lhs.substr(0, lhs_pos) : "";
std::string rhs_prefix = (rhs_pos > 0) ? rhs.substr(0, rhs_pos) : "";
// suffices
auto lhs_suffix = lhs.substr(lhs_pos + lcs.size());
auto rhs_suffix = rhs.substr(rhs_pos + lcs.size());
std::string lhs_suffix = lhs.substr(lhs_pos + lcs.size());
std::string rhs_suffix = rhs.substr(rhs_pos + lcs.size());
return std::make_tuple(trim(lhs_prefix), trim(lhs_suffix), trim(rhs_prefix), trim(rhs_suffix));
lhs_prefix = trim(std::move(lhs_prefix));
lhs_suffix = trim(std::move(lhs_suffix));
rhs_prefix = trim(std::move(rhs_prefix));
rhs_suffix = trim(std::move(rhs_suffix));
return std::make_tuple(lhs_prefix, lhs_suffix, rhs_prefix, rhs_suffix);
}
// Note: there is an overload without suffix checking below.
// (that's the reason we template the suffix table here)
template <typename StringView, typename SuffixTable>
inline bool requiresNameAnnounced(const StringView &from_name,
const StringView &from_ref,
const StringView &from_pronunciation,
const StringView &from_exits,
const StringView &to_name,
const StringView &to_ref,
const StringView &to_pronunciation,
const StringView &to_exits,
template <typename SuffixTable>
inline bool requiresNameAnnounced(const std::string &from_name,
const std::string &from_ref,
const std::string &from_pronunciation,
const std::string &from_exits,
const std::string &to_name,
const std::string &to_ref,
const std::string &to_pronunciation,
const std::string &to_exits,
const SuffixTable &suffix_table)
{
// first is empty and the second is not
@@ -129,7 +134,7 @@ inline bool requiresNameAnnounced(const StringView &from_name,
boost::starts_with(from_name, to_name) || boost::starts_with(to_name, from_name);
const auto checkForPrefixOrSuffixChange =
[](const StringView &first, const StringView &second, const SuffixTable &suffix_table) {
[](const std::string &first, const std::string &second, const SuffixTable &suffix_table) {
std::string first_prefix, first_suffix, second_prefix, second_suffix;
std::tie(first_prefix, first_suffix, second_prefix, second_suffix) =
decompose(first, second);
@@ -198,17 +203,17 @@ inline bool requiresNameAnnounced(const std::string &from_name,
struct NopSuffixTable final
{
NopSuffixTable() {}
bool isSuffix(const StringView &) const { return false; }
bool isSuffix(const std::string &) const { return false; }
} static const table;
return requiresNameAnnounced(util::StringView(from_name),
util::StringView(from_ref),
util::StringView(from_pronunciation),
util::StringView(from_exits),
util::StringView(to_name),
util::StringView(to_ref),
util::StringView(to_pronunciation),
util::StringView(to_exits),
return requiresNameAnnounced(from_name,
from_ref,
from_pronunciation,
from_exits,
to_name,
to_ref,
to_pronunciation,
to_exits,
table);
}
@@ -220,17 +225,37 @@ inline bool requiresNameAnnounced(const NameID from_name_id,
if (from_name_id == to_name_id)
return false;
else
return requiresNameAnnounced(name_table.GetNameForID(from_name_id),
name_table.GetRefForID(from_name_id),
name_table.GetPronunciationForID(from_name_id),
name_table.GetExitsForID(from_name_id),
return requiresNameAnnounced(name_table.GetNameForID(from_name_id).to_string(),
name_table.GetRefForID(from_name_id).to_string(),
name_table.GetPronunciationForID(from_name_id).to_string(),
name_table.GetExitsForID(from_name_id).to_string(),
//
name_table.GetNameForID(to_name_id),
name_table.GetRefForID(to_name_id),
name_table.GetPronunciationForID(to_name_id),
name_table.GetExitsForID(to_name_id),
name_table.GetNameForID(to_name_id).to_string(),
name_table.GetRefForID(to_name_id).to_string(),
name_table.GetPronunciationForID(to_name_id).to_string(),
name_table.GetExitsForID(to_name_id).to_string(),
//
suffix_table);
// FIXME: converts StringViews to strings since the name change heuristics mutates in place
}
inline bool requiresNameAnnounced(const NameID from_name_id,
const NameID to_name_id,
const util::NameTable &name_table)
{
if (from_name_id == to_name_id)
return false;
else
return requiresNameAnnounced(name_table.GetNameForID(from_name_id).to_string(),
name_table.GetRefForID(from_name_id).to_string(),
name_table.GetPronunciationForID(from_name_id).to_string(),
name_table.GetExitsForID(from_name_id).to_string(),
//
name_table.GetNameForID(to_name_id).to_string(),
name_table.GetRefForID(to_name_id).to_string(),
name_table.GetExitsForID(to_name_id).to_string(),
name_table.GetPronunciationForID(to_name_id).to_string());
// FIXME: converts StringViews to strings since the name change heuristics mutates in place
}
} // namespace guidance
-1
View File
@@ -10,7 +10,6 @@
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <tbb/atomic.h>
#include <array>
-1
View File
@@ -23,7 +23,6 @@
#include <boost/format.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <tbb/blocked_range.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_sort.h>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "osrm",
"version": "5.15.2",
"version": "5.14.0",
"private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": {
+2 -10
View File
@@ -37,10 +37,6 @@ function setup()
turn_bias = 1.075,
cardinal_directions = false,
-- Size of the vehicle, to be limited by physical restriction of the way
vehicle_height = 2.5, -- in metters, 2.5m is the height of van
vehicle_width = 1.9, -- in metters, ways with narrow tag are considered narrower than 2.2m
-- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other
suffix_list = {
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea'
@@ -104,7 +100,7 @@ function setup()
},
classes = Sequence {
'toll', 'motorway', 'ferry', 'restricted', 'tunnel'
'toll', 'motorway', 'ferry', 'restricted'
},
-- classes to support for exclude flags
@@ -257,8 +253,6 @@ function setup()
["at:rural"] = 100,
["at:trunk"] = 100,
["be:motorway"] = 120,
["by:urban"] = 60,
["by:motorway"] = 110,
["ch:rural"] = 80,
["ch:trunk"] = 100,
["ch:motorway"] = 120,
@@ -282,6 +276,7 @@ function setup()
["ru:living_street"] = 20,
["ru:urban"] = 60,
["ru:motorway"] = 110,
["ua:urban"] = 60,
["uk:nsl_single"] = (60*1609)/1000,
["uk:nsl_dual"] = (70*1609)/1000,
["uk:motorway"] = (70*1609)/1000,
@@ -361,9 +356,6 @@ function process_way(profile, way, result, relations)
-- routable. this includes things like status=impassable,
-- toll=yes and oneway=reversible
WayHandlers.blocked_ways,
WayHandlers.avoid_ways,
WayHandlers.handle_height,
WayHandlers.handle_width,
-- determine access status by checking our hierarchy of
-- access tags, e.g: motorcar, motor_vehicle, vehicle
-81
View File
@@ -1,81 +0,0 @@
local Sequence = require('lib/sequence')
Measure = {}
-- measurements conversion constants
local inch_to_meters = 0.0254
local feet_to_inches = 12
--- Parse string as a height in meters.
--- according to http://wiki.openstreetmap.org/wiki/Key:maxheight
function Measure.parse_value_meters(value)
local n = tonumber(value:gsub(",", "."):match("%d+%.?%d*"))
if n then
inches = value:match("'.*")
if inches then -- Imperial unit to metric
-- try to parse feets/inch
n = n * feet_to_inches
local m = tonumber(inches:match("%d+"))
if m then
n = n + m
end
n = n * inch_to_meters
end
return n
end
end
--- according to http://wiki.openstreetmap.org/wiki/Map_Features/Units#Explicit_specifications
local tonns_parse_patterns = Sequence {
"%d+",
"%d+.%d+",
"%d+.%d+ ?t"
}
local kg_parse_patterns = Sequence {
"%d+ ?kg"
}
--- Parse weight value in kilograms
function Measure.parse_value_kilograms(value)
-- try to parse kilograms
for i, templ in ipairs(kg_parse_patterns) do
m = string.match(value, templ)
if m then
return tonumber(m)
end
end
-- try to parse tonns
for i, templ in ipairs(tonns_parse_patterns) do
m = string.match(value, templ)
if m then
return tonumber(m) * 1000
end
end
end
--- Get maxheight of specified way in meters. If there are no
--- max height, then return nil
function Measure.get_max_height(raw_value)
if raw_value then
return Measure.parse_value_meters(raw_value)
end
end
--- Get maxwidth of specified way in meters.
function Measure.get_max_width(raw_value)
if raw_value then
return Measure.parse_value_meters(raw_value)
end
end
--- Get maxweight of specified way in kilogramms
function Measure.get_max_weight(raw_value)
if raw_value then
return Measure.parse_value_kilograms(raw_value)
end
end
return Measure;
-57
View File
@@ -8,7 +8,6 @@ local get_turn_lanes = require("lib/guidance").get_turn_lanes
local set_classification = require("lib/guidance").set_classification
local get_destination = require("lib/destination").get_destination
local Tags = require('lib/tags')
local Measure = require("lib/measure")
WayHandlers = {}
@@ -283,12 +282,6 @@ end
function WayHandlers.classes(profile,way,result,data)
local forward_toll, backward_toll = Tags.get_forward_backward_by_key(way, data, "toll")
local forward_route, backward_route = Tags.get_forward_backward_by_key(way, data, "route")
local tunnel = way:get_value_by_key("tunnel")
if tunnel and tunnel ~= "no" then
result.forward_classes["tunnel"] = true
result.backward_classes["tunnel"] = true
end
if forward_toll == "yes" then
result.forward_classes["toll"] = true
@@ -436,47 +429,6 @@ function WayHandlers.parse_maxspeed(source,profile)
return n
end
-- handle maxheight tags
function WayHandlers.handle_height(profile,way,result,data)
local keys = Sequence { 'maxheight:physical', 'maxheight' }
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
forward = Measure.get_max_height(forward)
backward = Measure.get_max_height(backward)
if forward and forward < profile.vehicle_height then
result.forward_mode = mode.inaccessible
end
if backward and backward < profile.vehicle_height then
result.backward_mode = mode.inaccessible
end
end
-- handle maxwidth tags
function WayHandlers.handle_width(profile,way,result,data)
local keys = Sequence { 'maxwidth:physical', 'maxwidth', 'width', 'est_width' }
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
local narrow = way:get_value_by_key('narrow')
if ((forward and forward == 'narrow') or (narrow and narrow == 'yes')) and profile.vehicle_width > 2.2 then
result.forward_mode = mode.inaccessible
elseif forward then
forward = Measure.get_max_width(forward)
if forward and forward <= profile.vehicle_width then
result.forward_mode = mode.inaccessible
end
end
if ((backward and backward == 'narrow') or (narrow and narrow == 'yes')) and profile.vehicle_width > 2.2 then
result.backward_mode = mode.inaccessible
elseif backward then
backward = Measure.get_max_width(backward)
if backward and backward <= profile.vehicle_width then
result.backward_mode = mode.inaccessible
end
end
end
-- handle oneways tags
function WayHandlers.oneway(profile,way,result,data)
if not profile.oneway_handling then
@@ -538,15 +490,6 @@ function WayHandlers.weights(profile,way,result,data)
end
end
-- handle general avoid rules
function WayHandlers.avoid_ways(profile,way,result,data)
if profile.avoid[data.highway] then
return false
end
end
-- handle various that can block access
function WayHandlers.blocked_ways(profile,way,result,data)
+2 -2
View File
@@ -71,10 +71,10 @@ def build_pretty_printer():
pp.add_printer('TurnLaneData', '::TurnLaneData$', TurnLaneDataPrinter)
return pp
## unregister OSRM pretty printer before (re)loading
gdb.pretty_printers = [x for x in gdb.pretty_printers if not isinstance(x, gdb.printing.RegexpCollectionPrettyPrinter) or x.name != 'OSRM']
gdb.pretty_printers = [x for x in gdb.pretty_printers if x.name != 'OSRM'] # unregister OSRM pretty printer before (re)loading
gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())
import geojson
import os
import time
+1 -2
View File
@@ -12,7 +12,6 @@
#include <boost/assert.hpp>
#include <tbb/blocked_range.h>
#include <tbb/enumerable_thread_specific.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_invoke.h>
@@ -385,7 +384,7 @@ void RenumberData(std::vector<RemainingNodeData> &remaining_nodes,
// we need to make a copy here because we are going to modify it
auto to_orig = new_to_old_node_id;
auto new_node_id = 0u;
auto new_node_id = 0;
// All remaining nodes get the low IDs
for (auto &remaining : remaining_nodes)
+1 -2
View File
@@ -11,13 +11,12 @@ bool EngineConfig::IsValid() const
// leads to an empty path
const bool all_path_are_empty = storage_config.GetPath("").empty();
const auto unlimited_or_more_than = [](const auto v, const auto limit) {
const auto unlimited_or_more_than = [](const int v, const int limit) {
return v == -1 || v > limit;
};
const bool limits_valid = unlimited_or_more_than(max_locations_distance_table, 2) &&
unlimited_or_more_than(max_locations_map_matching, 2) &&
unlimited_or_more_than(max_radius_map_matching, 0) &&
unlimited_or_more_than(max_locations_trip, 2) &&
unlimited_or_more_than(max_locations_viaroute, 2) &&
unlimited_or_more_than(max_results_nearest, 0) &&
@@ -41,14 +41,15 @@ bool noIntermediaryIntersections(const RouteStep &step)
}
// Link roads, as far as we are concerned, are short unnamed segments between to named segments.
bool isLinkRoad(const RouteStep &pre_link_step,
bool isLinkroad(const RouteStep &pre_link_step,
const RouteStep &link_step,
const RouteStep &post_link_step)
{
const constexpr double MAX_LINK_ROAD_LENGTH = 2 * MAX_COLLAPSE_DISTANCE;
const auto is_short = link_step.distance <= MAX_LINK_ROAD_LENGTH;
const auto unnamed = link_step.name.empty();
const auto between_named = !pre_link_step.name.empty() && !post_link_step.name.empty();
const auto unnamed = link_step.name_id == EMPTY_NAMEID;
const auto between_named =
(pre_link_step.name_id != EMPTY_NAMEID) && (post_link_step.name_id != EMPTY_NAMEID);
return is_short && unnamed && between_named && noIntermediaryIntersections(link_step);
}
@@ -195,7 +196,7 @@ bool isUTurn(const RouteStepIterator step_prior_to_intersection,
const auto only_allowed_turn = (numberOfAllowedTurns(*step_leaving_intersection) == 1) &&
noIntermediaryIntersections(*step_entering_intersection);
return collapsable || isLinkRoad(*step_prior_to_intersection,
return collapsable || isLinkroad(*step_prior_to_intersection,
*step_entering_intersection,
*step_leaving_intersection) ||
only_allowed_turn;
+3 -72
View File
@@ -17,7 +17,6 @@
#include <functional>
#include <iterator>
#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -140,17 +139,6 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("InvalidValue", "Invalid coordinate value.", json_result);
}
if (max_radius_map_matching > 0 && std::any_of(parameters.radiuses.begin(),
parameters.radiuses.end(),
[&](const auto &radius) {
if (!radius)
return false;
return *radius > max_radius_map_matching;
}))
{
return Error("TooBig", "Radius search size is too large for map matching.", json_result);
}
// Check for same or increasing timestamps. Impl. note: Incontrast to `sort(first,
// last, less_equal)` checking `greater` in reverse meets irreflexive requirements.
const auto time_increases_monotonically = std::is_sorted(
@@ -175,16 +163,6 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
tidied = api::tidy::keep_all(parameters);
}
// Error: first and last points should be waypoints
if (!parameters.waypoints.empty() &&
(tidied.parameters.waypoints[0] != 0 ||
tidied.parameters.waypoints.back() != (tidied.parameters.coordinates.size() - 1)))
{
return Error("InvalidValue",
"First and last coordinates must be specified as waypoints.",
json_result);
}
// assuming radius is the standard deviation of a normal distribution
// that models GPS noise (in this model), x3 should give us the correct
// search radius with > 99% confidence
@@ -240,34 +218,6 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("NoMatch", "Could not match the trace.", json_result);
}
// trace was split, we don't support the waypoints parameter across multiple match objects
if (sub_matchings.size() > 1 && !parameters.waypoints.empty())
{
return Error("NoMatch", "Could not match the trace with the given waypoints.", json_result);
}
// Error: Check if user-supplied waypoints can be found in the resulting matches
if (!parameters.waypoints.empty())
{
std::set<std::size_t> tidied_waypoints(tidied.parameters.waypoints.begin(),
tidied.parameters.waypoints.end());
for (const auto &sm : sub_matchings)
{
std::for_each(sm.indices.begin(),
sm.indices.end(),
[&tidied_waypoints](const auto index) { tidied_waypoints.erase(index); });
}
if (!tidied_waypoints.empty())
{
return Error(
"NoMatch", "Requested waypoint parameter could not be matched.", json_result);
}
}
// we haven't errored yet, only allow leg collapsing if it was originally requested
BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1);
const auto collapse_legs = !parameters.waypoints.empty();
// each sub_route will correspond to a MatchObject
std::vector<InternalRouteResult> sub_routes(sub_matchings.size());
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
{
@@ -284,31 +234,12 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
}
// force uturns to be on
// we split the phantom nodes anyway and only have bi-directional phantom nodes for
// possible uturns
// force uturns to be on, since we split the phantom nodes anyway and only have
// bi-directional
// phantom nodes for possible uturns
sub_routes[index] =
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
if (collapse_legs)
{
std::vector<bool> waypoint_legs;
waypoint_legs.reserve(sub_matchings[index].indices.size());
for (unsigned i = 0, j = 0; i < sub_matchings[index].indices.size(); ++i)
{
auto current_wp = tidied.parameters.waypoints[j];
if (current_wp == sub_matchings[index].indices[i])
{
waypoint_legs.push_back(true);
++j;
}
else
{
waypoint_legs.push_back(false);
}
}
sub_routes[index] = CollapseInternalRouteResult(sub_routes[index], waypoint_legs);
}
}
api::MatchAPI match_api{facade, parameters, tidied};
@@ -784,8 +784,9 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
begin(weighted_packed_paths) + 1,
alternative_paths_last);
alternative_paths_last = filterPackedPathsByCellSharing(
begin(weighted_packed_paths), alternative_paths_last, partition);
alternative_paths_last = filterPackedPathsByCellSharing(begin(weighted_packed_paths), //
end(weighted_packed_paths), //
partition); //
BOOST_ASSERT(weighted_packed_paths.size() >= 1);
+92 -127
View File
@@ -7,8 +7,6 @@
#include "extractor/scripting_environment.hpp"
#include "extractor/suffix_table.hpp"
#include "extractor/intersection/intersection_analysis.hpp"
#include "extractor/serialization.hpp"
#include "storage/io.hpp"
@@ -377,9 +375,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
m_edge_based_node_container.nodes[edge_based_node_id].segregated =
segregated_edges.count(eid) > 0;
const auto ebn_weight = m_edge_based_node_weights[nbe_to_ebn_mapping[eid]];
BOOST_ASSERT(ebn_weight == INVALID_EDGE_WEIGHT || ebn_weight == edge_data.weight);
m_edge_based_node_weights.push_back(ebn_weight);
m_edge_based_node_weights.push_back(m_edge_based_node_weights[eid]);
edge_based_node_id++;
progress.PrintStatus(progress_counter++);
@@ -423,39 +419,22 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
TurnDataExternalContainer turn_data_container;
SuffixTable street_name_suffix_table(scripting_environment);
const auto &turn_lanes_data = transformTurnLaneMapIntoArrays(lane_description_map);
guidance::MergableRoadDetector mergable_road_detector(m_node_based_graph,
m_edge_based_node_container,
m_coordinates,
m_compressed_edge_container,
node_restriction_map,
m_barrier_nodes,
turn_lanes_data,
name_table,
street_name_suffix_table);
// Loop over all turns and generate new set of edges.
// Three nested loop look super-linear, but we are dealing with a (kind of)
// linear number of turns only.
SuffixTable street_name_suffix_table(scripting_environment);
guidance::TurnAnalysis turn_analysis(m_node_based_graph,
m_edge_based_node_container,
m_coordinates,
m_compressed_edge_container,
node_restriction_map,
m_barrier_nodes,
turn_lanes_data,
m_compressed_edge_container,
name_table,
street_name_suffix_table);
util::guidance::LaneDataIdMap lane_data_map;
guidance::lanes::TurnLaneHandler turn_lane_handler(m_node_based_graph,
m_edge_based_node_container,
m_coordinates,
m_compressed_edge_container,
node_restriction_map,
m_barrier_nodes,
turn_lanes_data,
lane_description_map,
turn_analysis,
lane_data_map);
@@ -558,14 +537,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// the situation of the turn
const auto node_along_road_entering,
const auto node_based_edge_from,
const auto intersection_node,
const auto node_at_center_of_intersection,
const auto node_based_edge_to,
const auto incoming_bearing,
const auto &intersection,
const auto &turn,
const auto entry_class_id) {
const auto node_restricted = isRestricted(node_along_road_entering,
intersection_node,
node_at_center_of_intersection,
m_node_based_graph.GetTarget(turn.eid),
conditional_restriction_map);
@@ -577,7 +556,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
conditional = {{edge_based_node_from,
edge_based_node_to,
{static_cast<std::uint64_t>(-1),
m_coordinates[intersection_node],
m_coordinates[node_at_center_of_intersection],
conditions}}};
}
@@ -593,15 +572,15 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
TurnData turn_data = {turn.instruction,
turn.lane_data_id,
entry_class_id,
util::guidance::TurnBearing(incoming_bearing),
util::guidance::TurnBearing(intersection[0].bearing),
util::guidance::TurnBearing(turn.bearing)};
// compute weight and duration penalties
auto is_traffic_light = m_traffic_lights.count(intersection_node);
auto is_traffic_light = m_traffic_lights.count(node_at_center_of_intersection);
ExtractionTurn extracted_turn(
turn.angle,
m_node_based_graph.GetOutDegree(intersection_node),
turn.instruction.IsUTurn(),
m_node_based_graph.GetOutDegree(node_at_center_of_intersection),
turn.instruction.direction_modifier == guidance::DirectionModifier::UTurn,
is_traffic_light,
edge_data1.flags.restricted,
edge_data2.flags.restricted,
@@ -651,7 +630,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
lookup::TurnIndexBlock turn_index_block = {from_node, intersection_node, to_node};
lookup::TurnIndexBlock turn_index_block = {
from_node, node_at_center_of_intersection, to_node};
// insert data into the designated buffer
return std::make_pair(
@@ -673,26 +653,17 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
if (buffer->nodes_processed == 0)
return buffer;
for (auto intersection_node = intersection_node_range.begin(),
for (auto node_at_center_of_intersection = intersection_node_range.begin(),
end = intersection_node_range.end();
intersection_node < end;
++intersection_node)
node_at_center_of_intersection < end;
++node_at_center_of_intersection)
{
// We capture the thread-local work in these objects, then flush
// them in a controlled manner at the end of the parallel range
const auto &incoming_edges =
intersection::getIncomingEdges(m_node_based_graph, intersection_node);
const auto &outgoing_edges =
intersection::getOutgoingEdges(m_node_based_graph, intersection_node);
intersection::IntersectionEdgeGeometries edge_geometries;
std::unordered_set<EdgeID> merged_edge_ids;
std::tie(edge_geometries, merged_edge_ids) =
intersection::getIntersectionGeometries(m_node_based_graph,
m_compressed_edge_container,
m_coordinates,
mergable_road_detector,
intersection_node);
const auto shape_result =
turn_analysis.ComputeIntersectionShapes(node_at_center_of_intersection);
// all nodes in the graph are connected in both directions. We check all
// outgoing nodes to find the incoming edge. This is a larger search overhead,
@@ -712,33 +683,45 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// From the flags alone, we cannot determine which nodes are connected to
// `b` by an outgoing edge. Therefore, we have to search all connected edges for
// edges entering `b`
for (const auto &incoming_edge : incoming_edges)
for (const EdgeID outgoing_edge :
m_node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection))
{
const NodeID node_along_road_entering =
m_node_based_graph.GetTarget(outgoing_edge);
const auto incoming_edge = m_node_based_graph.FindEdge(
node_along_road_entering, node_at_center_of_intersection);
if (m_node_based_graph.GetEdgeData(incoming_edge).reversed)
continue;
++node_based_edge_counter;
const auto intersection_view =
convertToIntersectionView(m_node_based_graph,
m_edge_based_node_container,
node_restriction_map,
m_barrier_nodes,
edge_geometries,
turn_lanes_data,
incoming_edge,
outgoing_edges,
merged_edge_ids);
auto intersection_with_flags_and_angles =
turn_analysis.GetIntersectionGenerator()
.TransformIntersectionShapeIntoView(
node_along_road_entering,
incoming_edge,
shape_result.annotated_normalized_shape.normalized_shape,
shape_result.intersection_shape,
shape_result.annotated_normalized_shape.performed_merges);
auto intersection = turn_analysis.AssignTurnTypes(
incoming_edge.node, incoming_edge.edge, intersection_view);
auto intersection =
turn_analysis.AssignTurnTypes(node_along_road_entering,
incoming_edge,
intersection_with_flags_and_angles);
OSRM_ASSERT(intersection.valid(),
m_coordinates[node_at_center_of_intersection]);
OSRM_ASSERT(intersection.valid(), m_coordinates[intersection_node]);
intersection = turn_lane_handler.assignTurnLanes(
incoming_edge.node, incoming_edge.edge, std::move(intersection));
node_along_road_entering, incoming_edge, std::move(intersection));
// the entry class depends on the turn, so we have to classify the
// interesction for every edge
const auto turn_classification =
classifyIntersection(intersection, m_coordinates[intersection_node]);
// interesction for
// every edge
const auto turn_classification = classifyIntersection(
intersection, m_coordinates[node_at_center_of_intersection]);
const auto entry_class_id =
entry_class_hash.ConcurrentFindOrAdd(turn_classification.first);
@@ -749,37 +732,19 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// Note - this is strictly speaking not thread safe, but we know we
// should never be touching the same element twice, so we should
// be fine.
bearing_class_by_node_based_node[intersection_node] = bearing_class_id;
bearing_class_by_node_based_node[node_at_center_of_intersection] =
bearing_class_id;
// check if we are turning off a via way
const auto turning_off_via_way =
way_restriction_map.IsViaWay(incoming_edge.node, intersection_node);
const auto turning_off_via_way = way_restriction_map.IsViaWay(
node_along_road_entering, node_at_center_of_intersection);
// Save reversed incoming bearing to compute turn angles
const auto reversed_incoming_bearing = util::bearing::reverse(
findEdgeBearing(edge_geometries, incoming_edge.edge));
for (const auto &outgoing_edge : outgoing_edges)
for (const auto &turn : intersection)
{
if (!intersection::isTurnAllowed(m_node_based_graph,
m_edge_based_node_container,
node_restriction_map,
m_barrier_nodes,
edge_geometries,
turn_lanes_data,
incoming_edge,
outgoing_edge))
// only keep valid turns
if (!turn.entry_allowed)
continue;
const auto turn =
std::find_if(intersection.begin(),
intersection.end(),
[edge = outgoing_edge.edge](const auto &road) {
return road.eid == edge;
});
OSRM_ASSERT(turn != intersection.end(),
m_coordinates[intersection_node]);
// In case a way restriction starts at a given location, add a turn onto
// every artificial node eminating here.
//
@@ -801,22 +766,22 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// duplicated node associated with the turn. (e.g. ab via bc switches bc
// to bc_dup)
auto const target_id = way_restriction_map.RemapIfRestricted(
nbe_to_ebn_mapping[outgoing_edge.edge],
incoming_edge.node,
outgoing_edge.node,
m_node_based_graph.GetTarget(outgoing_edge.edge),
nbe_to_ebn_mapping[turn.eid],
node_along_road_entering,
node_at_center_of_intersection,
m_node_based_graph.GetTarget(turn.eid),
m_number_of_edge_based_nodes);
{ // scope to forget edge_with_data after
const auto edge_with_data_and_condition =
generate_edge(nbe_to_ebn_mapping[incoming_edge.edge],
generate_edge(nbe_to_ebn_mapping[incoming_edge],
target_id,
incoming_edge.node,
incoming_edge.edge,
outgoing_edge.node,
outgoing_edge.edge,
reversed_incoming_bearing,
*turn,
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
buffer->continuous_data.edges_list.push_back(
@@ -843,7 +808,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
if (turning_off_via_way)
{
const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs(
incoming_edge.node, intersection_node);
node_along_road_entering, node_at_center_of_intersection);
// next to the normal restrictions tracked in `entry_allowed`, via
// ways might introduce additional restrictions. These are handled
@@ -851,12 +816,12 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
for (auto duplicated_node_id : duplicated_nodes)
{
const auto from_id =
NodeID(m_number_of_edge_based_nodes -
way_restriction_map.NumberOfDuplicatedNodes() +
duplicated_node_id);
m_number_of_edge_based_nodes -
way_restriction_map.NumberOfDuplicatedNodes() +
duplicated_node_id;
auto const node_at_end_of_turn =
m_node_based_graph.GetTarget(outgoing_edge.edge);
m_node_based_graph.GetTarget(turn.eid);
const auto is_way_restricted = way_restriction_map.IsRestricted(
duplicated_node_id, node_at_end_of_turn);
@@ -871,14 +836,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// add into delayed data
auto edge_with_data_and_condition =
generate_edge(from_id,
nbe_to_ebn_mapping[outgoing_edge.edge],
incoming_edge.node,
incoming_edge.edge,
outgoing_edge.node,
outgoing_edge.edge,
reversed_incoming_bearing,
*turn,
generate_edge(NodeID(from_id),
nbe_to_ebn_mapping[turn.eid],
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
buffer->delayed_data.push_back(
@@ -895,24 +860,24 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
{
// add a new conditional for the edge we just created
buffer->conditionals.push_back(
{from_id,
nbe_to_ebn_mapping[outgoing_edge.edge],
{NodeID(from_id),
nbe_to_ebn_mapping[turn.eid],
{static_cast<std::uint64_t>(-1),
m_coordinates[intersection_node],
m_coordinates[node_at_center_of_intersection],
restriction.condition}});
}
}
else
{
auto edge_with_data_and_condition =
generate_edge(from_id,
nbe_to_ebn_mapping[outgoing_edge.edge],
incoming_edge.node,
incoming_edge.edge,
outgoing_edge.node,
outgoing_edge.edge,
reversed_incoming_bearing,
*turn,
generate_edge(NodeID(from_id),
nbe_to_ebn_mapping[turn.eid],
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
buffer->delayed_data.push_back(
+230 -7
View File
@@ -13,8 +13,6 @@
#include "extractor/restriction_parser.hpp"
#include "extractor/scripting_environment.hpp"
#include "extractor/guidance/segregated_intersection_classification.hpp"
#include "storage/io.hpp"
#include "util/exception.hpp"
@@ -222,8 +220,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
util::Log() << "Find segregated edges in node-based graph ..." << std::flush;
TIMER_START(segregated);
util::NameTable names(config.GetPath(".osrm.names").string());
auto segregated_edges = guidance::findSegregatedNodes(node_based_graph_factory, names);
auto segregated_edges = FindSegregatedNodes(node_based_graph_factory);
TIMER_STOP(segregated);
util::Log() << "ok, after " << TIMER_SEC(segregated) << "s";
@@ -365,7 +362,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
TIMER_START(parsing);
{ // Parse OSM header
osmium::io::Reader reader(input_file, pool, osmium::osm_entity_bits::nothing);
osmium::io::Reader reader(input_file, osmium::osm_entity_bits::nothing);
osmium::io::Header header = reader.header();
std::string generator = header.get("generator");
@@ -545,7 +542,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
{ // Relations reading pipeline
util::Log() << "Parse relations ...";
osmium::io::Reader reader(input_file, pool, osmium::osm_entity_bits::relation, read_meta);
osmium::io::Reader reader(input_file, osmium::osm_entity_bits::relation, read_meta);
tbb::parallel_pipeline(
num_threads, buffer_reader(reader) & buffer_relation_cache & buffer_storage_relation);
}
@@ -553,7 +550,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
{ // Nodes and ways reading pipeline
util::Log() << "Parse ways and nodes ...";
osmium::io::Reader reader(input_file,
pool,
osmium::osm_entity_bits::node | osmium::osm_entity_bits::way |
osmium::osm_entity_bits::relation,
read_meta);
@@ -842,5 +838,232 @@ void Extractor::WriteCompressedNodeBasedGraph(const std::string &path,
}
}
struct EdgeInfo
{
NodeID node;
util::StringView name;
// 0 - outgoing (forward), 1 - incoming (reverse), 2 - both outgoing and incoming
int direction;
ClassData road_class;
guidance::RoadPriorityClass::Enum road_priority_class;
struct LessName
{
bool operator()(EdgeInfo const &e1, EdgeInfo const &e2) const { return e1.name < e2.name; }
};
};
bool IsSegregated(std::vector<EdgeInfo> v1,
std::vector<EdgeInfo> v2,
EdgeInfo const &current,
double edgeLength)
{
if (v1.size() < 2 || v2.size() < 2)
return false;
auto const sort_by_name_fn = [](std::vector<EdgeInfo> &v) {
std::sort(v.begin(), v.end(), EdgeInfo::LessName());
};
sort_by_name_fn(v1);
sort_by_name_fn(v2);
// Internal edge with the name should be connected with any other neibour edge with the same
// name, e.g. isolated edge with unique name is not segregated.
// b - 'b' road continues here
// |
// - - a - |
// b - segregated edge
// - - a - |
if (!current.name.empty())
{
auto const findNameFn = [&current](std::vector<EdgeInfo> const &v) {
return std::binary_search(v.begin(), v.end(), current, EdgeInfo::LessName());
};
if (!findNameFn(v1) && !findNameFn(v2))
return false;
}
// set_intersection like routine to get equal result pairs
std::vector<std::pair<EdgeInfo const *, EdgeInfo const *>> commons;
auto i1 = v1.begin();
auto i2 = v2.begin();
while (i1 != v1.end() && i2 != v2.end())
{
if (i1->name == i2->name)
{
if (!i1->name.empty())
commons.push_back(std::make_pair(&(*i1), &(*i2)));
++i1;
++i2;
}
else if (i1->name < i2->name)
++i1;
else
++i2;
}
if (commons.size() < 2)
return false;
auto const check_equal_class = [](std::pair<EdgeInfo const *, EdgeInfo const *> const &e) {
// Or (e.first->road_class & e.second->road_class != 0)
return e.first->road_class == e.second->road_class;
};
size_t equal_class_count = 0;
for (auto const &e : commons)
if (check_equal_class(e))
++equal_class_count;
if (equal_class_count < 2)
return false;
auto const get_length_threshold = [](EdgeInfo const *e) {
switch (e->road_priority_class)
{
case guidance::RoadPriorityClass::MOTORWAY:
case guidance::RoadPriorityClass::TRUNK:
return 30.0;
case guidance::RoadPriorityClass::PRIMARY:
return 20.0;
case guidance::RoadPriorityClass::SECONDARY:
case guidance::RoadPriorityClass::TERTIARY:
return 10.0;
default:
return 5.0;
}
};
double threshold = std::numeric_limits<double>::max();
for (auto const &e : commons)
threshold =
std::min(threshold, get_length_threshold(e.first) + get_length_threshold(e.second));
return edgeLength <= threshold;
}
std::unordered_set<EdgeID> Extractor::FindSegregatedNodes(NodeBasedGraphFactory &factory)
{
util::NameTable names(config.GetPath(".osrm.names").string());
auto const &graph = factory.GetGraph();
auto const &annotation = factory.GetAnnotationData();
guidance::CoordinateExtractor coordExtractor(
graph, factory.GetCompressedEdges(), factory.GetCoordinates());
auto const get_edge_length = [&](NodeID from_node, EdgeID edgeID, NodeID to_node) {
auto const geom = coordExtractor.GetCoordinatesAlongRoad(from_node, edgeID, false, to_node);
double length = 0.0;
for (size_t i = 1; i < geom.size(); ++i)
{
length += osrm::util::coordinate_calculation::haversineDistance(geom[i - 1], geom[i]);
}
return length;
};
auto const get_edge_info = [&](NodeID node, auto const &edgeData) -> EdgeInfo {
/// @todo Make string normalization/lowercase/trim for comparison ...
auto const id = annotation[edgeData.annotation_data].name_id;
BOOST_ASSERT(id != INVALID_NAMEID);
auto const name = names.GetNameForID(id);
return {node,
name,
edgeData.reversed ? 1 : 0,
annotation[edgeData.annotation_data].classes,
edgeData.flags.road_classification.GetClass()};
};
auto const collect_edge_info_fn = [&](auto const &edges1, NodeID node2) {
std::vector<EdgeInfo> info;
for (auto const &e : edges1)
{
NodeID const target = graph.GetTarget(e);
if (target == node2)
continue;
info.push_back(get_edge_info(target, graph.GetEdgeData(e)));
}
if (info.empty())
return info;
std::sort(info.begin(), info.end(), [](EdgeInfo const &e1, EdgeInfo const &e2) {
return e1.node < e2.node;
});
// Merge equal infos with correct direction.
auto curr = info.begin();
auto next = curr;
while (++next != info.end())
{
if (curr->node == next->node)
{
BOOST_ASSERT(curr->name == next->name);
BOOST_ASSERT(curr->road_class == next->road_class);
BOOST_ASSERT(curr->direction != next->direction);
curr->direction = 2;
}
else
curr = next;
}
info.erase(
std::unique(info.begin(),
info.end(),
[](EdgeInfo const &e1, EdgeInfo const &e2) { return e1.node == e2.node; }),
info.end());
return info;
};
auto const isSegregatedFn = [&](auto const &edgeData,
auto const &edges1,
NodeID node1,
auto const &edges2,
NodeID node2,
double edgeLength) {
return IsSegregated(collect_edge_info_fn(edges1, node2),
collect_edge_info_fn(edges2, node1),
get_edge_info(node1, edgeData),
edgeLength);
};
std::unordered_set<EdgeID> segregated_edges;
for (NodeID sourceID = 0; sourceID < graph.GetNumberOfNodes(); ++sourceID)
{
auto const sourceEdges = graph.GetAdjacentEdgeRange(sourceID);
for (EdgeID edgeID : sourceEdges)
{
auto const &edgeData = graph.GetEdgeData(edgeID);
if (edgeData.reversed)
continue;
NodeID const targetID = graph.GetTarget(edgeID);
auto const targetEdges = graph.GetAdjacentEdgeRange(targetID);
double const length = get_edge_length(sourceID, edgeID, targetID);
if (isSegregatedFn(edgeData, sourceEdges, sourceID, targetEdges, targetID, length))
segregated_edges.insert(edgeID);
}
}
return segregated_edges;
}
} // namespace extractor
} // namespace osrm
+8 -14
View File
@@ -12,24 +12,18 @@ namespace extractor
namespace guidance
{
DrivewayHandler::DrivewayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
DrivewayHandler::DrivewayHandler(const IntersectionGenerator &intersection_generator,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const std::vector<util::Coordinate> &coordinates,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
: IntersectionHandler(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
coordinates,
name_table,
street_name_suffix_table)
street_name_suffix_table,
intersection_generator)
{
}
@@ -70,12 +64,12 @@ operator()(const NodeID nid, const EdgeID source_edge_id, Intersection intersect
});
(void)nid;
OSRM_ASSERT(road != intersection.end(), node_coordinates[nid]);
OSRM_ASSERT(road != intersection.end(), coordinates[nid]);
if (road->instruction == TurnInstruction::INVALID())
return intersection;
OSRM_ASSERT(road->instruction.type == TurnType::Turn, node_coordinates[nid]);
OSRM_ASSERT(road->instruction.type == TurnType::Turn, coordinates[nid]);
road->instruction.type =
isSameName(source_edge_id, road->eid) ? TurnType::NoTurn : TurnType::NewName;
@@ -1,33 +0,0 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
#include "util/guidance/name_announcements.hpp"
namespace osrm
{
namespace extractor
{
namespace guidance
{
// check if two name ids can be seen as identical (in presence of refs/others)
// in our case this translates into no name announcement in either direction (lhs->rhs and
// rhs->lhs)
bool HaveIdenticalNames(const NameID lhs,
const NameID rhs,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
{
const auto non_empty = (lhs != EMPTY_NAMEID) && (rhs != EMPTY_NAMEID);
// symmetrical check for announcements
return non_empty &&
!util::guidance::requiresNameAnnounced(lhs, rhs, name_table, street_name_suffix_table) &&
!util::guidance::requiresNameAnnounced(rhs, lhs, name_table, street_name_suffix_table);
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_*/
@@ -0,0 +1,488 @@
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/geojson_debug_policies.hpp"
#include "util/geojson_debug_logger.hpp"
#include "util/assert.hpp"
#include "util/bearing.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/log.hpp"
#include <algorithm>
#include <cmath>
#include <functional> // mem_fn
#include <limits>
#include <numeric>
#include <utility>
#include <boost/range/algorithm/count_if.hpp>
namespace osrm
{
namespace extractor
{
namespace guidance
{
namespace
{
const constexpr bool USE_LOW_PRECISION_MODE = true;
// the inverse of use low precision mode
const constexpr bool USE_HIGH_PRECISION_MODE = !USE_LOW_PRECISION_MODE;
}
IntersectionGenerator::IntersectionGenerator(
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const std::vector<util::Coordinate> &coordinates,
const CompressedEdgeContainer &compressed_edge_container)
: node_based_graph(node_based_graph), node_data_container(node_data_container),
restriction_map(restriction_map), barrier_nodes(barrier_nodes), coordinates(coordinates),
coordinate_extractor(node_based_graph, compressed_edge_container, coordinates)
{
}
IntersectionView IntersectionGenerator::operator()(const NodeID from_node,
const EdgeID via_eid) const
{
return GetConnectedRoads(from_node, via_eid, USE_HIGH_PRECISION_MODE);
}
IntersectionShape
IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_intersection,
const boost::optional<NodeID> sorting_base,
const bool use_low_precision_angles) const
{
const auto intersection_degree = node_based_graph.GetOutDegree(node_at_center_of_intersection);
const util::Coordinate turn_coordinate = coordinates[node_at_center_of_intersection];
// compute bearings in a relatively small circle to prevent wrong roads order with true bearings
struct RoadWithInitialBearing
{
double bearing;
IntersectionShapeData road;
};
std::vector<RoadWithInitialBearing> initial_roads_ordering;
// reserve enough items (+ the possibly missing u-turn edge)
initial_roads_ordering.reserve(intersection_degree);
// number of lanes at the intersection changes how far we look down the road
const auto edge_range = node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection);
const auto max_lanes_intersection =
std::accumulate(edge_range.begin(),
edge_range.end(),
std::uint8_t{0},
[this](const auto current_max, const auto current_eid) {
return std::max(current_max,
node_based_graph.GetEdgeData(current_eid)
.flags.road_classification.GetNumberOfLanes());
});
for (const EdgeID edge_connected_to_intersection :
node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection))
{
BOOST_ASSERT(edge_connected_to_intersection != SPECIAL_EDGEID);
const NodeID to_node = node_based_graph.GetTarget(edge_connected_to_intersection);
double bearing = 0.;
auto coordinates = coordinate_extractor.GetCoordinatesAlongRoad(
node_at_center_of_intersection, edge_connected_to_intersection, !INVERT, to_node);
const auto close_coordinate =
coordinate_extractor.ExtractCoordinateAtLength(2. /*m*/, coordinates);
const auto initial_bearing =
util::coordinate_calculation::bearing(turn_coordinate, close_coordinate);
const auto segment_length = util::coordinate_calculation::getLength(
coordinates.begin(),
coordinates.end(),
util::coordinate_calculation::haversineDistance);
const auto extract_coordinate = [&](const NodeID from_node,
const EdgeID via_eid,
const bool traversed_in_reverse,
const NodeID to_node) {
return (use_low_precision_angles || intersection_degree <= 2)
? coordinate_extractor.GetCoordinateCloseToTurn(
from_node, via_eid, traversed_in_reverse, to_node)
: coordinate_extractor.ExtractRepresentativeCoordinate(
from_node,
via_eid,
traversed_in_reverse,
to_node,
max_lanes_intersection,
std::move(coordinates));
};
// we have to look down the road a bit to get the correct turn
const auto coordinate_along_edge_leaving = extract_coordinate(
node_at_center_of_intersection, edge_connected_to_intersection, !INVERT, to_node);
bearing =
util::coordinate_calculation::bearing(turn_coordinate, coordinate_along_edge_leaving);
// OSM data sometimes contains duplicated nodes with identical coordinates, or
// because of coordinate precision rounding, end up at the same coordinate.
// It's impossible to calculate a bearing between these, so we log a warning
// that the data should be checked.
// The bearing calculation should return 0 in these cases, which may not be correct,
// but is at least not random.
if (turn_coordinate == coordinate_along_edge_leaving)
{
util::Log(logDEBUG) << "Zero length segment at " << coordinate_along_edge_leaving
<< " could cause invalid intersection exit bearing.";
BOOST_ASSERT(std::abs(bearing) <= 0.1);
}
initial_roads_ordering.push_back(
{initial_bearing, {edge_connected_to_intersection, bearing, segment_length}});
}
if (!initial_roads_ordering.empty())
{
const auto base_initial_bearing = [&]() {
if (sorting_base)
{
const auto itr = std::find_if(initial_roads_ordering.begin(),
initial_roads_ordering.end(),
[&](const auto &data) {
return node_based_graph.GetTarget(
data.road.eid) == *sorting_base;
});
if (itr != initial_roads_ordering.end())
return util::bearing::reverse(itr->bearing);
}
return util::bearing::reverse(initial_roads_ordering.begin()->bearing);
}();
// sort roads with respect to the initial bearings, a tie-breaker for equal initial bearings
// is to order roads via final bearings to have roads in clockwise order
//
// rhs <---. lhs <----.
// / /
// lhs / rhs /
//
// lhs road is before rhs one rhs road is before lhs one
// bearing::angleBetween < 180 bearing::angleBetween > 180
const auto initial_bearing_order = makeCompareShapeDataAngleToBearing(base_initial_bearing);
std::sort(initial_roads_ordering.begin(),
initial_roads_ordering.end(),
[&initial_bearing_order](const auto &lhs, const auto &rhs) {
return initial_bearing_order(lhs, rhs) ||
(lhs.bearing == rhs.bearing &&
util::bearing::angleBetween(lhs.road.bearing, rhs.road.bearing) <
180);
});
// copy intersection data in the initial order
IntersectionShape intersection;
intersection.reserve(initial_roads_ordering.size());
std::transform(initial_roads_ordering.begin(),
initial_roads_ordering.end(),
std::back_inserter(intersection),
[](const auto &entry) { return entry.road; });
if (intersection.size() > 2)
{ // Check bearings ordering with respect to true bearings
const auto base_bearing = intersection.front().bearing;
const auto bearings_order =
makeCompareShapeDataAngleToBearing(util::bearing::reverse(base_bearing));
for (auto curr = intersection.begin(), next = std::next(curr);
next != intersection.end();
++curr, ++next)
{
if (bearings_order(*next, *curr))
{ // If the true bearing is out of the initial order (next before current) then
// adjust the next bearing to keep the order. The adjustment angle is at most
// 0.5° or a half-angle between the current bearing and the base bearing.
// to prevent overlapping over base bearing + 360°.
const auto angle_adjustment = std::min(
.5, util::restrictAngleToValidRange(base_bearing - curr->bearing) / 2.);
next->bearing =
util::restrictAngleToValidRange(curr->bearing + angle_adjustment);
}
}
}
return intersection;
}
return IntersectionShape{};
}
// a
// |
// |
// v
// For an intersection from_node --via_eid--> turn_node ----> c
// ^
// |
// |
// b
// This functions returns _all_ turns as if the graph was undirected.
// That means we not only get (from_node, turn_node, c) in the above example
// but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are
// marked as invalid and only needed for intersection classification.
IntersectionView IntersectionGenerator::GetConnectedRoads(const NodeID from_node,
const EdgeID via_eid,
const bool use_low_precision_angles) const
{
// make sure the via-eid is valid
BOOST_ASSERT([this](const NodeID from_node, const EdgeID via_eid) {
const auto range = node_based_graph.GetAdjacentEdgeRange(from_node);
return range.front() <= via_eid && via_eid <= range.back();
}(from_node, via_eid));
auto intersection = ComputeIntersectionShape(
node_based_graph.GetTarget(via_eid), boost::none, use_low_precision_angles);
return TransformIntersectionShapeIntoView(from_node, via_eid, std::move(intersection));
}
IntersectionGenerationParameters
IntersectionGenerator::SkipDegreeTwoNodes(const NodeID starting_node, const EdgeID via_edge) const
{
NodeID query_node = starting_node;
EdgeID query_edge = via_edge;
const auto get_next_edge = [this](const NodeID from, const EdgeID via) {
const NodeID new_node = node_based_graph.GetTarget(via);
BOOST_ASSERT(node_based_graph.GetOutDegree(new_node) == 2);
const EdgeID begin_edges_new_node = node_based_graph.BeginEdges(new_node);
return (node_based_graph.GetTarget(begin_edges_new_node) == from) ? begin_edges_new_node + 1
: begin_edges_new_node;
};
std::unordered_set<NodeID> visited_nodes;
// skip trivial nodes without generating the intersection in between, stop at the very first
// intersection of degree > 2
while (0 == visited_nodes.count(query_node) &&
2 == node_based_graph.GetOutDegree(node_based_graph.GetTarget(query_edge)))
{
visited_nodes.insert(query_node);
const auto next_node = node_based_graph.GetTarget(query_edge);
const auto next_edge = get_next_edge(query_node, query_edge);
query_node = next_node;
query_edge = next_edge;
// check if there is a relevant change in the graph
if (!CanBeCompressed(node_based_graph.GetEdgeData(query_edge),
node_based_graph.GetEdgeData(next_edge),
node_data_container) ||
(node_based_graph.GetTarget(next_edge) == starting_node))
break;
}
return {query_node, query_edge};
}
IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
const NodeID previous_node,
const EdgeID entering_via_edge,
const IntersectionShape &intersection_shape) const
{
// requires a copy of the intersection
return TransformIntersectionShapeIntoView(previous_node,
entering_via_edge,
intersection_shape, // creates a copy
intersection_shape, // reference to local
{}); // empty vector of performed merges
}
IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
const NodeID previous_node,
const EdgeID entering_via_edge,
const IntersectionShape &normalized_intersection,
const IntersectionShape &intersection,
const std::vector<IntersectionNormalizationOperation> &performed_merges) const
{
const auto node_at_intersection = node_based_graph.GetTarget(entering_via_edge);
// request all turn restrictions
auto const restrictions = restriction_map.Restrictions(previous_node, node_at_intersection);
// check turn restrictions to find a node that is the only allowed target when coming from a
// node to an intersection
// d
// |
// a - b - c and `only_straight_on ab | bc would return `c` for `a,b`
const auto find_only_valid_turn = [&]() -> boost::optional<NodeID> {
const auto itr = std::find_if(restrictions.first, restrictions.second, [](auto pair) {
return pair.second->is_only;
});
if (itr != restrictions.second)
return itr->second->AsNodeRestriction().to;
else
return boost::none;
};
const auto only_valid_turn = find_only_valid_turn();
// barriers change our behaviour regarding u-turns
const bool is_barrier_node = barrier_nodes.find(node_at_intersection) != barrier_nodes.end();
const auto connect_to_previous_node = [this, previous_node](const IntersectionShapeData road) {
return node_based_graph.GetTarget(road.eid) == previous_node;
};
// check which of the edges is the u-turn edge
const auto uturn_edge_itr =
std::find_if(intersection.begin(), intersection.end(), connect_to_previous_node);
// there needs to be a connection, otherwise stuff went seriously wrong. Note that this is not
// necessarily the same id as `entering_via_edge`.
// In cases where parallel edges are present, we only remember the minimal edge. Both share
// exactly the same coordinates, so the u-turn is still the best choice here.
BOOST_ASSERT(uturn_edge_itr != intersection.end());
const auto is_restricted = [&](const NodeID destination) {
// check if we have a dedicated destination
if (only_valid_turn)
return *only_valid_turn != destination;
// check if explicitly forbidden
return restrictions.second !=
std::find_if(restrictions.first, restrictions.second, [&](const auto &restriction) {
return restriction.second->AsNodeRestriction().to == destination;
});
};
const auto is_allowed_turn = [&](const IntersectionShapeData &road) {
const auto &road_data = node_based_graph.GetEdgeData(road.eid);
const NodeID road_destination_node = node_based_graph.GetTarget(road.eid);
// reverse edges are never valid turns because the resulting turn would look like this:
// from_node --via_edge--> node_at_intersection <--onto_edge-- to_node
// however we need this for capture intersection shape for incoming one-ways
return !road_data.reversed &&
// we are not turning over a barrier
(!is_barrier_node || road_destination_node == previous_node) &&
// don't allow restricted turns
!is_restricted(road_destination_node);
};
// due to merging of roads, the u-turn might actually not be part of the intersection anymore
// uturn is a pair of {edge id, bearing}
const auto uturn = [&]() {
const auto merge_entry = std::find_if(
performed_merges.begin(), performed_merges.end(), [&uturn_edge_itr](const auto entry) {
return entry.merged_eid == uturn_edge_itr->eid;
});
if (merge_entry != performed_merges.end())
{
const auto merged_into_id = merge_entry->into_eid;
const auto merged_u_turn = std::find_if(
normalized_intersection.begin(),
normalized_intersection.end(),
[&](const IntersectionShapeData &road) { return road.eid == merged_into_id; });
BOOST_ASSERT(merged_u_turn != normalized_intersection.end());
return std::make_pair(merged_u_turn->eid,
util::bearing::reverse(merged_u_turn->bearing));
}
else
{
const auto uturn_edge_at_normalized_intersection_itr =
std::find_if(normalized_intersection.begin(),
normalized_intersection.end(),
connect_to_previous_node);
BOOST_ASSERT(uturn_edge_at_normalized_intersection_itr !=
normalized_intersection.end());
return std::make_pair(
uturn_edge_at_normalized_intersection_itr->eid,
util::bearing::reverse(uturn_edge_at_normalized_intersection_itr->bearing));
}
}();
IntersectionView intersection_view;
intersection_view.reserve(normalized_intersection.size());
std::transform(normalized_intersection.begin(),
normalized_intersection.end(),
std::back_inserter(intersection_view),
[&](const IntersectionShapeData &road) {
return IntersectionViewData(
road,
is_allowed_turn(road),
util::bearing::angleBetween(uturn.second, road.bearing));
});
const auto uturn_edge_at_intersection_view_itr =
std::find_if(intersection_view.begin(), intersection_view.end(), connect_to_previous_node);
// number of found valid exit roads
const auto valid_count =
std::count_if(intersection_view.begin(),
intersection_view.end(),
[](const IntersectionViewData &road) { return road.entry_allowed; });
// in general, we don't wan't to allow u-turns. If we don't look at a barrier, we have to check
// for dead end streets. These are the only ones that we allow uturns for, next to barriers
// (which are also kind of a dead end, but we don't have to check these again :))
if (uturn_edge_at_intersection_view_itr != intersection_view.end() &&
((uturn_edge_at_intersection_view_itr->entry_allowed && !is_barrier_node &&
valid_count != 1) ||
valid_count == 0))
{
const auto allow_uturn_at_dead_end = [&]() {
const auto &uturn_data = node_based_graph.GetEdgeData(uturn_edge_itr->eid);
// we can't turn back onto oneway streets
if (uturn_data.reversed)
return false;
// don't allow explicitly restricted turns
if (is_restricted(previous_node))
return false;
// we define dead ends as roads that can only be entered via the possible u-turn
const auto is_bidirectional = [&](const EdgeID entering_via_edge) {
const auto to_node = node_based_graph.GetTarget(entering_via_edge);
const auto reverse_edge = node_based_graph.FindEdge(to_node, node_at_intersection);
BOOST_ASSERT(reverse_edge != SPECIAL_EDGEID);
return !node_based_graph.GetEdgeData(reverse_edge).reversed;
};
const auto bidirectional_edges = [&]() {
std::uint32_t count = 0;
for (const auto eid : node_based_graph.GetAdjacentEdgeRange(node_at_intersection))
if (is_bidirectional(eid))
++count;
return count;
}();
// Checking for dead-end streets is kind of difficult. There is obvious dead ends
// (single road connected)
return bidirectional_edges <= 1;
}();
uturn_edge_at_intersection_view_itr->entry_allowed = allow_uturn_at_dead_end;
}
std::sort(std::begin(intersection_view),
std::end(intersection_view),
std::mem_fn(&IntersectionViewData::CompareByAngle));
// Move entering_via_edge to intersection front and place all roads prior entering_via_edge
// at the end of the intersection view with 360° angle
auto entering_via_it = std::find_if(intersection_view.begin(),
intersection_view.end(),
[&uturn](auto &road) { return road.eid == uturn.first; });
OSRM_ASSERT(entering_via_it != intersection_view.end() && entering_via_it->angle >= 0. &&
entering_via_it->angle < std::numeric_limits<double>::epsilon(),
coordinates[node_at_intersection]);
if (entering_via_it != intersection_view.begin() && entering_via_it != intersection_view.end())
{
std::for_each(
intersection_view.begin(), entering_via_it, [](auto &road) { road.angle = 360.; });
std::rotate(intersection_view.begin(), entering_via_it, intersection_view.end());
}
return intersection_view;
}
const CoordinateExtractor &IntersectionGenerator::GetCoordinateExtractor() const
{
return coordinate_extractor;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
+64 -60
View File
@@ -1,6 +1,5 @@
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/constants.hpp"
#include "extractor/intersection/intersection_analysis.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/name_announcements.hpp"
@@ -46,27 +45,17 @@ inline bool requiresAnnouncement(const util::NodeBasedDynamicGraph &node_based_g
}
} // namespace detail
IntersectionHandler::IntersectionHandler(
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator)
: node_based_graph(node_based_graph), node_data_container(node_data_container),
node_coordinates(node_coordinates), compressed_geometries(compressed_geometries),
node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes),
turn_lanes_data(turn_lanes_data), name_table(name_table),
street_name_suffix_table(street_name_suffix_table), graph_walker(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data)
coordinates(coordinates), name_table(name_table),
street_name_suffix_table(street_name_suffix_table),
intersection_generator(intersection_generator),
graph_walker(node_based_graph, node_data_container, intersection_generator)
{
}
@@ -82,19 +71,17 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge,
if (!on_ramp && onto_ramp)
return TurnType::OnRamp;
const auto &in_name_id =
const auto &in_name =
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
.name_id;
const auto &out_name_id =
const auto &out_name =
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
.name_id;
const auto &in_name_empty = name_table.GetNameForID(in_name_id).empty();
const auto &out_name_empty = name_table.GetNameForID(out_name_id).empty();
const auto same_name = !util::guidance::requiresNameAnnounced(
in_name_id, out_name_id, name_table, street_name_suffix_table);
in_name, out_name, name_table, street_name_suffix_table);
if (!in_name_empty && !out_name_empty && same_name)
if (in_name != EMPTY_NAMEID && out_name != EMPTY_NAMEID && same_name)
{
return TurnType::Continue;
}
@@ -102,19 +89,6 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge,
return TurnType::Turn;
}
TurnType::Enum IntersectionHandler::areSameClasses(const EdgeID via_edge,
const ConnectedRoad &road) const
{
const auto &in_classes =
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
.classes;
const auto &out_classes =
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
.classes;
return in_classes == out_classes;
}
TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t num_roads,
const EdgeID via_edge,
const bool through_street,
@@ -186,8 +160,8 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
// or actually follow the full road. When 2399 lands, we can exchange here for a
// precalculated distance value.
const auto distance = util::coordinate_calculation::haversineDistance(
node_coordinates[node_based_graph.GetTarget(via_edge)],
node_coordinates[node_based_graph.GetTarget(road.eid)]);
coordinates[node_based_graph.GetTarget(via_edge)],
coordinates[node_based_graph.GetTarget(road.eid)]);
return {TurnType::Turn,
(angularDeviation(road.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
@@ -208,8 +182,7 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
if (needs_notification)
return {TurnType::Notification, getTurnDirection(road.angle)};
else
return {num_roads == 2 && areSameClasses(via_edge, road) ? TurnType::NoTurn
: TurnType::Suppressed,
return {num_roads == 2 ? TurnType::NoTurn : TurnType::Suppressed,
getTurnDirection(road.angle)};
}
}
@@ -218,7 +191,7 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
{
return {TurnType::Notification, getTurnDirection(road.angle)};
}
if (num_roads > 2 || !areSameClasses(via_edge, road))
if (num_roads > 2)
{
return {TurnType::Suppressed, getTurnDirection(road.angle)};
}
@@ -432,6 +405,44 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid,
}
}
bool IntersectionHandler::isThroughStreet(const std::size_t index,
const Intersection &intersection) const
{
const auto &data_at_index = node_data_container.GetAnnotation(
node_based_graph.GetEdgeData(intersection[index].eid).annotation_data);
if (data_at_index.name_id == EMPTY_NAMEID)
return false;
// a through street cannot start at our own position -> index 1
for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index)
{
if (road_index == index)
continue;
const auto &road = intersection[road_index];
const auto &road_data = node_data_container.GetAnnotation(
node_based_graph.GetEdgeData(road.eid).annotation_data);
// roads have a near straight angle (180 degree)
const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
const bool have_same_name =
road_data.name_id != EMPTY_NAMEID &&
!util::guidance::requiresNameAnnounced(
data_at_index.name_id, road_data.name_id, name_table, street_name_suffix_table);
const bool have_same_category =
node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification ==
node_based_graph.GetEdgeData(road.eid).flags.road_classification;
if (is_nearly_straight && have_same_name && have_same_category)
return true;
}
return false;
}
boost::optional<IntersectionHandler::IntersectionViewAndNode>
IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) const
{
@@ -449,24 +460,17 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons
// Starting at node `a` via edge `e0` the intersection generator returns the intersection at `c`
// writing `tl` (traffic signal) node and the edge `e1` which has the intersection as target.
const auto intersection_parameters =
intersection::skipDegreeTwoNodes(node_based_graph, {at, via});
const auto intersection_parameters = intersection_generator.SkipDegreeTwoNodes(at, via);
// This should never happen, guard against nevertheless
if (intersection_parameters.node == SPECIAL_NODEID ||
intersection_parameters.edge == SPECIAL_EDGEID)
if (intersection_parameters.nid == SPECIAL_NODEID ||
intersection_parameters.via_eid == SPECIAL_EDGEID)
{
return boost::none;
}
auto intersection = intersection::getConnectedRoads<false>(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
intersection_parameters);
auto intersection_node = node_based_graph.GetTarget(intersection_parameters.edge);
auto intersection =
intersection_generator(intersection_parameters.nid, intersection_parameters.via_eid);
auto intersection_node = node_based_graph.GetTarget(intersection_parameters.via_eid);
if (intersection.size() <= 2 || intersection.isTrafficSignalOrBarrier())
{
@@ -484,8 +488,8 @@ bool IntersectionHandler::isSameName(const EdgeID source_edge_id, const EdgeID t
const auto &target_edge_data = node_data_container.GetAnnotation(
node_based_graph.GetEdgeData(target_edge_id).annotation_data);
return !name_table.GetNameForID(source_edge_data.name_id).empty() && //
!name_table.GetNameForID(target_edge_data.name_id).empty() && //
return source_edge_data.name_id != EMPTY_NAMEID && //
target_edge_data.name_id != EMPTY_NAMEID && //
!util::guidance::requiresNameAnnounced(source_edge_data.name_id,
target_edge_data.name_id,
name_table,
@@ -0,0 +1,430 @@
#include "extractor/guidance/intersection_normalizer.hpp"
#include "util/bearing.hpp"
#include "util/coordinate_calculation.hpp"
#include <tuple>
#include <utility>
using osrm::util::angularDeviation;
namespace osrm
{
namespace extractor
{
namespace guidance
{
IntersectionNormalizer::IntersectionNormalizer(
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator)
: node_based_graph(node_based_graph), intersection_generator(intersection_generator),
mergable_road_detector(node_based_graph,
node_data_container,
coordinates,
intersection_generator,
intersection_generator.GetCoordinateExtractor(),
name_table,
street_name_suffix_table)
{
}
IntersectionNormalizer::NormalizationResult IntersectionNormalizer::
operator()(const NodeID node_at_intersection, IntersectionShape intersection) const
{
const auto intersection_copy = intersection;
auto merged_shape_and_merges =
MergeSegregatedRoads(node_at_intersection, std::move(intersection));
merged_shape_and_merges.normalized_shape = AdjustBearingsForMergeAtDestination(
node_at_intersection, std::move(merged_shape_and_merges.normalized_shape));
return merged_shape_and_merges;
}
bool IntersectionNormalizer::CanMerge(const NodeID intersection_node,
const IntersectionShape &intersection,
std::size_t fist_index_in_ccw,
std::size_t second_index_in_ccw) const
{
BOOST_ASSERT(((fist_index_in_ccw + 1) % intersection.size()) == second_index_in_ccw);
// don't merge on degree two, since it's most likely a bollard/traffic light or a round way
if (intersection.size() <= 2)
return false;
const auto can_merge = mergable_road_detector.CanMergeRoad(
intersection_node, intersection[fist_index_in_ccw], intersection[second_index_in_ccw]);
/*
* Merging should never depend on order/never merge more than two roads. To ensure that we don't
* merge anything that is impacted by neighboring roads (e.g. three roads of the same name as in
* parking lots/border checkpoints), we check if the neigboring roads would be merged as well.
* In that case, we cannot merge, since we would end up merging multiple items together
*/
const auto is_distinct = [&]() {
const auto next_index_in_ccw = (second_index_in_ccw + 1) % intersection.size();
const auto distinct_to_next_in_ccw = mergable_road_detector.IsDistinctFrom(
intersection[second_index_in_ccw], intersection[next_index_in_ccw]);
const auto prev_index_in_ccw =
(fist_index_in_ccw + intersection.size() - 1) % intersection.size();
const auto distinct_to_prev_in_ccw = mergable_road_detector.IsDistinctFrom(
intersection[prev_index_in_ccw], intersection[fist_index_in_ccw]);
return distinct_to_next_in_ccw && distinct_to_prev_in_ccw;
};
// use lazy evaluation to check only if mergable
return can_merge && is_distinct();
}
IntersectionNormalizationOperation
IntersectionNormalizer::DetermineMergeDirection(const IntersectionShapeData &lhs,
const IntersectionShapeData &rhs) const
{
if (node_based_graph.GetEdgeData(lhs.eid).reversed)
return {lhs.eid, rhs.eid};
else
return {rhs.eid, lhs.eid};
}
IntersectionShapeData IntersectionNormalizer::MergeRoads(const IntersectionShapeData &into,
const IntersectionShapeData &from) const
{
// we only merge small angles. If the difference between both is large, we are looking at a
// bearing leading north. Such a bearing cannot be handled via the basic average. In this
// case we actually need to shift the bearing by half the difference.
const auto aroundZero = [](const double first, const double second) {
return (std::max(first, second) - std::min(first, second)) >= 180;
};
// find the angle between two other angles
const auto combineAngles = [aroundZero](const double first, const double second) {
if (!aroundZero(first, second))
return .5 * (first + second);
else
{
const auto offset = angularDeviation(first, second);
auto new_angle = std::max(first, second) + .5 * offset;
if (new_angle >= 360)
return new_angle - 360;
return new_angle;
}
};
auto result = into;
BOOST_ASSERT(!node_based_graph.GetEdgeData(into.eid).reversed);
result.bearing = combineAngles(into.bearing, from.bearing);
BOOST_ASSERT(0 <= result.bearing && result.bearing < 360.0);
return result;
}
IntersectionShapeData
IntersectionNormalizer::MergeRoads(const IntersectionNormalizationOperation direction,
const IntersectionShapeData &lhs,
const IntersectionShapeData &rhs,
const double opposite_bearing) const
{
// In some intersections, turning roads can introduce artificial turns if we merge here.
// Consider a scenario like:
// 
// a . g - f
// | .
// | .
// |.
// d-b--------e
// |
// c
// 
// Merging `bgf` and `be` would introduce an angle, even though d-b-e is perfectly straight
// We don't change the angle, if such an opposite road exists
if (direction.merged_eid == lhs.eid)
{
// change the angle only if the opposite direction is not nearly straight
if (angularDeviation(opposite_bearing, rhs.bearing) >
(STRAIGHT_ANGLE - MAXIMAL_ALLOWED_NO_TURN_DEVIATION))
return rhs;
else
return MergeRoads(rhs, lhs);
}
else
{
if (angularDeviation(opposite_bearing, lhs.bearing) >
(STRAIGHT_ANGLE - MAXIMAL_ALLOWED_NO_TURN_DEVIATION))
return lhs;
else
return MergeRoads(lhs, rhs);
}
}
/*
* Segregated Roads often merge onto a single intersection.
* While technically representing different roads, they are
* often looked at as a single road.
* Due to the merging, turn Angles seem off, wenn we compute them from the
* initial positions.
*
* b<b<b<b(1)<b<b<b
* aaaaa-b
* b>b>b>b(2)>b>b>b
*
* Would be seen as a slight turn going fro a to (2). A Sharp turn going from
* (1) to (2).
*
* In cases like these, we megre this segregated roads into a single road to
* end up with a case like:
*
* aaaaa-bbbbbb
*
* for the turn representation.
* Anything containing the first u-turn in a merge affects all other angles
* and is handled separately from all others.
*/
IntersectionNormalizer::NormalizationResult
IntersectionNormalizer::MergeSegregatedRoads(const NodeID intersection_node,
IntersectionShape intersection) const
{
const auto getRight = [&](std::size_t index) {
return (index + intersection.size() - 1) % intersection.size();
};
// This map stores for all edges that participated in a merging operation in which edge id they
// end up in the end. We only store what we have merged into other edges.
std::vector<IntersectionNormalizationOperation> merging_map;
const auto merge = [this, &merging_map](const IntersectionShapeData &first,
const IntersectionShapeData &second,
const double opposite_bearing) {
const auto direction = DetermineMergeDirection(first, second);
BOOST_ASSERT(
std::find_if(merging_map.begin(), merging_map.end(), [direction](const auto pair) {
return pair.merged_eid == direction.merged_eid;
}) == merging_map.end());
merging_map.push_back(direction);
return MergeRoads(direction, first, second, opposite_bearing);
};
if (intersection.size() <= 1)
return {intersection, merging_map};
const auto intersection_copy = intersection;
const auto opposite_bearing = [this, intersection_copy](const IntersectionShapeData &lhs,
const IntersectionShapeData &rhs) {
if (node_based_graph.GetEdgeData(lhs.eid).reversed)
{
return intersection_copy.FindClosestBearing(util::bearing::reverse(rhs.bearing))
->bearing;
}
else
{
BOOST_ASSERT(node_based_graph.GetEdgeData(rhs.eid).reversed);
return intersection_copy.FindClosestBearing(util::bearing::reverse(lhs.bearing))
->bearing;
}
};
// check for merges including the basic u-turn
// these result in an adjustment of all other angles. This is due to how these angles are
// perceived. Considering the following example:
//
// c b
// Y
// a
//
// coming from a to b (given a road that splits at the fork into two one-ways), the turn is not
// considered as a turn but rather as going straight.
// Now if we look at the situation merging:
//
// a b
// \ /
// e - + - d
// |
// c
//
// With a,b representing the same road, the intersection itself represents a classif for way
// intersection so we handle it like
//
// (a),b
// |
// e - + - d
// |
// c
//
// To be able to consider this adjusted representation down the line, we merge some roads.
// If the merge occurs at the u-turn edge, we need to adjust all angles, though, since they are
// with respect to the now changed perceived location of a. If we move (a) to the left, we add
// the difference to all angles. Otherwise we subtract it.
// these result in an adjustment of all other angles
if (CanMerge(intersection_node, intersection, intersection.size() - 1, 0))
{
// moving `a` to the left
const auto opposite = opposite_bearing(intersection.front(), intersection.back());
intersection[0] = merge(intersection.front(), intersection.back(), opposite);
// FIXME if we have a left-sided country, we need to switch this off and enable it
// below
intersection.pop_back();
}
else if (CanMerge(intersection_node, intersection, 0, 1))
{
const auto opposite = opposite_bearing(intersection.front(), intersection[1]);
intersection[0] = merge(intersection.front(), intersection[1], opposite);
intersection.erase(intersection.begin() + 1);
}
// a merge including the first u-turn requires an adjustment of the turn angles
// therefore these are handled prior to this step
for (std::size_t index = 2; index < intersection.size(); ++index)
{
if (CanMerge(intersection_node, intersection, getRight(index), index))
{
const auto opposite =
opposite_bearing(intersection[getRight(index)], intersection[index]);
intersection[getRight(index)] =
merge(intersection[getRight(index)], intersection[index], opposite);
intersection.erase(intersection.begin() + index);
--index;
}
}
return {intersection, merging_map};
}
// OSM can have some very steep angles for joining roads. Considering the following intersection:
// x
// |
// v __________c
// /
// a ---d
// \ __________b
//
// with c->d as a oneway
// and d->b as a oneway, the turn von x->d is actually a turn from x->a. So when looking at the
// intersection coming from x, we want to interpret the situation as
// x
// |
// a __ d __ v__________c
// |
// |_______________b
//
// Where we see the turn to `d` as a right turn, rather than going straight.
// We do this by adjusting the local turn angle at `x` to turn onto `d` to be reflective of this
// situation, where `v` would be the node at the intersection.
IntersectionShape
IntersectionNormalizer::AdjustBearingsForMergeAtDestination(const NodeID node_at_intersection,
IntersectionShape intersection) const
{
// nothing to do for dead ends
if (intersection.size() <= 1)
return intersection;
// we don't adjust any road that is longer than 30 meters (between centers of intersections),
// since the road is probably too long otherwise to impact perception.
const double constexpr PRUNING_DISTANCE = 30;
// never adjust u-turns
for (std::size_t index = 0; index < intersection.size(); ++index)
{
auto &road = intersection[index];
// only consider roads that are close
if (road.segment_length > PRUNING_DISTANCE)
continue;
// to find out about the above situation, we need to look at the next intersection (at d in
// the example). If the initial road can be merged to the left/right, we are about to adjust
// the angle.
const auto next_intersection_along_road = intersection_generator.ComputeIntersectionShape(
node_based_graph.GetTarget(road.eid), node_at_intersection);
if (next_intersection_along_road.size() <= 1)
continue;
const auto node_at_next_intersection = node_based_graph.GetTarget(road.eid);
const auto adjustAngle = [](double angle, double offset) {
angle += offset;
if (angle > 360)
return angle - 360.;
else if (angle < 0)
return angle + 360.;
return angle;
};
const auto range = node_based_graph.GetAdjacentEdgeRange(node_at_next_intersection);
if (range.size() <= 1)
continue;
// the order does not matter
const auto get_offset = [](const IntersectionShapeData &lhs,
const IntersectionShapeData &rhs) {
return 0.5 * angularDeviation(lhs.bearing, rhs.bearing);
};
// When offsetting angles in our turns, we don't want to get past the next turn. This
// function simply limits an offset to be at most half the distance to the next turn in the
// offfset direction
const auto get_corrected_offset = [](
const double offset,
const IntersectionShapeData &road,
const IntersectionShapeData &next_road_in_offset_direction) {
const auto offset_limit =
angularDeviation(road.bearing, next_road_in_offset_direction.bearing);
// limit the offset with an additional buffer
return (offset + MAXIMAL_ALLOWED_NO_TURN_DEVIATION > offset_limit) ? 0.5 * offset_limit
: offset;
};
// only if straighmost angles get smaller, we consider it an improvement
auto const improves_straightmost = [&](auto const index, auto const offset) {
const auto itr = next_intersection_along_road.FindClosestBearing(
util::bearing::reverse(next_intersection_along_road[index].bearing));
const auto angle = util::bearing::angleBetween(
util::bearing::reverse(itr->bearing), next_intersection_along_road[index].bearing);
return util::angularDeviation(angle, STRAIGHT_ANGLE) >
util::angularDeviation(angle + offset, STRAIGHT_ANGLE);
};
// check if the u-turn edge at the next intersection could be merged to the left/right. If
// this is the case and the road is not far away (see previous distance check), if
// influences the perceived angle.
if (CanMerge(node_at_next_intersection, next_intersection_along_road, 0, 1))
{
const auto offset =
get_offset(next_intersection_along_road[0], next_intersection_along_road[1]);
if (improves_straightmost(0, -offset) && improves_straightmost(1, offset))
{
const auto corrected_offset = get_corrected_offset(
offset,
road,
intersection[(intersection.size() + index - 1) % intersection.size()]);
// at the target intersection, we merge to the right, so we need to shift the
// current
// angle to the left
road.bearing = adjustAngle(road.bearing, corrected_offset);
}
}
else if (CanMerge(node_at_next_intersection,
next_intersection_along_road,
next_intersection_along_road.size() - 1,
0))
{
const auto offset =
get_offset(next_intersection_along_road[0],
next_intersection_along_road[next_intersection_along_road.size() - 1]);
if (improves_straightmost(0, offset) &&
improves_straightmost(next_intersection_along_road.size() - 1, -offset))
{
const auto corrected_offset = get_corrected_offset(
offset, road, intersection[(index + 1) % intersection.size()]);
// at the target intersection, we merge to the left, so we need to shift the current
// angle to the right
road.bearing = adjustAngle(road.bearing, -corrected_offset);
}
}
}
return intersection;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
+52 -105
View File
@@ -1,7 +1,8 @@
#include "extractor/guidance/mergable_road_detector.hpp"
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/node_based_graph_walker.hpp"
#include "extractor/intersection/intersection_analysis.hpp"
#include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp"
@@ -22,8 +23,6 @@ namespace guidance
namespace
{
// check a connected road for equality of a name
// returns 'true' if no equality because this is used as a filter elsewhere, i.e. filter if fn
// returns 'true'
inline auto makeCheckRoadForName(const NameID name_id,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
@@ -33,40 +32,32 @@ inline auto makeCheckRoadForName(const NameID name_id,
return [name_id, &node_based_graph, &node_data_container, &name_table, &suffix_table](
const MergableRoadDetector::MergableRoadData &road) {
// since we filter here, we don't want any other name than the one we are looking for
const auto road_name_id =
const auto road_name =
node_data_container
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
.name_id;
const auto road_name_empty = name_table.GetNameForID(road_name_id).empty();
const auto in_name_empty = name_table.GetNameForID(name_id).empty();
if (in_name_empty || road_name_empty)
if (name_id == EMPTY_NAMEID || road_name == EMPTY_NAMEID)
return true;
const auto requires_announcement =
util::guidance::requiresNameAnnounced(
name_id, road_name_id, name_table, suffix_table) ||
util::guidance::requiresNameAnnounced(road_name_id, name_id, name_table, suffix_table);
util::guidance::requiresNameAnnounced(name_id, road_name, name_table, suffix_table) ||
util::guidance::requiresNameAnnounced(road_name, name_id, name_table, suffix_table);
return requires_announcement;
};
}
}
MergableRoadDetector::MergableRoadDetector(
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
MergableRoadDetector::MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const IntersectionGenerator &intersection_generator,
const CoordinateExtractor &coordinate_extractor,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
: node_based_graph(node_based_graph), node_data_container(node_data_container),
node_coordinates(node_coordinates), compressed_geometries(compressed_geometries),
node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes),
turn_lanes_data(turn_lanes_data), name_table(name_table),
street_name_suffix_table(street_name_suffix_table),
coordinate_extractor(node_based_graph, compressed_geometries, node_coordinates)
node_coordinates(node_coordinates), intersection_generator(intersection_generator),
coordinate_extractor(coordinate_extractor), name_table(name_table),
street_name_suffix_table(street_name_suffix_table)
{
}
@@ -122,6 +113,16 @@ bool MergableRoadDetector::CanMergeRoad(const NodeID intersection_node,
!IsCircularShape(intersection_node, lhs, rhs);
}
bool MergableRoadDetector::HaveIdenticalNames(const NameID lhs, const NameID rhs) const
{
const auto non_empty = (lhs != EMPTY_NAMEID) && (rhs != EMPTY_NAMEID);
// symmetrical check for announcements
return non_empty &&
!util::guidance::requiresNameAnnounced(lhs, rhs, name_table, street_name_suffix_table) &&
!util::guidance::requiresNameAnnounced(rhs, lhs, name_table, street_name_suffix_table);
}
bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
const MergableRoadData &rhs) const
{
@@ -133,9 +134,7 @@ bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
.name_id,
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(rhs.eid).annotation_data)
.name_id,
name_table,
street_name_suffix_table);
.name_id);
}
bool MergableRoadDetector::EdgeDataSupportsMerge(
@@ -157,8 +156,7 @@ bool MergableRoadDetector::EdgeDataSupportsMerge(
return false;
// we require valid names
if (!HaveIdenticalNames(
lhs_annotation.name_id, rhs_annotation.name_id, name_table, street_name_suffix_table))
if (!HaveIdenticalNames(lhs_annotation.name_id, rhs_annotation.name_id))
return false;
return lhs_flags.road_classification == rhs_flags.road_classification;
@@ -167,9 +165,8 @@ bool MergableRoadDetector::EdgeDataSupportsMerge(
bool MergableRoadDetector::IsTrafficLoop(const NodeID intersection_node,
const MergableRoadData &road) const
{
const auto connection =
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, road.eid});
return intersection_node == node_based_graph.GetTarget(connection.edge);
const auto connection = intersection_generator.SkipDegreeTwoNodes(intersection_node, road.eid);
return intersection_node == node_based_graph.GetTarget(connection.via_eid);
}
bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
@@ -178,22 +175,8 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
{
// selection data to the right and left
const auto constexpr SMALL_RANDOM_HOPLIMIT = 5;
IntersectionFinderAccumulator left_accumulator(SMALL_RANDOM_HOPLIMIT,
node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data),
right_accumulator(SMALL_RANDOM_HOPLIMIT,
node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data);
IntersectionFinderAccumulator left_accumulator(SMALL_RANDOM_HOPLIMIT, intersection_generator),
right_accumulator(SMALL_RANDOM_HOPLIMIT, intersection_generator);
/* Standard following the straightmost road
* Since both items have the same id, we can `select` based on any setup
@@ -205,13 +188,8 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
/*requires entry=*/false,
false);
NodeBasedGraphWalker graph_walker(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data);
NodeBasedGraphWalker graph_walker(
node_based_graph, node_data_container, intersection_generator);
graph_walker.TraverseRoad(intersection_node, lhs.eid, left_accumulator, selector);
/* if the intersection does not have a right turn, we continue onto the next one once
* (skipping over a single small side street)
@@ -283,13 +261,7 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
// check if both intersections are connected
IntersectionFinderAccumulator connect_accumulator(SMALL_RANDOM_HOPLIMIT,
node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data);
intersection_generator);
graph_walker.TraverseRoad(node_based_graph.GetTarget(left_accumulator.via_edge_id),
connector_turn->eid,
connect_accumulator,
@@ -304,13 +276,8 @@ bool MergableRoadDetector::IsCircularShape(const NodeID intersection_node,
const MergableRoadData &lhs,
const MergableRoadData &rhs) const
{
NodeBasedGraphWalker graph_walker(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data);
NodeBasedGraphWalker graph_walker(
node_based_graph, node_data_container, intersection_generator);
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
SelectStraightmostRoadByNameAndOnlyChoice selector(
@@ -376,13 +343,8 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
return false;
// Find a coordinate following a road that is far away
NodeBasedGraphWalker graph_walker(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data);
NodeBasedGraphWalker graph_walker(
node_based_graph, node_data_container, intersection_generator);
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
SelectStraightmostRoadByNameAndOnlyChoice selector(
@@ -452,16 +414,10 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
return false;
// compare reference distance:
const auto distance_mid_left_to_right = util::coordinate_calculation::findClosestDistance(
const auto distance_between_roads = util::coordinate_calculation::findClosestDistance(
coordinates_to_the_left[coordinates_to_the_left.size() / 2],
coordinates_to_the_right.begin(),
coordinates_to_the_right.end());
const auto distance_mid_right_to_left = util::coordinate_calculation::findClosestDistance(
coordinates_to_the_right[coordinates_to_the_right.size() / 2],
coordinates_to_the_left.begin(),
coordinates_to_the_left.end());
const auto distance_between_roads =
std::min(distance_mid_left_to_right, distance_mid_right_to_left);
const auto lane_count_lhs = std::max<int>(
1, node_based_graph.GetEdgeData(lhs.eid).flags.road_classification.GetNumberOfLanes());
@@ -482,12 +438,12 @@ bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node,
* location with the same name repeatet at least three times
*/
const auto left_connection =
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, lhs.eid});
intersection_generator.SkipDegreeTwoNodes(intersection_node, lhs.eid);
const auto right_connection =
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, rhs.eid});
intersection_generator.SkipDegreeTwoNodes(intersection_node, rhs.eid);
const auto left_candidate = node_based_graph.GetTarget(left_connection.edge);
const auto right_candidate = node_based_graph.GetTarget(right_connection.edge);
const auto left_candidate = node_based_graph.GetTarget(left_connection.via_eid);
const auto right_candidate = node_based_graph.GetTarget(right_connection.via_eid);
const auto candidate_is_valid =
left_candidate == right_candidate && left_candidate != intersection_node;
@@ -509,18 +465,16 @@ bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node,
.name_id;
const auto has_required_name = [this, required_name_id](const auto edge_id) {
const auto road_name_id =
const auto road_name =
node_data_container
.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
.name_id;
const auto &road_name_empty = name_table.GetNameForID(road_name_id).empty();
const auto &required_name_empty = name_table.GetNameForID(required_name_id).empty();
if (required_name_empty && road_name_empty)
if (required_name_id == EMPTY_NAMEID || road_name == EMPTY_NAMEID)
return false;
return !util::guidance::requiresNameAnnounced(
required_name_id, road_name_id, name_table, street_name_suffix_table) ||
required_name_id, road_name, name_table, street_name_suffix_table) ||
!util::guidance::requiresNameAnnounced(
road_name_id, required_name_id, name_table, street_name_suffix_table);
road_name, required_name_id, name_table, street_name_suffix_table);
};
/* the beautiful way would be:
@@ -555,16 +509,9 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node,
const MergableRoadData &road) const
{
const auto next_intersection_parameters =
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, road.eid});
const auto next_intersection_along_road =
intersection::getConnectedRoads<false>(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
next_intersection_parameters);
intersection_generator.SkipDegreeTwoNodes(intersection_node, road.eid);
const auto next_intersection_along_road = intersection_generator.GetConnectedRoads(
next_intersection_parameters.nid, next_intersection_parameters.via_eid);
const auto extract_name_id = [this](const MergableRoadData &road) {
return node_data_container
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
@@ -589,7 +536,7 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node,
// we cannot be looking at the same road we came from
if (node_based_graph.GetTarget(opposite_of_next_road_along_path->eid) ==
next_intersection_parameters.node)
next_intersection_parameters.nid)
return false;
/* check if the opposite of the next road decision was sane. It could have been just as well our
+25 -61
View File
@@ -2,7 +2,6 @@
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/road_classification.hpp"
#include "util/assert.hpp"
#include "util/bearing.hpp"
#include "util/guidance/name_announcements.hpp"
@@ -43,21 +42,15 @@ inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_base
MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator)
: IntersectionHandler(node_based_graph,
node_data_container,
coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
name_table,
street_name_suffix_table)
street_name_suffix_table,
intersection_generator)
{
}
@@ -239,12 +232,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
intersection[1].instruction =
getInstructionForObvious(intersection.size(),
via_eid,
isThroughStreet(1,
intersection,
node_based_graph,
node_data_container,
name_table,
street_name_suffix_table),
isThroughStreet(1, intersection),
intersection[1]);
}
else
@@ -258,16 +246,8 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
if (road.angle == continue_angle)
{
road.instruction =
getInstructionForObvious(intersection.size(),
via_eid,
isThroughStreet(1,
intersection,
node_based_graph,
node_data_container,
name_table,
street_name_suffix_table),
road);
road.instruction = getInstructionForObvious(
intersection.size(), via_eid, isThroughStreet(1, intersection), road);
}
else if (road.angle < continue_angle)
{
@@ -291,11 +271,17 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
// handle motorway forks
else if (exiting_motorways > 1)
{
if (exiting_motorways == 2)
if (exiting_motorways == 2 && intersection.size() == 2)
{
intersection[1].instruction =
getInstructionForObvious(intersection.size(),
via_eid,
isThroughStreet(1, intersection),
intersection[1]);
intersection[0].entry_allowed = false; // UTURN on the freeway
}
else if (exiting_motorways == 2)
{
OSRM_ASSERT(intersection.size() != 2,
node_coordinates[node_based_graph.GetTarget(via_eid)]);
// standard fork
std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
second_valid = std::numeric_limits<std::size_t>::max();
@@ -366,16 +352,8 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
BOOST_ASSERT(!intersection[0].entry_allowed);
BOOST_ASSERT(isMotorwayClass(intersection[1].eid, node_based_graph));
intersection[1].instruction =
getInstructionForObvious(intersection.size(),
via_eid,
isThroughStreet(1,
intersection,
node_based_graph,
node_data_container,
name_table,
street_name_suffix_table),
intersection[1]);
intersection[1].instruction = getInstructionForObvious(
intersection.size(), via_eid, isThroughStreet(1, intersection), intersection[1]);
}
else if (intersection.size() == 3)
{
@@ -401,15 +379,11 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
//
// 7 1
// 0
const auto &first_intersection_name_empty =
name_table.GetNameForID(first_intersection_data.name_id).empty();
const auto &second_intersection_name_empty =
name_table.GetNameForID(second_intersection_data.name_id).empty();
if (intersection[1].entry_allowed)
{
if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
!second_intersection_name_empty && !first_intersection_name_empty &&
first_second_same_name)
second_intersection_data.name_id != EMPTY_NAMEID &&
first_intersection_data.name_id != EMPTY_NAMEID && first_second_same_name)
{
// circular order indicates a merge to the left (0-3 onto 4
if (angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) <
@@ -425,12 +399,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
intersection[1].instruction =
getInstructionForObvious(intersection.size(),
via_eid,
isThroughStreet(1,
intersection,
node_based_graph,
node_data_container,
name_table,
street_name_suffix_table),
isThroughStreet(1, intersection),
intersection[1]);
}
}
@@ -438,8 +407,8 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
{
BOOST_ASSERT(intersection[2].entry_allowed);
if (isMotorwayClass(intersection[2].eid, node_based_graph) &&
!second_intersection_name_empty && !first_intersection_name_empty &&
first_second_same_name)
second_intersection_data.name_id != EMPTY_NAMEID &&
first_intersection_data.name_id != EMPTY_NAMEID && first_second_same_name)
{
// circular order (5-0) onto 4
if (angularDeviation(intersection[2].angle, STRAIGHT_ANGLE) <
@@ -455,12 +424,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
intersection[2].instruction =
getInstructionForObvious(intersection.size(),
via_eid,
isThroughStreet(2,
intersection,
node_based_graph,
node_data_container,
name_table,
street_name_suffix_table),
isThroughStreet(2, intersection),
intersection[2]);
}
}
@@ -1,5 +1,4 @@
#include "extractor/guidance/node_based_graph_walker.hpp"
#include "extractor/intersection/intersection_analysis.hpp"
#include "util/bearing.hpp"
#include "util/coordinate_calculation.hpp"
@@ -15,18 +14,11 @@ namespace guidance
{
// ---------------------------------------------------------------------------------
NodeBasedGraphWalker::NodeBasedGraphWalker(
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data)
NodeBasedGraphWalker::NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const IntersectionGenerator &intersection_generator)
: node_based_graph(node_based_graph), node_data_container(node_data_container),
node_coordinates(node_coordinates), compressed_geometries(compressed_geometries),
node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes),
turn_lanes_data(turn_lanes_data)
intersection_generator(intersection_generator)
{
}
@@ -243,18 +235,8 @@ operator()(const NodeID /*nid*/,
// ---------------------------------------------------------------------------------
IntersectionFinderAccumulator::IntersectionFinderAccumulator(
const std::uint8_t hop_limit,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data)
: hops(0), hop_limit(hop_limit), node_based_graph(node_based_graph),
node_data_container(node_data_container), node_coordinates(node_coordinates),
compressed_geometries(compressed_geometries), node_restriction_map(node_restriction_map),
barrier_nodes(barrier_nodes), turn_lanes_data(turn_lanes_data)
const std::uint8_t hop_limit, const IntersectionGenerator &intersection_generator)
: hops(0), hop_limit(hop_limit), intersection_generator(intersection_generator)
{
}
@@ -279,14 +261,7 @@ void IntersectionFinderAccumulator::update(const NodeID from_node,
nid = from_node;
via_edge_id = via_edge;
intersection = intersection::getConnectedRoads<true>(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
{from_node, via_edge});
intersection = intersection_generator.GetConnectedRoads(from_node, via_edge, true);
}
} // namespace guidance
+91 -32
View File
@@ -23,26 +23,21 @@ namespace extractor
namespace guidance
{
RoundaboutHandler::RoundaboutHandler(
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const CompressedEdgeContainer &compressed_edge_container,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table,
const IntersectionGenerator &intersection_generator)
: IntersectionHandler(node_based_graph,
node_data_container,
coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
name_table,
street_name_suffix_table),
coordinate_extractor(node_based_graph, compressed_geometries, coordinates)
street_name_suffix_table,
intersection_generator),
compressed_edge_container(compressed_edge_container),
coordinate_extractor(node_based_graph, compressed_edge_container, coordinates)
{
}
@@ -61,6 +56,7 @@ bool RoundaboutHandler::canProcess(const NodeID from_nid,
Intersection RoundaboutHandler::
operator()(const NodeID from_nid, const EdgeID via_eid, Intersection intersection) const
{
invalidateExitAgainstDirection(from_nid, via_eid, intersection);
const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection);
const auto roundabout_type = getRoundaboutType(node_based_graph.GetTarget(via_eid));
// find the radius of the roundabout
@@ -111,6 +107,77 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
return {on_roundabout, can_enter_roundabout, can_exit_roundabout_separately};
}
void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
const EdgeID via_eid,
Intersection &intersection) const
{
const auto &in_edge_class = node_based_graph.GetEdgeData(via_eid).flags;
if (in_edge_class.roundabout || in_edge_class.circular)
return;
// Find range in which exits that must be invalidated (shaded areas):
// exit..end exit..end begin..exit for ↺ roundabouts
// *************************************
// * <--. ^ <--. / <--. *
// * | / | /░ | *
// * |/ |v░░ -->| *
// * |^ |\ ░ ░░░|\ *
// * |░\ |░\░ ░░░| \ *
// * --'░░░\ --'░░░v --' v *
// *************************************
//
// begin..exit begin..exit exit..end for ↻ roundabouts
// *************************************
// * --.░░░^ --.░░░/ --. ^ *
// * |░/░ |░/ ░░░| / *
// * |/░░ |v ░░░|/ *
// * |^░░ |\ -->| *
// * | \░ | \ | *
// * <--' \ <--' v <--' *
// *************************************
bool roundabout_entry_first = false;
auto invalidate_from = intersection.end(), invalidate_to = intersection.end();
for (auto road = intersection.begin(); road != intersection.end(); ++road)
{
const auto &edge = node_based_graph.GetEdgeData(road->eid);
if (edge.flags.roundabout || edge.flags.circular)
{
if (edge.reversed)
{
if (roundabout_entry_first)
{ // invalidate turns in range exit..end
invalidate_from = road + 1;
invalidate_to = intersection.end();
}
else
{ // invalidate turns in range begin..exit
invalidate_from = intersection.begin() + 1;
invalidate_to = road;
}
}
else
{
roundabout_entry_first = true;
}
}
}
OSRM_ASSERT(invalidate_from <= invalidate_to, coordinates[from_nid]);
// Exiting roundabouts at an entry point is technically a data-modelling issue.
// This workaround handles cases in which an exit precedes and entry. The resulting
// u-turn against the roundabout direction is invalidated.
for (; invalidate_from != invalidate_to; ++invalidate_from)
{
const auto &edge = node_based_graph.GetEdgeData(invalidate_from->eid);
if (!edge.flags.roundabout && !edge.flags.circular &&
node_based_graph.GetTarget(invalidate_from->eid) != from_nid)
{
invalidate_from->entry_allowed = false;
}
}
}
// If we want to see a roundabout as a turn, the exits have to be distinct enough to be seen a
// dedicated turns. We are limiting it to four-way intersections with well distinct bearings.
// All entry/roads and exit roads have to be simple. Not segregated roads.
@@ -148,7 +215,7 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
continue;
// there is a single non-roundabout edge
const auto src_coordinate = node_coordinates[node];
const auto src_coordinate = coordinates[node];
const auto edge_range = node_based_graph.GetAdjacentEdgeRange(node);
const auto number_of_lanes_at_intersection = std::accumulate(
@@ -228,8 +295,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
return SPECIAL_EDGEID;
}
const auto &edge_name_empty = name_table.GetNameForID(edge_data.name_id).empty();
if (!edge_name_empty)
if (EMPTY_NAMEID != edge_data.name_id)
{
const auto announce = [&](unsigned id) {
@@ -240,6 +306,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
if (std::all_of(begin(roundabout_name_ids), end(roundabout_name_ids), announce))
roundabout_name_ids.insert(edge_data.name_id);
}
continue_edge = edge_id;
}
else if (!edge.flags.roundabout && !edge.flags.circular)
@@ -267,11 +334,11 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
const auto getEdgeLength = [&](const NodeID source_node, EdgeID eid) {
double length = 0.;
auto last_coord = node_coordinates[source_node];
const auto &edge_bucket = compressed_geometries.GetBucketReference(eid);
auto last_coord = coordinates[source_node];
const auto &edge_bucket = compressed_edge_container.GetBucketReference(eid);
for (const auto &compressed_edge : edge_bucket)
{
const auto next_coord = node_coordinates[compressed_edge.node_id];
const auto next_coord = coordinates[compressed_edge.node_id];
length += util::coordinate_calculation::haversineDistance(last_coord, next_coord);
last_coord = next_coord;
}
@@ -478,16 +545,8 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
if (util::angularDeviation(turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE &&
crossing_roundabout)
{
turn.instruction =
getInstructionForObvious(intersection.size(),
via_eid,
isThroughStreet(idx,
intersection,
node_based_graph,
node_data_container,
name_table,
street_name_suffix_table),
turn);
turn.instruction = getInstructionForObvious(
intersection.size(), via_eid, isThroughStreet(idx, intersection), turn);
}
else
{
@@ -1,243 +0,0 @@
#include "extractor/guidance/segregated_intersection_classification.hpp"
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/node_based_graph_factory.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/name_table.hpp"
namespace osrm
{
namespace extractor
{
namespace guidance
{
struct EdgeInfo
{
NodeID node;
util::StringView name;
// 0 - outgoing (forward), 1 - incoming (reverse), 2 - both outgoing and incoming
int direction;
ClassData road_class;
RoadPriorityClass::Enum road_priority_class;
struct LessName
{
bool operator()(EdgeInfo const &e1, EdgeInfo const &e2) const { return e1.name < e2.name; }
};
};
bool IsSegregated(std::vector<EdgeInfo> v1,
std::vector<EdgeInfo> v2,
EdgeInfo const &current,
double edgeLength)
{
if (v1.size() < 2 || v2.size() < 2)
return false;
auto const sort_by_name_fn = [](std::vector<EdgeInfo> &v) {
std::sort(v.begin(), v.end(), EdgeInfo::LessName());
};
sort_by_name_fn(v1);
sort_by_name_fn(v2);
// Internal edge with the name should be connected with any other neibour edge with the same
// name, e.g. isolated edge with unique name is not segregated.
// b - 'b' road continues here
// |
// - - a - |
// b - segregated edge
// - - a - |
if (!current.name.empty())
{
auto const findNameFn = [&current](std::vector<EdgeInfo> const &v) {
return std::binary_search(v.begin(), v.end(), current, EdgeInfo::LessName());
};
if (!findNameFn(v1) && !findNameFn(v2))
return false;
}
// set_intersection like routine to get equal result pairs
std::vector<std::pair<EdgeInfo const *, EdgeInfo const *>> commons;
auto i1 = v1.begin();
auto i2 = v2.begin();
while (i1 != v1.end() && i2 != v2.end())
{
if (i1->name == i2->name)
{
if (!i1->name.empty())
commons.push_back(std::make_pair(&(*i1), &(*i2)));
++i1;
++i2;
}
else if (i1->name < i2->name)
++i1;
else
++i2;
}
if (commons.size() < 2)
return false;
auto const check_equal_class = [](std::pair<EdgeInfo const *, EdgeInfo const *> const &e) {
// Or (e.first->road_class & e.second->road_class != 0)
return e.first->road_class == e.second->road_class;
};
size_t equal_class_count = 0;
for (auto const &e : commons)
if (check_equal_class(e))
++equal_class_count;
if (equal_class_count < 2)
return false;
auto const get_length_threshold = [](EdgeInfo const *e) {
switch (e->road_priority_class)
{
case RoadPriorityClass::MOTORWAY:
case RoadPriorityClass::TRUNK:
return 30.0;
case RoadPriorityClass::PRIMARY:
return 20.0;
case RoadPriorityClass::SECONDARY:
case RoadPriorityClass::TERTIARY:
return 10.0;
default:
return 5.0;
}
};
double threshold = std::numeric_limits<double>::max();
for (auto const &e : commons)
threshold =
std::min(threshold, get_length_threshold(e.first) + get_length_threshold(e.second));
return edgeLength <= threshold;
}
std::unordered_set<EdgeID> findSegregatedNodes(const NodeBasedGraphFactory &factory,
const util::NameTable &names)
{
auto const &graph = factory.GetGraph();
auto const &annotation = factory.GetAnnotationData();
CoordinateExtractor coordExtractor(
graph, factory.GetCompressedEdges(), factory.GetCoordinates());
auto const get_edge_length = [&](NodeID from_node, EdgeID edgeID, NodeID to_node) {
auto const geom = coordExtractor.GetCoordinatesAlongRoad(from_node, edgeID, false, to_node);
double length = 0.0;
for (size_t i = 1; i < geom.size(); ++i)
{
length += util::coordinate_calculation::haversineDistance(geom[i - 1], geom[i]);
}
return length;
};
auto const get_edge_info = [&](NodeID node, auto const &edgeData) -> EdgeInfo {
/// @todo Make string normalization/lowercase/trim for comparison ...
auto const id = annotation[edgeData.annotation_data].name_id;
BOOST_ASSERT(id != INVALID_NAMEID);
auto const name = names.GetNameForID(id);
return {node,
name,
edgeData.reversed ? 1 : 0,
annotation[edgeData.annotation_data].classes,
edgeData.flags.road_classification.GetClass()};
};
auto const collect_edge_info_fn = [&](auto const &edges1, NodeID node2) {
std::vector<EdgeInfo> info;
for (auto const &e : edges1)
{
NodeID const target = graph.GetTarget(e);
if (target == node2)
continue;
info.push_back(get_edge_info(target, graph.GetEdgeData(e)));
}
if (info.empty())
return info;
std::sort(info.begin(), info.end(), [](EdgeInfo const &e1, EdgeInfo const &e2) {
return e1.node < e2.node;
});
// Merge equal infos with correct direction.
auto curr = info.begin();
auto next = curr;
while (++next != info.end())
{
if (curr->node == next->node)
{
BOOST_ASSERT(curr->name == next->name);
BOOST_ASSERT(curr->road_class == next->road_class);
BOOST_ASSERT(curr->direction != next->direction);
curr->direction = 2;
}
else
curr = next;
}
info.erase(
std::unique(info.begin(),
info.end(),
[](EdgeInfo const &e1, EdgeInfo const &e2) { return e1.node == e2.node; }),
info.end());
return info;
};
auto const isSegregatedFn = [&](auto const &edgeData,
auto const &edges1,
NodeID node1,
auto const &edges2,
NodeID node2,
double edgeLength) {
return IsSegregated(collect_edge_info_fn(edges1, node2),
collect_edge_info_fn(edges2, node1),
get_edge_info(node1, edgeData),
edgeLength);
};
std::unordered_set<EdgeID> segregated_edges;
for (NodeID sourceID = 0; sourceID < graph.GetNumberOfNodes(); ++sourceID)
{
auto const sourceEdges = graph.GetAdjacentEdgeRange(sourceID);
for (EdgeID edgeID : sourceEdges)
{
auto const &edgeData = graph.GetEdgeData(edgeID);
if (edgeData.reversed)
continue;
NodeID const targetID = graph.GetTarget(edgeID);
auto const targetEdges = graph.GetAdjacentEdgeRange(targetID);
double const length = get_edge_length(sourceID, edgeID, targetID);
if (isSegregatedFn(edgeData, sourceEdges, sourceID, targetEdges, targetID, length))
segregated_edges.insert(edgeID);
}
}
return segregated_edges;
}
}
}
}
+53 -61
View File
@@ -1,6 +1,5 @@
#include "extractor/guidance/sliproad_handler.hpp"
#include "extractor/guidance/constants.hpp"
#include "util/assert.hpp"
#include "util/bearing.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/name_announcements.hpp"
@@ -22,25 +21,18 @@ namespace extractor
namespace guidance
{
SliproadHandler::SliproadHandler(const util::NodeBasedDynamicGraph &node_based_graph,
SliproadHandler::SliproadHandler(const IntersectionGenerator &intersection_generator,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const std::vector<util::Coordinate> &coordinates,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
: IntersectionHandler(node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
coordinates,
name_table,
street_name_suffix_table),
coordinate_extractor(node_based_graph, compressed_geometries, node_coordinates)
street_name_suffix_table,
intersection_generator)
{
}
@@ -250,14 +242,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
// Starting out at the intersection and going onto the Sliproad we skip artificial
// degree two intersections and limit the max hop count in doing so.
IntersectionFinderAccumulator intersection_finder{10,
node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data};
IntersectionFinderAccumulator intersection_finder{10, intersection_generator};
const SkipTrafficSignalBarrierRoadSelector road_selector{};
(void)graph_walker.TraverseRoad(intersection_node_id, // start node
sliproad_edge, // onto edge
@@ -344,24 +329,9 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
}
// If the sliproad candidate is a through street, we cannot handle it as a sliproad.
auto sliproad_in_target_intersection =
std::find_if(begin(target_intersection),
end(target_intersection),
[&](const auto &road) { return road.eid == sliproad_edge; });
if (sliproad_in_target_intersection != target_intersection.end())
if (isThroughStreet(sliproad_edge, target_intersection))
{
auto index_of_sliproad_in_target_intersection =
sliproad_in_target_intersection - target_intersection.begin();
if (isThroughStreet<IntersectionView>(index_of_sliproad_in_target_intersection,
target_intersection,
node_based_graph,
node_data_container,
name_table,
street_name_suffix_table))
{
continue;
}
continue;
}
// The turn off of the Sliproad has to be obvious and a narrow turn and must not be a
@@ -401,6 +371,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
//
// Sliproad Not a Sliproad
{
const auto &coordinate_extractor = intersection_generator.GetCoordinateExtractor();
const NodeID start = intersection_node_id; // b
const EdgeID edge = sliproad_edge; // bd
@@ -451,8 +423,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
// Only check for curvature and ~90 degree when it makes sense to do so.
const constexpr auto MIN_LENGTH = 3.;
const auto length = haversineDistance(node_coordinates[intersection_node_id],
node_coordinates[main_road_intersection->node]);
const auto length = haversineDistance(coordinates[intersection_node_id],
coordinates[main_road_intersection->node]);
const double minimal_crossroad_angle_of_intersection = 40.;
@@ -502,7 +474,10 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
// Name mismatch: check roads at `c` and `d` for same name
const auto name_mismatch = [&](const NameID road_name_id) {
return util::guidance::requiresNameAnnounced(road_name_id, //
const auto unnamed = road_name_id == EMPTY_NAMEID;
return unnamed ||
util::guidance::requiresNameAnnounced(road_name_id, //
candidate_data.name_id, //
name_table, //
street_name_suffix_table); //
@@ -524,15 +499,11 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
node_data_container
.GetAnnotation(node_based_graph.GetEdgeData(main_road.eid).annotation_data)
.name_id;
const auto main_road_name_empty = name_table.GetNameForID(main_road_name_id).empty();
const auto &sliproad_annotation =
node_data_container.GetAnnotation(sliproad_edge_data.annotation_data);
const auto sliproad_name_empty =
name_table.GetNameForID(sliproad_annotation.name_id).empty();
const auto candidate_road_name_empty =
name_table.GetNameForID(candidate_data.name_id).empty();
if (!sliproad_edge_data.flags.road_classification.IsLinkClass() &&
!sliproad_name_empty && !main_road_name_empty && !candidate_road_name_empty &&
sliproad_annotation.name_id != EMPTY_NAMEID && main_road_name_id != EMPTY_NAMEID &&
candidate_data.name_id != EMPTY_NAMEID &&
util::guidance::requiresNameAnnounced(main_road_name_id,
sliproad_annotation.name_id,
name_table,
@@ -573,15 +544,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
}
else
{
const auto skip_traffic_light_intersection = intersection::getConnectedRoads<false>(
node_based_graph,
node_data_container,
node_coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
{node_based_graph.GetTarget(sliproad_edge), candidate_road.eid});
const auto skip_traffic_light_intersection = intersection_generator(
node_based_graph.GetTarget(sliproad_edge), candidate_road.eid);
if (skip_traffic_light_intersection.isTrafficSignalOrBarrier() &&
node_based_graph.GetTarget(skip_traffic_light_intersection[1].eid) ==
main_road_intersection->node)
@@ -611,7 +575,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
intersection[*obvious].instruction.direction_modifier =
getTurnDirection(intersection[*obvious].angle);
}
else if (!name_table.GetNameForID(main_annotation.name_id).empty())
else if (main_annotation.name_id != EMPTY_NAMEID)
{
intersection[*obvious].instruction.type = TurnType::NewName;
intersection[*obvious].instruction.direction_modifier =
@@ -690,6 +654,8 @@ bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const Edg
BOOST_ASSERT(start != SPECIAL_NODEID);
BOOST_ASSERT(onto != SPECIAL_EDGEID);
const auto &coordinate_extractor = intersection_generator.GetCoordinateExtractor();
// Base max distance threshold on the current road class we're on
const auto &data = node_based_graph.GetEdgeData(onto).flags;
const auto threshold = scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, // <- scales down
@@ -704,6 +670,32 @@ bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const Edg
return accumulator.too_far_away;
}
bool SliproadHandler::isThroughStreet(const EdgeID from, const IntersectionView &intersection) const
{
BOOST_ASSERT(from != SPECIAL_EDGEID);
BOOST_ASSERT(!intersection.empty());
const auto from_annotation_id = node_based_graph.GetEdgeData(from).annotation_data;
const auto &edge_name_id = node_data_container.GetAnnotation(from_annotation_id).name_id;
auto first = begin(intersection) + 1; // Skip UTurn road
auto last = end(intersection);
auto same_name = [&](const auto &road) {
const auto annotation_id = node_based_graph.GetEdgeData(road.eid).annotation_data;
const auto &road_name_id = node_data_container.GetAnnotation(annotation_id).name_id;
return edge_name_id != EMPTY_NAMEID && //
road_name_id != EMPTY_NAMEID && //
!util::guidance::requiresNameAnnounced(edge_name_id,
road_name_id,
name_table,
street_name_suffix_table); //
};
return std::find_if(first, last, same_name) != last;
}
bool SliproadHandler::roadContinues(const EdgeID current, const EdgeID next) const
{
const auto &current_data =
@@ -734,9 +726,9 @@ bool SliproadHandler::isValidSliproadArea(const double max_area,
{
using namespace util::coordinate_calculation;
const auto first = node_coordinates[a];
const auto second = node_coordinates[b];
const auto third = node_coordinates[c];
const auto first = coordinates[a];
const auto second = coordinates[b];
const auto third = coordinates[c];
const auto length = haversineDistance(first, second);
const auto heigth = haversineDistance(second, third);
@@ -11,25 +11,18 @@ namespace extractor
namespace guidance
{
SuppressModeHandler::SuppressModeHandler(
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const extractor::CompressedEdgeContainer &compressed_geometries,
const RestrictionMap &node_restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
SuppressModeHandler::SuppressModeHandler(const IntersectionGenerator &intersection_generator,
const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &coordinates,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
: IntersectionHandler(node_based_graph,
node_data_container,
coordinates,
compressed_geometries,
node_restriction_map,
barrier_nodes,
turn_lanes_data,
name_table,
street_name_suffix_table)
street_name_suffix_table,
intersection_generator)
{
}
+76 -48
View File
@@ -23,79 +23,89 @@ using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
const EdgeBasedNodeDataContainer &node_data_container,
const std::vector<util::Coordinate> &node_coordinates,
const CompressedEdgeContainer &compressed_edge_container,
const std::vector<util::Coordinate> &coordinates,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const guidance::TurnLanesIndexedArray &turn_lanes_data,
const CompressedEdgeContainer &compressed_edge_container,
const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table)
: node_based_graph(node_based_graph), roundabout_handler(node_based_graph,
node_data_container,
node_coordinates,
compressed_edge_container,
restriction_map,
barrier_nodes,
turn_lanes_data,
name_table,
street_name_suffix_table),
: node_based_graph(node_based_graph), intersection_generator(node_based_graph,
node_data_container,
restriction_map,
barrier_nodes,
coordinates,
compressed_edge_container),
intersection_normalizer(node_based_graph,
node_data_container,
coordinates,
name_table,
street_name_suffix_table,
intersection_generator),
roundabout_handler(node_based_graph,
node_data_container,
coordinates,
compressed_edge_container,
name_table,
street_name_suffix_table,
intersection_generator),
motorway_handler(node_based_graph,
node_data_container,
node_coordinates,
compressed_edge_container,
restriction_map,
barrier_nodes,
turn_lanes_data,
coordinates,
name_table,
street_name_suffix_table),
street_name_suffix_table,
intersection_generator),
turn_handler(node_based_graph,
node_data_container,
node_coordinates,
compressed_edge_container,
restriction_map,
barrier_nodes,
turn_lanes_data,
coordinates,
name_table,
street_name_suffix_table),
sliproad_handler(node_based_graph,
street_name_suffix_table,
intersection_generator),
sliproad_handler(intersection_generator,
node_based_graph,
node_data_container,
node_coordinates,
compressed_edge_container,
restriction_map,
barrier_nodes,
turn_lanes_data,
coordinates,
name_table,
street_name_suffix_table),
suppress_mode_handler(node_based_graph,
suppress_mode_handler(intersection_generator,
node_based_graph,
node_data_container,
node_coordinates,
compressed_edge_container,
restriction_map,
barrier_nodes,
turn_lanes_data,
coordinates,
name_table,
street_name_suffix_table),
driveway_handler(node_based_graph,
driveway_handler(intersection_generator,
node_based_graph,
node_data_container,
node_coordinates,
compressed_edge_container,
restriction_map,
barrier_nodes,
turn_lanes_data,
coordinates,
name_table,
street_name_suffix_table),
statistics_handler(node_based_graph,
statistics_handler(intersection_generator,
node_based_graph,
node_data_container,
node_coordinates,
compressed_edge_container,
restriction_map,
barrier_nodes,
turn_lanes_data,
coordinates,
name_table,
street_name_suffix_table)
{
}
Intersection TurnAnalysis::operator()(const NodeID node_prior_to_intersection,
const EdgeID entering_via_edge) const
{
TurnAnalysis::ShapeResult shape_result =
ComputeIntersectionShapes(node_based_graph.GetTarget(entering_via_edge));
// assign valid flags to normalized_shape
const auto intersection_view = intersection_generator.TransformIntersectionShapeIntoView(
node_prior_to_intersection,
entering_via_edge,
shape_result.annotated_normalized_shape.normalized_shape,
shape_result.intersection_shape,
shape_result.annotated_normalized_shape.performed_merges);
// assign the turn types to the intersection
return AssignTurnTypes(node_prior_to_intersection, entering_via_edge, intersection_view);
}
Intersection TurnAnalysis::AssignTurnTypes(const NodeID node_prior_to_intersection,
const EdgeID entering_via_edge,
const IntersectionView &intersection_view) const
@@ -181,6 +191,19 @@ Intersection TurnAnalysis::AssignTurnTypes(const NodeID node_prior_to_intersecti
return intersection;
}
TurnAnalysis::ShapeResult
TurnAnalysis::ComputeIntersectionShapes(const NodeID node_at_center_of_intersection) const
{
ShapeResult intersection_shape;
intersection_shape.intersection_shape =
intersection_generator.ComputeIntersectionShape(node_at_center_of_intersection);
intersection_shape.annotated_normalized_shape = intersection_normalizer(
node_at_center_of_intersection, intersection_shape.intersection_shape);
return intersection_shape;
}
// Sets basic turn types as fallback for otherwise unhandled turns
Intersection TurnAnalysis::setTurnTypes(const NodeID node_prior_to_intersection,
const EdgeID,
@@ -202,6 +225,11 @@ Intersection TurnAnalysis::setTurnTypes(const NodeID node_prior_to_intersection,
return intersection;
}
const IntersectionGenerator &TurnAnalysis::GetIntersectionGenerator() const
{
return intersection_generator;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm

Some files were not shown because too many files have changed in this diff Show More