Compare commits
35 Commits
v5.5.0-rc.2
...
v5.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
| f88f51fd98 | |||
| 98659fb0a0 | |||
| 8a1afe456f | |||
| f1384f5e44 | |||
| 1cd5394a16 | |||
| 8c7f744b1a | |||
| 896445a337 | |||
| 8c21e1267e | |||
| ad3fd46da5 | |||
| 62f0e11bfa | |||
| 03d653c0bb | |||
| cbfb055f81 | |||
| 2288704bb5 | |||
| 97dcf4eef9 | |||
| 17e15033e1 | |||
| 875f482203 | |||
| df3c39cef5 | |||
| a28a20a1ba | |||
| 17a18b5c7c | |||
| 423c083038 | |||
| 468d8c0031 | |||
| 6f4c6e84ae | |||
| 4b1aae40af | |||
| 0e6863aec1 | |||
| 949d505783 | |||
| d11927046f | |||
| 9461c83511 | |||
| 532cbfce13 | |||
| 0fbd18b0dd | |||
| 3f07a830e6 | |||
| 24b01fae00 | |||
| 0817cd6dfd | |||
| 9d8b92f418 | |||
| 928a6f0c7d | |||
| 29b3caf529 |
@@ -19,6 +19,7 @@
|
||||
- Improved turn angle calculation, detecting offsets due to lanes / minor variations due to inaccuracies
|
||||
- Corrected the bearings returned for intermediate steps - requires reprocessing
|
||||
- Improved turn locations for collapsed turns
|
||||
- Sliproad classification refinements: the situations we detect as Sliproads now resemble more closely the reality
|
||||
- Trip Plugin
|
||||
- changed internal behaviour to prefer the smallest lexicographic result over the largest one
|
||||
- Bugfixes
|
||||
@@ -27,6 +28,8 @@
|
||||
- fixed a bug that could result in inconsistent behaviour when collapsing instructions
|
||||
- fixed a bug that could result in crashes when leaving a ferry directly onto a motorway ramp
|
||||
- fixed a bug in the tile plugin that resulted in discovering invalid edges for connections
|
||||
- improved error messages when missing files during traffic updates (#3114)
|
||||
- For single coordinate geometries the GeoJSON `Point` encoding was broken. We now always emit `LineString`s even in the one-coordinate-case (backwards compatible) (#3425)
|
||||
- Debug Tiles
|
||||
- Added support for turn penalties
|
||||
- Internals
|
||||
|
||||
+5
-3
@@ -56,6 +56,8 @@ set(OSRM_VERSION_MINOR 5)
|
||||
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}")
|
||||
|
||||
# these two functions build up custom variables:
|
||||
# DEPENDENCIES_INCLUDE_DIRS and OSRM_DEFINES
|
||||
# These variables we want to pass to
|
||||
@@ -92,7 +94,7 @@ endif()
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/)
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/variant/include)
|
||||
|
||||
add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
|
||||
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
|
||||
@@ -637,7 +639,7 @@ set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
|
||||
file(GLOB VariantGlob third_party/variant/*.hpp)
|
||||
file(GLOB VariantGlob third_party/variant/include/mapbox/*.hpp)
|
||||
file(GLOB LibraryGlob include/osrm/*.hpp)
|
||||
file(GLOB ParametersGlob include/engine/api/*_parameters.hpp)
|
||||
set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/phantom_node.hpp)
|
||||
@@ -652,7 +654,7 @@ install(FILES ${ExtractorHeader} DESTINATION include/osrm/extractor)
|
||||
install(FILES ${ContractorHeader} DESTINATION include/osrm/contractor)
|
||||
install(FILES ${LibraryGlob} DESTINATION include/osrm)
|
||||
install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api)
|
||||
install(FILES ${VariantGlob} DESTINATION include/variant)
|
||||
install(FILES ${VariantGlob} DESTINATION include/mapbox)
|
||||
install(TARGETS osrm-extract DESTINATION bin)
|
||||
install(TARGETS osrm-contract DESTINATION bin)
|
||||
install(TARGETS osrm-datastore DESTINATION bin)
|
||||
|
||||
+1
-1
@@ -519,7 +519,7 @@ step.
|
||||
|------------|--------------------------------------------------------------------|
|
||||
| polyline | [polyline](https://www.npmjs.com/package/polyline) with precision 5 in [latitude,longitude] encoding |
|
||||
| polyline6 | [polyline](https://www.npmjs.com/package/polyline) with precision 6 in [latitude,longitude] encoding |
|
||||
| geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) or [GeoJSON `Point`](http://geojson.org/geojson-spec.html#point) if it is only one coordinate (not wrapped by a GeoJSON feature)|
|
||||
| geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) |
|
||||
|
||||
- `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.
|
||||
|
||||
@@ -30,6 +30,35 @@ Feature: Car - Restricted access
|
||||
| | | no | yes | x |
|
||||
| | | yes | no | |
|
||||
|
||||
Scenario: Car - Access tag hierarchy and forward/backward
|
||||
Then routability should be
|
||||
| access | access:forward | access:backward | motorcar | motorcar:forward | motorcar:backward | forw | backw |
|
||||
| | | | | | | x | x |
|
||||
| yes | | | | | | x | x |
|
||||
| yes | no | | | | | | x |
|
||||
| yes | yes | | no | | | | |
|
||||
| yes | yes | | yes | no | | | x |
|
||||
| yes | | | | | | x | x |
|
||||
| yes | | no | | | | x | |
|
||||
| yes | | yes | no | | | | |
|
||||
| yes | | yes | yes | | no | x | |
|
||||
| no | | | | | | | |
|
||||
| no | yes | | | | | x | |
|
||||
| no | no | | yes | | | x | x |
|
||||
| no | no | | no | yes | | x | |
|
||||
| no | | | | | | | |
|
||||
| no | | yes | | | | | x |
|
||||
| no | | no | yes | | | x | x |
|
||||
| no | | no | no | | yes | | x |
|
||||
| | no | | | no | | | x |
|
||||
| | | no | | | no | x | |
|
||||
| | no | | | | no | | |
|
||||
| | | no | no | | | | |
|
||||
| | no | | | yes | | x | x |
|
||||
| | | no | | | yes | x | x |
|
||||
| | yes | | | no | | | x |
|
||||
| | | yes | | | no | x | |
|
||||
|
||||
Scenario: Car - Access tag hierarchy on nodes
|
||||
Then routability should be
|
||||
| node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
|
||||
@@ -149,6 +178,7 @@ Feature: Car - Restricted access
|
||||
| runway | | | | yes | |
|
||||
| primary | | | | no | x |
|
||||
|
||||
@hov
|
||||
Scenario: Car - only designated HOV ways are ignored by default
|
||||
Then routability should be
|
||||
| highway | hov | bothw |
|
||||
@@ -156,6 +186,7 @@ Feature: Car - Restricted access
|
||||
| primary | yes | x |
|
||||
| primary | no | x |
|
||||
|
||||
@hov
|
||||
Scenario: Car - a way with all lanes HOV-designated is inaccessible by default (similar to hov=designated)
|
||||
Then routability should be
|
||||
| highway | hov:lanes:forward | hov:lanes:backward | hov:lanes | oneway | forw | backw |
|
||||
@@ -166,8 +197,8 @@ Feature: Car - Restricted access
|
||||
| primary | designated\|no | designated\|no | | | x | x |
|
||||
| primary | yes\|no | yes\|no | | | x | x |
|
||||
| primary | | | | | x | x |
|
||||
| primary | designated | | | -1 | | |
|
||||
| primary | | designated | | -1 | | x |
|
||||
| primary | designated | | | -1 | | x |
|
||||
| primary | | designated | | -1 | | |
|
||||
| primary | | | designated | yes | | |
|
||||
| primary | | | designated | -1 | | |
|
||||
| primary | | | designated\| | yes | x | |
|
||||
@@ -189,3 +220,15 @@ Feature: Car - Restricted access
|
||||
Then routability should be
|
||||
| highway | toll | bothw |
|
||||
| primary | yes | |
|
||||
|
||||
Scenario: Car - directional access tags
|
||||
Then routability should be
|
||||
| highway | access | access:forward | access:backward | forw | backw |
|
||||
| primary | yes | yes | yes | x | x |
|
||||
| primary | yes | | no | x | |
|
||||
| primary | yes | no | | | x |
|
||||
| primary | yes | no | no | | |
|
||||
| primary | no | no | no | | |
|
||||
| primary | no | | yes | | x |
|
||||
| primary | no | yes | | x | |
|
||||
| primary | no | yes | yes | x | x |
|
||||
|
||||
@@ -123,3 +123,14 @@ OSRM will use 4/5 of the projected free-flow speed.
|
||||
| primary | 30 | 1 | -1 | | 23 km/h |
|
||||
| primary | 30 | 1 | | 15 km/h | 15 km/h |
|
||||
| primary | 30 | 2 | | 23 km/h | 23 km/h |
|
||||
|
||||
Scenario: Car - Forwward/backward maxspeed on reverse oneways
|
||||
Then routability should be
|
||||
| highway | maxspeed | maxspeed:forward | maxspeed:backward | oneway | forw | backw |
|
||||
| primary | | | | -1 | | 52 km/h |
|
||||
| primary | 30 | | | -1 | | 23 km/h |
|
||||
| primary | | 30 | | -1 | | 52 km/h |
|
||||
| primary | | | 30 | -1 | | 23 km/h |
|
||||
| primary | 20 | 30 | | -1 | | 16 km/h |
|
||||
| primary | 20 | | 30 | -1 | | 23 km/h |
|
||||
|
||||
|
||||
+13
-13
@@ -78,24 +78,24 @@ Feature: Car - Street names in instructions
|
||||
Scenario: Inner city expressway with on road
|
||||
Given the node map
|
||||
"""
|
||||
a b c g
|
||||
f
|
||||
|
||||
|
||||
|
||||
a b . . . c g
|
||||
`f .
|
||||
`
|
||||
.
|
||||
.
|
||||
d
|
||||
|
||||
|
||||
|
||||
.
|
||||
.
|
||||
.
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | name:pronunciation |
|
||||
| abc | primary | road | roooaad |
|
||||
| cg | primary | road | roooaad |
|
||||
| bfd | trunk_link | | |
|
||||
| cde | trunk | trunk | truank |
|
||||
| nodes | highway | name | name:pronunciation | oneway |
|
||||
| abc | primary | road | roooaad | |
|
||||
| cg | primary | road | roooaad | |
|
||||
| bfd | trunk_link | sliproad | | yes |
|
||||
| cde | trunk | trunk | truank | yes |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
|
||||
@@ -5,13 +5,17 @@ Feature: Turn Lane Guidance
|
||||
Given the profile "car"
|
||||
Given a grid size of 3 meters
|
||||
|
||||
|
||||
@sliproads
|
||||
Scenario: Separate Turn Lanes
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a b c g
|
||||
d
|
||||
.
|
||||
a ... b ..... c . g
|
||||
` .
|
||||
`... d
|
||||
.
|
||||
f
|
||||
"""
|
||||
|
||||
@@ -41,8 +45,10 @@ Feature: Turn Lane Guidance
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a b c g
|
||||
d
|
||||
a . . b . . . c g
|
||||
` .
|
||||
` .
|
||||
` d
|
||||
f
|
||||
"""
|
||||
|
||||
@@ -67,21 +73,22 @@ Feature: Turn Lane Guidance
|
||||
| a,g | in,straight,straight | depart,new name straight,arrive | ,left:false straight:true right:false, |
|
||||
| a,f | in,cross,cross | depart,turn right,arrive | ,left:false straight:false right:true, |
|
||||
|
||||
|
||||
@sliproads
|
||||
Scenario: Separate Turn Lanes Next to other turns
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a - - b.-.- - c-g
|
||||
| ' 'd
|
||||
| f
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
i - - h - - - j
|
||||
. e
|
||||
a . . b . . . c g
|
||||
. ` .
|
||||
. ` .
|
||||
. d
|
||||
. f
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
i . . h . . . j
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -109,6 +116,7 @@ Feature: Turn Lane Guidance
|
||||
| a,j | in,turn,other,other | depart,turn right,turn left,arrive | ,,left:true right:false, |
|
||||
| a,i | in,turn,other,other | depart,turn right,turn right,arrive | ,,left:false right:true, |
|
||||
|
||||
|
||||
@todo @2654 @none
|
||||
#https://github.com/Project-OSRM/osrm-backend/issues/2645
|
||||
#http://www.openstreetmap.org/export#map=19/52.56054/13.32152
|
||||
@@ -231,6 +239,7 @@ Feature: Turn Lane Guidance
|
||||
| a,j | ghough,market,market | depart,turn left,arrive | ,none:true straight:false straight:false straight:false, |
|
||||
| a,f | ghough,ghough,ghough | depart,continue slight left,arrive | ,none:true straight:true straight:false straight:false, |
|
||||
|
||||
|
||||
Scenario: Check sliproad handler loop's exit condition, Issue #2896
|
||||
# http://www.openstreetmap.org/way/198481519
|
||||
Given the node locations
|
||||
|
||||
@@ -55,3 +55,38 @@ Feature: Collapse
|
||||
| waypoints | route | turns |
|
||||
| a,g | road,road,road | depart,continue uturn,arrive |
|
||||
| d,c | road,road,road | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Forking before a turn (forky)
|
||||
Given the node map
|
||||
"""
|
||||
g
|
||||
.
|
||||
c
|
||||
a . . b .'
|
||||
`d.
|
||||
f e
|
||||
"""
|
||||
# note: check clooapse.feature for a similar test case where we do not
|
||||
# classify the situation as Sliproad and therefore keep the fork inst.
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway | highway |
|
||||
| ab | road | yes | primary |
|
||||
| bd | road | yes | primary |
|
||||
| bc | road | yes | primary |
|
||||
| de | road | yes | primary |
|
||||
| fd | cross | no | secondary |
|
||||
| dc | cross | no | secondary |
|
||||
| cg | cross | no | secondary |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | bd | dc | d | no_left_turn |
|
||||
| restriction | bc | dc | c | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | road,cross,cross | depart,turn left,arrive |
|
||||
| a,e | road,road,road | depart,continue right,arrive |
|
||||
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
|
||||
| a,f | road,road,cross,cross | depart,continue slight right,turn right,arrive |
|
||||
|
||||
@@ -701,12 +701,15 @@ Feature: Collapse
|
||||
Given the node map
|
||||
"""
|
||||
g
|
||||
|
||||
.
|
||||
c
|
||||
a b
|
||||
d
|
||||
a . . b .'
|
||||
` d.
|
||||
f e
|
||||
"""
|
||||
# as it is right now we don't classify this as a sliproad,
|
||||
# check collapse-detail.feature for a similar test case
|
||||
# which removes the fork here due to it being a Sliproad.
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway | highway |
|
||||
@@ -725,10 +728,9 @@ Feature: Collapse
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | road,cross,cross | depart,turn left,arrive |
|
||||
| a,e | road,road,road | depart,continue straight,arrive |
|
||||
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
|
||||
| a,f | road,road,cross,cross | depart,continue straight,turn right,arrive |
|
||||
| a,g | road,cross,cross | depart,fork left,arrive |
|
||||
| a,e | road,road,road | depart,fork slight right,arrive |
|
||||
| a,f | road,road,cross,cross | depart,fork slight right,turn right,arrive |
|
||||
|
||||
Scenario: On-Off on Highway
|
||||
Given the node map
|
||||
|
||||
@@ -9,23 +9,23 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a b c d
|
||||
h
|
||||
|
||||
1
|
||||
|
||||
a b . . c d
|
||||
`h .
|
||||
`
|
||||
1 `
|
||||
.
|
||||
f
|
||||
|
||||
.
|
||||
g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | trunk | first |
|
||||
| cd | trunk | first |
|
||||
| bhf | trunk_link | |
|
||||
| cfg | primary | second |
|
||||
| ec | primary | second |
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | trunk | first | |
|
||||
| cd | trunk | first | |
|
||||
| bhf | trunk_link | | yes |
|
||||
| cfg | primary | second | yes |
|
||||
| ec | primary | second | |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
@@ -51,12 +51,12 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | maxspeed |
|
||||
| abc | trunk | first | 70 |
|
||||
| cd | trunk | first | 2 |
|
||||
| bhf | trunk_link | | 2 |
|
||||
| cfg | primary | second | 50 |
|
||||
| ec | primary | second | 50 |
|
||||
| nodes | highway | name | maxspeed | oneway |
|
||||
| abc | trunk | first | 70 | |
|
||||
| cd | trunk | first | 2 | |
|
||||
| bhf | trunk_link | | 2 | yes |
|
||||
| cfg | primary | second | 50 | yes |
|
||||
| ec | primary | second | 50 | |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
@@ -125,24 +125,24 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
Scenario: Inner city expressway with on road
|
||||
Given the node map
|
||||
"""
|
||||
a b c g
|
||||
f
|
||||
|
||||
|
||||
|
||||
a b . . . c g
|
||||
`f .
|
||||
`
|
||||
.
|
||||
.
|
||||
d
|
||||
|
||||
|
||||
|
||||
.
|
||||
.
|
||||
.
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | primary | road |
|
||||
| cg | primary | road |
|
||||
| bfd | trunk_link | |
|
||||
| cde | trunk | trunk |
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | primary | road | |
|
||||
| cg | primary | road | |
|
||||
| bfd | trunk_link | | yes |
|
||||
| cde | trunk | trunk | yes |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
@@ -240,8 +240,8 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| qe | secondary_link | Ettlinger Allee | | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | ref |
|
||||
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
|
||||
| waypoints | route | turns | ref |
|
||||
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
|
||||
|
||||
Scenario: Traffic Lights everywhere
|
||||
#http://map.project-osrm.org/?z=18¢er=48.995336%2C8.383813&loc=48.995467%2C8.384548&loc=48.995115%2C8.382761&hl=en&alt=0
|
||||
@@ -271,11 +271,11 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| jcghf | primary | Brauerstrasse | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
|
||||
| a,1 | Ebertstrasse,, | depart,turn right,arrive |
|
||||
| waypoints | route | turns |
|
||||
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
|
||||
| a,1 | Ebertstrasse,, | depart,turn slight right,arrive |
|
||||
|
||||
#2839
|
||||
Scenario: Self-Loop
|
||||
@@ -431,3 +431,354 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,i | road,road,road | depart,fork slight left,arrive |
|
||||
|
||||
|
||||
# The following tests are current false positives / false negatives #3199
|
||||
|
||||
@sliproads
|
||||
# http://www.openstreetmap.org/#map=19/52.59847/13.14815
|
||||
Scenario: Sliproad Detection
|
||||
Given the node map
|
||||
"""
|
||||
a . . .
|
||||
. .
|
||||
b . . . . . . c . . . d
|
||||
` . .
|
||||
e . .
|
||||
` . .
|
||||
f . .
|
||||
` . .
|
||||
g i
|
||||
` h .
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abefgh | residential | Nachtigallensteig |
|
||||
| bcd | residential | Kiebitzsteig |
|
||||
| cg | residential | Haenflingsteig |
|
||||
| hid | residential | Waldkauzsteig |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | Nachtigallensteig,Kiebitzsteig,Kiebitzsteig | depart,turn left,arrive |
|
||||
| a,h | Nachtigallensteig,Nachtigallensteig | depart,arrive |
|
||||
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a obvious Sliproad
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
` e
|
||||
.`
|
||||
. `
|
||||
f g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbef | primary | dbef | yes |
|
||||
| aeg | primary | aeg | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,aeg,dbef,dbef | depart,turn right,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Through Street, not a Sliproad although obvious
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
` e
|
||||
. `
|
||||
. `
|
||||
f g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbef | primary | dbef | yes |
|
||||
| aeg | primary | aeg | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,aeg,dbef,dbef | depart,turn right,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Sliproad target turn is restricted
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . . . b . . c
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
`.
|
||||
e
|
||||
.`
|
||||
f `
|
||||
. ` g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sa | primary | sabc | |
|
||||
| abc | primary | sabc | |
|
||||
| dbe | primary | dbef | yes |
|
||||
| ef | primary | dbef | |
|
||||
| ae | primary | aeg | yes |
|
||||
| eg | primary | aeg | |
|
||||
# the reason we have to split ways at e is that otherwise we can't handle restrictions via e
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | ae | ef | e | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,dbef,dbef | depart,turn right,arrive |
|
||||
| s,g | sabc,aeg,aeg | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a Sliproad, road not continuing straight
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
` e . . g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbe | primary | dbe | yes |
|
||||
| aeg | primary | aeg | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,c | sabc,sabc | depart,arrive |
|
||||
| s,g | sabc,aeg,aeg | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Intersection too far away with Traffic Light shortly after initial split
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . . . . . . . . . . . . t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . b . . c
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . .
|
||||
` e
|
||||
.
|
||||
f
|
||||
.
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| t | traffic_signals |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| satbc | primary | sabc | |
|
||||
| dbef | primary | dbef | yes |
|
||||
| ae | primary | ae | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,ae,dbef,dbef | depart,turn slight right,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Traffic Signal on Sliproad
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . . . . b . . c
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
t .
|
||||
` .
|
||||
e
|
||||
.
|
||||
.
|
||||
f
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| t | traffic_signals |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbe | primary | dbe | yes |
|
||||
| ef | primary | ef | |
|
||||
| ate | primary | ate | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,ef,ef | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Sliproad tagged as link
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . . . . b . . c
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
e
|
||||
.
|
||||
.
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | motorway | sabc | |
|
||||
| dbef | motorway | dbef | yes |
|
||||
| ae | motorway_link | ae | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,dbef,dbef | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Sliproad with same-ish names
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
. e
|
||||
..
|
||||
.
|
||||
f
|
||||
.
|
||||
t
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | ref | oneway |
|
||||
| sabc | primary | main | | |
|
||||
| dbe | primary | crossing | r0 | yes |
|
||||
| eft | primary | crossing | r0;r1 | yes |
|
||||
| af | primary | sliproad | | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,t | main,crossing,crossing | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a Sliproad, name mismatch
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
. e
|
||||
. .
|
||||
..
|
||||
.
|
||||
f
|
||||
.
|
||||
t
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | main | |
|
||||
| dbe | primary | top | yes |
|
||||
| ef | primary | bottom | yes |
|
||||
| ft | primary | away | yes |
|
||||
| af | primary | sliproad | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,t | main,away,away | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a Sliproad, low road priority
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
. e
|
||||
. .
|
||||
..
|
||||
.
|
||||
f
|
||||
.
|
||||
t
|
||||
"""
|
||||
|
||||
And the ways
|
||||
# maxspeed otherwise service road will never be routed over and we won't see instructions
|
||||
| nodes | highway | name | maxspeed | oneway |
|
||||
| sabc | primary | main | 30 km/h | |
|
||||
| dbe | primary | crossing | 30 km/h | yes |
|
||||
| eft | primary | crossing | 30 km/h | yes |
|
||||
| ft | primary | away | 30 km/h | yes |
|
||||
| af | service | sliproad | 30 km/h | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,t | main,away,away | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a Sliproad, more than three roads at target intersection
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
. e
|
||||
. .
|
||||
..
|
||||
. h
|
||||
f .
|
||||
. g
|
||||
t
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | main | |
|
||||
| dbe | primary | top | yes |
|
||||
| eft | primary | bottom | yes |
|
||||
| fh | primary | another | |
|
||||
| fg | primary | another | |
|
||||
| af | primary | sliproad | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,g | main,sliproad,another,another | depart,turn right,turn left,arrive |
|
||||
|
||||
@@ -317,30 +317,30 @@ Feature: Simple Turns
|
||||
Scenario: Curved Turn At Cross
|
||||
Given the node map
|
||||
"""
|
||||
h
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
| . b - - - - - - - - - - - - - - - - - - a
|
||||
| .
|
||||
| .
|
||||
| c
|
||||
|
|
||||
|
|
||||
|
|
||||
d
|
||||
|
|
||||
|
|
||||
|
|
||||
e |
|
||||
. |
|
||||
. |
|
||||
g - - - - - - - - - - - - - f |
|
||||
|
|
||||
|
|
||||
|
|
||||
i
|
||||
h
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
| . b - - - - - - - - - - - - - - - - - - - - - - - a
|
||||
| .
|
||||
| .
|
||||
| c
|
||||
|
|
||||
|
|
||||
|
|
||||
d
|
||||
|
|
||||
|
|
||||
|
|
||||
e |
|
||||
. |
|
||||
. |
|
||||
g - - - - - - - - - - - - - - - - - - f |
|
||||
|
|
||||
|
|
||||
|
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -443,9 +443,9 @@ Feature: Simple Turns
|
||||
| ef | residential | road | 2 | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | locations |
|
||||
| g,f | turn,road,road | depart,turn left,arrive | g,e,f |
|
||||
| c,f | road,road,road | depart,continue right,arrive | c,b,f |
|
||||
| waypoints | route | turns | locations | # |
|
||||
| g,f | turn,road | depart,arrive | g,f | #could offer an additional turn at `e` if you don't detect the turn in between as curve |
|
||||
| c,f | road,road,road | depart,continue right,arrive | c,b,f | |
|
||||
|
||||
#http://www.openstreetmap.org/search?query=52.479264%2013.295617#map=19/52.47926/13.29562
|
||||
Scenario: Splitting Roads with curved split
|
||||
@@ -627,12 +627,14 @@ Feature: Simple Turns
|
||||
| 1,h | ,allee,allee | depart,turn left,arrive |
|
||||
| 2,h | ,allee,allee | depart,turn left,arrive |
|
||||
|
||||
|
||||
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
|
||||
@todo
|
||||
Scenario: Curved Turn on Separated Directions
|
||||
Given the node map
|
||||
"""
|
||||
e d
|
||||
f - - - - - - - - - - - - - - - c - - - - - - - - - - - j
|
||||
f c - - - - - - - - - - - j
|
||||
| l ' |
|
||||
| ' |
|
||||
| ' |
|
||||
@@ -680,6 +682,58 @@ Feature: Simple Turns
|
||||
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
|
||||
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
|
||||
|
||||
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
|
||||
Scenario: Curved Turn on Separated Directions
|
||||
Given the node map
|
||||
"""
|
||||
e d
|
||||
f c - - - - - - - - - - - j
|
||||
| l ' |
|
||||
| ' |
|
||||
| ' |
|
||||
| ' |
|
||||
| ' |
|
||||
| n |
|
||||
| |
|
||||
| ' |
|
||||
| |
|
||||
| ' |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
|' |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
g |
|
||||
h - - - - - - - - - - - - - - - b - - - - - - - - - - - o
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
i a
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway | lanes | highway |
|
||||
| jc | Kapweg | yes | 3 | primary |
|
||||
| clngh | Kapweg | yes | | primary_link |
|
||||
| hbo | Kapweg | yes | 2 | primary |
|
||||
| efh | Kurt | yes | 4 | secondary |
|
||||
| hi | Kurt | yes | 3 | primary |
|
||||
| ab | Kurt | yes | 4 | primary |
|
||||
| cd | Kurt | yes | 3 | secondary |
|
||||
| bc | Kurt | yes | 2 | primary |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| j,i | Kapweg,Kurt,Kurt | depart,turn left,arrive |
|
||||
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
|
||||
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
|
||||
|
||||
#http://www.openstreetmap.org/#map=19/52.53731/13.36033
|
||||
Scenario: Splitting Road to Left
|
||||
Given the node map
|
||||
@@ -1112,8 +1166,9 @@ Feature: Simple Turns
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | lanes |
|
||||
| abcdefghijklmnopc | circled | residential | 1 |
|
||||
| nodes | name | highway | lanes | oneway |
|
||||
| abc | circled | residential | 1 | no |
|
||||
| cdefghijklmnopc | circled | residential | 1 | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | bearings | route | turns |
|
||||
@@ -1168,3 +1223,40 @@ Feature: Simple Turns
|
||||
When I route I should get
|
||||
| waypoints | route |
|
||||
| a,e | ab,bcde,bcde |
|
||||
|
||||
|
||||
@3401
|
||||
Scenario: Curve With Duplicated Coordinates
|
||||
Given the node locations
|
||||
| node | lat | lon | # |
|
||||
| a | 0.9999280745650984 | 1.0 | |
|
||||
| b | 0.9999280745650984 | 1.0000179813587253 | |
|
||||
| c | 0.9999280745650984 | 1.0000359627174509 | |
|
||||
| d | 0.9999460559238238 | 1.0000674300952204 | |
|
||||
| e | 0.9999640372825492 | 1.0000809161142643 | |
|
||||
| f | 0.9999820186412746 | 1.0000854114539457 | |
|
||||
| g | 1.0 | 1.0000854114539457 | |
|
||||
| h | 1.0 | 1.0000854114539457 | #same as g |
|
||||
| z | 0.9999100932063729 | 1.0000179813587253 | |
|
||||
# g
|
||||
# |
|
||||
# f
|
||||
# '
|
||||
# e
|
||||
# '
|
||||
# d
|
||||
# '
|
||||
#a - b - c
|
||||
# |
|
||||
# z
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | lanes | # |
|
||||
| ab | yes | 1 | |
|
||||
| zb | yes | 1 | |
|
||||
| bcdefgh | yes | 1 | #intentional duplication |
|
||||
|
||||
# we don't care for turn instructions, this is a coordinate extraction bug check
|
||||
When I route I should get
|
||||
| waypoints | route | intersections |
|
||||
| a,g | ab,bcdefgh,bcdefgh | true:90;true:45 false:180 false:270;true:180 |
|
||||
|
||||
@@ -3,6 +3,14 @@ Feature: osrm-contract command line options: invalid options
|
||||
|
||||
Background:
|
||||
Given the profile "testbot"
|
||||
And the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
And the data has been extracted
|
||||
|
||||
Scenario: osrm-contract - Non-existing option
|
||||
When I try to run "osrm-contract --fly-me-to-the-moon"
|
||||
@@ -10,3 +18,11 @@ Feature: osrm-contract command line options: invalid options
|
||||
And stderr should contain "option"
|
||||
And stderr should contain "fly-me-to-the-moon"
|
||||
And it should exit with an error
|
||||
|
||||
# This tests the error messages when you try to use --segment-speed-file,
|
||||
# but osrm-extract has not been run with --generate-edge-lookup
|
||||
Scenario: osrm-contract - Someone forgot --generate-edge-lookup on osrm-extract
|
||||
When I try to run "osrm-contract --segment-speed-file /dev/null {processed_file}"
|
||||
Then stderr should contain "Error while trying to mmap"
|
||||
Then stderr should contain ".osrm.edge_penalties"
|
||||
And it should exit with an error
|
||||
|
||||
@@ -81,6 +81,7 @@ class Contractor
|
||||
EdgeID
|
||||
LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
|
||||
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
const std::string &edge_segment_lookup_path,
|
||||
const std::string &edge_penalty_path,
|
||||
const std::vector<std::string> &segment_speed_path,
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include "util/deallocating_vector.hpp"
|
||||
#include "util/dynamic_graph.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/percent.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include "util/xor_fast_hash.hpp"
|
||||
@@ -156,11 +156,10 @@ class GraphContractor
|
||||
#ifndef NDEBUG
|
||||
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING)
|
||||
<< "Edge weight large -> "
|
||||
<< static_cast<unsigned int>(std::max(diter->weight, 1)) << " : "
|
||||
<< static_cast<unsigned int>(diter->source) << " -> "
|
||||
<< static_cast<unsigned int>(diter->target);
|
||||
util::Log(logWARNING) << "Edge weight large -> "
|
||||
<< static_cast<unsigned int>(std::max(diter->weight, 1))
|
||||
<< " : " << static_cast<unsigned int>(diter->source) << " -> "
|
||||
<< static_cast<unsigned int>(diter->target);
|
||||
}
|
||||
#endif
|
||||
edges.emplace_back(diter->source,
|
||||
@@ -245,15 +244,14 @@ class GraphContractor
|
||||
}
|
||||
}
|
||||
}
|
||||
util::SimpleLogger().Write() << "merged " << edges.size() - edge << " edges out of "
|
||||
<< edges.size();
|
||||
util::Log() << "merged " << edges.size() - edge << " edges out of " << edges.size();
|
||||
edges.resize(edge);
|
||||
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
|
||||
edges.clear();
|
||||
edges.shrink_to_fit();
|
||||
|
||||
BOOST_ASSERT(0 == edges.capacity());
|
||||
util::SimpleLogger().Write() << "contractor finished initalization";
|
||||
util::Log() << "contractor finished initalization";
|
||||
}
|
||||
|
||||
void Run(double core_factor = 1.0)
|
||||
@@ -270,7 +268,6 @@ class GraphContractor
|
||||
const constexpr size_t DeleteGrainSize = 1;
|
||||
|
||||
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
util::Percent p(number_of_nodes);
|
||||
|
||||
ThreadDataContainer thread_data_list(number_of_nodes);
|
||||
|
||||
@@ -292,9 +289,10 @@ class GraphContractor
|
||||
bool use_cached_node_priorities = !node_levels.empty();
|
||||
if (use_cached_node_priorities)
|
||||
{
|
||||
std::cout << "using cached node priorities ..." << std::flush;
|
||||
util::UnbufferedLog log;
|
||||
log << "using cached node priorities ...";
|
||||
node_priorities.swap(node_levels);
|
||||
std::cout << "ok" << std::endl;
|
||||
log << "ok";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -302,7 +300,8 @@ class GraphContractor
|
||||
node_priorities.resize(number_of_nodes);
|
||||
node_levels.resize(number_of_nodes);
|
||||
|
||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||
util::UnbufferedLog log;
|
||||
log << "initializing elimination PQ ...";
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
|
||||
[this, &node_priorities, &node_depth, &thread_data_list](
|
||||
const tbb::blocked_range<int> &range) {
|
||||
@@ -313,11 +312,14 @@ class GraphContractor
|
||||
this->EvaluateNodePriority(data, node_depth[x], x);
|
||||
}
|
||||
});
|
||||
std::cout << "ok" << std::endl;
|
||||
log << "ok";
|
||||
}
|
||||
BOOST_ASSERT(node_priorities.size() == number_of_nodes);
|
||||
|
||||
std::cout << "preprocessing " << number_of_nodes << " nodes ..." << std::flush;
|
||||
util::Log() << "preprocessing " << number_of_nodes << " nodes ...";
|
||||
|
||||
util::UnbufferedLog log;
|
||||
util::Percent p(log, number_of_nodes);
|
||||
|
||||
unsigned current_level = 0;
|
||||
bool flushed_contractor = false;
|
||||
@@ -331,7 +333,7 @@ class GraphContractor
|
||||
new_edge_set; // this one is not explicitely
|
||||
// cleared since it goes out of
|
||||
// scope anywa
|
||||
std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
|
||||
log << " [flush " << number_of_contracted_nodes << " nodes] ";
|
||||
|
||||
// Delete old heap data to free memory that we need for the coming operations
|
||||
thread_data_list.data.clear();
|
||||
@@ -599,9 +601,8 @@ class GraphContractor
|
||||
is_core_node.clear();
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes "
|
||||
<< contractor_graph->GetNumberOfEdges() << " edges."
|
||||
<< std::endl;
|
||||
util::Log() << "[core] " << remaining_nodes.size() << " nodes "
|
||||
<< contractor_graph->GetNumberOfEdges() << " edges.";
|
||||
|
||||
thread_data_list.data.clear();
|
||||
}
|
||||
@@ -618,8 +619,9 @@ class GraphContractor
|
||||
|
||||
template <class Edge> inline void GetEdges(util::DeallocatingVector<Edge> &edges)
|
||||
{
|
||||
util::Percent p(contractor_graph->GetNumberOfNodes());
|
||||
util::SimpleLogger().Write() << "Getting edges of minimized graph";
|
||||
util::UnbufferedLog log;
|
||||
log << "Getting edges of minimized graph ";
|
||||
util::Percent p(log, contractor_graph->GetNumberOfNodes());
|
||||
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
if (contractor_graph->GetNumberOfNodes())
|
||||
{
|
||||
|
||||
@@ -54,22 +54,25 @@ util::json::Object makeGeoJSONGeometry(ForwardIter begin, ForwardIter end)
|
||||
auto num_coordinates = std::distance(begin, end);
|
||||
BOOST_ASSERT(num_coordinates != 0);
|
||||
util::json::Object geojson;
|
||||
geojson.values["type"] = "LineString";
|
||||
util::json::Array coordinates;
|
||||
if (num_coordinates > 1)
|
||||
{
|
||||
geojson.values["type"] = "LineString";
|
||||
util::json::Array coordinates;
|
||||
coordinates.values.reserve(num_coordinates);
|
||||
std::transform(
|
||||
begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat);
|
||||
geojson.values["coordinates"] = std::move(coordinates);
|
||||
auto into = std::back_inserter(coordinates.values);
|
||||
std::transform(begin, end, into, &detail::coordinateToLonLat);
|
||||
}
|
||||
else if (num_coordinates > 0)
|
||||
{
|
||||
geojson.values["type"] = "Point";
|
||||
util::json::Array coordinates;
|
||||
coordinates.values.push_back(detail::coordinateToLonLat(*begin));
|
||||
geojson.values["coordinates"] = std::move(coordinates);
|
||||
// For a single location we create a [location, location] LineString
|
||||
// instead of a single Point making the GeoJSON output consistent.
|
||||
coordinates.values.reserve(2);
|
||||
auto location = detail::coordinateToLonLat(*begin);
|
||||
coordinates.values.push_back(location);
|
||||
coordinates.values.push_back(location);
|
||||
}
|
||||
geojson.values["coordinates"] = std::move(coordinates);
|
||||
|
||||
return geojson;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
|
||||
#include "engine/geospatial_query.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/guidance/turn_bearing.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/packed_vector.hpp"
|
||||
#include "util/range_table.hpp"
|
||||
#include "util/rectangle.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
#include "util/static_rtree.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
@@ -116,7 +118,7 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
{
|
||||
m_check_sum =
|
||||
*data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::HSGR_CHECKSUM);
|
||||
util::SimpleLogger().Write() << "set checksum: " << m_check_sum;
|
||||
util::Log() << "set checksum: " << m_check_sum;
|
||||
}
|
||||
|
||||
void InitializeProfilePropertiesPointer(storage::DataLayout &data_layout, char *memory_block)
|
||||
@@ -144,9 +146,9 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
file_index_path = boost::filesystem::path(file_index_ptr);
|
||||
if (!boost::filesystem::exists(file_index_path))
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
|
||||
util::Log(logDEBUG) << "Leaf file name " << file_index_path.string();
|
||||
throw util::exception("Could not load " + file_index_path.string() +
|
||||
"Is any data loaded into shared memory?");
|
||||
"Is any data loaded into shared memory?" + SOURCE_REF);
|
||||
}
|
||||
|
||||
auto tree_ptr =
|
||||
|
||||
@@ -46,23 +46,27 @@ class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
|
||||
// if this returns false this is still in use
|
||||
if (exclusive_lock.try_lock())
|
||||
{
|
||||
// Now check if this is still the newest dataset
|
||||
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
|
||||
lock(shared_barriers->current_regions_mutex);
|
||||
|
||||
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
|
||||
const auto current_timestamp =
|
||||
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
||||
|
||||
if (current_timestamp->timestamp == shared_timestamp)
|
||||
if (storage::SharedMemory::RegionExists(data_region))
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "Retaining data with shared timestamp "
|
||||
<< shared_timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
storage::SharedMemory::Remove(data_region);
|
||||
storage::SharedMemory::Remove(layout_region);
|
||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
||||
|
||||
// Now check if this is still the newest dataset
|
||||
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
|
||||
lock(shared_barriers->current_regions_mutex);
|
||||
|
||||
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
|
||||
const auto current_timestamp =
|
||||
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
||||
|
||||
if (current_timestamp->timestamp == shared_timestamp)
|
||||
{
|
||||
util::Log(logDEBUG) << "Retaining data with shared timestamp " << shared_timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
storage::SharedMemory::Remove(data_region);
|
||||
storage::SharedMemory::Remove(layout_region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,8 +78,7 @@ class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
|
||||
: shared_barriers(shared_barriers_), layout_region(layout_region_),
|
||||
data_region(data_region_), shared_timestamp(shared_timestamp_)
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "Loading new data with shared timestamp "
|
||||
<< shared_timestamp;
|
||||
util::Log(logDEBUG) << "Loading new data with shared timestamp " << shared_timestamp;
|
||||
|
||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
||||
m_layout_memory = storage::makeSharedMemory(layout_region);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "engine/plugins/trip.hpp"
|
||||
#include "engine/plugins/viaroute.hpp"
|
||||
#include "engine/status.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
#include "engine/guidance/leg_geometry.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
|
||||
@@ -8,14 +8,12 @@
|
||||
#include "engine/guidance/leg_geometry.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
#include "engine/guidance/step_maneuver.hpp"
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
@@ -156,7 +154,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
intersection.entry.push_back(entry_class.allowsEntry(idx));
|
||||
}
|
||||
std::int16_t bearing_in_driving_direction =
|
||||
util::bearing::reverseBearing(std::round(bearings.first));
|
||||
util::reverseBearing(std::round(bearings.first));
|
||||
maneuver = {intersection.location,
|
||||
bearing_in_driving_direction,
|
||||
bearings.second,
|
||||
@@ -216,14 +214,13 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
BOOST_ASSERT(segment_index == number_of_segments - 1);
|
||||
bearings = detail::getArriveBearings(leg_geometry);
|
||||
|
||||
intersection = {
|
||||
target_node.location,
|
||||
std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}),
|
||||
std::vector<bool>({true}),
|
||||
0,
|
||||
Intersection::NO_INDEX,
|
||||
util::guidance::LaneTuple(),
|
||||
{}};
|
||||
intersection = {target_node.location,
|
||||
std::vector<short>({static_cast<short>(util::reverseBearing(bearings.first))}),
|
||||
std::vector<bool>({true}),
|
||||
0,
|
||||
Intersection::NO_INDEX,
|
||||
util::guidance::LaneTuple(),
|
||||
{}};
|
||||
|
||||
// This step has length zero, the only reason we need it is the target location
|
||||
maneuver = {intersection.location,
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_
|
||||
#define OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Runs fn on RouteStep sub-ranges determined to be roundabouts.
|
||||
// The function fn is getting called with a roundabout range as in: [enter, .., leave].
|
||||
//
|
||||
// The following situations are taken care for (i.e. we discard them):
|
||||
// - partial roundabout: enter without exit or exit without enter
|
||||
// - data issues: no roundabout, exit before enter
|
||||
template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, Iter last, Fn fn)
|
||||
{
|
||||
while (first != last)
|
||||
{
|
||||
const auto enter = std::find_if(first, last, [](const RouteStep &step) {
|
||||
return entersRoundabout(step.maneuver.instruction);
|
||||
});
|
||||
|
||||
// enter has to come before leave, otherwise: faulty data / partial roundabout, skip those
|
||||
const auto leave = std::find_if(enter, last, [](const RouteStep &step) {
|
||||
return leavesRoundabout(step.maneuver.instruction);
|
||||
});
|
||||
|
||||
// No roundabouts, or partial one (like start / end inside a roundabout)
|
||||
if (enter == last || leave == last)
|
||||
break;
|
||||
|
||||
(void)fn(std::make_pair(enter, leave));
|
||||
|
||||
// Skip to first step after the currently handled enter / leave pair
|
||||
first = std::next(leave);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_ */
|
||||
@@ -11,10 +11,11 @@
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
@@ -71,6 +72,33 @@ struct RouteStep
|
||||
std::size_t geometry_begin;
|
||||
std::size_t geometry_end;
|
||||
std::vector<Intersection> intersections;
|
||||
|
||||
LaneID numLanesToTheRight() const
|
||||
{
|
||||
return intersections.front().lanes.first_lane_from_the_right;
|
||||
}
|
||||
|
||||
LaneID numLanesToTheLeft() const
|
||||
{
|
||||
LaneID const total = intersections.front().lane_description.size();
|
||||
return total - (intersections.front().lanes.lanes_in_turn +
|
||||
intersections.front().lanes.first_lane_from_the_right);
|
||||
}
|
||||
|
||||
auto lanesToTheLeft() const
|
||||
{
|
||||
const auto &description = intersections.front().lane_description;
|
||||
LaneID num_lanes_left = numLanesToTheLeft();
|
||||
return boost::make_iterator_range(description.begin(),
|
||||
description.begin() + num_lanes_left);
|
||||
}
|
||||
|
||||
auto lanesToTheRight() const
|
||||
{
|
||||
const auto &description = intersections.front().lane_description;
|
||||
LaneID num_lanes_right = numLanesToTheRight();
|
||||
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
|
||||
}
|
||||
};
|
||||
|
||||
inline RouteStep getInvalidRouteStep()
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
#ifndef OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
|
||||
#define OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
using util::guidance::entersRoundabout;
|
||||
using util::guidance::leavesRoundabout;
|
||||
using util::guidance::staysOnRoundabout;
|
||||
|
||||
// Silent Turn Instructions are not to be mentioned to the outside world but
|
||||
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::NoTurn ||
|
||||
instruction.type == extractor::guidance::TurnType::Suppressed ||
|
||||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
|
||||
}
|
||||
|
||||
inline extractor::guidance::DirectionModifier::Enum angleToDirectionModifier(const double bearing)
|
||||
{
|
||||
if (bearing < 135)
|
||||
{
|
||||
return extractor::guidance::DirectionModifier::Right;
|
||||
}
|
||||
|
||||
if (bearing <= 225)
|
||||
{
|
||||
return extractor::guidance::DirectionModifier::Straight;
|
||||
}
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
}
|
||||
|
||||
// Runs fn on RouteStep sub-ranges determined to be roundabouts.
|
||||
// The function fn is getting called with a roundabout range as in: [enter, .., leave].
|
||||
//
|
||||
// The following situations are taken care for (i.e. we discard them):
|
||||
// - partial roundabout: enter without exit or exit without enter
|
||||
// - data issues: no roundabout, exit before enter
|
||||
template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, Iter last, Fn fn)
|
||||
{
|
||||
while (first != last)
|
||||
{
|
||||
const auto enter = std::find_if(first, last, [](const RouteStep &step) {
|
||||
return entersRoundabout(step.maneuver.instruction);
|
||||
});
|
||||
|
||||
// enter has to come before leave, otherwise: faulty data / partial roundabout, skip those
|
||||
const auto leave = std::find_if(enter, last, [](const RouteStep &step) {
|
||||
return leavesRoundabout(step.maneuver.instruction);
|
||||
});
|
||||
|
||||
// No roundabouts, or partial one (like start / end inside a roundabout)
|
||||
if (enter == last || leave == last)
|
||||
break;
|
||||
|
||||
(void)fn(std::make_pair(enter, leave));
|
||||
|
||||
// Skip to first step after the currently handled enter / leave pair
|
||||
first = std::next(leave);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
LaneID inline numLanesToTheRight(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
return step.intersections.front().lanes.first_lane_from_the_right;
|
||||
}
|
||||
|
||||
LaneID inline numLanesToTheLeft(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
LaneID const total = step.intersections.front().lane_description.size();
|
||||
return total - (step.intersections.front().lanes.lanes_in_turn +
|
||||
step.intersections.front().lanes.first_lane_from_the_right);
|
||||
}
|
||||
|
||||
auto inline lanesToTheLeft(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
const auto &description = step.intersections.front().lane_description;
|
||||
LaneID num_lanes_left = numLanesToTheLeft(step);
|
||||
return boost::make_iterator_range(description.begin(), description.begin() + num_lanes_left);
|
||||
}
|
||||
|
||||
auto inline lanesToTheRight(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
const auto &description = step.intersections.front().lane_description;
|
||||
LaneID num_lanes_right = numLanesToTheRight(step);
|
||||
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_ */
|
||||
@@ -235,10 +235,10 @@ class AlternativeRouting final
|
||||
}
|
||||
}
|
||||
|
||||
// util::SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
|
||||
// util::Log(logDEBUG) << "fwd_search_space size: " <<
|
||||
// forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
|
||||
// nodes";
|
||||
// util::SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
|
||||
// util::Log(logDEBUG) << "rev_search_space size: " <<
|
||||
// reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
|
||||
// nodes";
|
||||
|
||||
@@ -601,7 +601,7 @@ class AlternativeRouting final
|
||||
// //compute forward sharing
|
||||
// while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
|
||||
// (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
|
||||
// // util::SimpleLogger().Write() << "retrieving edge (" <<
|
||||
// // util::Log() << "retrieving edge (" <<
|
||||
// packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
|
||||
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
|
||||
// packed_alternate_path[aindex+1]);
|
||||
@@ -640,7 +640,7 @@ class AlternativeRouting final
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int weight = forward_heap.GetKey(node);
|
||||
// const NodeID parentnode = forward_heap.GetData(node).parent;
|
||||
// util::SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
|
||||
// util::Log() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
|
||||
// edge ("
|
||||
// << parentnode << "," << node << "), dist: " << weight;
|
||||
|
||||
@@ -665,11 +665,11 @@ class AlternativeRouting final
|
||||
{
|
||||
*middle_node = node;
|
||||
*upper_bound_to_shortest_path_weight = new_weight;
|
||||
// util::SimpleLogger().Write() << "accepted middle_node " << *middle_node
|
||||
// util::Log() << "accepted middle_node " << *middle_node
|
||||
// << " at
|
||||
// weight " << new_weight;
|
||||
// } else {
|
||||
// util::SimpleLogger().Write() << "discarded middle_node " << *middle_node
|
||||
// util::Log() << "discarded middle_node " << *middle_node
|
||||
// << "
|
||||
// at weight " << new_weight;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define TRIP_BRUTE_FORCE_HPP
|
||||
|
||||
#include "util/dist_table_wrapper.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "util/dist_table_wrapper.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define TRIP_NEAREST_NEIGHBOUR_HPP
|
||||
|
||||
#include "util/dist_table_wrapper.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/parsing_toolkit.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -109,13 +109,13 @@ inline unsigned parseDuration(const std::string &s)
|
||||
inline std::string
|
||||
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
|
||||
{
|
||||
return extractor::guidance::trimLaneString(std::move(lane_string), count_left, count_right);
|
||||
return guidance::trimLaneString(std::move(lane_string), count_left, count_right);
|
||||
}
|
||||
|
||||
inline std::string applyAccessTokens(const std::string &lane_string,
|
||||
const std::string &access_tokens)
|
||||
{
|
||||
return extractor::guidance::applyAccessTokens(lane_string, access_tokens);
|
||||
return guidance::applyAccessTokens(lane_string, access_tokens);
|
||||
}
|
||||
|
||||
// Takes a string representing a list separated by delim and canonicalizes containing spaces.
|
||||
|
||||
@@ -46,7 +46,6 @@ struct ExtractionWay
|
||||
roundabout = false;
|
||||
circular = false;
|
||||
is_startpoint = true;
|
||||
is_access_restricted = false;
|
||||
name.clear();
|
||||
ref.clear();
|
||||
pronunciation.clear();
|
||||
@@ -96,7 +95,6 @@ struct ExtractionWay
|
||||
std::string turn_lanes_backward;
|
||||
bool roundabout;
|
||||
bool circular;
|
||||
bool is_access_restricted;
|
||||
bool is_startpoint;
|
||||
TravelMode forward_travel_mode : 4;
|
||||
TravelMode backward_travel_mode : 4;
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
|
||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
namespace osrm
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp" // EdgeID
|
||||
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/range/algorithm/find_if.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -27,11 +35,18 @@ struct IntersectionShapeData
|
||||
|
||||
inline auto makeCompareShapeDataByBearing(const double base_bearing)
|
||||
{
|
||||
return [base_bearing](const IntersectionShapeData &lhs, const IntersectionShapeData &rhs) {
|
||||
return util::bearing::angleBetweenBearings(base_bearing, lhs.bearing) <
|
||||
util::bearing::angleBetweenBearings(base_bearing, rhs.bearing);
|
||||
return [base_bearing](const auto &lhs, const auto &rhs) {
|
||||
return util::angleBetweenBearings(base_bearing, lhs.bearing) <
|
||||
util::angleBetweenBearings(base_bearing, rhs.bearing);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
inline auto makeCompareAngularDeviation(const double angle)
|
||||
{
|
||||
return [angle](const auto &lhs, const auto &rhs) {
|
||||
return util::angularDeviation(lhs.angle, angle) < util::angularDeviation(rhs.angle, angle);
|
||||
};
|
||||
}
|
||||
|
||||
// When viewing an intersection from an incoming edge, we can transform a shape into a view which
|
||||
// gives additional information on angles and whether a turn is allowed
|
||||
@@ -53,7 +68,7 @@ struct IntersectionViewData : IntersectionShapeData
|
||||
// A Connected Road is the internal representation of a potential turn. Internally, we require
|
||||
// full list of all connected roads to determine the outcome.
|
||||
// The reasoning behind is that even invalid turns can influence the perceived angles, or even
|
||||
// instructions themselves. An pososible example can be described like this:
|
||||
// instructions themselves. An possible example can be described like this:
|
||||
//
|
||||
// aaa(2)aa
|
||||
// a - bbbbb
|
||||
@@ -61,8 +76,7 @@ struct IntersectionViewData : IntersectionShapeData
|
||||
//
|
||||
// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
|
||||
// In addition, they can influence whether a turn is obvious or not. b->(2) would also be no
|
||||
// turn-operation,
|
||||
// but rather a name change.
|
||||
// turn-operation, but rather a name change.
|
||||
//
|
||||
// If this were a normal intersection with
|
||||
//
|
||||
@@ -96,47 +110,117 @@ struct ConnectedRoad final : IntersectionViewData
|
||||
// small helper function to print the content of a connected road
|
||||
std::string toString(const ConnectedRoad &road);
|
||||
|
||||
// Intersections are sorted roads: [0] being the UTurn road, then from sharp right to sharp left.
|
||||
|
||||
using IntersectionShape = std::vector<IntersectionShapeData>;
|
||||
|
||||
struct IntersectionView final : std::vector<IntersectionViewData>
|
||||
// Common operations shared among IntersectionView and Intersections.
|
||||
// Inherit to enable those operations on your compatible type. CRTP pattern.
|
||||
template <typename Self> struct EnableIntersectionOps
|
||||
{
|
||||
// Find the turn whose angle offers the least angular deviation to the specified angle
|
||||
// For turn angles [0, 90, 260] and a query of 180 we return the 260 degree turn.
|
||||
auto findClosestTurn(double angle) const
|
||||
{
|
||||
auto comp = makeCompareAngularDeviation(angle);
|
||||
return std::min_element(self()->begin(), self()->end(), comp);
|
||||
}
|
||||
|
||||
// Check validity of the intersection object. We assume a few basic properties every set of
|
||||
// connected roads should follow throughout guidance pre-processing. This utility function
|
||||
// allows checking intersections for validity
|
||||
auto valid() const
|
||||
{
|
||||
if (self()->empty())
|
||||
return false;
|
||||
|
||||
auto comp = [](const auto &lhs, const auto &rhs) { return lhs.CompareByAngle(rhs); };
|
||||
|
||||
const auto ordered = std::is_sorted(self()->begin(), self()->end(), comp);
|
||||
|
||||
if (!ordered)
|
||||
return false;
|
||||
|
||||
const auto uturn = self()->operator[](0).angle < std::numeric_limits<double>::epsilon();
|
||||
|
||||
if (!uturn)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Given all possible turns which is the highest connected number of lanes per turn.
|
||||
// This value is used for example during generation of intersections.
|
||||
auto getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &graph) const
|
||||
{
|
||||
const std::function<std::uint8_t(const ConnectedRoad &)> to_lane_count =
|
||||
[&](const ConnectedRoad &road) {
|
||||
return graph.GetEdgeData(road.eid).road_classification.GetNumberOfLanes();
|
||||
};
|
||||
|
||||
std::uint8_t max_lanes = 0;
|
||||
const auto extract_maximal_value = [&max_lanes](std::uint8_t value) {
|
||||
max_lanes = std::max(max_lanes, value);
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto view = *self() | boost::adaptors::transformed(to_lane_count);
|
||||
boost::range::find_if(view, extract_maximal_value);
|
||||
return max_lanes;
|
||||
}
|
||||
|
||||
// Returns the UTurn road we took to arrive at this intersection.
|
||||
const auto &getUTurnRoad() const { return self()->operator[](0); }
|
||||
|
||||
// Returns the right-most road at this intersection.
|
||||
const auto &getRightmostRoad() const
|
||||
{
|
||||
return self()->size() > 1 ? self()->operator[](1) : self()->getUTurnRoad();
|
||||
}
|
||||
|
||||
// Returns the left-most road at this intersection.
|
||||
const auto &getLeftmostRoad() const
|
||||
{
|
||||
return self()->size() > 1 ? self()->back() : self()->getUTurnRoad();
|
||||
}
|
||||
|
||||
// Can this be skipped over?
|
||||
auto isTrafficSignalOrBarrier() const { return self()->size() == 2; }
|
||||
|
||||
// Checks if there is at least one road available (except UTurn road) on which to continue.
|
||||
auto isDeadEnd() const
|
||||
{
|
||||
auto pred = [](const auto &road) { return road.entry_allowed; };
|
||||
return !std::any_of(self()->begin() + 1, self()->end(), pred);
|
||||
}
|
||||
|
||||
// Returns the number of roads we can enter at this intersection, respectively.
|
||||
auto countEnterable() const
|
||||
{
|
||||
auto pred = [](const auto &road) { return road.entry_allowed; };
|
||||
return std::count_if(self()->begin(), self()->end(), pred);
|
||||
}
|
||||
|
||||
// Returns the number of roads we can not enter at this intersection, respectively.
|
||||
auto countNonEnterable() const { return self()->size() - self()->countEnterable(); }
|
||||
|
||||
private:
|
||||
auto self() { return static_cast<Self *>(this); }
|
||||
auto self() const { return static_cast<const Self *>(this); }
|
||||
};
|
||||
|
||||
struct IntersectionView final : std::vector<IntersectionViewData>, //
|
||||
EnableIntersectionOps<IntersectionView> //
|
||||
{
|
||||
using Base = std::vector<IntersectionViewData>;
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return std::is_sorted(begin(), end(), std::mem_fn(&IntersectionViewData::CompareByAngle));
|
||||
};
|
||||
|
||||
Base::iterator findClosestTurn(double angle);
|
||||
Base::const_iterator findClosestTurn(double angle) const;
|
||||
};
|
||||
|
||||
struct Intersection final : std::vector<ConnectedRoad>
|
||||
struct Intersection final : std::vector<ConnectedRoad>, //
|
||||
EnableIntersectionOps<Intersection> //
|
||||
{
|
||||
using Base = std::vector<ConnectedRoad>;
|
||||
/*
|
||||
* find the turn whose angle offers the least angularDeviation to the specified angle
|
||||
* E.g. for turn angles [0,90,260] and a query of 180 we return the 260 degree turn (difference
|
||||
* 80 over the difference of 90 to the 90 degree turn)
|
||||
*/
|
||||
Base::iterator findClosestTurn(double angle);
|
||||
Base::const_iterator findClosestTurn(double angle) const;
|
||||
|
||||
/*
|
||||
* Check validity of the intersection object. We assume a few basic properties every set of
|
||||
* connected roads should follow throughout guidance pre-processing. This utility function
|
||||
* allows checking intersections for validity
|
||||
*/
|
||||
bool valid() const;
|
||||
|
||||
// given all possible turns, which is the highest connected number of lanes per turn. This value
|
||||
// is used, for example, during generation of intersections.
|
||||
std::uint8_t getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &) const;
|
||||
};
|
||||
|
||||
Intersection::const_iterator findClosestTurn(const Intersection &intersection, const double angle);
|
||||
Intersection::iterator findClosestTurn(Intersection &intersection, const double angle);
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -35,6 +35,12 @@ class IntersectionGenerator
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
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;
|
||||
|
||||
/*
|
||||
@@ -43,6 +49,7 @@ class IntersectionGenerator
|
||||
* 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,
|
||||
@@ -53,11 +60,11 @@ class IntersectionGenerator
|
||||
// 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.
|
||||
IntersectionView GetActualNextIntersection(const NodeID starting_node,
|
||||
const EdgeID via_edge,
|
||||
NodeID *resulting_from_node,
|
||||
EdgeID *resulting_via_edge) const;
|
||||
// more than a single next road. This function skips over degree two nodes to find coorect input
|
||||
// for GetConnectedRoads.
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::pair<NodeID, EdgeID> SkipDegreeTwoNodes(const NodeID starting_node,
|
||||
const EdgeID via_edge) const;
|
||||
|
||||
// Allow access to the coordinate extractor for all owners
|
||||
const CoordinateExtractor &GetCoordinateExtractor() const;
|
||||
|
||||
@@ -3,15 +3,22 @@
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/guidance/node_based_graph_walker.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/guidance/name_announcements.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -48,9 +55,7 @@ class IntersectionHandler
|
||||
const util::NameTable &name_table;
|
||||
const SuffixTable &street_name_suffix_table;
|
||||
const IntersectionGenerator &intersection_generator;
|
||||
|
||||
// counts the number on allowed entry roads
|
||||
std::size_t countValid(const Intersection &intersection) const;
|
||||
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;
|
||||
@@ -59,7 +64,8 @@ class IntersectionHandler
|
||||
// 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
|
||||
// turn angles.
|
||||
std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
|
||||
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||
std::size_t findObviousTurn(const EdgeID via_edge, const IntersectionType &intersection) const;
|
||||
|
||||
// Obvious turns can still take multiple forms. This function looks at the turn onto a road
|
||||
// candidate when coming from a via_edge and determines the best instruction to emit.
|
||||
@@ -83,9 +89,458 @@ 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
|
||||
{
|
||||
IntersectionView intersection; // < actual intersection
|
||||
NodeID node; // < node at this intersection
|
||||
};
|
||||
|
||||
// Skips over artificial intersections i.e. traffic lights, barriers etc.
|
||||
// Returns the next non-artificial intersection and its node in the node based
|
||||
// graph if an intersection could be found or none otherwise.
|
||||
//
|
||||
// a ... tl ... b .. c
|
||||
// .
|
||||
// .
|
||||
// d
|
||||
//
|
||||
// ^ at
|
||||
// ^ via
|
||||
//
|
||||
// For this scenario returns intersection at `b` and `b`.
|
||||
boost::optional<IntersectionHandler::IntersectionViewAndNode>
|
||||
getNextIntersection(const NodeID at, const EdgeID via) const;
|
||||
};
|
||||
|
||||
// Impl.
|
||||
|
||||
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||
std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
const IntersectionType &intersection) const
|
||||
{
|
||||
using Road = typename IntersectionType::value_type;
|
||||
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
|
||||
using osrm::util::angularDeviation;
|
||||
|
||||
// no obvious road
|
||||
if (intersection.size() == 1)
|
||||
return 0;
|
||||
|
||||
// a single non u-turn is obvious
|
||||
if (intersection.size() == 2)
|
||||
return 1;
|
||||
|
||||
const EdgeData &in_way_data = node_based_graph.GetEdgeData(via_edge);
|
||||
|
||||
// the strategy for picking the most obvious turn involves deciding between
|
||||
// an overall best candidate and a best candidate that shares the same name
|
||||
// as the in road, i.e. a continue road
|
||||
std::size_t best_option = 0;
|
||||
double best_option_deviation = 180;
|
||||
std::size_t best_continue = 0;
|
||||
double best_continue_deviation = 180;
|
||||
|
||||
/* helper functions */
|
||||
const auto IsContinueRoad = [&](const EdgeData &way_data) {
|
||||
return !util::guidance::requiresNameAnnounced(
|
||||
in_way_data.name_id, way_data.name_id, name_table, street_name_suffix_table);
|
||||
};
|
||||
auto sameOrHigherPriority = [&in_way_data](const auto &way_data) {
|
||||
return way_data.road_classification.GetPriority() <=
|
||||
in_way_data.road_classification.GetPriority();
|
||||
};
|
||||
auto IsLowPriority = [](const auto &way_data) {
|
||||
return way_data.road_classification.IsLowPriorityRoadClass();
|
||||
};
|
||||
// These two Compare functions are used for sifting out best option and continue
|
||||
// candidates by evaluating all the ways in an intersection by what they share
|
||||
// with the in way. Ideal candidates are of similar road class with the in way
|
||||
// and are require relatively straight turns.
|
||||
const auto RoadCompare = [&](const auto &lhs, const auto &rhs) {
|
||||
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto lhs_deviation = angularDeviation(lhs.angle, STRAIGHT_ANGLE);
|
||||
const auto rhs_deviation = angularDeviation(rhs.angle, STRAIGHT_ANGLE);
|
||||
|
||||
const bool rhs_same_classification =
|
||||
rhs_data.road_classification == in_way_data.road_classification;
|
||||
const bool lhs_same_classification =
|
||||
lhs_data.road_classification == in_way_data.road_classification;
|
||||
const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_data);
|
||||
const bool rhs_low_priority = IsLowPriority(rhs_data);
|
||||
const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_data);
|
||||
const bool lhs_low_priority = IsLowPriority(lhs_data);
|
||||
auto left_tie = std::tie(lhs.entry_allowed,
|
||||
lhs_same_or_higher_priority,
|
||||
rhs_low_priority,
|
||||
rhs_deviation,
|
||||
lhs_same_classification);
|
||||
auto right_tie = std::tie(rhs.entry_allowed,
|
||||
rhs_same_or_higher_priority,
|
||||
lhs_low_priority,
|
||||
lhs_deviation,
|
||||
rhs_same_classification);
|
||||
return left_tie > right_tie;
|
||||
};
|
||||
const auto RoadCompareSameName = [&](const auto &lhs, const auto &rhs) {
|
||||
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto lhs_continues = IsContinueRoad(lhs_data);
|
||||
const auto rhs_continues = IsContinueRoad(rhs_data);
|
||||
const auto left_tie = std::tie(lhs.entry_allowed, lhs_continues);
|
||||
const auto right_tie = std::tie(rhs.entry_allowed, rhs_continues);
|
||||
return left_tie > right_tie || (left_tie == right_tie && RoadCompare(lhs, rhs));
|
||||
};
|
||||
|
||||
auto best_option_it = std::min_element(begin(intersection), end(intersection), RoadCompare);
|
||||
|
||||
// min element should only return end() when vector is empty
|
||||
BOOST_ASSERT(best_option_it != end(intersection));
|
||||
|
||||
best_option = std::distance(begin(intersection), best_option_it);
|
||||
best_option_deviation = angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
|
||||
const auto &best_option_data = node_based_graph.GetEdgeData(intersection[best_option].eid);
|
||||
|
||||
// Unless the in way is also low priority, it is generally undesirable to
|
||||
// indicate that a low priority road is obvious
|
||||
if (IsLowPriority(best_option_data) &&
|
||||
best_option_data.road_classification != in_way_data.road_classification)
|
||||
{
|
||||
best_option = 0;
|
||||
best_option_deviation = 180;
|
||||
}
|
||||
|
||||
// double check if the way with the lowest deviation from straight is still be better choice
|
||||
const auto straightest = intersection.findClosestTurn(STRAIGHT_ANGLE);
|
||||
if (straightest != best_option_it)
|
||||
{
|
||||
const EdgeData &straightest_data = node_based_graph.GetEdgeData(straightest->eid);
|
||||
double straightest_data_deviation = angularDeviation(straightest->angle, STRAIGHT_ANGLE);
|
||||
const auto deviation_diff =
|
||||
std::abs(best_option_deviation - straightest_data_deviation) > FUZZY_ANGLE_DIFFERENCE;
|
||||
const auto not_ramp_class = !straightest_data.road_classification.IsRampClass();
|
||||
const auto not_link_class = !straightest_data.road_classification.IsLinkClass();
|
||||
if (deviation_diff && !IsLowPriority(straightest_data) && not_ramp_class &&
|
||||
not_link_class && !IsContinueRoad(best_option_data))
|
||||
{
|
||||
best_option = std::distance(begin(intersection), straightest);
|
||||
best_option_deviation =
|
||||
angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
|
||||
}
|
||||
}
|
||||
|
||||
// No non-low priority roads? Declare no obvious turn
|
||||
if (best_option == 0)
|
||||
return 0;
|
||||
|
||||
auto best_continue_it =
|
||||
std::min_element(begin(intersection), end(intersection), RoadCompareSameName);
|
||||
const auto best_continue_data = node_based_graph.GetEdgeData(best_continue_it->eid);
|
||||
if (IsContinueRoad(best_continue_data) ||
|
||||
(in_way_data.name_id == EMPTY_NAMEID && best_continue_data.name_id == EMPTY_NAMEID))
|
||||
{
|
||||
best_continue = std::distance(begin(intersection), best_continue_it);
|
||||
best_continue_deviation =
|
||||
angularDeviation(intersection[best_continue].angle, STRAIGHT_ANGLE);
|
||||
}
|
||||
|
||||
// if the best angle is going straight but the road is turning, declare no obvious turn
|
||||
if (0 != best_continue && best_option != best_continue &&
|
||||
best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
||||
node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification ==
|
||||
best_option_data.road_classification)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get a count of number of ways from that intersection that qualify to have
|
||||
// continue instruction because they share a name with the approaching way
|
||||
const std::int64_t continue_count =
|
||||
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
|
||||
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid));
|
||||
});
|
||||
const std::int64_t continue_count_valid =
|
||||
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
|
||||
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid)) && way.entry_allowed;
|
||||
});
|
||||
|
||||
// checks if continue candidates are sharp turns
|
||||
const bool all_continues_are_narrow = [&]() {
|
||||
return std::count_if(begin(intersection), end(intersection), [&](const Road &road) {
|
||||
const EdgeData &road_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const double &road_angle = angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||
return IsContinueRoad(road_data) && (road_angle < NARROW_TURN_ANGLE);
|
||||
}) == continue_count;
|
||||
}();
|
||||
|
||||
// return true if the best_option candidate is more promising than the best_continue candidate
|
||||
// otherwise return false, the best_continue candidate is more promising
|
||||
const auto best_over_best_continue = [&]() {
|
||||
// no continue road exists
|
||||
if (best_continue == 0)
|
||||
return true;
|
||||
|
||||
// we have multiple continues and not all are narrow. This suggests that
|
||||
// the continue candidates are ambiguous
|
||||
if (!all_continues_are_narrow && (continue_count >= 2 && intersection.size() >= 4))
|
||||
return true;
|
||||
|
||||
// if the best continue is not narrow and we also have at least 2 possible choices, the
|
||||
// intersection size does not matter anymore
|
||||
if (continue_count_valid >= 2 && best_continue_deviation >= 2 * NARROW_TURN_ANGLE)
|
||||
return true;
|
||||
|
||||
// continue data now most certainly exists
|
||||
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
|
||||
|
||||
// best_continue is obvious by road class
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
continue_data.road_classification,
|
||||
best_option_data.road_classification))
|
||||
return false;
|
||||
|
||||
// best_option is obvious by road class
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
continue_data.road_classification))
|
||||
return true;
|
||||
|
||||
// the best_option deviation is very straight and not a ramp
|
||||
if (best_option_deviation < best_continue_deviation &&
|
||||
best_option_deviation < FUZZY_ANGLE_DIFFERENCE &&
|
||||
!best_option_data.road_classification.IsRampClass())
|
||||
return true;
|
||||
|
||||
// the continue road is of a lower priority, while the road continues on the same priority
|
||||
// with a better angle
|
||||
if (best_option_deviation < best_continue_deviation &&
|
||||
in_way_data.road_classification == best_option_data.road_classification &&
|
||||
continue_data.road_classification.GetPriority() >
|
||||
best_option_data.road_classification.GetPriority())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (best_over_best_continue)
|
||||
{
|
||||
// Find left/right deviation
|
||||
// skipping over service roads
|
||||
const std::size_t left_index = [&]() {
|
||||
const auto index_candidate = (best_option + 1) % intersection.size();
|
||||
if (index_candidate == 0)
|
||||
return index_candidate;
|
||||
const auto &candidate_data =
|
||||
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
candidate_data.road_classification))
|
||||
return (index_candidate + 1) % intersection.size();
|
||||
else
|
||||
return index_candidate;
|
||||
|
||||
}();
|
||||
const auto right_index = [&]() {
|
||||
BOOST_ASSERT(best_option > 0);
|
||||
const auto index_candidate = best_option - 1;
|
||||
if (index_candidate == 0)
|
||||
return index_candidate;
|
||||
const auto candidate_data =
|
||||
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
candidate_data.road_classification))
|
||||
return index_candidate - 1;
|
||||
else
|
||||
return index_candidate;
|
||||
}();
|
||||
|
||||
const double left_deviation =
|
||||
angularDeviation(intersection[left_index].angle, STRAIGHT_ANGLE);
|
||||
const double right_deviation =
|
||||
angularDeviation(intersection[right_index].angle, STRAIGHT_ANGLE);
|
||||
|
||||
// return best_option candidate if it is nearly straight and distinct from the nearest other
|
||||
// out
|
||||
// way
|
||||
if (best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
||||
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
|
||||
return best_option;
|
||||
|
||||
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid);
|
||||
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid);
|
||||
|
||||
const bool obvious_to_left =
|
||||
left_index == 0 || obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
left_data.road_classification);
|
||||
const bool obvious_to_right =
|
||||
right_index == 0 || obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
right_data.road_classification);
|
||||
|
||||
// if the best_option turn isn't narrow, but there is a nearly straight turn, we don't
|
||||
// consider the
|
||||
// turn obvious
|
||||
const auto check_narrow = [&intersection, best_option_deviation](const std::size_t index) {
|
||||
return angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) <=
|
||||
FUZZY_ANGLE_DIFFERENCE &&
|
||||
(best_option_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed);
|
||||
};
|
||||
|
||||
// other narrow turns?
|
||||
if (check_narrow(right_index) && !obvious_to_right)
|
||||
return 0;
|
||||
|
||||
if (check_narrow(left_index) && !obvious_to_left)
|
||||
return 0;
|
||||
|
||||
// checks if a given way in the intersection is distinct enough from the best_option
|
||||
// candidate
|
||||
const auto isDistinct = [&](const std::size_t index, const double deviation) {
|
||||
/*
|
||||
If the neighbor is not possible to enter, we allow for a lower
|
||||
distinction rate. If the road category is smaller, its also adjusted. Only
|
||||
roads of the same priority require the full distinction ratio.
|
||||
*/
|
||||
const auto &best_option_data =
|
||||
node_based_graph.GetEdgeData(intersection[best_option].eid);
|
||||
const auto adjusted_distinction_ratio = [&]() {
|
||||
// not allowed competitors are easily distinct
|
||||
if (!intersection[index].entry_allowed)
|
||||
return 0.7 * DISTINCTION_RATIO;
|
||||
// a bit less obvious are road classes
|
||||
else if (in_way_data.road_classification == best_option_data.road_classification &&
|
||||
best_option_data.road_classification.GetPriority() <
|
||||
node_based_graph.GetEdgeData(intersection[index].eid)
|
||||
.road_classification.GetPriority())
|
||||
return 0.8 * DISTINCTION_RATIO;
|
||||
// if road classes are the same, we use the full ratio
|
||||
else
|
||||
return DISTINCTION_RATIO;
|
||||
}();
|
||||
return index == 0 || deviation / best_option_deviation >= adjusted_distinction_ratio ||
|
||||
(deviation <= NARROW_TURN_ANGLE && !intersection[index].entry_allowed);
|
||||
};
|
||||
|
||||
const bool distinct_to_left = isDistinct(left_index, left_deviation);
|
||||
const bool distinct_to_right = isDistinct(right_index, right_deviation);
|
||||
// Well distinct turn that is nearly straight
|
||||
if ((distinct_to_left || obvious_to_left) && (distinct_to_right || obvious_to_right))
|
||||
return best_option;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
|
||||
if (std::abs(best_continue_deviation) < 1)
|
||||
return best_continue;
|
||||
|
||||
// check if any other similar best continues exist
|
||||
std::size_t i, last = intersection.size();
|
||||
for (i = 1; i < last; ++i)
|
||||
{
|
||||
if (i == best_continue || !intersection[i].entry_allowed)
|
||||
continue;
|
||||
|
||||
const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid);
|
||||
const bool is_obvious_by_road_class =
|
||||
obviousByRoadClass(in_way_data.road_classification,
|
||||
continue_data.road_classification,
|
||||
turn_data.road_classification);
|
||||
|
||||
// if the main road is obvious by class, we ignore the current road as a potential
|
||||
// prevention of obviousness
|
||||
if (is_obvious_by_road_class)
|
||||
continue;
|
||||
|
||||
// continuation could be grouped with a straight turn and the turning road is a ramp
|
||||
if (turn_data.road_classification.IsRampClass() &&
|
||||
best_continue_deviation < GROUP_ANGLE &&
|
||||
!continue_data.road_classification.IsRampClass())
|
||||
continue;
|
||||
|
||||
// perfectly straight turns prevent obviousness
|
||||
const auto turn_deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
|
||||
if (turn_deviation < FUZZY_ANGLE_DIFFERENCE)
|
||||
return 0;
|
||||
|
||||
const auto deviation_ratio = turn_deviation / best_continue_deviation;
|
||||
|
||||
// in comparison to normal deviations, a continue road can offer a smaller distinction
|
||||
// ratio. Other roads close to the turn angle are not as obvious, if one road continues.
|
||||
if (deviation_ratio < DISTINCTION_RATIO / 1.5)
|
||||
return 0;
|
||||
|
||||
/* in comparison to another continuing road, we need a better distinction. This prevents
|
||||
situations where the turn is probably less obvious. An example are places that have a
|
||||
road with the same name entering/exiting:
|
||||
|
||||
d
|
||||
/
|
||||
/
|
||||
a -- b
|
||||
\
|
||||
\
|
||||
c
|
||||
*/
|
||||
|
||||
const auto same_name = !util::guidance::requiresNameAnnounced(
|
||||
turn_data.name_id, continue_data.name_id, name_table, street_name_suffix_table);
|
||||
|
||||
if (same_name && deviation_ratio < 1.5 * DISTINCTION_RATIO)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Segregated intersections can result in us finding an obvious turn, even though its only
|
||||
// obvious due to a very short segment in between. So if the segment coming in is very
|
||||
// short, we check the previous intersection for other continues in the opposite bearing.
|
||||
const auto node_at_intersection = node_based_graph.GetTarget(via_edge);
|
||||
|
||||
const double constexpr MAX_COLLAPSE_DISTANCE = 30;
|
||||
const auto distance_at_u_turn = intersection[0].segment_length;
|
||||
if (distance_at_u_turn < MAX_COLLAPSE_DISTANCE)
|
||||
{
|
||||
// this request here actually goes against the direction of the ingoing edgeid. This can
|
||||
// even reverse the direction. Since we don't want to compute actual turns but simply
|
||||
// try to find whether there is a turn going to the opposite direction of our obvious
|
||||
// turn, this should be alright.
|
||||
NodeID new_node;
|
||||
const auto previous_intersection = [&]() {
|
||||
EdgeID turn_edge;
|
||||
std::tie(new_node, turn_edge) = intersection_generator.SkipDegreeTwoNodes(
|
||||
node_at_intersection, intersection[0].eid);
|
||||
return intersection_generator.GetConnectedRoads(new_node, turn_edge);
|
||||
}();
|
||||
|
||||
if (new_node != node_at_intersection)
|
||||
{
|
||||
const auto continue_road = intersection[best_continue];
|
||||
for (const auto &comparison_road : previous_intersection)
|
||||
{
|
||||
// since we look at the intersection in the wrong direction, a similar angle
|
||||
// actually represents a near 180 degree different in bearings between the two
|
||||
// roads. So if there is a road that is enterable in the opposite direction just
|
||||
// prior, a turn is not obvious
|
||||
const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.eid);
|
||||
if (angularDeviation(comparison_road.angle, STRAIGHT_ANGLE) > GROUP_ANGLE &&
|
||||
angularDeviation(comparison_road.angle, continue_road.angle) <
|
||||
FUZZY_ANGLE_DIFFERENCE &&
|
||||
!turn_data.reversed && continue_data.CanCombineWith(turn_data))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best_continue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -57,16 +57,17 @@ class IntersectionNormalizer
|
||||
|
||||
const IntersectionGenerator &intersection_generator;
|
||||
|
||||
// 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
|
||||
/* 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,
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
@@ -43,7 +42,7 @@ class NodeBasedGraphWalker
|
||||
boost::optional<std::pair<NodeID, EdgeID>> TraverseRoad(NodeID starting_at_node_id,
|
||||
EdgeID following_edge_id,
|
||||
accumulator_type &accumulator,
|
||||
const selector_type &selector);
|
||||
const selector_type &selector) const;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
@@ -141,7 +140,7 @@ boost::optional<std::pair<NodeID, EdgeID>>
|
||||
NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
|
||||
EdgeID current_edge_id,
|
||||
accumulator_type &accumulator,
|
||||
const selector_type &selector)
|
||||
const selector_type &selector) const
|
||||
{
|
||||
/*
|
||||
* since graph hopping is used in many ways, we don't generate an adjusted intersection
|
||||
@@ -192,6 +191,60 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
|
||||
return {};
|
||||
}
|
||||
|
||||
struct SkipTrafficSignalBarrierRoadSelector
|
||||
{
|
||||
boost::optional<EdgeID> operator()(const NodeID,
|
||||
const EdgeID,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &) const
|
||||
{
|
||||
if (intersection.isTrafficSignalOrBarrier())
|
||||
{
|
||||
return boost::make_optional(intersection[1].eid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DistanceToNextIntersectionAccumulator
|
||||
{
|
||||
DistanceToNextIntersectionAccumulator(
|
||||
const extractor::guidance::CoordinateExtractor &extractor_,
|
||||
const util::NodeBasedDynamicGraph &graph_,
|
||||
const double threshold)
|
||||
: extractor{extractor_}, graph{graph_}, threshold{threshold}
|
||||
{
|
||||
}
|
||||
|
||||
bool terminate()
|
||||
{
|
||||
if (distance > threshold)
|
||||
{
|
||||
too_far_away = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void update(const NodeID start, const EdgeID onto, const NodeID)
|
||||
{
|
||||
using namespace util::coordinate_calculation;
|
||||
|
||||
const auto coords = extractor.GetForwardCoordinatesAlongRoad(start, onto);
|
||||
distance += getLength(coords, &haversineDistance);
|
||||
}
|
||||
|
||||
const extractor::guidance::CoordinateExtractor &extractor;
|
||||
const util::NodeBasedDynamicGraph &graph;
|
||||
const double threshold;
|
||||
bool too_far_away = false;
|
||||
double distance = 0.;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
#ifndef OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
|
||||
#define OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Public service vehicle lanes and similar can introduce additional lanes into the lane string that
|
||||
// are not specifically marked for left/right turns. This function can be used from the profile to
|
||||
// trim the lane string appropriately
|
||||
//
|
||||
// left|throught|
|
||||
// in combination with lanes:psv:forward=1
|
||||
// will be corrected to left|throught, since the final lane is not drivable.
|
||||
// This is in contrast to a situation with lanes:psv:forward=0 (or not set) where left|through|
|
||||
// represents left|through|through
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string
|
||||
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
|
||||
{
|
||||
if (count_left)
|
||||
{
|
||||
bool sane = count_left < static_cast<std::int32_t>(lane_string.size());
|
||||
for (std::int32_t i = 0; i < count_left; ++i)
|
||||
// this is adjusted for our fake pipe. The moment cucumber can handle multiple escaped
|
||||
// pipes, the '&' part can be removed
|
||||
if (lane_string[i] != '|')
|
||||
{
|
||||
sane = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sane)
|
||||
{
|
||||
lane_string.erase(lane_string.begin(), lane_string.begin() + count_left);
|
||||
}
|
||||
}
|
||||
if (count_right)
|
||||
{
|
||||
bool sane = count_right < static_cast<std::int32_t>(lane_string.size());
|
||||
for (auto itr = lane_string.rbegin();
|
||||
itr != lane_string.rend() && itr != lane_string.rbegin() + count_right;
|
||||
++itr)
|
||||
{
|
||||
if (*itr != '|')
|
||||
{
|
||||
sane = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sane)
|
||||
lane_string.resize(lane_string.size() - count_right);
|
||||
}
|
||||
return lane_string;
|
||||
}
|
||||
|
||||
// https://github.com/Project-OSRM/osrm-backend/issues/2638
|
||||
// It can happen that some lanes are not drivable by car. Here we handle this tagging scheme
|
||||
// (vehicle:lanes) to filter out not-allowed roads
|
||||
// lanes=3
|
||||
// turn:lanes=left|through|through|right
|
||||
// vehicle:lanes=yes|yes|no|yes
|
||||
// bicycle:lanes=yes|no|designated|yes
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
|
||||
{
|
||||
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
|
||||
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
|
||||
tokenizer tokens(lane_string, sep);
|
||||
tokenizer access(access_tokens, sep);
|
||||
|
||||
// strings don't match, don't do anything
|
||||
if (std::distance(std::begin(tokens), std::end(tokens)) !=
|
||||
std::distance(std::begin(access), std::end(access)))
|
||||
return lane_string;
|
||||
|
||||
std::string result_string = "";
|
||||
const static std::string yes = "yes";
|
||||
|
||||
for (auto token_itr = std::begin(tokens), access_itr = std::begin(access);
|
||||
token_itr != std::end(tokens);
|
||||
++token_itr, ++access_itr)
|
||||
{
|
||||
if (*access_itr == yes)
|
||||
{
|
||||
// we have to add this in front, because the next token could be invalid. Doing this on
|
||||
// non-empty strings makes sure that the token string will be valid in the end
|
||||
if (!result_string.empty())
|
||||
result_string += '|';
|
||||
|
||||
result_string += *token_itr;
|
||||
}
|
||||
}
|
||||
return result_string;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
|
||||
@@ -4,9 +4,8 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <osmium/osm.hpp>
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -126,6 +125,22 @@ inline bool canBeSeenAsFork(const RoadClassification first, const RoadClassifica
|
||||
return std::abs(static_cast<int>(first.GetPriority()) -
|
||||
static_cast<int>(second.GetPriority())) <= 1;
|
||||
}
|
||||
|
||||
inline bool obviousByRoadClass(const RoadClassification in_classification,
|
||||
const RoadClassification obvious_candidate,
|
||||
const RoadClassification compare_candidate)
|
||||
{
|
||||
// lower numbers are of higher priority
|
||||
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
|
||||
compare_candidate.GetPriority();
|
||||
|
||||
const bool continues_on_same_class = in_classification == obvious_candidate;
|
||||
return (has_high_priority && continues_on_same_class) ||
|
||||
(!obvious_candidate.IsLowPriorityRoadClass() &&
|
||||
!in_classification.IsLowPriorityRoadClass() &&
|
||||
compare_candidate.IsLowPriorityRoadClass());
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -22,7 +22,7 @@ namespace guidance
|
||||
|
||||
// Intersection handlers deal with all issues related to intersections.
|
||||
// They assign appropriate turn operations to the TurnOperations.
|
||||
class SliproadHandler : public IntersectionHandler
|
||||
class SliproadHandler final : public IntersectionHandler
|
||||
{
|
||||
public:
|
||||
SliproadHandler(const IntersectionGenerator &intersection_generator,
|
||||
@@ -42,6 +42,37 @@ class SliproadHandler : public IntersectionHandler
|
||||
Intersection operator()(const NodeID nid,
|
||||
const EdgeID via_eid,
|
||||
Intersection intersection) const override final;
|
||||
|
||||
private:
|
||||
boost::optional<std::size_t> getObviousIndexWithSliproads(const EdgeID from,
|
||||
const Intersection &intersection,
|
||||
const NodeID at) const;
|
||||
|
||||
// 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;
|
||||
|
||||
// Is the area under the triangle a valid Sliproad triangle
|
||||
bool isValidSliproadArea(const double max_area, const NodeID, const NodeID, const NodeID) const;
|
||||
|
||||
// Is the Sliproad a link the both roads it shortcuts must not be links
|
||||
bool isValidSliproadLink(const IntersectionViewData &sliproad,
|
||||
const IntersectionViewData &first,
|
||||
const IntersectionViewData &second) const;
|
||||
|
||||
// Could a Sliproad reach this intersection?
|
||||
static bool canBeTargetOfSliproad(const IntersectionView &intersection);
|
||||
|
||||
// Scales a threshold based on the underlying road classification.
|
||||
// Example: a 100 m threshold for a highway if different on living streets.
|
||||
// The return value is guaranteed to not be larger than `threshold`.
|
||||
static double scaledThresholdByRoadClass(const double max_threshold,
|
||||
const RoadClassification &classification);
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
#ifndef OSRM_GUIDANCE_TOOLKIT_HPP_
|
||||
#define OSRM_GUIDANCE_TOOLKIT_HPP_
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/road_classification.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
using util::guidance::LaneTupleIdPair;
|
||||
using LaneDataIdMap = std::unordered_map<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
|
||||
|
||||
using util::guidance::angularDeviation;
|
||||
using util::guidance::entersRoundabout;
|
||||
using util::guidance::leavesRoundabout;
|
||||
|
||||
// To simplify handling of Left/Right hand turns, we can mirror turns and write an intersection
|
||||
// handler only for one side. The mirror function turns a left-hand turn in a equivalent right-hand
|
||||
// turn and vice versa.
|
||||
|
||||
inline bool hasRoundaboutType(const TurnInstruction instruction)
|
||||
{
|
||||
using namespace extractor::guidance::TurnType;
|
||||
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
|
||||
TurnType::EnterAndExitRoundabout,
|
||||
TurnType::EnterRotary,
|
||||
TurnType::EnterAndExitRotary,
|
||||
TurnType::EnterRoundaboutIntersection,
|
||||
TurnType::EnterAndExitRoundaboutIntersection,
|
||||
TurnType::EnterRoundaboutAtExit,
|
||||
TurnType::ExitRoundabout,
|
||||
TurnType::EnterRotaryAtExit,
|
||||
TurnType::ExitRotary,
|
||||
TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
TurnType::ExitRoundaboutIntersection,
|
||||
TurnType::StayOnRoundabout};
|
||||
|
||||
const auto *first = valid_types;
|
||||
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
|
||||
|
||||
return std::find(first, last, instruction.type) != last;
|
||||
}
|
||||
|
||||
// Public service vehicle lanes and similar can introduce additional lanes into the lane string that
|
||||
// are not specifically marked for left/right turns. This function can be used from the profile to
|
||||
// trim the lane string appropriately
|
||||
//
|
||||
// left|throught|
|
||||
// in combination with lanes:psv:forward=1
|
||||
// will be corrected to left|throught, since the final lane is not drivable.
|
||||
// This is in contrast to a situation with lanes:psv:forward=0 (or not set) where left|through|
|
||||
// represents left|through|through
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string
|
||||
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
|
||||
{
|
||||
if (count_left)
|
||||
{
|
||||
bool sane = count_left < static_cast<std::int32_t>(lane_string.size());
|
||||
for (std::int32_t i = 0; i < count_left; ++i)
|
||||
// this is adjusted for our fake pipe. The moment cucumber can handle multiple escaped
|
||||
// pipes, the '&' part can be removed
|
||||
if (lane_string[i] != '|')
|
||||
{
|
||||
sane = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sane)
|
||||
{
|
||||
lane_string.erase(lane_string.begin(), lane_string.begin() + count_left);
|
||||
}
|
||||
}
|
||||
if (count_right)
|
||||
{
|
||||
bool sane = count_right < static_cast<std::int32_t>(lane_string.size());
|
||||
for (auto itr = lane_string.rbegin();
|
||||
itr != lane_string.rend() && itr != lane_string.rbegin() + count_right;
|
||||
++itr)
|
||||
{
|
||||
if (*itr != '|')
|
||||
{
|
||||
sane = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sane)
|
||||
lane_string.resize(lane_string.size() - count_right);
|
||||
}
|
||||
return lane_string;
|
||||
}
|
||||
|
||||
// https://github.com/Project-OSRM/osrm-backend/issues/2638
|
||||
// It can happen that some lanes are not drivable by car. Here we handle this tagging scheme
|
||||
// (vehicle:lanes) to filter out not-allowed roads
|
||||
// lanes=3
|
||||
// turn:lanes=left|through|through|right
|
||||
// vehicle:lanes=yes|yes|no|yes
|
||||
// bicycle:lanes=yes|no|designated|yes
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
|
||||
{
|
||||
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
|
||||
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
|
||||
tokenizer tokens(lane_string, sep);
|
||||
tokenizer access(access_tokens, sep);
|
||||
|
||||
// strings don't match, don't do anything
|
||||
if (std::distance(std::begin(tokens), std::end(tokens)) !=
|
||||
std::distance(std::begin(access), std::end(access)))
|
||||
return lane_string;
|
||||
|
||||
std::string result_string = "";
|
||||
const static std::string yes = "yes";
|
||||
|
||||
for (auto token_itr = std::begin(tokens), access_itr = std::begin(access);
|
||||
token_itr != std::end(tokens);
|
||||
++token_itr, ++access_itr)
|
||||
{
|
||||
if (*access_itr == yes)
|
||||
{
|
||||
// we have to add this in front, because the next token could be invalid. Doing this on
|
||||
// non-empty strings makes sure that the token string will be valid in the end
|
||||
if (!result_string.empty())
|
||||
result_string += '|';
|
||||
|
||||
result_string += *token_itr;
|
||||
}
|
||||
}
|
||||
return result_string;
|
||||
}
|
||||
|
||||
inline bool obviousByRoadClass(const RoadClassification in_classification,
|
||||
const RoadClassification obvious_candidate,
|
||||
const RoadClassification compare_candidate)
|
||||
{
|
||||
// lower numbers are of higher priority
|
||||
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
|
||||
compare_candidate.GetPriority();
|
||||
|
||||
const bool continues_on_same_class = in_classification == obvious_candidate;
|
||||
return (has_high_priority && continues_on_same_class) ||
|
||||
(!obvious_candidate.IsLowPriorityRoadClass() &&
|
||||
!in_classification.IsLowPriorityRoadClass() &&
|
||||
compare_candidate.IsLowPriorityRoadClass());
|
||||
}
|
||||
|
||||
/* We use the sum of least squares to calculate a linear regression through our
|
||||
* coordinates.
|
||||
* This regression gives a good idea of how the road can be perceived and corrects for
|
||||
* initial and final corrections
|
||||
*/
|
||||
inline std::pair<util::Coordinate, util::Coordinate>
|
||||
leastSquareRegression(const std::vector<util::Coordinate> &coordinates)
|
||||
{
|
||||
BOOST_ASSERT(coordinates.size() >= 2);
|
||||
double sum_lon = 0, sum_lat = 0, sum_lon_lat = 0, sum_lon_lon = 0;
|
||||
double min_lon = static_cast<double>(toFloating(coordinates.front().lon));
|
||||
double max_lon = static_cast<double>(toFloating(coordinates.front().lon));
|
||||
for (const auto coord : coordinates)
|
||||
{
|
||||
min_lon = std::min(min_lon, static_cast<double>(toFloating(coord.lon)));
|
||||
max_lon = std::max(max_lon, static_cast<double>(toFloating(coord.lon)));
|
||||
sum_lon += static_cast<double>(toFloating(coord.lon));
|
||||
sum_lon_lon +=
|
||||
static_cast<double>(toFloating(coord.lon)) * static_cast<double>(toFloating(coord.lon));
|
||||
sum_lat += static_cast<double>(toFloating(coord.lat));
|
||||
sum_lon_lat +=
|
||||
static_cast<double>(toFloating(coord.lon)) * static_cast<double>(toFloating(coord.lat));
|
||||
}
|
||||
|
||||
const auto dividend = coordinates.size() * sum_lon_lat - sum_lon * sum_lat;
|
||||
const auto divisor = coordinates.size() * sum_lon_lon - sum_lon * sum_lon;
|
||||
if (std::abs(divisor) < std::numeric_limits<double>::epsilon())
|
||||
return std::make_pair(coordinates.front(), coordinates.back());
|
||||
|
||||
// slope of the regression line
|
||||
const auto slope = dividend / divisor;
|
||||
const auto intercept = (sum_lat - slope * sum_lon) / coordinates.size();
|
||||
|
||||
const auto GetLatAtLon = [intercept,
|
||||
slope](const util::FloatLongitude longitude) -> util::FloatLatitude {
|
||||
return {intercept + slope * static_cast<double>((longitude))};
|
||||
};
|
||||
|
||||
const util::Coordinate regression_first = {
|
||||
toFixed(util::FloatLongitude{min_lon - 1}),
|
||||
toFixed(util::FloatLatitude(GetLatAtLon(util::FloatLongitude{min_lon - 1})))};
|
||||
const util::Coordinate regression_end = {
|
||||
toFixed(util::FloatLongitude{max_lon + 1}),
|
||||
toFixed(util::FloatLatitude(GetLatAtLon(util::FloatLongitude{max_lon + 1})))};
|
||||
|
||||
return {regression_first, regression_end};
|
||||
}
|
||||
|
||||
inline std::uint8_t getLaneCountAtIntersection(const NodeID intersection_node,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
std::uint8_t lanes = 0;
|
||||
for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(intersection_node))
|
||||
lanes = std::max(
|
||||
lanes, node_based_graph.GetEdgeData(onto_edge).road_classification.GetNumberOfLanes());
|
||||
return lanes;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_GUIDANCE_TOOLKIT_HPP_
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "extractor/guidance/motorway_handler.hpp"
|
||||
#include "extractor/guidance/roundabout_handler.hpp"
|
||||
#include "extractor/guidance/sliproad_handler.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_classification.hpp"
|
||||
#include "extractor/guidance/turn_handler.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
|
||||
#define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/guidance/bearing_class.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
|
||||
#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "extractor/guidance/roundabout_type.hpp"
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
namespace osrm
|
||||
@@ -150,6 +150,162 @@ inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs)
|
||||
return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier;
|
||||
}
|
||||
|
||||
// check if a instruction is associated in any form with a roundabout
|
||||
inline bool hasRoundaboutType(const TurnInstruction instruction)
|
||||
{
|
||||
using namespace extractor::guidance::TurnType;
|
||||
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
|
||||
TurnType::EnterAndExitRoundabout,
|
||||
TurnType::EnterRotary,
|
||||
TurnType::EnterAndExitRotary,
|
||||
TurnType::EnterRoundaboutIntersection,
|
||||
TurnType::EnterAndExitRoundaboutIntersection,
|
||||
TurnType::EnterRoundaboutAtExit,
|
||||
TurnType::ExitRoundabout,
|
||||
TurnType::EnterRotaryAtExit,
|
||||
TurnType::ExitRotary,
|
||||
TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
TurnType::ExitRoundaboutIntersection,
|
||||
TurnType::StayOnRoundabout};
|
||||
|
||||
const auto *first = valid_types;
|
||||
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
|
||||
|
||||
return std::find(first, last, instruction.type) != last;
|
||||
}
|
||||
|
||||
inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersection ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
|
||||
}
|
||||
|
||||
inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::ExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::ExitRoundaboutIntersection ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
|
||||
}
|
||||
|
||||
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
|
||||
}
|
||||
|
||||
// Silent Turn Instructions are not to be mentioned to the outside world but
|
||||
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::NoTurn ||
|
||||
instruction.type == extractor::guidance::TurnType::Suppressed ||
|
||||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
|
||||
}
|
||||
|
||||
inline bool hasRampType(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::OffRamp ||
|
||||
instruction.type == extractor::guidance::TurnType::OnRamp;
|
||||
}
|
||||
|
||||
inline extractor::guidance::DirectionModifier::Enum getTurnDirection(const double angle)
|
||||
{
|
||||
// An angle of zero is a u-turn
|
||||
// 180 goes perfectly straight
|
||||
// 0-180 are right turns
|
||||
// 180-360 are left turns
|
||||
if (angle > 0 && angle < 60)
|
||||
return extractor::guidance::DirectionModifier::SharpRight;
|
||||
if (angle >= 60 && angle < 140)
|
||||
return extractor::guidance::DirectionModifier::Right;
|
||||
if (angle >= 140 && angle < 160)
|
||||
return extractor::guidance::DirectionModifier::SlightRight;
|
||||
if (angle >= 160 && angle <= 200)
|
||||
return extractor::guidance::DirectionModifier::Straight;
|
||||
if (angle > 200 && angle <= 220)
|
||||
return extractor::guidance::DirectionModifier::SlightLeft;
|
||||
if (angle > 220 && angle <= 300)
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
if (angle > 300 && angle < 360)
|
||||
return extractor::guidance::DirectionModifier::SharpLeft;
|
||||
return extractor::guidance::DirectionModifier::UTurn;
|
||||
}
|
||||
|
||||
// swaps left <-> right modifier types
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline extractor::guidance::DirectionModifier::Enum
|
||||
mirrorDirectionModifier(const extractor::guidance::DirectionModifier::Enum modifier)
|
||||
{
|
||||
const constexpr extractor::guidance::DirectionModifier::Enum results[] = {
|
||||
extractor::guidance::DirectionModifier::UTurn,
|
||||
extractor::guidance::DirectionModifier::SharpLeft,
|
||||
extractor::guidance::DirectionModifier::Left,
|
||||
extractor::guidance::DirectionModifier::SlightLeft,
|
||||
extractor::guidance::DirectionModifier::Straight,
|
||||
extractor::guidance::DirectionModifier::SlightRight,
|
||||
extractor::guidance::DirectionModifier::Right,
|
||||
extractor::guidance::DirectionModifier::SharpRight};
|
||||
return results[modifier];
|
||||
}
|
||||
|
||||
inline bool hasLeftModifier(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpLeft ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Left ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightLeft;
|
||||
}
|
||||
|
||||
inline bool hasRightModifier(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpRight ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Right ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightRight;
|
||||
}
|
||||
|
||||
inline bool isLeftTurn(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
switch (instruction.type)
|
||||
{
|
||||
case TurnType::Merge:
|
||||
return hasRightModifier(instruction);
|
||||
default:
|
||||
return hasLeftModifier(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isRightTurn(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
switch (instruction.type)
|
||||
{
|
||||
case TurnType::Merge:
|
||||
return hasLeftModifier(instruction);
|
||||
default:
|
||||
return hasRightModifier(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
inline DirectionModifier::Enum bearingToDirectionModifier(const double bearing)
|
||||
{
|
||||
if (bearing < 135)
|
||||
{
|
||||
return extractor::guidance::DirectionModifier::Right;
|
||||
}
|
||||
|
||||
if (bearing <= 225)
|
||||
{
|
||||
return extractor::guidance::DirectionModifier::Straight;
|
||||
}
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "extractor/guidance/turn_lane_types.hpp"
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_HANDLER_HPP_
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
#include "extractor/guidance/turn_lane_data.hpp"
|
||||
#include "extractor/guidance/turn_lane_types.hpp"
|
||||
@@ -74,7 +73,7 @@ class TurnLaneHandler
|
||||
std::vector<TurnLaneType::Mask> &turn_lane_masks,
|
||||
LaneDescriptionMap &lane_description_map,
|
||||
const TurnAnalysis &turn_analysis,
|
||||
LaneDataIdMap &id_map);
|
||||
util::guidance::LaneDataIdMap &id_map);
|
||||
|
||||
~TurnLaneHandler();
|
||||
|
||||
@@ -91,7 +90,7 @@ class TurnLaneHandler
|
||||
std::vector<TurnLaneType::Mask> &turn_lane_masks;
|
||||
LaneDescriptionMap &lane_description_map;
|
||||
const TurnAnalysis &turn_analysis;
|
||||
LaneDataIdMap &id_map;
|
||||
util::guidance::LaneDataIdMap &id_map;
|
||||
|
||||
// Find out which scenario we have to handle
|
||||
TurnLaneScenario deduceScenario(const NodeID at,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_MATCHER_HPP_
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/guidance/turn_lane_data.hpp"
|
||||
|
||||
@@ -10,8 +9,6 @@
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -47,7 +44,7 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
|
||||
const LaneDataVector &lane_data,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const LaneDescriptionID lane_string_id,
|
||||
LaneDataIdMap &lane_data_to_id);
|
||||
util::guidance::LaneDataIdMap &lane_data_to_id);
|
||||
|
||||
} // namespace lanes
|
||||
} // namespace guidance
|
||||
|
||||
@@ -8,11 +8,9 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#include "util/json_container.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
namespace osrm
|
||||
|
||||
@@ -47,7 +47,6 @@ struct InternalExtractorEdge
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
false, // access restricted
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
@@ -64,7 +63,6 @@ struct InternalExtractorEdge
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
@@ -78,7 +76,6 @@ struct InternalExtractorEdge
|
||||
backward,
|
||||
roundabout,
|
||||
circular,
|
||||
access_restricted,
|
||||
startpoint,
|
||||
travel_mode,
|
||||
is_split,
|
||||
@@ -106,7 +103,6 @@ struct InternalExtractorEdge
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
false, // access restricted
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
@@ -123,7 +119,6 @@ struct InternalExtractorEdge
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
false, // access restricted
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
|
||||
@@ -23,7 +23,6 @@ struct NodeBasedEdge
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
@@ -40,7 +39,6 @@ struct NodeBasedEdge
|
||||
bool backward : 1;
|
||||
bool roundabout : 1;
|
||||
bool circular : 1;
|
||||
bool access_restricted : 1;
|
||||
bool startpoint : 1;
|
||||
bool is_split : 1;
|
||||
TravelMode travel_mode : 4;
|
||||
@@ -58,7 +56,6 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
@@ -73,9 +70,8 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
|
||||
inline NodeBasedEdge::NodeBasedEdge()
|
||||
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
|
||||
backward(false), roundabout(false), circular(false), access_restricted(false),
|
||||
startpoint(true), is_split(false), travel_mode(false),
|
||||
lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
backward(false), roundabout(false), circular(false), startpoint(true), is_split(false),
|
||||
travel_mode(false), lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -87,16 +83,14 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
const LaneDescriptionID lane_description_id,
|
||||
guidance::RoadClassification road_classification)
|
||||
: source(source), target(target), name_id(name_id), weight(weight), forward(forward),
|
||||
backward(backward), roundabout(roundabout), circular(circular),
|
||||
access_restricted(access_restricted), startpoint(startpoint), is_split(is_split),
|
||||
travel_mode(travel_mode), lane_description_id(lane_description_id),
|
||||
backward(backward), roundabout(roundabout), circular(circular), startpoint(startpoint),
|
||||
is_split(is_split), travel_mode(travel_mode), lane_description_id(lane_description_id),
|
||||
road_classification(std::move(road_classification))
|
||||
{
|
||||
}
|
||||
@@ -126,7 +120,6 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
@@ -140,7 +133,6 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
backward,
|
||||
roundabout,
|
||||
circular,
|
||||
access_restricted,
|
||||
startpoint,
|
||||
travel_mode,
|
||||
is_split,
|
||||
|
||||
@@ -66,13 +66,14 @@ class RasterGrid
|
||||
}
|
||||
catch (std::exception const &ex)
|
||||
{
|
||||
throw util::exception(
|
||||
std::string("Failed to read from raster source with exception: ") + ex.what());
|
||||
throw util::exception("Failed to read from raster source " + filepath.string() + ": " +
|
||||
ex.what() + SOURCE_REF);
|
||||
}
|
||||
|
||||
if (!r || itr != end)
|
||||
{
|
||||
throw util::exception("Failed to parse raster source correctly.");
|
||||
throw util::exception("Failed to parse raster source: " + filepath.string() +
|
||||
SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/std_hash.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
@@ -146,8 +146,8 @@ template <typename GraphT> class TarjanSCC
|
||||
|
||||
if (size_of_current_component > 1000)
|
||||
{
|
||||
util::SimpleLogger().Write() << "large component [" << component_index
|
||||
<< "]=" << size_of_current_component;
|
||||
util::Log() << "large component [" << component_index
|
||||
<< "]=" << size_of_current_component;
|
||||
}
|
||||
|
||||
++component_index;
|
||||
@@ -158,7 +158,7 @@ template <typename GraphT> class TarjanSCC
|
||||
}
|
||||
|
||||
TIMER_STOP(SCC_RUN);
|
||||
util::SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
|
||||
util::Log() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
|
||||
|
||||
size_one_counter = std::count_if(component_size_vector.begin(),
|
||||
component_size_vector.end(),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "server/service_handler.hpp"
|
||||
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
@@ -36,8 +36,7 @@ class Server
|
||||
static std::shared_ptr<Server>
|
||||
CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
|
||||
{
|
||||
util::SimpleLogger().Write() << "http 1.1 compression handled by zlib version "
|
||||
<< zlibVersion();
|
||||
util::Log() << "http 1.1 compression handled by zlib version " << zlibVersion();
|
||||
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
|
||||
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
|
||||
return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
|
||||
@@ -62,7 +61,7 @@ class Server
|
||||
acceptor.bind(endpoint);
|
||||
acceptor.listen();
|
||||
|
||||
util::SimpleLogger().Write() << "Listening on: " << acceptor.local_endpoint();
|
||||
util::Log() << "Listening on: " << acceptor.local_endpoint();
|
||||
|
||||
acceptor.async_accept(
|
||||
new_connection->socket(),
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "osrm/osrm.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
|
||||
#include <variant/variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
+84
-12
@@ -2,13 +2,13 @@
|
||||
#define OSRM_STORAGE_IO_HPP_
|
||||
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/fingerprint.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/iostreams/seek.hpp>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
@@ -23,7 +23,7 @@ namespace io
|
||||
class FileReader
|
||||
{
|
||||
private:
|
||||
const std::string filename;
|
||||
const boost::filesystem::path filepath;
|
||||
boost::filesystem::ifstream input_stream;
|
||||
|
||||
public:
|
||||
@@ -47,16 +47,16 @@ class FileReader
|
||||
{
|
||||
}
|
||||
|
||||
FileReader(const boost::filesystem::path &filename_, const FingerprintFlag flag)
|
||||
: filename(filename_.string())
|
||||
FileReader(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
|
||||
: filepath(filepath_)
|
||||
{
|
||||
input_stream.open(filename_, std::ios::binary);
|
||||
input_stream.open(filepath, std::ios::binary);
|
||||
if (!input_stream)
|
||||
throw util::exception("Error opening " + filename + ":" + std::strerror(errno));
|
||||
throw util::exception("Error opening " + filepath.string());
|
||||
|
||||
if (flag == VerifyFingerprint && !ReadAndCheckFingerprint())
|
||||
{
|
||||
throw util::exception("Fingerprint mismatch in " + filename);
|
||||
throw util::exception("Fingerprint mismatch in " + filepath_.string() + SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,10 +77,10 @@ class FileReader
|
||||
{
|
||||
if (result.eof())
|
||||
{
|
||||
throw util::exception("Error reading from " + filename +
|
||||
": Unexpected end of file");
|
||||
throw util::exception("Error reading from " + filepath.string() +
|
||||
": Unexpected end of file " + SOURCE_REF);
|
||||
}
|
||||
throw util::exception("Error reading from " + filename + ": " + std::strerror(errno));
|
||||
throw util::exception("Error reading from " + filepath.string() + " " + SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ class FileReader
|
||||
{
|
||||
std::getline(input_stream, thisline);
|
||||
}
|
||||
catch (const std::ios_base::failure &e)
|
||||
catch (const std::ios_base::failure & /*e*/)
|
||||
{
|
||||
// EOF is OK here, everything else, re-throw
|
||||
if (!input_stream.eof())
|
||||
@@ -170,6 +170,78 @@ class FileReader
|
||||
return thisline;
|
||||
}
|
||||
};
|
||||
|
||||
class FileWriter
|
||||
{
|
||||
private:
|
||||
const boost::filesystem::path filepath;
|
||||
boost::filesystem::ofstream output_stream;
|
||||
|
||||
public:
|
||||
enum FingerprintFlag
|
||||
{
|
||||
GenerateFingerprint,
|
||||
HasNoFingerprint
|
||||
};
|
||||
|
||||
FileWriter(const std::string &filename, const FingerprintFlag flag)
|
||||
: FileWriter(boost::filesystem::path(filename), flag)
|
||||
{
|
||||
}
|
||||
|
||||
FileWriter(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
|
||||
: filepath(filepath_)
|
||||
{
|
||||
output_stream.open(filepath, std::ios::binary);
|
||||
if (!output_stream)
|
||||
throw util::exception("Error opening " + filepath.string());
|
||||
|
||||
if (flag == GenerateFingerprint)
|
||||
{
|
||||
WriteFingerprint();
|
||||
}
|
||||
}
|
||||
|
||||
/* Write count objects of type T from pointer src to output stream */
|
||||
template <typename T> bool WriteFrom(T *src, const std::size_t count)
|
||||
{
|
||||
#if not defined __GNUC__ or __GNUC__ > 4
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"bytewise writing requires trivially copyable type");
|
||||
#endif
|
||||
|
||||
if (count == 0)
|
||||
return true;
|
||||
|
||||
const auto &result = output_stream.write(reinterpret_cast<char *>(src), count * sizeof(T));
|
||||
if (!result)
|
||||
{
|
||||
throw util::exception("Error writing to " + filepath.string());
|
||||
}
|
||||
|
||||
return static_cast<bool>(output_stream);
|
||||
}
|
||||
|
||||
template <typename T> bool WriteFrom(T &target) { return WriteFrom(&target, 1); }
|
||||
|
||||
template <typename T> bool WriteOne(T tmp) { return WriteFrom(tmp); }
|
||||
|
||||
bool WriteElementCount32(const std::uint32_t count) { return WriteOne<std::uint32_t>(count); }
|
||||
bool WriteElementCount64(const std::uint64_t count) { return WriteOne<std::uint64_t>(count); }
|
||||
|
||||
template <typename T> bool SerializeVector(std::vector<T> &data)
|
||||
{
|
||||
const auto count = data.size();
|
||||
WriteElementCount64(count);
|
||||
return WriteFrom(data.data(), count);
|
||||
}
|
||||
|
||||
bool WriteFingerprint()
|
||||
{
|
||||
const auto fingerprint = util::FingerPrint::GetValid();
|
||||
return WriteOne(fingerprint);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "storage/io.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/fingerprint.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
@@ -44,8 +44,8 @@ inline HSGRHeader readHSGRHeader(io::FileReader &input_file)
|
||||
const auto fingerprint_loaded = input_file.ReadOne<util::FingerPrint>();
|
||||
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
util::Log(logWARNING) << ".hsgr was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
HSGRHeader header;
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#define SHARED_DATA_TYPE_HPP
|
||||
|
||||
#include "util/exception.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -175,13 +176,13 @@ struct DataLayout
|
||||
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
if (!start_canary_alive)
|
||||
{
|
||||
throw util::exception(std::string("Start canary of block corrupted. (") +
|
||||
block_id_to_name[bid] + ")");
|
||||
throw util::exception("Start canary of block corrupted. (" +
|
||||
std::string(block_id_to_name[bid]) + ")" + SOURCE_REF);
|
||||
}
|
||||
if (!end_canary_alive)
|
||||
{
|
||||
throw util::exception(std::string("End canary of block corrupted. (") +
|
||||
block_id_to_name[bid] + ")");
|
||||
throw util::exception("End canary of block corrupted. (" +
|
||||
std::string(block_id_to_name[bid]) + ")" + SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#define SHARED_MEMORY_HPP
|
||||
|
||||
#include "util/exception.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
@@ -62,8 +63,7 @@ class SharedMemory
|
||||
{
|
||||
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key);
|
||||
|
||||
util::SimpleLogger().Write(logDEBUG) << "opening " << shm.get_shmid() << " from id "
|
||||
<< id;
|
||||
util::Log(logDEBUG) << "opening " << shm.get_shmid() << " from id " << id;
|
||||
|
||||
region = boost::interprocess::mapped_region(shm, access);
|
||||
}
|
||||
@@ -72,14 +72,14 @@ class SharedMemory
|
||||
{
|
||||
shm = boost::interprocess::xsi_shared_memory(
|
||||
boost::interprocess::open_or_create, key, size);
|
||||
util::SimpleLogger().Write(logDEBUG) << "opening/creating " << shm.get_shmid()
|
||||
<< " from id " << id << " with size " << size;
|
||||
util::Log(logDEBUG) << "opening/creating " << shm.get_shmid() << " from id " << id
|
||||
<< " with size " << size;
|
||||
#ifdef __linux__
|
||||
if (-1 == shmctl(shm.get_shmid(), SHM_LOCK, nullptr))
|
||||
{
|
||||
if (ENOMEM == errno)
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
|
||||
util::Log(logWARNING) << "could not lock shared memory to RAM";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -133,7 +133,7 @@ class SharedMemory
|
||||
static bool Remove(const boost::interprocess::xsi_key &key)
|
||||
{
|
||||
boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
|
||||
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory " << xsi.get_shmid();
|
||||
util::Log(logDEBUG) << "deallocating prev memory " << xsi.get_shmid();
|
||||
return boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
|
||||
}
|
||||
|
||||
@@ -173,8 +173,7 @@ class SharedMemory
|
||||
shm.truncate(size);
|
||||
region = boost::interprocess::mapped_region(shm, access);
|
||||
|
||||
util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
|
||||
<< " bytes";
|
||||
util::Log(logDEBUG) << "writeable memory allocated " << size << " bytes";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +220,7 @@ class SharedMemory
|
||||
|
||||
static bool Remove(char *key)
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory for key " << key;
|
||||
util::Log(logDEBUG) << "deallocating prev memory for key " << key;
|
||||
return boost::interprocess::shared_memory_object::remove(key);
|
||||
}
|
||||
|
||||
@@ -242,7 +241,7 @@ makeSharedMemory(const IdentifierT &id, const uint64_t size = 0, bool read_write
|
||||
{
|
||||
if (0 == size)
|
||||
{
|
||||
throw util::exception("lock file does not exist, exiting");
|
||||
throw util::exception("lock file does not exist, exiting" + SOURCE_REF);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -253,9 +252,9 @@ makeSharedMemory(const IdentifierT &id, const uint64_t size = 0, bool read_write
|
||||
}
|
||||
catch (const boost::interprocess::interprocess_exception &e)
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
|
||||
<< e.get_error_code();
|
||||
throw util::exception(e.what());
|
||||
util::Log(logERROR) << "Error while attempting to allocate shared memory: " << e.what()
|
||||
<< ", code " << e.get_error_code();
|
||||
throw util::exception(e.what() + SOURCE_REF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef BEARING_HPP
|
||||
#define BEARING_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
namespace osrm
|
||||
@@ -89,6 +91,7 @@ inline bool CheckInBounds(const int A, const int B, const int range)
|
||||
return normalized_B - range <= normalized_A && normalized_A <= normalized_B + range;
|
||||
}
|
||||
}
|
||||
} // namespace bearing
|
||||
|
||||
inline double reverseBearing(const double bearing)
|
||||
{
|
||||
@@ -128,7 +131,13 @@ inline double angleBetweenBearings(const double entry_bearing, const double exit
|
||||
return angle >= 360 ? angle - 360 : angle;
|
||||
}
|
||||
|
||||
} // namespace bearing
|
||||
// minimal difference between two angles/bearings going left or right
|
||||
inline double angularDeviation(const double angle, const double from)
|
||||
{
|
||||
const double deviation = std::abs(angle - from);
|
||||
return std::min(360 - deviation, deviation);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
|
||||
|
||||
@@ -136,6 +136,9 @@ bool isCCW(const Coordinate first_coordinate,
|
||||
const Coordinate second_coordinate,
|
||||
const Coordinate third_coordinate);
|
||||
|
||||
std::pair<util::Coordinate, util::Coordinate>
|
||||
leastSquareRegression(const std::vector<util::Coordinate> &coordinates);
|
||||
|
||||
} // ns coordinate_calculation
|
||||
} // ns util
|
||||
} // ns osrm
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef SOURCE_MACROS_HPP
|
||||
#define SOURCE_MACROS_HPP
|
||||
#include <cstring>
|
||||
|
||||
// Helper macros, don't use these ones
|
||||
// STRIP the OSRM_PROJECT_DIR from the front of a filename. Expected to come
|
||||
// from CMake's CURRENT_SOURCE_DIR, which doesn't have a trailing /, hence the +1
|
||||
#define _PROJECT_RELATIVE_PATH(x) std::string(x).substr(strlen(OSRM_PROJECT_DIR) + 1)
|
||||
// Return the path of a file, relative to the OSRM_PROJECT_DIR
|
||||
#define _OSRM_SOURCE_FILE _PROJECT_RELATIVE_PATH(__FILE__)
|
||||
|
||||
// This is the macro to use
|
||||
#define SOURCE_REF std::string(" (at ") + _OSRM_SOURCE_FILE + ":" + std::to_string(__LINE__) + ")"
|
||||
|
||||
#endif // SOURCE_MACROS_HPP
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
|
||||
#include <boost/uuid/name_generator.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
@@ -57,7 +58,7 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
|
||||
{
|
||||
if (!IsMagicNumberOK(other))
|
||||
{
|
||||
throw exception("hsgr input file misses magic number. Check or reprocess the file");
|
||||
throw exception(std::string("hsgr input file misses magic number. Check or reprocess the file") + SOURCE_REF);
|
||||
}
|
||||
return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
|
||||
}
|
||||
@@ -66,7 +67,7 @@ bool FingerPrint::TestContractor(const FingerPrint &other) const
|
||||
{
|
||||
if (!IsMagicNumberOK(other))
|
||||
{
|
||||
throw exception("osrm input file misses magic number. Check or reprocess the file");
|
||||
throw exception(std::string("osrm input file misses magic number. Check or reprocess the file") + SOURCE_REF);
|
||||
}
|
||||
return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
|
||||
}
|
||||
@@ -75,7 +76,7 @@ bool FingerPrint::TestRTree(const FingerPrint &other) const
|
||||
{
|
||||
if (!IsMagicNumberOK(other))
|
||||
{
|
||||
throw exception("r-tree input file misses magic number. Check or reprocess the file");
|
||||
throw exception(std::string("r-tree input file misses magic number. Check or reprocess the file") + SOURCE_REF);
|
||||
}
|
||||
return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
|
||||
}
|
||||
@@ -84,7 +85,7 @@ bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
|
||||
{
|
||||
if (!IsMagicNumberOK(other))
|
||||
{
|
||||
throw exception("missing magic number. Check or reprocess the file");
|
||||
throw exception(std::string("missing magic number. Check or reprocess the file") + SOURCE_REF);
|
||||
}
|
||||
return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "util/json_container.hpp"
|
||||
#include "util/json_renderer.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -63,11 +63,11 @@ class GeojsonLogger
|
||||
// make sure to syncronize logging output, our writing should be sequential
|
||||
std::lock_guard<std::mutex> guard(lock);
|
||||
|
||||
// if there is no logfile, we cannot write
|
||||
// if there is no logfile, we cannot write (possible reason: the guard might be out of scope
|
||||
// (e.g. if it is anonymous))
|
||||
if (!ofs.is_open() || (nullptr == policy))
|
||||
{
|
||||
// this can only happend between two guards when concurrent writing occurs
|
||||
return false;
|
||||
throw util::exception("Trying to use the geojson printer without an open logger.");
|
||||
}
|
||||
|
||||
// use our policy to convert the arguments into geojson, this can be done in parallel
|
||||
@@ -92,7 +92,7 @@ class GeojsonLogger
|
||||
// out on log output. Such a sad life
|
||||
if (ofs.is_open())
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING)
|
||||
util::Log(logWARNING)
|
||||
<< "Overwriting " << logfile
|
||||
<< ". Is this desired behaviour? If this message occurs more than once rethink the "
|
||||
"location of your Logger Guard.";
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "storage/io.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/fingerprint.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
@@ -60,7 +60,7 @@ NodeID loadNodesFromFile(storage::io::FileReader &file_reader,
|
||||
std::vector<extractor::QueryNode> &node_array)
|
||||
{
|
||||
NodeID number_of_nodes = file_reader.ReadElementCount32();
|
||||
SimpleLogger().Write() << "Importing number_of_nodes new = " << number_of_nodes << " nodes ";
|
||||
Log() << "Importing number_of_nodes new = " << number_of_nodes << " nodes ";
|
||||
|
||||
node_array.resize(number_of_nodes);
|
||||
|
||||
@@ -99,14 +99,14 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
|
||||
BOOST_ASSERT(sizeof(EdgeID) == sizeof(number_of_edges));
|
||||
|
||||
edge_list.resize(number_of_edges);
|
||||
SimpleLogger().Write() << " and " << number_of_edges << " edges ";
|
||||
Log() << " and " << number_of_edges << " edges ";
|
||||
|
||||
file_reader.ReadInto(edge_list.data(), number_of_edges);
|
||||
|
||||
BOOST_ASSERT(edge_list.size() > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
SimpleLogger().Write() << "Validating loaded edges...";
|
||||
Log() << "Validating loaded edges...";
|
||||
tbb::parallel_sort(
|
||||
edge_list.begin(),
|
||||
edge_list.end(),
|
||||
@@ -129,7 +129,7 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
|
||||
}
|
||||
#endif
|
||||
|
||||
SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
|
||||
Log() << "Graph loaded ok and has " << edge_list.size() << " edges";
|
||||
|
||||
return number_of_edges;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
#ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
|
||||
#define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
|
||||
#ifndef OSRM_UTIL_GUIDANCE_NAME_ANNOUNCEMENT_HPP_
|
||||
#define OSRM_UTIL_GUIDANCE_NAME_ANNOUNCEMENT_HPP_
|
||||
|
||||
/* A set of tools required for guidance in both pre and post-processing */
|
||||
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/guidance/bearing_class.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -29,122 +23,6 @@ namespace util
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
inline double angularDeviation(const double angle, const double from)
|
||||
{
|
||||
const double deviation = std::abs(angle - from);
|
||||
return std::min(360 - deviation, deviation);
|
||||
}
|
||||
|
||||
inline bool hasRampType(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::OffRamp ||
|
||||
instruction.type == extractor::guidance::TurnType::OnRamp;
|
||||
}
|
||||
|
||||
inline extractor::guidance::DirectionModifier::Enum getTurnDirection(const double angle)
|
||||
{
|
||||
// An angle of zero is a u-turn
|
||||
// 180 goes perfectly straight
|
||||
// 0-180 are right turns
|
||||
// 180-360 are left turns
|
||||
if (angle > 0 && angle < 60)
|
||||
return extractor::guidance::DirectionModifier::SharpRight;
|
||||
if (angle >= 60 && angle < 140)
|
||||
return extractor::guidance::DirectionModifier::Right;
|
||||
if (angle >= 140 && angle < 160)
|
||||
return extractor::guidance::DirectionModifier::SlightRight;
|
||||
if (angle >= 160 && angle <= 200)
|
||||
return extractor::guidance::DirectionModifier::Straight;
|
||||
if (angle > 200 && angle <= 220)
|
||||
return extractor::guidance::DirectionModifier::SlightLeft;
|
||||
if (angle > 220 && angle <= 300)
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
if (angle > 300 && angle < 360)
|
||||
return extractor::guidance::DirectionModifier::SharpLeft;
|
||||
return extractor::guidance::DirectionModifier::UTurn;
|
||||
}
|
||||
|
||||
// swaps left <-> right modifier types
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline extractor::guidance::DirectionModifier::Enum
|
||||
mirrorDirectionModifier(const extractor::guidance::DirectionModifier::Enum modifier)
|
||||
{
|
||||
const constexpr extractor::guidance::DirectionModifier::Enum results[] = {
|
||||
extractor::guidance::DirectionModifier::UTurn,
|
||||
extractor::guidance::DirectionModifier::SharpLeft,
|
||||
extractor::guidance::DirectionModifier::Left,
|
||||
extractor::guidance::DirectionModifier::SlightLeft,
|
||||
extractor::guidance::DirectionModifier::Straight,
|
||||
extractor::guidance::DirectionModifier::SlightRight,
|
||||
extractor::guidance::DirectionModifier::Right,
|
||||
extractor::guidance::DirectionModifier::SharpRight};
|
||||
return results[modifier];
|
||||
}
|
||||
|
||||
inline bool hasLeftModifier(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpLeft ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Left ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightLeft;
|
||||
}
|
||||
|
||||
inline bool hasRightModifier(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpRight ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Right ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightRight;
|
||||
}
|
||||
|
||||
inline bool isLeftTurn(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
switch (instruction.type)
|
||||
{
|
||||
case extractor::guidance::TurnType::Merge:
|
||||
return hasRightModifier(instruction);
|
||||
default:
|
||||
return hasLeftModifier(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isRightTurn(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
switch (instruction.type)
|
||||
{
|
||||
case extractor::guidance::TurnType::Merge:
|
||||
return hasLeftModifier(instruction);
|
||||
default:
|
||||
return hasRightModifier(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersection ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
|
||||
}
|
||||
|
||||
inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::ExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::ExitRoundaboutIntersection ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
|
||||
}
|
||||
|
||||
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
|
||||
}
|
||||
|
||||
// Name Change Logic
|
||||
// Used both during Extraction as well as during Post-Processing
|
||||
|
||||
@@ -304,4 +182,4 @@ inline bool requiresNameAnnounced(const NameID from_name_id,
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */
|
||||
#endif /* OSRM_UTIL_GUIDANCE_NAME_ANNOUNCEMENT_HPP_ */
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "util/typedefs.hpp"
|
||||
@@ -96,6 +97,8 @@ class LaneTupleIdPair
|
||||
}
|
||||
};
|
||||
|
||||
using LaneDataIdMap = std::unordered_map<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
|
||||
+17
-11
@@ -1,7 +1,7 @@
|
||||
#ifndef OSRM_INCLUDE_UTIL_IO_HPP_
|
||||
#define OSRM_INCLUDE_UTIL_IO_HPP_
|
||||
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
@@ -54,7 +54,8 @@ template <typename simple_type>
|
||||
bool serializeVectorIntoAdjacencyArray(const std::string &filename,
|
||||
const std::vector<std::vector<simple_type>> &data)
|
||||
{
|
||||
std::ofstream out_stream(filename, std::ios::binary);
|
||||
storage::io::FileWriter file(filename, storage::io::FileWriter::HasNoFingerprint);
|
||||
|
||||
std::vector<std::uint32_t> offsets;
|
||||
offsets.reserve(data.size() + 1);
|
||||
std::uint64_t current_offset = 0;
|
||||
@@ -64,18 +65,23 @@ bool serializeVectorIntoAdjacencyArray(const std::string &filename,
|
||||
current_offset += vec.size();
|
||||
offsets.push_back(boost::numeric_cast<std::uint32_t>(current_offset));
|
||||
}
|
||||
if (!serializeVector(out_stream, offsets))
|
||||
return false;
|
||||
|
||||
std::vector<simple_type> all_data;
|
||||
all_data.reserve(offsets.back());
|
||||
for (auto const &vec : data)
|
||||
all_data.insert(all_data.end(), vec.begin(), vec.end());
|
||||
|
||||
if (!serializeVector(out_stream, all_data))
|
||||
if (!file.SerializeVector(offsets))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return static_cast<bool>(out_stream);
|
||||
if (!file.SerializeVector(all_data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename simple_type, std::size_t WRITE_BLOCK_BUFFER_SIZE = 1024>
|
||||
@@ -119,9 +125,10 @@ void deserializeAdjacencyArray(const std::string &filename,
|
||||
|
||||
// offsets have to match up with the size of the data
|
||||
if (offsets.empty() || (offsets.back() != boost::numeric_cast<std::uint32_t>(data.size())))
|
||||
throw util::exception("Error in " + filename + (offsets.empty()
|
||||
? "Offsets are empty"
|
||||
: "Offset and data size do not match"));
|
||||
throw util::exception(
|
||||
"Error in " + filename +
|
||||
(offsets.empty() ? "Offsets are empty" : "Offset and data size do not match") +
|
||||
SOURCE_REF);
|
||||
}
|
||||
|
||||
inline bool serializeFlags(const boost::filesystem::path &path, const std::vector<bool> &flags)
|
||||
@@ -147,8 +154,7 @@ inline bool serializeFlags(const boost::filesystem::path &path, const std::vecto
|
||||
++chunk_count;
|
||||
flag_stream.write(reinterpret_cast<const char *>(&chunk), sizeof(chunk));
|
||||
}
|
||||
SimpleLogger().Write() << "Wrote " << number_of_bits << " bits in " << chunk_count
|
||||
<< " chunks (Flags).";
|
||||
Log() << "Wrote " << number_of_bits << " bits in " << chunk_count << " chunks (Flags).";
|
||||
return static_cast<bool>(flag_stream);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef JSON_CONTAINER_HPP
|
||||
#define JSON_CONTAINER_HPP
|
||||
|
||||
#include <variant/variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#ifndef LOG_HPP
|
||||
#define LOG_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
logINFO,
|
||||
logWARNING,
|
||||
logERROR,
|
||||
logDEBUG
|
||||
};
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
class LogPolicy
|
||||
{
|
||||
public:
|
||||
void Unmute();
|
||||
|
||||
void Mute();
|
||||
|
||||
bool IsMute() const;
|
||||
|
||||
static LogPolicy &GetInstance();
|
||||
|
||||
LogPolicy(const LogPolicy &) = delete;
|
||||
LogPolicy &operator=(const LogPolicy &) = delete;
|
||||
|
||||
private:
|
||||
LogPolicy() : m_is_mute(true) {}
|
||||
std::atomic<bool> m_is_mute;
|
||||
};
|
||||
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
Log(LogLevel level_ = logINFO);
|
||||
Log(LogLevel level_, std::ostream &ostream);
|
||||
|
||||
virtual ~Log();
|
||||
std::mutex &get_mutex();
|
||||
|
||||
template <typename T> inline std::ostream &operator<<(const T &data) { return stream << data; }
|
||||
|
||||
protected:
|
||||
LogLevel level;
|
||||
std::ostringstream buffer;
|
||||
std::ostream &stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* Modified logger - this one doesn't buffer - it writes directly to stdout,
|
||||
* and the final newline is only printed when the object is destructed.
|
||||
* Useful for logging situations where you don't want to newline right away
|
||||
*/
|
||||
class UnbufferedLog : public Log
|
||||
{
|
||||
public:
|
||||
UnbufferedLog(LogLevel level_ = logINFO);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LOG_HPP */
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef MEMINFO_HPP
|
||||
#define MEMINFO_HPP
|
||||
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <stxxl/mng>
|
||||
#ifndef _WIN32
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
inline void DumpMemoryStats()
|
||||
{
|
||||
#if STXXL_VERSION_MAJOR > 1 || (STXXL_VERSION_MAJOR == 1 && STXXL_VERSION_MINOR >= 4)
|
||||
auto manager = stxxl::block_manager::get_instance();
|
||||
util::Log() << "STXXL: peak bytes used: " << manager->get_maximum_allocation();
|
||||
util::Log() << "STXXL: total disk allocated: " << manager->get_total_bytes();
|
||||
#else
|
||||
#warning STXXL 1.4+ recommended - STXXL memory summary will not be available
|
||||
util::Log() << "STXXL: memory summary not available, needs STXXL 1.4 or higher";
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
rusage usage;
|
||||
getrusage(RUSAGE_SELF, &usage);
|
||||
#ifdef __linux__
|
||||
// Under linux, ru.maxrss is in kb
|
||||
util::Log() << "RAM: peak bytes used: " << usage.ru_maxrss * 1024;
|
||||
#else // __linux__
|
||||
// Under BSD systems (OSX), it's in bytes
|
||||
util::Log() << "RAM: peak bytes used: " << usage.ru_maxrss;
|
||||
#endif // __linux__
|
||||
#else // _WIN32
|
||||
util::Log() << "RAM: peak bytes used: <not implemented on Windows>";
|
||||
#endif // _WIN32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,8 +19,8 @@ struct NodeBasedEdgeData
|
||||
{
|
||||
NodeBasedEdgeData()
|
||||
: distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
|
||||
name_id(std::numeric_limits<unsigned>::max()), access_restricted(false), reversed(false),
|
||||
roundabout(false), circular(false), travel_mode(TRAVEL_MODE_INACCESSIBLE),
|
||||
name_id(std::numeric_limits<unsigned>::max()), reversed(false), roundabout(false),
|
||||
circular(false), travel_mode(TRAVEL_MODE_INACCESSIBLE),
|
||||
lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
{
|
||||
}
|
||||
@@ -28,24 +28,21 @@ struct NodeBasedEdgeData
|
||||
NodeBasedEdgeData(int distance,
|
||||
unsigned edge_id,
|
||||
unsigned name_id,
|
||||
bool access_restricted,
|
||||
bool reversed,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
extractor::TravelMode travel_mode,
|
||||
const LaneDescriptionID lane_description_id)
|
||||
: distance(distance), edge_id(edge_id), name_id(name_id),
|
||||
access_restricted(access_restricted), reversed(reversed), roundabout(roundabout),
|
||||
circular(circular), startpoint(startpoint), travel_mode(travel_mode),
|
||||
lane_description_id(lane_description_id)
|
||||
: distance(distance), edge_id(edge_id), name_id(name_id), reversed(reversed),
|
||||
roundabout(roundabout), circular(circular), startpoint(startpoint),
|
||||
travel_mode(travel_mode), lane_description_id(lane_description_id)
|
||||
{
|
||||
}
|
||||
|
||||
int distance;
|
||||
unsigned edge_id;
|
||||
unsigned name_id;
|
||||
bool access_restricted : 1;
|
||||
bool reversed : 1;
|
||||
bool roundabout : 1;
|
||||
bool circular : 1;
|
||||
@@ -58,7 +55,6 @@ struct NodeBasedEdgeData
|
||||
{
|
||||
return (reversed == other.reversed) && (roundabout == other.roundabout) &&
|
||||
(circular == other.circular) && (startpoint == other.startpoint) &&
|
||||
(access_restricted == other.access_restricted) &&
|
||||
(travel_mode == other.travel_mode) &&
|
||||
(road_classification == other.road_classification);
|
||||
}
|
||||
@@ -88,7 +84,6 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
|
||||
output_edge.data.roundabout = input_edge.roundabout;
|
||||
output_edge.data.circular = input_edge.circular;
|
||||
output_edge.data.name_id = input_edge.name_id;
|
||||
output_edge.data.access_restricted = input_edge.access_restricted;
|
||||
output_edge.data.travel_mode = input_edge.travel_mode;
|
||||
output_edge.data.startpoint = input_edge.startpoint;
|
||||
output_edge.data.road_classification = input_edge.road_classification;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "util/isatty.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -13,8 +14,13 @@ namespace util
|
||||
|
||||
class Percent
|
||||
{
|
||||
Log &log;
|
||||
|
||||
public:
|
||||
explicit Percent(unsigned max_value, unsigned step = 5) { Reinit(max_value, step); }
|
||||
explicit Percent(Log &log_, unsigned max_value, unsigned step = 5) : log{log_}
|
||||
{
|
||||
Reinit(max_value, step);
|
||||
}
|
||||
|
||||
// Reinitializes
|
||||
void Reinit(unsigned max_value, unsigned step = 5)
|
||||
@@ -36,7 +42,7 @@ class Percent
|
||||
PrintPercent(current_value / static_cast<double>(m_max_value) * 100.);
|
||||
}
|
||||
if (current_value + 1 == m_max_value)
|
||||
std::cout << " 100%" << std::endl;
|
||||
log << " 100%";
|
||||
}
|
||||
|
||||
void PrintIncrement()
|
||||
@@ -67,19 +73,17 @@ class Percent
|
||||
m_last_percent += m_step;
|
||||
if (m_last_percent % 10 == 0)
|
||||
{
|
||||
std::cout << " " << m_last_percent << "% ";
|
||||
log << " " << m_last_percent << "% ";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << ".";
|
||||
log << ".";
|
||||
}
|
||||
|
||||
// When not on a TTY, print newlines after each progress indicator so
|
||||
// so that progress is visible to line-buffered logging systems
|
||||
if (!IsStdoutATTY())
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout.flush();
|
||||
log << "" << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef SIMPLE_LOGGER_HPP
|
||||
#define SIMPLE_LOGGER_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
logINFO,
|
||||
logWARNING,
|
||||
logDEBUG
|
||||
};
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
class LogPolicy
|
||||
{
|
||||
public:
|
||||
void Unmute();
|
||||
|
||||
void Mute();
|
||||
|
||||
bool IsMute() const;
|
||||
|
||||
static LogPolicy &GetInstance();
|
||||
|
||||
LogPolicy(const LogPolicy &) = delete;
|
||||
LogPolicy &operator=(const LogPolicy &) = delete;
|
||||
|
||||
private:
|
||||
LogPolicy() : m_is_mute(true) {}
|
||||
std::atomic<bool> m_is_mute;
|
||||
};
|
||||
|
||||
class SimpleLogger
|
||||
{
|
||||
public:
|
||||
SimpleLogger();
|
||||
|
||||
virtual ~SimpleLogger();
|
||||
std::mutex &get_mutex();
|
||||
std::ostringstream &Write(LogLevel l = logINFO) noexcept;
|
||||
|
||||
private:
|
||||
std::ostringstream os;
|
||||
LogLevel level;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SIMPLE_LOGGER_HPP */
|
||||
@@ -378,7 +378,8 @@ class StaticRTree
|
||||
catch (const std::exception &exc)
|
||||
{
|
||||
throw exception(boost::str(boost::format("Leaf file %1% mapping failed: %2%") %
|
||||
leaf_file % exc.what()));
|
||||
leaf_file % exc.what()) +
|
||||
SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ local set_classification = require("lib/guidance").set_classification
|
||||
barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["block"] = true }
|
||||
access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true }
|
||||
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = true }
|
||||
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
|
||||
access_tags_hierarchy = { "bicycle", "vehicle", "access" }
|
||||
cycleway_tags = {["track"]=true,["lane"]=true,["opposite"]=true,["opposite_lane"]=true,["opposite_track"]=true,["share_busway"]=true,["sharrow"]=true,["shared"]=true }
|
||||
service_tag_restricted = { ["parking_aisle"] = true }
|
||||
restrictions = { "bicycle" }
|
||||
unsafe_highway_list = { ["primary"] = true, ["secondary"] = true, ["tertiary"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true}
|
||||
|
||||
|
||||
+109
-173
@@ -5,6 +5,7 @@ local set_classification = require("lib/guidance").set_classification
|
||||
local get_turn_lanes = require("lib/guidance").get_turn_lanes
|
||||
local Set = require('lib/set')
|
||||
local Sequence = require('lib/sequence')
|
||||
local Directional = require('lib/directional')
|
||||
|
||||
-- Begin of globals
|
||||
barrier_whitelist = Set {
|
||||
@@ -39,11 +40,6 @@ access_tag_blacklist = Set {
|
||||
'delivery'
|
||||
}
|
||||
|
||||
access_tag_restricted = Set {
|
||||
'destination',
|
||||
'delivery'
|
||||
}
|
||||
|
||||
access_tags_hierarchy = Sequence {
|
||||
'motorcar',
|
||||
'motor_vehicle',
|
||||
@@ -51,11 +47,6 @@ access_tags_hierarchy = Sequence {
|
||||
'access'
|
||||
}
|
||||
|
||||
service_tag_restricted = Set {
|
||||
'parking_aisle',
|
||||
'parking'
|
||||
}
|
||||
|
||||
service_tag_forbidden = Set {
|
||||
'emergency_access'
|
||||
}
|
||||
@@ -287,69 +278,51 @@ end
|
||||
|
||||
-- abort early if this way is obviouslt not routable
|
||||
function initial_routability_check(way,result,data)
|
||||
data.speed_type = way:get_value_by_key('highway')
|
||||
data.highway = way:get_value_by_key('highway')
|
||||
|
||||
return data.speed_type ~= nil or
|
||||
return data.highway ~= nil or
|
||||
way:get_value_by_key('route') ~= nil or
|
||||
way:get_value_by_key('bridge') ~= nil
|
||||
end
|
||||
|
||||
-- handle high occupancy vehicle tags
|
||||
function handle_hov(way,result)
|
||||
-- respect user-preference for HOV-only ways
|
||||
if ignore_hov_ways then
|
||||
local hov = way:get_value_by_key("hov")
|
||||
if "designated" == hov then
|
||||
-- all lanes restricted to hov vehicles?
|
||||
local function has_all_designated_hov_lanes(lanes)
|
||||
if not lanes then
|
||||
return false
|
||||
end
|
||||
-- This gmatch call effectively splits the string on | chars.
|
||||
-- we append an extra | to the end so that we can match the final part
|
||||
for lane in (lanes .. '|'):gmatch("([^|]*)|") do
|
||||
if lane and lane ~= "designated" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- also respect user-preference for HOV-only ways when all lanes are HOV-designated
|
||||
local function has_all_designated_hov_lanes(lanes)
|
||||
local all = true
|
||||
-- This gmatch call effectively splits the string on | chars.
|
||||
-- we append an extra | to the end so that we can match the final part
|
||||
for lane in (lanes .. '|'):gmatch("([^|]*)|") do
|
||||
if lane and lane ~= "designated" then
|
||||
all = false
|
||||
break
|
||||
end
|
||||
end
|
||||
return all
|
||||
end
|
||||
-- handle high occupancy vehicle tags
|
||||
function handle_hov(way,result,data)
|
||||
-- respect user-preference for HOV
|
||||
if not ignore_hov_ways then
|
||||
return
|
||||
end
|
||||
|
||||
local hov_lanes = way:get_value_by_key("hov:lanes")
|
||||
local hov_lanes_forward = way:get_value_by_key("hov:lanes:forward")
|
||||
local hov_lanes_backward = way:get_value_by_key("hov:lanes:backward")
|
||||
-- check if way is hov only
|
||||
local hov = way:get_value_by_key("hov")
|
||||
if "designated" == hov then
|
||||
return false
|
||||
end
|
||||
|
||||
local hov_all_designated = hov_lanes and
|
||||
has_all_designated_hov_lanes(hov_lanes)
|
||||
|
||||
local hov_all_designated_forward = hov_lanes_forward and
|
||||
has_all_designated_hov_lanes(hov_lanes_forward)
|
||||
|
||||
local hov_all_designated_backward = hov_lanes_backward and
|
||||
has_all_designated_hov_lanes(hov_lanes_backward)
|
||||
|
||||
-- forward/backward lane depend on a way's direction
|
||||
local oneway = way:get_value_by_key("oneway")
|
||||
local reverse = oneway == "-1"
|
||||
|
||||
if hov_all_designated or hov_all_designated_forward then
|
||||
if reverse then
|
||||
result.backward_mode = mode.inaccessible
|
||||
else
|
||||
result.forward_mode = mode.inaccessible
|
||||
end
|
||||
end
|
||||
|
||||
if hov_all_designated_backward then
|
||||
if reverse then
|
||||
result.forward_mode = mode.inaccessible
|
||||
else
|
||||
result.backward_mode = mode.inaccessible
|
||||
end
|
||||
end
|
||||
-- check if all lanes are hov only
|
||||
local hov_lanes_forward, hov_lanes_backward = Directional.get_values_by_key(way,data,'hov:lanes')
|
||||
local inaccessible_forward = has_all_designated_hov_lanes(hov_lanes_forward)
|
||||
local inaccessible_backward = has_all_designated_hov_lanes(hov_lanes_backward)
|
||||
|
||||
if inaccessible_forward then
|
||||
result.forward_mode = mode.inaccessible
|
||||
end
|
||||
if inaccessible_backward then
|
||||
result.backward_mode = mode.inaccessible
|
||||
end
|
||||
end
|
||||
|
||||
@@ -394,8 +367,18 @@ end
|
||||
|
||||
-- check accessibility by traversing our acces tag hierarchy
|
||||
function handle_access(way,result,data)
|
||||
data.access = find_access_tag(way, access_tags_hierarchy)
|
||||
if access_tag_blacklist[data.access] then
|
||||
data.forward_access, data.backward_access =
|
||||
Directional.get_values_by_set(way,data,access_tags_hierarchy)
|
||||
|
||||
if access_tag_blacklist[data.forward_access] then
|
||||
result.forward_mode = mode.inaccessible
|
||||
end
|
||||
|
||||
if access_tag_blacklist[data.backward_access] then
|
||||
result.backward_mode = mode.inaccessible
|
||||
end
|
||||
|
||||
if result.forward_mode == mode.inaccessible and result.backward_mode == mode.inaccessible then
|
||||
return false
|
||||
end
|
||||
end
|
||||
@@ -440,30 +423,21 @@ end
|
||||
-- handle speed (excluding maxspeed)
|
||||
function handle_speed(way,result,data)
|
||||
if result.forward_speed == -1 then
|
||||
local highway_speed = speed_profile[way:get_value_by_key("highway")]
|
||||
local max_speed = parse_maxspeed( way:get_value_by_key("maxspeed") )
|
||||
local highway_speed = speed_profile[data.highway]
|
||||
-- Set the avg speed on the way if it is accessible by road class
|
||||
if highway_speed then
|
||||
if max_speed and max_speed > highway_speed then
|
||||
result.forward_speed = max_speed
|
||||
result.backward_speed = max_speed
|
||||
-- max_speed = math.huge
|
||||
else
|
||||
result.forward_speed = highway_speed
|
||||
result.backward_speed = highway_speed
|
||||
end
|
||||
result.forward_speed = highway_speed
|
||||
result.backward_speed = highway_speed
|
||||
else
|
||||
-- Set the avg speed on ways that are marked accessible
|
||||
if access_tag_whitelist[data.access] then
|
||||
if access_tag_whitelist[data.forward_access] then
|
||||
result.forward_speed = speed_profile["default"]
|
||||
end
|
||||
|
||||
if access_tag_whitelist[data.backward_access] then
|
||||
result.backward_speed = speed_profile["default"]
|
||||
end
|
||||
end
|
||||
if 0 == max_speed then
|
||||
max_speed = math.huge
|
||||
end
|
||||
result.forward_speed = min(result.forward_speed, max_speed)
|
||||
result.backward_speed = min(result.backward_speed, max_speed)
|
||||
end
|
||||
|
||||
if -1 == result.forward_speed and -1 == result.backward_speed then
|
||||
@@ -472,7 +446,7 @@ function handle_speed(way,result,data)
|
||||
|
||||
if handle_side_roads(way,result) == false then return false end
|
||||
if handle_surface(way,result) == false then return false end
|
||||
if handle_maxspeed(way,result) == false then return false end
|
||||
if handle_maxspeed(way,data,result) == false then return false end
|
||||
if handle_speed_scaling(way,result) == false then return false end
|
||||
if handle_alternating_speed(way,result) == false then return false end
|
||||
end
|
||||
@@ -529,23 +503,15 @@ function handle_names(way,result)
|
||||
end
|
||||
|
||||
-- handle turn lanes
|
||||
function handle_turn_lanes(way,result)
|
||||
local turn_lanes = ''
|
||||
local turn_lanes_forward = ''
|
||||
local turn_lanes_backward = ''
|
||||
function handle_turn_lanes(way,result,data)
|
||||
local forward, backward = get_turn_lanes(way,data)
|
||||
|
||||
turn_lanes, turn_lanes_forward, turn_lanes_backward = get_turn_lanes(way)
|
||||
if turn_lanes and turn_lanes ~= '' then
|
||||
result.turn_lanes_forward = turn_lanes;
|
||||
result.turn_lanes_backward = turn_lanes;
|
||||
else
|
||||
if turn_lanes_forward and turn_lanes_forward ~= '' then
|
||||
result.turn_lanes_forward = turn_lanes_forward;
|
||||
end
|
||||
if forward then
|
||||
result.turn_lanes_forward = forward
|
||||
end
|
||||
|
||||
if turn_lanes_backward and turn_lanes_backward ~= '' then
|
||||
result.turn_lanes_backward = turn_lanes_backward;
|
||||
end
|
||||
if backward then
|
||||
result.turn_lanes_backward = backward
|
||||
end
|
||||
end
|
||||
|
||||
@@ -565,22 +531,10 @@ function handle_roundabouts(way,result)
|
||||
end
|
||||
end
|
||||
|
||||
-- Set access restriction flag if access is allowed under certain restrictions only
|
||||
function handle_restricted(way,result,data)
|
||||
if data.access and access_tag_restricted[data.access] then
|
||||
result.is_access_restricted = true
|
||||
end
|
||||
end
|
||||
|
||||
-- service roads
|
||||
function handle_service(way,result)
|
||||
local service = way:get_value_by_key("service")
|
||||
if service then
|
||||
-- Set access restriction flag if service is allowed under certain restrictions only
|
||||
if service_tag_restricted[service] then
|
||||
result.is_access_restricted = true
|
||||
end
|
||||
|
||||
-- Set don't allow access to certain service roads
|
||||
if service_tag_forbidden[service] then
|
||||
result.forward_mode = mode.inaccessible
|
||||
@@ -633,69 +587,55 @@ function handle_speed_scaling(way,result)
|
||||
end
|
||||
end
|
||||
|
||||
-- oneways
|
||||
function handle_oneway(way,result)
|
||||
-- handle oneways tags
|
||||
function handle_oneway(way,result,data)
|
||||
local oneway = way:get_value_by_key("oneway")
|
||||
data.oneway = oneway
|
||||
if obey_oneway then
|
||||
if oneway == "-1" then
|
||||
data.is_reverse_oneway = true
|
||||
result.forward_mode = mode.inaccessible
|
||||
|
||||
local is_forward = false
|
||||
local destination = get_destination(way, is_forward)
|
||||
result.destinations = canonicalizeStringList(destination, ",")
|
||||
elseif oneway == "yes" or
|
||||
oneway == "1" or
|
||||
oneway == "true" or
|
||||
way:get_value_by_key("junction") == "roundabout" or
|
||||
way:get_value_by_key("junction") == "circular" or
|
||||
(way:get_value_by_key("highway") == "motorway" and oneway ~= "no") then
|
||||
|
||||
oneway == "true" then
|
||||
data.is_forward_oneway = true
|
||||
result.backward_mode = mode.inaccessible
|
||||
|
||||
local is_forward = true
|
||||
local destination = get_destination(way, is_forward)
|
||||
result.destinations = canonicalizeStringList(destination, ",")
|
||||
else
|
||||
local junction = way:get_value_by_key("junction")
|
||||
if data.highway == "motorway" or
|
||||
junction == "roundabout" or
|
||||
junction == "circular" then
|
||||
if oneway ~= "no" then
|
||||
-- implied oneway
|
||||
data.is_forward_oneway = true
|
||||
result.backward_mode = mode.inaccessible
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- maxspeed and advisory maxspeed
|
||||
function handle_maxspeed(way,result)
|
||||
-- Override speed settings if explicit forward/backward maxspeeds are given
|
||||
local maxspeed_forward = parse_maxspeed(way:get_value_by_key("maxspeed:forward"))
|
||||
local maxspeed_backward = parse_maxspeed(way:get_value_by_key("maxspeed:backward"))
|
||||
if maxspeed_forward and maxspeed_forward > 0 then
|
||||
if mode.inaccessible ~= result.forward_mode and
|
||||
mode.inaccessible ~= result.backward_mode then
|
||||
result.backward_speed = result.forward_speed
|
||||
end
|
||||
result.forward_speed = maxspeed_forward
|
||||
-- handle destination tags
|
||||
function handle_destinations(way,result,data)
|
||||
if data.is_forward_oneway or data.is_reverse_oneway then
|
||||
local destination = get_destination(way, data.is_forward_oneway)
|
||||
result.destinations = canonicalizeStringList(destination, ",")
|
||||
end
|
||||
if maxspeed_backward and maxspeed_backward > 0 then
|
||||
result.backward_speed = maxspeed_backward
|
||||
end
|
||||
|
||||
-- maxspeed and advisory maxspeed
|
||||
function handle_maxspeed(way,data,result)
|
||||
local keys = Sequence { 'maxspeed:advisory', 'maxspeed' }
|
||||
local forward, backward = Directional.get_values_by_set(way,data,keys)
|
||||
forward = parse_maxspeed(forward)
|
||||
backward = parse_maxspeed(backward)
|
||||
|
||||
if forward and forward > 0 then
|
||||
result.forward_speed = forward
|
||||
end
|
||||
|
||||
-- Override speed settings if advisory forward/backward maxspeeds are given
|
||||
local advisory_speed = parse_maxspeed(way:get_value_by_key("maxspeed:advisory"))
|
||||
local advisory_forward = parse_maxspeed(way:get_value_by_key("maxspeed:advisory:forward"))
|
||||
local advisory_backward = parse_maxspeed(way:get_value_by_key("maxspeed:advisory:backward"))
|
||||
-- apply bi-directional advisory speed first
|
||||
if advisory_speed and advisory_speed > 0 then
|
||||
if mode.inaccessible ~= result.forward_mode then
|
||||
result.forward_speed = advisory_speed
|
||||
end
|
||||
if mode.inaccessible ~= result.backward_mode then
|
||||
result.backward_speed = advisory_speed
|
||||
end
|
||||
end
|
||||
if advisory_forward and advisory_forward > 0 then
|
||||
if mode.inaccessible ~= result.forward_mode and mode.inaccessible ~= result.backward_mode then
|
||||
result.backward_speed = result.forward_speed
|
||||
end
|
||||
result.forward_speed = advisory_forward
|
||||
end
|
||||
if advisory_backward and advisory_backward > 0 then
|
||||
result.backward_speed = advisory_backward
|
||||
if backward and backward > 0 then
|
||||
result.backward_speed = backward
|
||||
end
|
||||
end
|
||||
|
||||
@@ -713,6 +653,7 @@ function handle_alternating_speed(way,result)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- determine if this way can be used as a start/end point for routing
|
||||
function handle_startpoint(way,result)
|
||||
-- only allow this road as start point if it not a ferry
|
||||
@@ -721,8 +662,8 @@ function handle_startpoint(way,result)
|
||||
end
|
||||
|
||||
-- set the road classification based on guidance globals configuration
|
||||
function handle_classification(way,result)
|
||||
set_classification(way:get_value_by_key("highway"),result,way)
|
||||
function handle_classification(way,result,data)
|
||||
set_classification(data.highway,result,way)
|
||||
end
|
||||
|
||||
-- main entry point for processsing a way
|
||||
@@ -754,8 +695,11 @@ function way_function(way, result)
|
||||
-- access tags, e.g: motorcar, motor_vehicle, vehicle
|
||||
if handle_access(way,result,data) == false then return end
|
||||
|
||||
-- check high occupancy vehicle restrictions
|
||||
if handle_hov(way,result) == false then return end
|
||||
-- check whether forward/backward directons are routable
|
||||
if handle_oneway(way,result,data) == false then return end
|
||||
|
||||
-- check whether forward/backward directons are routable
|
||||
if handle_destinations(way,result,data) == false then return end
|
||||
|
||||
-- check whether we're using a special transport mode
|
||||
if handle_ferries(way,result) == false then return end
|
||||
@@ -764,27 +708,19 @@ function way_function(way, result)
|
||||
-- handle service road restrictions
|
||||
if handle_service(way,result) == false then return end
|
||||
|
||||
-- check whether forward/backward directons are routable
|
||||
if handle_oneway(way,result) == false then return end
|
||||
-- check high occupancy vehicle restrictions
|
||||
if handle_hov(way,result,data) == false then return end
|
||||
|
||||
-- compute speed taking into account way type, maxspeed tags, etc.
|
||||
if handle_speed(way,result,data) == false then return end
|
||||
|
||||
-- handle turn lanes and road classification, used for guidance
|
||||
if handle_turn_lanes(way,result) == false then return end
|
||||
if handle_classification(way,result) == false then return end
|
||||
if handle_turn_lanes(way,result,data) == false then return end
|
||||
if handle_classification(way,result,data) == false then return end
|
||||
|
||||
-- handle various other flags
|
||||
if handle_roundabouts(way,result) == false then return end
|
||||
if handle_startpoint(way,result) == false then return end
|
||||
if handle_restricted(way,result,data) == false then return end
|
||||
|
||||
-- handle roundabout flags
|
||||
if handle_roundabouts(way,result) == false then return end
|
||||
|
||||
-- check if this way can be routed through, but not used as
|
||||
-- origin or destination
|
||||
if handle_restricted(way,result,data) == false then return end
|
||||
|
||||
-- set name, ref and pronunciation
|
||||
if handle_names(way,result) == false then return end
|
||||
|
||||
+51
-3
@@ -43,8 +43,10 @@ mode = {
|
||||
|
||||
-- input tags, normally extracted from OSM data
|
||||
local way = {
|
||||
highway = 'motorway',
|
||||
highway = 'primary',
|
||||
name = 'Main Street',
|
||||
--access = 'no'
|
||||
["access:forward"] = 'no'
|
||||
--width = '3',
|
||||
--maxspeed = '30',
|
||||
--['maxspeed:advisory'] = '25',
|
||||
@@ -56,13 +58,32 @@ local way = {
|
||||
--route = 'ferry',
|
||||
--duration = '00:01:00',
|
||||
--hov = 'designated',
|
||||
--access = 'no'
|
||||
--hov:lanes:forward"] = 'designated',
|
||||
|
||||
--destination = 'Berlin',
|
||||
["destination:ref"] = 'Nuremberg',
|
||||
--["destination:ref"] = 'Nuremberg',
|
||||
--["destination:ref:forward"] = 'Hamburg;Dresden',
|
||||
}
|
||||
-- tag function normally provided via C++
|
||||
function way:get_value_by_key(k)
|
||||
if not self['_debug'] then
|
||||
self['_debug'] = {
|
||||
_counts = {}
|
||||
}
|
||||
end
|
||||
|
||||
if self['_debug']['_total'] then
|
||||
self['_debug']['_total'] = self['_debug']['_total'] + 1
|
||||
else
|
||||
self['_debug']['_total'] = 1
|
||||
end
|
||||
|
||||
if self['_debug']['_counts'][k] then
|
||||
self['_debug']['_counts'][k] = self['_debug']['_counts'][k] + 1
|
||||
else
|
||||
self['_debug']['_counts'][k] = 1
|
||||
end
|
||||
|
||||
return self[k]
|
||||
end
|
||||
|
||||
@@ -83,6 +104,27 @@ function canonicalizeStringList(str)
|
||||
return str
|
||||
end
|
||||
|
||||
-- helpers for sorting associative array
|
||||
function get_keys_sorted_by_value(tbl, sortFunction)
|
||||
local keys = {}
|
||||
for key in pairs(tbl) do
|
||||
table.insert(keys, key)
|
||||
end
|
||||
|
||||
table.sort(keys, function(a, b)
|
||||
return sortFunction(tbl[a], tbl[b])
|
||||
end)
|
||||
|
||||
return keys
|
||||
end
|
||||
|
||||
-- helper for printing sorted array
|
||||
function print_sorted(sorted,associative)
|
||||
for _, key in ipairs(sorted) do
|
||||
print(associative[key], key)
|
||||
end
|
||||
end
|
||||
|
||||
-- start state of result table, normally set form C++
|
||||
local result = {
|
||||
road_classification = {},
|
||||
@@ -100,3 +142,9 @@ way_function(way,result)
|
||||
pprint(way)
|
||||
print("=>")
|
||||
pprint(result)
|
||||
print("\n")
|
||||
print("Tag fetches:")
|
||||
sorted_counts = get_keys_sorted_by_value(way._debug._counts, function(a, b) return a > b end)
|
||||
print_sorted(sorted_counts, way._debug._counts)
|
||||
|
||||
print(way._debug._total, 'total')
|
||||
|
||||
@@ -6,9 +6,7 @@ local find_access_tag = require("lib/access").find_access_tag
|
||||
barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["block"] = true}
|
||||
access_tag_whitelist = { ["yes"] = true, ["foot"] = true, ["permissive"] = true, ["designated"] = true }
|
||||
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = true }
|
||||
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
|
||||
access_tags_hierarchy = { "foot", "access" }
|
||||
service_tag_restricted = { ["parking_aisle"] = true }
|
||||
ignore_in_grid = { ["ferry"] = true }
|
||||
restrictions = { "foot" }
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
local Directional = {}
|
||||
|
||||
-- return [forward,backward] values for a specific tag.
|
||||
-- e.g. for maxspeed search forward:
|
||||
-- maxspeed:forward
|
||||
-- maxspeed
|
||||
-- and backward:
|
||||
-- maxspeed:backward
|
||||
-- maxspeed
|
||||
|
||||
function Directional.get_values_by_key(way,data,key)
|
||||
local forward = way:get_value_by_key(key .. ':forward')
|
||||
local backward = way:get_value_by_key(key .. ':backward')
|
||||
|
||||
if forward and backward then
|
||||
return forward, backward
|
||||
end
|
||||
|
||||
local common = way:get_value_by_key(key)
|
||||
return forward or common,
|
||||
backward or common
|
||||
end
|
||||
|
||||
-- return [forward,backward] values, searching a
|
||||
-- prioritized sequence of tags
|
||||
-- e.g. for the sequence [maxspeed,advisory] search forward:
|
||||
-- maxspeed:forward
|
||||
-- maxspeed
|
||||
-- advisory:forward
|
||||
-- advisory
|
||||
-- and for backward:
|
||||
-- maxspeed:backward
|
||||
-- maxspeed
|
||||
-- advisory:backward
|
||||
-- advisory
|
||||
|
||||
function Directional.get_values_by_set(way,data,keys)
|
||||
local forward, backward
|
||||
for i,key in ipairs(keys) do
|
||||
if not forward then
|
||||
forward = way:get_value_by_key(key .. ':forward')
|
||||
end
|
||||
if not backward then
|
||||
backward = way:get_value_by_key(key .. ':backward')
|
||||
end
|
||||
if not forward or not backward then
|
||||
local common = way:get_value_by_key(key)
|
||||
forward = forward or common
|
||||
backward = backward or common
|
||||
end
|
||||
if forward and backward then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return forward, backward
|
||||
end
|
||||
|
||||
return Directional
|
||||
+120
-128
@@ -1,154 +1,146 @@
|
||||
local Directional = require('lib/directional')
|
||||
local Set = require('lib/set')
|
||||
|
||||
local Guidance = {}
|
||||
|
||||
-- Guidance: Default Mapping from roads to types/priorities
|
||||
highway_classes = { ["motorway"] = road_priority_class.motorway,
|
||||
["motorway_link"] = road_priority_class.link_road,
|
||||
["trunk"] = road_priority_class.trunk,
|
||||
["trunk_link"] = road_priority_class.link_road,
|
||||
["primary"] = road_priority_class.primary,
|
||||
["primary_link"] = road_priority_class.link_road,
|
||||
["secondary"] = road_priority_class.secondary,
|
||||
["secondary_link"] = road_priority_class.link_road,
|
||||
["tertiary"] = road_priority_class.tertiary,
|
||||
["tertiary_link"] = road_priority_class.link_road,
|
||||
["unclassified"] = road_priority_class.side_residential,
|
||||
["residential"] = road_priority_class.side_residential,
|
||||
["service"] = road_priority_class.connectivity,
|
||||
["living_street"] = road_priority_class.main_residential,
|
||||
["track"] = road_priority_class.bike_path,
|
||||
["path"] = road_priority_class.bike_path,
|
||||
["footway"] = road_priority_class.foot_path,
|
||||
["pedestrian"] = road_priority_class.foot_path,
|
||||
["steps"] = road_priority_class.foot_path}
|
||||
highway_classes = {
|
||||
motorway = road_priority_class.motorway,
|
||||
motorway_link = road_priority_class.link_road,
|
||||
trunk = road_priority_class.trunk,
|
||||
trunk_link = road_priority_class.link_road,
|
||||
primary = road_priority_class.primary,
|
||||
primary_link = road_priority_class.link_road,
|
||||
secondary = road_priority_class.secondary,
|
||||
secondary_link = road_priority_class.link_road,
|
||||
tertiary = road_priority_class.tertiary,
|
||||
tertiary_link = road_priority_class.link_road,
|
||||
unclassified = road_priority_class.side_residential,
|
||||
residential = road_priority_class.side_residential,
|
||||
service = road_priority_class.connectivity,
|
||||
living_street = road_priority_class.main_residential,
|
||||
track = road_priority_class.bike_path,
|
||||
path = road_priority_class.bike_path,
|
||||
footway = road_priority_class.foot_path,
|
||||
pedestrian = road_priority_class.foot_path,
|
||||
steps = road_priority_class.foot_path
|
||||
}
|
||||
|
||||
default_highway_class = road_priority_class.connectivity;
|
||||
|
||||
motorway_types = { ["motorway"] = true, ["motorway_link"] = true, ["trunk"] = true, ["trunk_link"] = true }
|
||||
motorway_types = Set {
|
||||
'motorway',
|
||||
'motorway_link',
|
||||
'trunk',
|
||||
'trunk_link'
|
||||
}
|
||||
|
||||
-- these road types are set with a car in mind. For bicycle/walk we probably need different ones
|
||||
road_types = { ["motorway"] = true,
|
||||
["motorway_link"] = true,
|
||||
["trunk"] = true,
|
||||
["trunk_link"] = true,
|
||||
["primary"] = true,
|
||||
["primary_link"] = true,
|
||||
["secondary"] = true,
|
||||
["secondary_link"] = true,
|
||||
["tertiary"] = true,
|
||||
["tertiary_link"] = true,
|
||||
["unclassified"] = true,
|
||||
["residential"] = true,
|
||||
["living_street"] = true }
|
||||
road_types = Set {
|
||||
'motorway',
|
||||
'motorway_link',
|
||||
'trunk',
|
||||
'trunk_link',
|
||||
'primary',
|
||||
'primary_link',
|
||||
'secondary',
|
||||
'secondary_link',
|
||||
'tertiary',
|
||||
'tertiary_link',
|
||||
'unclassified',
|
||||
'residential',
|
||||
'living_street'
|
||||
}
|
||||
|
||||
link_types = { ["motorway_link"] = true, ["trunk_link"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true }
|
||||
link_types = Set {
|
||||
'motorway_link',
|
||||
'trunk_link',
|
||||
'primary_link',
|
||||
'secondary_link',
|
||||
'tertiary_link'
|
||||
}
|
||||
|
||||
function Guidance.set_classification (highway, result, input_way)
|
||||
if motorway_types[highway] then
|
||||
result.road_classification.motorway_class = true;
|
||||
end
|
||||
if link_types[highway] then
|
||||
result.road_classification.link_class = true;
|
||||
end
|
||||
if highway_classes[highway] ~= nil then
|
||||
result.road_classification.road_priority_class = highway_classes[highway]
|
||||
else
|
||||
result.road_classification.road_priority_class = default_highway_class
|
||||
end
|
||||
if road_types[highway] then
|
||||
result.road_classification.may_be_ignored = false;
|
||||
else
|
||||
result.road_classification.may_be_ignored = true;
|
||||
end
|
||||
if motorway_types[highway] then
|
||||
result.road_classification.motorway_class = true;
|
||||
end
|
||||
if link_types[highway] then
|
||||
result.road_classification.link_class = true;
|
||||
end
|
||||
if highway_classes[highway] ~= nil then
|
||||
result.road_classification.road_priority_class = highway_classes[highway]
|
||||
else
|
||||
result.road_classification.road_priority_class = default_highway_class
|
||||
end
|
||||
if road_types[highway] then
|
||||
result.road_classification.may_be_ignored = false;
|
||||
else
|
||||
result.road_classification.may_be_ignored = true;
|
||||
end
|
||||
|
||||
local lane_count = input_way:get_value_by_key("lanes")
|
||||
if lane_count then
|
||||
local lc = tonumber(lane_count)
|
||||
if lc ~= nil then
|
||||
result.road_classification.num_lanes = lc
|
||||
end
|
||||
else
|
||||
local total_count = 0
|
||||
local forward_count = input_way:get_value_by_key("lanes:forward")
|
||||
if forward_count then
|
||||
local fc = tonumber(forward_count)
|
||||
if fc ~= nil then
|
||||
total_count = fc
|
||||
end
|
||||
end
|
||||
local backward_count = input_way:get_value_by_key("lanes:backward")
|
||||
if backward_count then
|
||||
local bc = tonumber(backward_count)
|
||||
if bc ~= nil then
|
||||
total_count = total_count + bc
|
||||
end
|
||||
end
|
||||
if total_count ~= 0 then
|
||||
result.road_classification.num_lanes = total_count
|
||||
end
|
||||
local lane_count = input_way:get_value_by_key("lanes")
|
||||
if lane_count then
|
||||
local lc = tonumber(lane_count)
|
||||
if lc ~= nil then
|
||||
result.road_classification.num_lanes = lc
|
||||
end
|
||||
else
|
||||
local total_count = 0
|
||||
local forward_count = input_way:get_value_by_key("lanes:forward")
|
||||
if forward_count then
|
||||
local fc = tonumber(forward_count)
|
||||
if fc ~= nil then
|
||||
total_count = fc
|
||||
end
|
||||
end
|
||||
local backward_count = input_way:get_value_by_key("lanes:backward")
|
||||
if backward_count then
|
||||
local bc = tonumber(backward_count)
|
||||
if bc ~= nil then
|
||||
total_count = total_count + bc
|
||||
end
|
||||
end
|
||||
if total_count ~= 0 then
|
||||
result.road_classification.num_lanes = total_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- returns forward,backward psv lane count
|
||||
local function get_psv_counts(way)
|
||||
local psv = way:get_value_by_key("lanes:psv")
|
||||
local psv_forward = way:get_value_by_key("lanes:psv:forward");
|
||||
local psv_backward = way:get_value_by_key("lanes:psv:backward");
|
||||
|
||||
local fw = 0;
|
||||
local bw = 0;
|
||||
if psv then
|
||||
fw = tonumber(psv)
|
||||
if( fw == nil ) then
|
||||
fw = 0
|
||||
end
|
||||
end
|
||||
if psv_forward then
|
||||
fw = tonumber(psv_forward)
|
||||
if( fw == nil ) then
|
||||
fw = 0
|
||||
end
|
||||
end
|
||||
if psv_backward then
|
||||
bw = tonumber(psv_backward);
|
||||
if( bw == nil ) then
|
||||
bw = 0
|
||||
end
|
||||
end
|
||||
return fw, bw
|
||||
local function get_psv_counts(way,data)
|
||||
local psv_forward, psv_backward = Directional.get_values_by_key(way,data,'lanes:psv')
|
||||
if psv_forward then
|
||||
psv_forward = tonumber(psv_forward)
|
||||
end
|
||||
if psv_backward then
|
||||
psv_backward = tonumber(psv_backward)
|
||||
end
|
||||
return psv_forward or 0,
|
||||
psv_backward or 0
|
||||
end
|
||||
|
||||
-- trims lane string with regard to supported lanes
|
||||
local function process_lanes(turn_lane,vehicle_lane,first_count,second_count)
|
||||
if turn_lane then
|
||||
if vehicle_lane then
|
||||
turn_lane = applyAccessTokens(turn_lane,vehicle_lane)
|
||||
elseif first_count ~= 0 or second_count ~= 0 then
|
||||
turn_lane = trimLaneString(turn_lane, first_count, second_count)
|
||||
end
|
||||
local function process_lanes(turn_lanes,vehicle_lanes,first_count,second_count)
|
||||
if turn_lanes then
|
||||
if vehicle_lanes then
|
||||
return applyAccessTokens(turn_lanes,vehicle_lanes)
|
||||
elseif first_count ~= 0 or second_count ~= 0 then
|
||||
return trimLaneString(turn_lanes, first_count, second_count)
|
||||
else
|
||||
return turn_lanes
|
||||
end
|
||||
return turn_lane;
|
||||
end
|
||||
end
|
||||
|
||||
-- this is broken for left-sided driving. It needs to switch left and right in case of left-sided driving
|
||||
function Guidance.get_turn_lanes(way)
|
||||
local fw_psv = 0
|
||||
local bw_psv = 0
|
||||
fw_psv, bw_psv = get_psv_counts(way)
|
||||
|
||||
local turn_lanes = way:get_value_by_key("turn:lanes")
|
||||
local turn_lanes_fw = way:get_value_by_key("turn:lanes:forward")
|
||||
local turn_lanes_bw = way:get_value_by_key("turn:lanes:backward")
|
||||
|
||||
local vehicle_lanes = way:get_value_by_key("vehicle:lanes");
|
||||
local vehicle_lanes_fw = way:get_value_by_key("vehicle:lanes:forward");
|
||||
local vehicle_lanes_bw = way:get_value_by_key("vehicle:lanes:backward");
|
||||
|
||||
turn_lanes = process_lanes(turn_lanes,vehicle_lanes,bw_psv,fw_psv)
|
||||
turn_lanes_fw = process_lanes(turn_lanes_fw,vehicle_lanes_fw,bw_psv,fw_psv)
|
||||
--backwards turn lanes need to treat bw_psv as fw_psv and vice versa
|
||||
turn_lanes_bw = process_lanes(turn_lanes_bw,vehicle_lanes_bw,fw_psv,bw_psv)
|
||||
|
||||
return turn_lanes, turn_lanes_fw, turn_lanes_bw
|
||||
function Guidance.get_turn_lanes(way,data)
|
||||
local psv_fw, psv_bw = get_psv_counts(way,data)
|
||||
local turn_lanes_fw, turn_lanes_bw = Directional.get_values_by_key(way,data,'turn:lanes')
|
||||
local vehicle_lanes_fw, vehicle_lanes_bw = Directional.get_values_by_key(way,data,'vehicle:lanes')
|
||||
|
||||
--note: backward lanes swap psv_bw and psv_fw
|
||||
return process_lanes(turn_lanes_fw,vehicle_lanes_fw,psv_bw,psv_fw) or turn_lanes,
|
||||
process_lanes(turn_lanes_bw,vehicle_lanes_bw,psv_fw,psv_bw) or turn_lanes
|
||||
end
|
||||
|
||||
return Guidance
|
||||
|
||||
+13
-6
@@ -1,11 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# here we set up the node version on the fly. currently only node 4, but can be used for more values if need be
|
||||
# This is done manually so that the build works the same on OS X
|
||||
rm -rf ~/.nvm/ && git clone --depth 1 --branch v0.30.1 https://github.com/creationix/nvm.git ~/.nvm
|
||||
source ~/.nvm/nvm.sh
|
||||
nvm install $1
|
||||
nvm use $1
|
||||
NODE_HOME=$HOME/node
|
||||
export NODE_HOME
|
||||
mkdir ${NODE_HOME}
|
||||
if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
|
||||
curl https://s3.amazonaws.com/mapbox/apps/install-node/v2.0.0/run | NV=4.4.2 NP=darwin-x64 OD=${NODE_HOME} sh
|
||||
else
|
||||
curl https://s3.amazonaws.com/mapbox/apps/install-node/v2.0.0/run | NV=4.4.2 NP=linux-x64 OD=${NODE_HOME} sh
|
||||
fi
|
||||
|
||||
PATH="${NODE_HOME}/bin:$PATH"
|
||||
export PATH
|
||||
node --version
|
||||
npm --version
|
||||
which node
|
||||
|
||||
|
||||
|
||||
+7
-3
@@ -7,12 +7,16 @@ set -o nounset
|
||||
# Runs the Clang Tidy Tool in parallel on the code base.
|
||||
# Requires a compilation database in the build directory.
|
||||
|
||||
# This works on both OSX and Linux, it's a POSIX thingy
|
||||
NPROC=$(getconf _NPROCESSORS_ONLN)
|
||||
|
||||
find src include unit_tests -type f -name '*.hpp' -o -name '*.cpp' \
|
||||
|
||||
find src include unit_tests -type f -name '*.hpp' -o -name '*.cpp' -print0 \
|
||||
| xargs \
|
||||
-0 \
|
||||
-I{} \
|
||||
-P $(nproc) \
|
||||
clang-tidy \
|
||||
-n 1 \
|
||||
./clang+llvm-3.9.0-x86_64-apple-darwin/bin/clang-tidy \
|
||||
-p build \
|
||||
-header-filter='.*' \
|
||||
{}
|
||||
|
||||
+122
-79
@@ -6,13 +6,13 @@
|
||||
#include "extractor/edge_based_graph_factory.hpp"
|
||||
#include "extractor/node_based_edge.hpp"
|
||||
|
||||
#include "storage/io.hpp"
|
||||
#include "storage/io.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/graph_loader.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/io.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
#include "util/static_rtree.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
@@ -105,13 +105,13 @@ EdgeWeight getNewWeight(IterType speed_iter,
|
||||
if (old_weight >= (new_segment_weight * log_edge_updates_factor))
|
||||
{
|
||||
auto speed_file = segment_speed_filenames.at(speed_iter->speed_source.source - 1);
|
||||
util::SimpleLogger().Write(logWARNING)
|
||||
<< "[weight updates] Edge weight update from " << old_secs << "s to " << new_secs
|
||||
<< "s New speed: " << speed_iter->speed_source.speed << " kph"
|
||||
<< ". Old speed: " << approx_original_speed << " kph"
|
||||
<< ". Segment length: " << segment_length << " m"
|
||||
<< ". Segment: " << speed_iter->segment.from << "," << speed_iter->segment.to
|
||||
<< " based on " << speed_file;
|
||||
util::Log(logWARNING) << "[weight updates] Edge weight update from " << old_secs
|
||||
<< "s to " << new_secs
|
||||
<< "s New speed: " << speed_iter->speed_source.speed << " kph"
|
||||
<< ". Old speed: " << approx_original_speed << " kph"
|
||||
<< ". Segment length: " << segment_length << " m"
|
||||
<< ". Segment: " << speed_iter->segment.from << ","
|
||||
<< speed_iter->segment.to << " based on " << speed_file;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,17 +131,29 @@ int Contractor::Run()
|
||||
|
||||
if (config.core_factor > 1.0 || config.core_factor < 0)
|
||||
{
|
||||
throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)");
|
||||
throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)" + SOURCE_REF);
|
||||
}
|
||||
|
||||
TIMER_START(preparing);
|
||||
|
||||
util::SimpleLogger().Write() << "Loading edge-expanded graph representation";
|
||||
util::Log() << "Reading node weights.";
|
||||
std::vector<EdgeWeight> node_weights;
|
||||
std::string node_file_name = config.osrm_input_path.string() + ".enw";
|
||||
|
||||
{
|
||||
storage::io::FileReader node_file(node_file_name,
|
||||
storage::io::FileReader::VerifyFingerprint);
|
||||
node_file.DeserializeVector(node_weights);
|
||||
}
|
||||
util::Log() << "Done reading node weights.";
|
||||
|
||||
util::Log() << "Loading edge-expanded graph representation";
|
||||
|
||||
util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;
|
||||
|
||||
EdgeID max_edge_id = LoadEdgeExpandedGraph(config.edge_based_graph_path,
|
||||
edge_based_edge_list,
|
||||
node_weights,
|
||||
config.edge_segment_lookup_path,
|
||||
config.edge_penalty_path,
|
||||
config.segment_speed_lookup_paths,
|
||||
@@ -163,17 +175,6 @@ int Contractor::Run()
|
||||
ReadNodeLevels(node_levels);
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write() << "Reading node weights.";
|
||||
std::vector<EdgeWeight> node_weights;
|
||||
std::string node_file_name = config.osrm_input_path.string() + ".enw";
|
||||
|
||||
{
|
||||
storage::io::FileReader node_file(node_file_name,
|
||||
storage::io::FileReader::VerifyFingerprint);
|
||||
node_file.DeserializeVector(node_weights);
|
||||
}
|
||||
util::SimpleLogger().Write() << "Done reading node weights.";
|
||||
|
||||
util::DeallocatingVector<QueryEdge> contracted_edge_list;
|
||||
ContractGraph(max_edge_id,
|
||||
edge_based_edge_list,
|
||||
@@ -183,7 +184,7 @@ int Contractor::Run()
|
||||
node_levels);
|
||||
TIMER_STOP(contraction);
|
||||
|
||||
util::SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
||||
util::Log() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
||||
|
||||
std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
|
||||
WriteCoreNodeMarker(std::move(is_core_node));
|
||||
@@ -199,11 +200,11 @@ int Contractor::Run()
|
||||
const auto edges_per_second =
|
||||
static_cast<std::uint64_t>(number_of_used_edges / TIMER_SEC(contraction));
|
||||
|
||||
util::SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
|
||||
util::SimpleLogger().Write() << "Contraction: " << nodes_per_second << " nodes/sec and "
|
||||
<< edges_per_second << " edges/sec";
|
||||
util::Log() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
|
||||
util::Log() << "Contraction: " << nodes_per_second << " nodes/sec and " << edges_per_second
|
||||
<< " edges/sec";
|
||||
|
||||
util::SimpleLogger().Write() << "finished preprocessing";
|
||||
util::Log() << "finished preprocessing";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -309,10 +310,13 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
|
||||
std::uint64_t to_node_id{};
|
||||
unsigned speed{};
|
||||
|
||||
std::size_t line_number = 0;
|
||||
|
||||
std::for_each(
|
||||
segment_speed_file_reader.GetLineIteratorBegin(),
|
||||
segment_speed_file_reader.GetLineIteratorEnd(),
|
||||
[&](const std::string &line) {
|
||||
++line_number;
|
||||
|
||||
using namespace boost::spirit::qi;
|
||||
|
||||
@@ -329,7 +333,11 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
|
||||
speed); //
|
||||
|
||||
if (!ok || it != last)
|
||||
throw util::exception{"Segment speed file " + filename + " malformed"};
|
||||
{
|
||||
const std::string message{"Segment speed file " + filename +
|
||||
" malformed on line " + std::to_string(line_number)};
|
||||
throw util::exception(message + SOURCE_REF);
|
||||
}
|
||||
|
||||
SegmentSpeedSource val{{OSMNodeID{from_node_id}, OSMNodeID{to_node_id}},
|
||||
{speed, static_cast<std::uint8_t>(file_id)}};
|
||||
@@ -337,8 +345,7 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
|
||||
local.push_back(std::move(val));
|
||||
});
|
||||
|
||||
util::SimpleLogger().Write() << "Loaded speed file " << filename << " with " << local.size()
|
||||
<< " speeds";
|
||||
util::Log() << "Loaded speed file " << filename << " with " << local.size() << " speeds";
|
||||
|
||||
{
|
||||
Mutex::scoped_lock _{flatten_mutex};
|
||||
@@ -349,7 +356,14 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
|
||||
}
|
||||
};
|
||||
|
||||
tbb::parallel_for(std::size_t{0}, segment_speed_filenames.size(), parse_segment_speed_file);
|
||||
try
|
||||
{
|
||||
tbb::parallel_for(std::size_t{0}, segment_speed_filenames.size(), parse_segment_speed_file);
|
||||
}
|
||||
catch (const tbb::captured_exception &e)
|
||||
{
|
||||
throw util::exception(e.what() + SOURCE_REF);
|
||||
}
|
||||
|
||||
// With flattened map-ish view of all the files, sort and unique them on from,to,source
|
||||
// The greater '>' is used here since we want to give files later on higher precedence
|
||||
@@ -370,9 +384,8 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
|
||||
|
||||
flatten.erase(it, end(flatten));
|
||||
|
||||
util::SimpleLogger().Write() << "In total loaded " << segment_speed_filenames.size()
|
||||
<< " speed file(s) with a total of " << flatten.size()
|
||||
<< " unique values";
|
||||
util::Log() << "In total loaded " << segment_speed_filenames.size()
|
||||
<< " speed file(s) with a total of " << flatten.size() << " unique values";
|
||||
|
||||
return flatten;
|
||||
}
|
||||
@@ -399,10 +412,13 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
|
||||
std::uint64_t to_node_id{};
|
||||
double penalty{};
|
||||
|
||||
std::size_t line_number = 0;
|
||||
|
||||
std::for_each(
|
||||
turn_penalty_file_reader.GetLineIteratorBegin(),
|
||||
turn_penalty_file_reader.GetLineIteratorEnd(),
|
||||
[&](const std::string &line) {
|
||||
++line_number;
|
||||
|
||||
using namespace boost::spirit::qi;
|
||||
|
||||
@@ -420,7 +436,11 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
|
||||
penalty); //
|
||||
|
||||
if (!ok || it != last)
|
||||
throw util::exception{"Turn penalty file " + filename + " malformed"};
|
||||
{
|
||||
const std::string message{"Turn penalty file " + filename +
|
||||
" malformed on line " + std::to_string(line_number)};
|
||||
throw util::exception(message + SOURCE_REF);
|
||||
}
|
||||
|
||||
TurnPenaltySource val{
|
||||
{OSMNodeID{from_node_id}, OSMNodeID{via_node_id}, OSMNodeID{to_node_id}},
|
||||
@@ -428,8 +448,8 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
|
||||
local.push_back(std::move(val));
|
||||
});
|
||||
|
||||
util::SimpleLogger().Write() << "Loaded penalty file " << filename << " with "
|
||||
<< local.size() << " turn penalties";
|
||||
util::Log() << "Loaded penalty file " << filename << " with " << local.size()
|
||||
<< " turn penalties";
|
||||
|
||||
{
|
||||
Mutex::scoped_lock _{flatten_mutex};
|
||||
@@ -440,7 +460,14 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
|
||||
}
|
||||
};
|
||||
|
||||
tbb::parallel_for(std::size_t{0}, turn_penalty_filenames.size(), parse_turn_penalty_file);
|
||||
try
|
||||
{
|
||||
tbb::parallel_for(std::size_t{0}, turn_penalty_filenames.size(), parse_turn_penalty_file);
|
||||
}
|
||||
catch (const tbb::captured_exception &e)
|
||||
{
|
||||
throw util::exception(e.what() + SOURCE_REF);
|
||||
}
|
||||
|
||||
// With flattened map-ish view of all the files, sort and unique them on from,to,source
|
||||
// The greater '>' is used here since we want to give files later on higher precedence
|
||||
@@ -463,9 +490,8 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
|
||||
|
||||
map.erase(it, end(map));
|
||||
|
||||
util::SimpleLogger().Write() << "In total loaded " << turn_penalty_filenames.size()
|
||||
<< " turn penalty file(s) with a total of " << map.size()
|
||||
<< " unique values";
|
||||
util::Log() << "In total loaded " << turn_penalty_filenames.size()
|
||||
<< " turn penalty file(s) with a total of " << map.size() << " unique values";
|
||||
|
||||
return map;
|
||||
}
|
||||
@@ -474,6 +500,7 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
|
||||
EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
std::string const &edge_based_graph_filename,
|
||||
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
const std::string &edge_segment_lookup_filename,
|
||||
const std::string &edge_penalty_filename,
|
||||
const std::vector<std::string> &segment_speed_filenames,
|
||||
@@ -486,19 +513,28 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
const double log_edge_updates_factor)
|
||||
{
|
||||
if (segment_speed_filenames.size() > 255 || turn_penalty_filenames.size() > 255)
|
||||
throw util::exception("Limit of 255 segment speed and turn penalty files each reached");
|
||||
throw util::exception("Limit of 255 segment speed and turn penalty files each reached" +
|
||||
SOURCE_REF);
|
||||
|
||||
util::SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
|
||||
util::Log() << "Opening " << edge_based_graph_filename;
|
||||
|
||||
auto mmap_file = [](const std::string &filename) {
|
||||
using boost::interprocess::file_mapping;
|
||||
using boost::interprocess::mapped_region;
|
||||
using boost::interprocess::read_only;
|
||||
|
||||
const file_mapping mapping{filename.c_str(), read_only};
|
||||
mapped_region region{mapping, read_only};
|
||||
region.advise(mapped_region::advice_sequential);
|
||||
return region;
|
||||
try
|
||||
{
|
||||
const file_mapping mapping{filename.c_str(), read_only};
|
||||
mapped_region region{mapping, read_only};
|
||||
region.advise(mapped_region::advice_sequential);
|
||||
return region;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
util::Log(logERROR) << "Error while trying to mmap " + filename + ": " + e.what();
|
||||
throw;
|
||||
}
|
||||
};
|
||||
|
||||
const auto edge_based_graph_region = mmap_file(edge_based_graph_filename);
|
||||
@@ -542,8 +578,7 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
graph_header.fingerprint.TestContractor(fingerprint_valid);
|
||||
|
||||
edge_based_edge_list.resize(graph_header.number_of_edges);
|
||||
util::SimpleLogger().Write() << "Reading " << graph_header.number_of_edges
|
||||
<< " edges from the edge based graph";
|
||||
util::Log() << "Reading " << graph_header.number_of_edges << " edges from the edge based graph";
|
||||
|
||||
SegmentSpeedSourceFlatMap segment_speed_lookup;
|
||||
TurnPenaltySourceFlatMap turn_penalty_lookup;
|
||||
@@ -735,15 +770,15 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
{
|
||||
if (i == LUA_SOURCE)
|
||||
{
|
||||
util::SimpleLogger().Write() << "Used " << merged_counters[LUA_SOURCE]
|
||||
<< " speeds from LUA profile or input map";
|
||||
util::Log() << "Used " << merged_counters[LUA_SOURCE]
|
||||
<< " speeds from LUA profile or input map";
|
||||
}
|
||||
else
|
||||
{
|
||||
// segments_speeds_counters has 0 as LUA, segment_speed_filenames not, thus we need
|
||||
// to susbstract 1 to avoid off-by-one error
|
||||
util::SimpleLogger().Write() << "Used " << merged_counters[i] << " speeds from "
|
||||
<< segment_speed_filenames[i - 1];
|
||||
util::Log() << "Used " << merged_counters[i] << " speeds from "
|
||||
<< segment_speed_filenames[i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -756,7 +791,8 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
std::ofstream geometry_stream(geometry_filename, std::ios::binary);
|
||||
if (!geometry_stream)
|
||||
{
|
||||
throw util::exception("Failed to open " + geometry_filename + " for writing");
|
||||
const std::string message{"Failed to open " + geometry_filename + " for writing"};
|
||||
throw util::exception(message + SOURCE_REF);
|
||||
}
|
||||
const unsigned number_of_indices = m_geometry_indices.size();
|
||||
const unsigned number_of_compressed_geometries = m_geometry_node_list.size();
|
||||
@@ -777,7 +813,9 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
std::ofstream datasource_stream(datasource_indexes_filename, std::ios::binary);
|
||||
if (!datasource_stream)
|
||||
{
|
||||
throw util::exception("Failed to open " + datasource_indexes_filename + " for writing");
|
||||
const std::string message{"Failed to open " + datasource_indexes_filename +
|
||||
" for writing"};
|
||||
throw util::exception(message + SOURCE_REF);
|
||||
}
|
||||
std::uint64_t number_of_datasource_entries = m_geometry_datasource.size();
|
||||
datasource_stream.write(reinterpret_cast<const char *>(&number_of_datasource_entries),
|
||||
@@ -793,7 +831,9 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
std::ofstream datasource_stream(datasource_names_filename, std::ios::binary);
|
||||
if (!datasource_stream)
|
||||
{
|
||||
throw util::exception("Failed to open " + datasource_names_filename + " for writing");
|
||||
const std::string message{"Failed to open " + datasource_names_filename +
|
||||
" for writing"};
|
||||
throw util::exception(message + SOURCE_REF);
|
||||
}
|
||||
datasource_stream << "lua profile" << std::endl;
|
||||
for (auto const &name : segment_speed_filenames)
|
||||
@@ -876,6 +916,11 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
previous_osm_node_id = segmentblocks[i].this_osm_node_id;
|
||||
}
|
||||
|
||||
// Update the node-weight cache. This is the weight of the edge-based-node only,
|
||||
// it doesn't include the turn. We may visit the same node multiple times, but
|
||||
// we should always assign the same value here.
|
||||
node_weights[inbuffer.source] = new_weight;
|
||||
|
||||
// We found a zero-speed edge, so we'll skip this whole edge-based-edge which
|
||||
// effectively removes it from the routing network.
|
||||
if (skip_this_edge)
|
||||
@@ -894,11 +939,11 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
|
||||
if (new_turn_weight + new_weight < compressed_edge_nodes)
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING)
|
||||
<< "turn penalty " << turn_iter->penalty_source.penalty << " for turn "
|
||||
<< penaltyblock->from_id << ", " << penaltyblock->via_id << ", "
|
||||
<< penaltyblock->to_id << " is too negative: clamping turn weight to "
|
||||
<< compressed_edge_nodes;
|
||||
util::Log(logWARNING) << "turn penalty " << turn_iter->penalty_source.penalty
|
||||
<< " for turn " << penaltyblock->from_id << ", "
|
||||
<< penaltyblock->via_id << ", " << penaltyblock->to_id
|
||||
<< " is too negative: clamping turn weight to "
|
||||
<< compressed_edge_nodes;
|
||||
}
|
||||
|
||||
inbuffer.weight = std::max(new_turn_weight + new_weight, compressed_edge_nodes);
|
||||
@@ -915,7 +960,7 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
|
||||
edge_based_edge_list.emplace_back(std::move(inbuffer));
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write() << "Done reading edges";
|
||||
util::Log() << "Done reading edges";
|
||||
return graph_header.max_edge_id;
|
||||
}
|
||||
|
||||
@@ -964,8 +1009,7 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
|
||||
// Sorting contracted edges in a way that the static query graph can read some in in-place.
|
||||
tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
|
||||
const std::uint64_t contracted_edge_count = contracted_edge_list.size();
|
||||
util::SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
|
||||
<< " edges";
|
||||
util::Log() << "Serializing compacted graph of " << contracted_edge_count << " edges";
|
||||
|
||||
const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
|
||||
boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
|
||||
@@ -982,15 +1026,14 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
|
||||
return tmp_max;
|
||||
}();
|
||||
|
||||
util::SimpleLogger().Write(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
|
||||
util::SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1)
|
||||
<< " nodes";
|
||||
util::Log(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
|
||||
util::Log(logDEBUG) << "contracted graph has " << (max_used_node_id + 1) << " nodes";
|
||||
|
||||
std::vector<util::StaticGraph<EdgeData>::NodeArrayEntry> node_array;
|
||||
// make sure we have at least one sentinel
|
||||
node_array.resize(max_node_id + 2);
|
||||
|
||||
util::SimpleLogger().Write() << "Building node array";
|
||||
util::Log() << "Building node array";
|
||||
util::StaticGraph<EdgeData>::EdgeIterator edge = 0;
|
||||
util::StaticGraph<EdgeData>::EdgeIterator position = 0;
|
||||
util::StaticGraph<EdgeData>::EdgeIterator last_edge;
|
||||
@@ -1014,11 +1057,11 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
|
||||
node_array[sentinel_counter].first_edge = contracted_edge_count;
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write() << "Serializing node array";
|
||||
util::Log() << "Serializing node array";
|
||||
|
||||
RangebasedCRC32 crc32_calculator;
|
||||
const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
|
||||
util::SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;
|
||||
util::Log() << "Writing CRC32: " << edges_crc32;
|
||||
|
||||
const std::uint64_t node_array_size = node_array.size();
|
||||
// serialize crc32, aka checksum
|
||||
@@ -1036,7 +1079,7 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
|
||||
}
|
||||
|
||||
// serialize all edges
|
||||
util::SimpleLogger().Write() << "Building edge array";
|
||||
util::Log() << "Building edge array";
|
||||
std::size_t number_of_used_edges = 0;
|
||||
|
||||
util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
|
||||
@@ -1055,15 +1098,15 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
|
||||
#ifndef NDEBUG
|
||||
if (current_edge.data.weight <= 0)
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING)
|
||||
<< "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
|
||||
<< ", target: " << contracted_edge_list[edge].target
|
||||
<< ", weight: " << current_edge.data.weight;
|
||||
util::Log(logWARNING) << "Edge: " << edge
|
||||
<< ",source: " << contracted_edge_list[edge].source
|
||||
<< ", target: " << contracted_edge_list[edge].target
|
||||
<< ", weight: " << current_edge.data.weight;
|
||||
|
||||
util::SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
|
||||
<< contracted_edge_list[edge].source << "/"
|
||||
<< node_array.size() - 1;
|
||||
return 1;
|
||||
util::Log(logWARNING) << "Failed at adjacency list of node "
|
||||
<< contracted_edge_list[edge].source << "/"
|
||||
<< node_array.size() - 1;
|
||||
throw util::exception("Edge weight is <= 0" + SOURCE_REF);
|
||||
}
|
||||
#endif
|
||||
hsgr_output_stream.write((char *)¤t_edge,
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "util/guidance/bearing_class.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "engine/datafacade/shared_memory_datafacade.hpp"
|
||||
|
||||
#include "storage/shared_barriers.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/interprocess/sync/named_condition.hpp>
|
||||
@@ -68,7 +68,9 @@ Engine::Engine(const EngineConfig &config)
|
||||
if (!DataWatchdog::TryConnect())
|
||||
{
|
||||
throw util::exception(
|
||||
"No shared memory blocks found, have you forgotten to run osrm-datastore?");
|
||||
std::string(
|
||||
"No shared memory blocks found, have you forgotten to run osrm-datastore?") +
|
||||
SOURCE_REF);
|
||||
}
|
||||
|
||||
watchdog = std::make_unique<DataWatchdog>();
|
||||
@@ -78,7 +80,7 @@ Engine::Engine(const EngineConfig &config)
|
||||
{
|
||||
if (!config.storage_config.IsValid())
|
||||
{
|
||||
throw util::exception("Invalid file paths given!");
|
||||
throw util::exception("Invalid file paths given!" + SOURCE_REF);
|
||||
}
|
||||
immutable_data_facade =
|
||||
std::make_shared<datafacade::ProcessMemoryDataFacade>(config.storage_config);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#include "util/for_each_pair.hpp"
|
||||
#include "util/group_by.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "engine/guidance/post_processing.hpp"
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
|
||||
#include <iterator>
|
||||
#include <unordered_set>
|
||||
@@ -14,8 +12,8 @@ using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
|
||||
namespace TurnType = osrm::extractor::guidance::TurnType;
|
||||
namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier;
|
||||
|
||||
using osrm::util::guidance::isLeftTurn;
|
||||
using osrm::util::guidance::isRightTurn;
|
||||
using osrm::extractor::guidance::isLeftTurn;
|
||||
using osrm::extractor::guidance::isRightTurn;
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -80,8 +78,8 @@ std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
|
||||
// where lanes in the turn fan in but for example the overall lanes at that location
|
||||
// fan out, we would have to know the asymmetric mapping of lanes. This is currently
|
||||
// not possible at the moment. In the following we implement a heuristic instead.
|
||||
const LaneID current_num_lanes_right_of_turn = numLanesToTheRight(current);
|
||||
const LaneID current_num_lanes_left_of_turn = numLanesToTheLeft(current);
|
||||
const LaneID current_num_lanes_right_of_turn = current.numLanesToTheRight();
|
||||
const LaneID current_num_lanes_left_of_turn = current.numLanesToTheLeft();
|
||||
|
||||
const LaneID num_shared_lanes = std::min(current_lanes.lanes_in_turn, //
|
||||
previous_lanes.lanes_in_turn); //
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#include "engine/guidance/post_processing.hpp"
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
|
||||
#include "engine/guidance/assemble_steps.hpp"
|
||||
#include "engine/guidance/lane_processing.hpp"
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/guidance/name_announcements.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
@@ -25,8 +23,11 @@
|
||||
using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
|
||||
namespace TurnType = osrm::extractor::guidance::TurnType;
|
||||
namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier;
|
||||
using osrm::util::guidance::angularDeviation;
|
||||
using osrm::util::guidance::getTurnDirection;
|
||||
using osrm::util::angularDeviation;
|
||||
using osrm::extractor::guidance::getTurnDirection;
|
||||
using osrm::extractor::guidance::hasRampType;
|
||||
using osrm::extractor::guidance::mirrorDirectionModifier;
|
||||
using osrm::extractor::guidance::bearingToDirectionModifier;
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -299,14 +300,13 @@ void closeOffRoundabout(const bool on_roundabout,
|
||||
TurnType::EnterRoundaboutIntersectionAtExit)
|
||||
{
|
||||
BOOST_ASSERT(!propagation_step.intersections.empty());
|
||||
const double angle = util::bearing::angleBetweenBearings(
|
||||
util::bearing::reverseBearing(
|
||||
entry_intersection.bearings[entry_intersection.in]),
|
||||
const double angle = util::angleBetweenBearings(
|
||||
util::reverseBearing(entry_intersection.bearings[entry_intersection.in]),
|
||||
exit_bearing);
|
||||
|
||||
auto bearings = propagation_step.intersections.front().bearings;
|
||||
propagation_step.maneuver.instruction.direction_modifier =
|
||||
util::guidance::getTurnDirection(angle);
|
||||
getTurnDirection(angle);
|
||||
}
|
||||
|
||||
forwardStepSignage(propagation_step, destination_copy);
|
||||
@@ -346,7 +346,7 @@ bool isUTurn(const RouteStep &in_step, const RouteStep &out_step, const RouteSte
|
||||
(isLinkroad(in_step) && out_step.name_id != EMPTY_NAMEID &&
|
||||
pre_in_step.name_id != EMPTY_NAMEID && !isNoticeableNameChange(pre_in_step, out_step));
|
||||
const bool takes_u_turn = bearingsAreReversed(
|
||||
util::bearing::reverseBearing(
|
||||
util::reverseBearing(
|
||||
in_step.intersections.front().bearings[in_step.intersections.front().in]),
|
||||
out_step.intersections.front().bearings[out_step.intersections.front().out]);
|
||||
|
||||
@@ -358,20 +358,20 @@ double findTotalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_ste
|
||||
const auto exit_intersection = exit_step.intersections.front();
|
||||
const auto exit_step_exit_bearing = exit_intersection.bearings[exit_intersection.out];
|
||||
const auto exit_step_entry_bearing =
|
||||
util::bearing::reverseBearing(exit_intersection.bearings[exit_intersection.in]);
|
||||
util::reverseBearing(exit_intersection.bearings[exit_intersection.in]);
|
||||
|
||||
const auto entry_intersection = entry_step.intersections.front();
|
||||
const auto entry_step_entry_bearing =
|
||||
util::bearing::reverseBearing(entry_intersection.bearings[entry_intersection.in]);
|
||||
util::reverseBearing(entry_intersection.bearings[entry_intersection.in]);
|
||||
const auto entry_step_exit_bearing = entry_intersection.bearings[entry_intersection.out];
|
||||
|
||||
const auto exit_angle =
|
||||
util::bearing::angleBetweenBearings(exit_step_entry_bearing, exit_step_exit_bearing);
|
||||
util::angleBetweenBearings(exit_step_entry_bearing, exit_step_exit_bearing);
|
||||
const auto entry_angle =
|
||||
util::bearing::angleBetweenBearings(entry_step_entry_bearing, entry_step_exit_bearing);
|
||||
util::angleBetweenBearings(entry_step_entry_bearing, entry_step_exit_bearing);
|
||||
|
||||
const double total_angle =
|
||||
util::bearing::angleBetweenBearings(entry_step_entry_bearing, exit_step_exit_bearing);
|
||||
util::angleBetweenBearings(entry_step_entry_bearing, exit_step_exit_bearing);
|
||||
// We allow for minor deviations from a straight line
|
||||
if (((entry_step.distance < MAX_COLLAPSE_DISTANCE && exit_step.intersections.size() == 1) ||
|
||||
(entry_angle <= 185 && exit_angle <= 185) || (entry_angle >= 175 && exit_angle >= 175)) &&
|
||||
@@ -521,8 +521,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
// tagged late
|
||||
const auto is_delayed_turn_onto_a_ramp =
|
||||
opening_turn.distance <= 4 * MAX_COLLAPSE_DISTANCE && without_choice &&
|
||||
util::guidance::hasRampType(finishing_turn.maneuver.instruction);
|
||||
return !util::guidance::hasRampType(opening_turn.maneuver.instruction) &&
|
||||
hasRampType(finishing_turn.maneuver.instruction);
|
||||
return !hasRampType(opening_turn.maneuver.instruction) &&
|
||||
(is_short_and_collapsable || is_not_too_long_and_choiceless ||
|
||||
isLinkroad(opening_turn) || is_delayed_turn_onto_a_ramp);
|
||||
}
|
||||
@@ -539,8 +539,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
if (TurnType::Merge == current_step.maneuver.instruction.type)
|
||||
{
|
||||
steps[step_index].maneuver.instruction.direction_modifier =
|
||||
util::guidance::mirrorDirectionModifier(
|
||||
steps[step_index].maneuver.instruction.direction_modifier);
|
||||
mirrorDirectionModifier(steps[step_index].maneuver.instruction.direction_modifier);
|
||||
steps[step_index].maneuver.instruction.type = TurnType::Turn;
|
||||
}
|
||||
else
|
||||
@@ -573,18 +572,18 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
if (continue_or_suppressed || turning_name)
|
||||
{
|
||||
const auto in_bearing = [](const RouteStep &step) {
|
||||
return util::bearing::reverseBearing(
|
||||
return util::reverseBearing(
|
||||
step.intersections.front().bearings[step.intersections.front().in]);
|
||||
};
|
||||
const auto out_bearing = [](const RouteStep &step) {
|
||||
return step.intersections.front().bearings[step.intersections.front().out];
|
||||
};
|
||||
|
||||
const auto first_angle = util::bearing::angleBetweenBearings(
|
||||
in_bearing(one_back_step), out_bearing(one_back_step));
|
||||
const auto second_angle = util::bearing::angleBetweenBearings(
|
||||
in_bearing(current_step), out_bearing(current_step));
|
||||
const auto bearing_turn_angle = util::bearing::angleBetweenBearings(
|
||||
const auto first_angle = util::angleBetweenBearings(in_bearing(one_back_step),
|
||||
out_bearing(one_back_step));
|
||||
const auto second_angle =
|
||||
util::angleBetweenBearings(in_bearing(current_step), out_bearing(current_step));
|
||||
const auto bearing_turn_angle = util::angleBetweenBearings(
|
||||
in_bearing(one_back_step), out_bearing(current_step));
|
||||
|
||||
// When looking at an intersection, some angles, even though present, feel more like
|
||||
@@ -669,7 +668,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
DirectionModifier::Straight;
|
||||
else
|
||||
steps[step_index].maneuver.instruction.direction_modifier =
|
||||
util::guidance::getTurnDirection(bearing_turn_angle);
|
||||
getTurnDirection(bearing_turn_angle);
|
||||
|
||||
// if the total direction of this turn is now straight, we can keep it suppressed/as
|
||||
// a new name. Else we have to interpret it as a turn.
|
||||
@@ -718,7 +717,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
};
|
||||
|
||||
// If we Merge onto the same street, we end up with a u-turn in some cases
|
||||
if (bearingsAreReversed(util::bearing::reverseBearing(getBearing(true, one_back_step)),
|
||||
if (bearingsAreReversed(util::reverseBearing(getBearing(true, one_back_step)),
|
||||
getBearing(false, current_step)))
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
@@ -737,9 +736,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
// need a highway-suppressed to get the turn onto a
|
||||
// highway...
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
util::guidance::mirrorDirectionModifier(
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier = mirrorDirectionModifier(
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier);
|
||||
}
|
||||
// on non merge-types, we check for a combined turn angle
|
||||
else if (TurnType::Merge != one_back_step.maneuver.instruction.type)
|
||||
@@ -759,8 +757,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
{
|
||||
steps[one_back_index] = elongate(std::move(steps[one_back_index]), current_step);
|
||||
const auto angle = findTotalTurnAngle(one_back_step, current_step);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
util::guidance::getTurnDirection(angle);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier = getTurnDirection(angle);
|
||||
|
||||
invalidateStep(steps[step_index]);
|
||||
}
|
||||
@@ -772,8 +769,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
steps[one_back_index] = elongate(std::move(steps[one_back_index]), current_step);
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::OnRamp;
|
||||
const auto angle = findTotalTurnAngle(one_back_step, current_step);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
util::guidance::getTurnDirection(angle);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier = getTurnDirection(angle);
|
||||
|
||||
forwardStepSignage(steps[one_back_index], current_step);
|
||||
invalidateStep(steps[step_index]);
|
||||
@@ -806,7 +802,7 @@ bool isStaggeredIntersection(const std::vector<RouteStep> &steps,
|
||||
const auto &intersection = step.intersections.front();
|
||||
const auto entry_bearing = intersection.bearings[intersection.in];
|
||||
const auto exit_bearing = intersection.bearings[intersection.out];
|
||||
return util::bearing::angleBetweenBearings(entry_bearing, exit_bearing);
|
||||
return util::angleBetweenBearings(entry_bearing, exit_bearing);
|
||||
};
|
||||
|
||||
// Instead of using turn modifiers (e.g. as in isRightTurn) we want to be more strict here.
|
||||
@@ -1123,7 +1119,7 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
|
||||
const auto angle = findTotalTurnAngle(one_back_step, current_step);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
util::guidance::getTurnDirection(angle);
|
||||
getTurnDirection(angle);
|
||||
invalidateStep(steps[step_index]);
|
||||
}
|
||||
else
|
||||
@@ -1462,7 +1458,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
||||
geometry.locations[next_to_last_step.geometry_end - 2],
|
||||
geometry.locations[last_step.geometry_begin]));
|
||||
last_step.maneuver.bearing_before = bearing;
|
||||
last_step.intersections.front().bearings.front() = util::bearing::reverseBearing(bearing);
|
||||
last_step.intersections.front().bearings.front() = util::reverseBearing(bearing);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(steps.back().geometry_end == geometry.locations.size());
|
||||
@@ -1494,7 +1490,7 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
|
||||
const auto initial_modifier =
|
||||
distance_to_start >= MINIMAL_RELATIVE_DISTANCE &&
|
||||
distance_to_start <= MAXIMAL_RELATIVE_DISTANCE
|
||||
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
|
||||
? bearingToDirectionModifier(util::coordinate_calculation::computeAngle(
|
||||
source_node.input_location, leg_geometry.locations[0], leg_geometry.locations[1]))
|
||||
: extractor::guidance::DirectionModifier::UTurn;
|
||||
|
||||
@@ -1505,7 +1501,7 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
|
||||
const auto final_modifier =
|
||||
distance_from_end >= MINIMAL_RELATIVE_DISTANCE &&
|
||||
distance_from_end <= MAXIMAL_RELATIVE_DISTANCE
|
||||
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
|
||||
? bearingToDirectionModifier(util::coordinate_calculation::computeAngle(
|
||||
leg_geometry.locations[leg_geometry.locations.size() - 2],
|
||||
leg_geometry.locations[leg_geometry.locations.size() - 1],
|
||||
target_node.input_location))
|
||||
@@ -1604,13 +1600,13 @@ std::vector<RouteStep> collapseUseLane(std::vector<RouteStep> steps)
|
||||
// the lane description is given left to right, lanes are counted from the right.
|
||||
// Therefore we access the lane description using the reverse iterator
|
||||
|
||||
auto right_most_lanes = lanesToTheRight(step);
|
||||
auto right_most_lanes = step.lanesToTheRight();
|
||||
if (!right_most_lanes.empty() && containsTag(right_most_lanes.front(),
|
||||
(extractor::guidance::TurnLaneType::straight |
|
||||
extractor::guidance::TurnLaneType::none)))
|
||||
return false;
|
||||
|
||||
auto left_most_lanes = lanesToTheLeft(step);
|
||||
auto left_most_lanes = step.lanesToTheLeft();
|
||||
if (!left_most_lanes.empty() && containsTag(left_most_lanes.back(),
|
||||
(extractor::guidance::TurnLaneType::straight |
|
||||
extractor::guidance::TurnLaneType::none)))
|
||||
|
||||
@@ -357,6 +357,26 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
||||
return offset;
|
||||
};
|
||||
|
||||
// In order to ensure consistent tile encoding, we need to process
|
||||
// all edges in the same order. Differences in OSX/Linux/Windows
|
||||
// sorting methods mean that GetEdgesInBox doesn't return the same
|
||||
// ordered array on all platforms.
|
||||
// GetEdgesInBox is marked `const`, so we can't sort the array itself,
|
||||
// instead we create an array of indexes and sort that instead.
|
||||
std::vector<std::size_t> sorted_edge_indexes(edges.size(), 0);
|
||||
std::iota(sorted_edge_indexes.begin(), sorted_edge_indexes.end(), 0); // fill with 1,2,3,...N
|
||||
|
||||
// Now, sort that array based on the edges list, using the u/v node IDs
|
||||
// as the sort condition
|
||||
std::sort(sorted_edge_indexes.begin(),
|
||||
sorted_edge_indexes.end(),
|
||||
[edges](const std::size_t &left, const std::size_t &right) -> bool {
|
||||
return (edges[left].u != edges[right].u) ? edges[left].u < edges[right].u
|
||||
: edges[left].v < edges[right].v;
|
||||
});
|
||||
// From here on, we'll iterate over the sorted_edge_indexes instead of `edges` directly.
|
||||
// Note, that we do this because `
|
||||
|
||||
// If we're zooming into 16 or higher, include turn data. Why? Because turns make the map
|
||||
// really cramped, so we don't bother including the data for tiles that span a large area.
|
||||
if (parameters.z >= MIN_ZOOM_FOR_TURNS)
|
||||
@@ -386,8 +406,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
||||
|
||||
// Build an adjacency list for all the road segments visible in
|
||||
// the tile
|
||||
for (const auto &edge : edges)
|
||||
for (const auto &edge_index : sorted_edge_indexes)
|
||||
{
|
||||
const auto &edge = edges[edge_index];
|
||||
if (edge.forward_segment_id.enabled)
|
||||
{
|
||||
// operator[] will construct an empty vector at [edge.u] if there is no value.
|
||||
@@ -435,11 +456,21 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
||||
// vw is the "exit"
|
||||
std::vector<contractor::QueryEdge::EdgeData> unpacked_shortcut;
|
||||
std::vector<EdgeWeight> approach_weight_vector;
|
||||
// Look at every node in the directed graph we created
|
||||
|
||||
// Make sure we traverse the startnodes in a consistent order
|
||||
// to ensure identical PBF encoding on all platforms.
|
||||
std::vector<NodeID> sorted_startnodes;
|
||||
sorted_startnodes.reserve(directed_graph.size());
|
||||
for (const auto &startnode : directed_graph)
|
||||
sorted_startnodes.push_back(startnode.first);
|
||||
std::sort(sorted_startnodes.begin(), sorted_startnodes.end());
|
||||
|
||||
// Look at every node in the directed graph we created
|
||||
for (const auto &startnode : sorted_startnodes)
|
||||
{
|
||||
const auto &nodedata = directed_graph[startnode];
|
||||
// For all the outgoing edges from the node
|
||||
for (const auto &approachedge : startnode.second)
|
||||
for (const auto &approachedge : nodedata)
|
||||
{
|
||||
// If the target of this edge doesn't exist in our directed
|
||||
// graph, it's probably outside the tile, so we can skip it
|
||||
@@ -455,7 +486,7 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
||||
continue;
|
||||
|
||||
// Skip u-turns
|
||||
if (startnode.first == exit_edge.target_node)
|
||||
if (startnode == exit_edge.target_node)
|
||||
continue;
|
||||
|
||||
// Find the connection between our source road and the target node
|
||||
@@ -528,7 +559,7 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
||||
const auto turn_cost = data.weight - sum_node_weight;
|
||||
|
||||
// Find the three nodes that make up the turn movement)
|
||||
const auto node_from = startnode.first;
|
||||
const auto node_from = startnode;
|
||||
const auto node_via = approachedge.target_node;
|
||||
const auto node_to = exit_edge.target_node;
|
||||
|
||||
@@ -584,8 +615,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
||||
// to "pre-loop" over all the edges to create the lookup tables. Once we have those, we
|
||||
// can then encode the features, and we'll know the indexes that feature properties
|
||||
// need to refer to.
|
||||
for (const auto &edge : edges)
|
||||
for (const auto &edge_index : sorted_edge_indexes)
|
||||
{
|
||||
const auto &edge = edges[edge_index];
|
||||
|
||||
const auto forward_datasource_vector =
|
||||
facade->GetUncompressedForwardDatasources(edge.packed_geometry_id);
|
||||
@@ -636,8 +668,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
||||
// Because we need to know the indexes into the vector tile lookup table,
|
||||
// we need to do an initial pass over the data and create the complete
|
||||
// index of used values.
|
||||
for (const auto &edge : edges)
|
||||
for (const auto &edge_index : sorted_edge_indexes)
|
||||
{
|
||||
const auto &edge = edges[edge_index];
|
||||
const auto forward_weight_vector =
|
||||
facade->GetUncompressedForwardWeights(edge.packed_geometry_id);
|
||||
const auto reverse_weight_vector =
|
||||
@@ -653,8 +686,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
|
||||
{
|
||||
// Each feature gets a unique id, starting at 1
|
||||
unsigned id = 1;
|
||||
for (const auto &edge : edges)
|
||||
for (const auto &edge_index : sorted_edge_indexes)
|
||||
{
|
||||
const auto &edge = edges[edge_index];
|
||||
// Get coordinates for start/end nodes of segment (NodeIDs u and v)
|
||||
const auto a = facade->GetCoordinateOfNode(edge.u);
|
||||
const auto b = facade->GetCoordinateOfNode(edge.v);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
@@ -55,42 +56,50 @@ std::string encode(std::vector<int> &numbers)
|
||||
|
||||
std::vector<util::Coordinate> decodePolyline(const std::string &geometry_string)
|
||||
{
|
||||
std::vector<util::Coordinate> new_coordinates;
|
||||
int index = 0, len = geometry_string.size();
|
||||
int lat = 0, lng = 0;
|
||||
// https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
||||
auto decode_polyline_integer = [](auto &first, auto last) {
|
||||
// varint coding parameters
|
||||
const std::uint32_t bits_in_chunk = 5;
|
||||
const std::uint32_t continuation_bit = 1 << bits_in_chunk;
|
||||
const std::uint32_t chunk_mask = (1 << bits_in_chunk) - 1;
|
||||
|
||||
while (index < len)
|
||||
std::uint32_t result = 0;
|
||||
for (std::uint32_t value = continuation_bit, shift = 0;
|
||||
(value & continuation_bit) && (shift < CHAR_BIT * sizeof(result) - 1) && first != last;
|
||||
++first, shift += bits_in_chunk)
|
||||
{
|
||||
value = *first - 63; // convert ASCII coding [?..~] to an integer [0..63]
|
||||
result |= (value & chunk_mask) << shift;
|
||||
}
|
||||
|
||||
// change "zig-zag" sign coding to two's complement
|
||||
result = ((result & 1) == 1) ? ~(result >> 1) : (result >> 1);
|
||||
return static_cast<std::int32_t>(result);
|
||||
};
|
||||
|
||||
auto polyline_to_coordinate = [](auto value) {
|
||||
return static_cast<std::int32_t>(value * detail::POLYLINE_TO_COORDINATE);
|
||||
};
|
||||
|
||||
std::vector<util::Coordinate> coordinates;
|
||||
std::int32_t latitude = 0, longitude = 0;
|
||||
|
||||
std::string::const_iterator first = geometry_string.begin();
|
||||
const std::string::const_iterator last = geometry_string.end();
|
||||
while (first != last)
|
||||
{
|
||||
int b, shift = 0, result = 0;
|
||||
do
|
||||
{
|
||||
b = geometry_string.at(index++) - 63;
|
||||
result |= (b & 0x1f) << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x20 && index < len);
|
||||
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
|
||||
lat += dlat;
|
||||
const auto dlat = decode_polyline_integer(first, last);
|
||||
const auto dlon = decode_polyline_integer(first, last);
|
||||
|
||||
shift = 0;
|
||||
result = 0;
|
||||
do
|
||||
{
|
||||
b = geometry_string.at(index++) - 63;
|
||||
result |= (b & 0x1f) << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x20 && index < len);
|
||||
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
|
||||
lng += dlng;
|
||||
latitude += dlat;
|
||||
longitude += dlon;
|
||||
|
||||
util::Coordinate p;
|
||||
p.lat =
|
||||
util::FixedLatitude{static_cast<std::int32_t>(lat * detail::POLYLINE_TO_COORDINATE)};
|
||||
p.lon =
|
||||
util::FixedLongitude{static_cast<std::int32_t>(lng * detail::POLYLINE_TO_COORDINATE)};
|
||||
new_coordinates.push_back(p);
|
||||
coordinates.emplace_back(
|
||||
util::Coordinate{util::FixedLongitude{polyline_to_coordinate(longitude)},
|
||||
util::FixedLatitude{polyline_to_coordinate(latitude)}});
|
||||
}
|
||||
|
||||
return new_coordinates;
|
||||
return coordinates;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -300,14 +300,13 @@ void CompressedEdgeContainer::PrintStatistics() const
|
||||
longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write()
|
||||
<< "Geometry successfully removed:"
|
||||
"\n compressed edges: "
|
||||
<< compressed_edges << "\n compressed geometries: " << compressed_geometries
|
||||
<< "\n longest chain length: " << longest_chain_length << "\n cmpr ratio: "
|
||||
<< ((float)compressed_edges / std::max(compressed_geometries, (uint64_t)1))
|
||||
<< "\n avg chain length: "
|
||||
<< (float)compressed_geometries / std::max((uint64_t)1, compressed_edges);
|
||||
util::Log() << "Geometry successfully removed:"
|
||||
"\n compressed edges: "
|
||||
<< compressed_edges << "\n compressed geometries: " << compressed_geometries
|
||||
<< "\n longest chain length: " << longest_chain_length << "\n cmpr ratio: "
|
||||
<< ((float)compressed_edges / std::max(compressed_geometries, (uint64_t)1))
|
||||
<< "\n avg chain length: "
|
||||
<< (float)compressed_geometries / std::max((uint64_t)1, compressed_edges);
|
||||
}
|
||||
|
||||
const CompressedEdgeContainer::OnewayEdgeBucket &
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
#include "util/exception.hpp"
|
||||
#include "util/guidance/turn_bearing.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/percent.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
#include "extractor/guidance/turn_lane_handler.hpp"
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
@@ -213,10 +212,10 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
|
||||
TIMER_STOP(generate_edges);
|
||||
|
||||
util::SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
|
||||
util::SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
|
||||
util::SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
|
||||
util::SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
|
||||
util::Log() << "Timing statistics for edge-expanded graph:";
|
||||
util::Log() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
|
||||
util::Log() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
|
||||
util::Log() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
|
||||
}
|
||||
|
||||
/// Renumbers all _forward_ edges and sets the edge_id.
|
||||
@@ -258,40 +257,44 @@ unsigned EdgeBasedGraphFactory::RenumberEdges()
|
||||
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
||||
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
||||
{
|
||||
util::Percent progress(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
m_compressed_edge_container.InitializeBothwayVector();
|
||||
|
||||
// loop over all edges and generate new set of nodes
|
||||
for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
util::Log() << "Generating edge expanded nodes ... ";
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
|
||||
progress.PrintStatus(node_u);
|
||||
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
|
||||
util::UnbufferedLog log;
|
||||
util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
m_compressed_edge_container.InitializeBothwayVector();
|
||||
|
||||
// loop over all edges and generate new set of nodes
|
||||
for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
{
|
||||
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
|
||||
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
|
||||
const NodeID node_v = m_node_based_graph->GetTarget(e1);
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_v);
|
||||
// pick only every other edge, since we have every edge as an outgoing
|
||||
// and incoming egde
|
||||
if (node_u > node_v)
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
|
||||
progress.PrintStatus(node_u);
|
||||
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
|
||||
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
|
||||
const NodeID node_v = m_node_based_graph->GetTarget(e1);
|
||||
|
||||
BOOST_ASSERT(node_u < node_v);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_v);
|
||||
// pick only every other edge, since we have every edge as an outgoing
|
||||
// and incoming egde
|
||||
if (node_u > node_v)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we found a non-forward edge reverse and try again
|
||||
if (edge_data.edge_id == SPECIAL_NODEID)
|
||||
{
|
||||
InsertEdgeBasedNode(node_v, node_u);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertEdgeBasedNode(node_u, node_v);
|
||||
BOOST_ASSERT(node_u < node_v);
|
||||
|
||||
// if we found a non-forward edge reverse and try again
|
||||
if (edge_data.edge_id == SPECIAL_NODEID)
|
||||
{
|
||||
InsertEdgeBasedNode(node_v, node_u);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertEdgeBasedNode(node_u, node_v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,8 +302,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
||||
BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
|
||||
BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size());
|
||||
|
||||
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
|
||||
<< " nodes in edge-expanded graph";
|
||||
util::Log() << "Generated " << m_edge_based_node_list.size() << " nodes in edge-expanded graph";
|
||||
}
|
||||
|
||||
/// Actually it also generates OriginalEdgeData and serializes them...
|
||||
@@ -312,7 +314,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const std::string &edge_fixed_penalties_filename,
|
||||
const bool generate_edge_lookup)
|
||||
{
|
||||
util::SimpleLogger().Write() << "generating edge-expanded edges";
|
||||
util::Log() << "Generating edge-expanded edges ";
|
||||
|
||||
std::size_t node_based_edge_counter = 0;
|
||||
std::size_t original_edges_counter = 0;
|
||||
@@ -341,7 +343,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// 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.
|
||||
util::Percent progress(m_node_based_graph->GetNumberOfNodes());
|
||||
SuffixTable street_name_suffix_table(scripting_environment);
|
||||
guidance::TurnAnalysis turn_analysis(*m_node_based_graph,
|
||||
m_node_info_list,
|
||||
@@ -352,7 +353,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
street_name_suffix_table,
|
||||
profile_properties);
|
||||
|
||||
guidance::LaneDataIdMap lane_data_map;
|
||||
util::guidance::LaneDataIdMap lane_data_map;
|
||||
guidance::lanes::TurnLaneHandler turn_lane_handler(*m_node_based_graph,
|
||||
turn_lane_offsets,
|
||||
turn_lane_masks,
|
||||
@@ -363,260 +364,275 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(),
|
||||
std::numeric_limits<std::uint32_t>::max());
|
||||
|
||||
// going over all nodes (which form the center of an intersection), we compute all
|
||||
// possible turns along these intersections.
|
||||
for (const auto node_at_center_of_intersection :
|
||||
util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
{
|
||||
progress.PrintStatus(node_at_center_of_intersection);
|
||||
util::UnbufferedLog log;
|
||||
|
||||
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, but the cost we need to pay to
|
||||
// generate edges here is worth the additional search overhead.
|
||||
//
|
||||
// a -> b <-> c
|
||||
// |
|
||||
// v
|
||||
// d
|
||||
//
|
||||
// will have:
|
||||
// a: b,rev=0
|
||||
// b: a,rev=1 c,rev=0 d,rev=0
|
||||
// c: b,rev=0
|
||||
//
|
||||
// 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 EdgeID outgoing_edge :
|
||||
m_node_based_graph->GetAdjacentEdgeRange(node_at_center_of_intersection))
|
||||
util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
|
||||
// going over all nodes (which form the center of an intersection), we compute all
|
||||
// possible turns along these intersections.
|
||||
for (const auto node_at_center_of_intersection :
|
||||
util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
{
|
||||
const NodeID node_along_road_entering = m_node_based_graph->GetTarget(outgoing_edge);
|
||||
progress.PrintStatus(node_at_center_of_intersection);
|
||||
|
||||
const auto incoming_edge = m_node_based_graph->FindEdge(node_along_road_entering,
|
||||
node_at_center_of_intersection);
|
||||
const auto shape_result =
|
||||
turn_analysis.ComputeIntersectionShapes(node_at_center_of_intersection);
|
||||
|
||||
if (m_node_based_graph->GetEdgeData(incoming_edge).reversed)
|
||||
continue;
|
||||
|
||||
++node_based_edge_counter;
|
||||
|
||||
auto intersection_with_flags_and_angles =
|
||||
turn_analysis.GetIntersectionGenerator().TransformIntersectionShapeIntoView(
|
||||
node_along_road_entering,
|
||||
incoming_edge,
|
||||
shape_result.normalised_intersection_shape,
|
||||
shape_result.intersection_shape,
|
||||
shape_result.merging_map);
|
||||
|
||||
auto intersection = turn_analysis.AssignTurnTypes(
|
||||
node_along_road_entering, incoming_edge, intersection_with_flags_and_angles);
|
||||
|
||||
BOOST_ASSERT(intersection.valid());
|
||||
|
||||
intersection = turn_lane_handler.assignTurnLanes(
|
||||
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);
|
||||
|
||||
const auto entry_class_id = [&](const util::guidance::EntryClass entry_class) {
|
||||
if (0 == entry_class_hash.count(entry_class))
|
||||
{
|
||||
const auto id = static_cast<std::uint16_t>(entry_class_hash.size());
|
||||
entry_class_hash[entry_class] = id;
|
||||
return id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return entry_class_hash.find(entry_class)->second;
|
||||
}
|
||||
}(turn_classification.first);
|
||||
|
||||
const auto bearing_class_id = [&](const util::guidance::BearingClass bearing_class) {
|
||||
if (0 == bearing_class_hash.count(bearing_class))
|
||||
{
|
||||
const auto id = static_cast<std::uint32_t>(bearing_class_hash.size());
|
||||
bearing_class_hash[bearing_class] = id;
|
||||
return id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return bearing_class_hash.find(bearing_class)->second;
|
||||
}
|
||||
}(turn_classification.second);
|
||||
bearing_class_by_node_based_node[node_at_center_of_intersection] = bearing_class_id;
|
||||
|
||||
for (const auto &turn : 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, but the cost we need to pay
|
||||
// to
|
||||
// generate edges here is worth the additional search overhead.
|
||||
//
|
||||
// a -> b <-> c
|
||||
// |
|
||||
// v
|
||||
// d
|
||||
//
|
||||
// will have:
|
||||
// a: b,rev=0
|
||||
// b: a,rev=1 c,rev=0 d,rev=0
|
||||
// c: b,rev=0
|
||||
//
|
||||
// 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 EdgeID outgoing_edge :
|
||||
m_node_based_graph->GetAdjacentEdgeRange(node_at_center_of_intersection))
|
||||
{
|
||||
// only keep valid turns
|
||||
if (!turn.entry_allowed)
|
||||
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;
|
||||
|
||||
// only add an edge if turn is not prohibited
|
||||
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(incoming_edge);
|
||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
|
||||
++node_based_edge_counter;
|
||||
|
||||
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
||||
BOOST_ASSERT(!edge_data1.reversed);
|
||||
BOOST_ASSERT(!edge_data2.reversed);
|
||||
auto intersection_with_flags_and_angles =
|
||||
turn_analysis.GetIntersectionGenerator().TransformIntersectionShapeIntoView(
|
||||
node_along_road_entering,
|
||||
incoming_edge,
|
||||
shape_result.normalised_intersection_shape,
|
||||
shape_result.intersection_shape,
|
||||
shape_result.merging_map);
|
||||
|
||||
// the following is the core of the loop.
|
||||
unsigned distance = edge_data1.distance;
|
||||
if (m_traffic_lights.find(node_at_center_of_intersection) != m_traffic_lights.end())
|
||||
{
|
||||
distance += profile_properties.traffic_signal_penalty;
|
||||
}
|
||||
auto intersection = turn_analysis.AssignTurnTypes(
|
||||
node_along_road_entering, incoming_edge, intersection_with_flags_and_angles);
|
||||
|
||||
const int32_t turn_penalty =
|
||||
scripting_environment.GetTurnPenalty(180. - turn.angle);
|
||||
BOOST_ASSERT(intersection.valid());
|
||||
|
||||
const auto turn_instruction = turn.instruction;
|
||||
if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
|
||||
{
|
||||
distance += profile_properties.u_turn_penalty;
|
||||
}
|
||||
intersection = turn_lane_handler.assignTurnLanes(
|
||||
node_along_road_entering, incoming_edge, std::move(intersection));
|
||||
|
||||
// don't add turn penalty if it is not an actual turn. This heuristic is necessary
|
||||
// since OSRM cannot handle looping roads/parallel roads
|
||||
if (turn_instruction.type != guidance::TurnType::NoTurn)
|
||||
distance += turn_penalty;
|
||||
// the entry class depends on the turn, so we have to classify the interesction for
|
||||
// every edge
|
||||
const auto turn_classification = classifyIntersection(intersection);
|
||||
|
||||
const bool is_encoded_forwards =
|
||||
m_compressed_edge_container.HasZippedEntryForForwardID(incoming_edge);
|
||||
const bool is_encoded_backwards =
|
||||
m_compressed_edge_container.HasZippedEntryForReverseID(incoming_edge);
|
||||
BOOST_ASSERT(is_encoded_forwards || is_encoded_backwards);
|
||||
if (is_encoded_forwards)
|
||||
{
|
||||
original_edge_data_vector.emplace_back(
|
||||
GeometryID{m_compressed_edge_container.GetZippedPositionForForwardID(
|
||||
incoming_edge),
|
||||
true},
|
||||
edge_data1.name_id,
|
||||
turn.lane_data_id,
|
||||
turn_instruction,
|
||||
entry_class_id,
|
||||
edge_data1.travel_mode,
|
||||
util::guidance::TurnBearing(intersection[0].bearing),
|
||||
util::guidance::TurnBearing(turn.bearing));
|
||||
}
|
||||
else if (is_encoded_backwards)
|
||||
{
|
||||
original_edge_data_vector.emplace_back(
|
||||
GeometryID{m_compressed_edge_container.GetZippedPositionForReverseID(
|
||||
incoming_edge),
|
||||
false},
|
||||
edge_data1.name_id,
|
||||
turn.lane_data_id,
|
||||
turn_instruction,
|
||||
entry_class_id,
|
||||
edge_data1.travel_mode,
|
||||
util::guidance::TurnBearing(intersection[0].bearing),
|
||||
util::guidance::TurnBearing(turn.bearing));
|
||||
}
|
||||
|
||||
++original_edges_counter;
|
||||
|
||||
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
|
||||
{
|
||||
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
|
||||
|
||||
// NOTE: potential overflow here if we hit 2^32 routable edges
|
||||
BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
|
||||
m_edge_based_edge_list.emplace_back(edge_data1.edge_id,
|
||||
edge_data2.edge_id,
|
||||
m_edge_based_edge_list.size(),
|
||||
distance,
|
||||
true,
|
||||
false);
|
||||
BOOST_ASSERT(original_edges_counter == m_edge_based_edge_list.size());
|
||||
|
||||
// Here is where we write out the mapping between the edge-expanded edges, and
|
||||
// the node-based edges that are originally used to calculate the `distance`
|
||||
// for the edge-expanded edges. About 40 lines back, there is:
|
||||
//
|
||||
// unsigned distance = edge_data1.distance;
|
||||
//
|
||||
// This tells us that the weight for an edge-expanded-edge is based on the weight
|
||||
// of the *source* node-based edge. Therefore, we will look up the individual
|
||||
// segments of the source node-based edge, and write out a mapping between
|
||||
// those and the edge-based-edge ID.
|
||||
// External programs can then use this mapping to quickly perform
|
||||
// updates to the edge-expanded-edge based directly on its ID.
|
||||
if (generate_edge_lookup)
|
||||
{
|
||||
const auto node_based_edges =
|
||||
m_compressed_edge_container.GetBucketReference(incoming_edge);
|
||||
NodeID previous = node_along_road_entering;
|
||||
|
||||
const unsigned node_count = node_based_edges.size() + 1;
|
||||
const QueryNode &first_node = m_node_info_list[previous];
|
||||
|
||||
lookup::SegmentHeaderBlock header = {node_count, first_node.node_id};
|
||||
|
||||
edge_segment_file.write(reinterpret_cast<const char *>(&header),
|
||||
sizeof(header));
|
||||
|
||||
for (auto target_node : node_based_edges)
|
||||
const auto entry_class_id = [&](const util::guidance::EntryClass entry_class) {
|
||||
if (0 == entry_class_hash.count(entry_class))
|
||||
{
|
||||
const QueryNode &from = m_node_info_list[previous];
|
||||
const QueryNode &to = m_node_info_list[target_node.node_id];
|
||||
const double segment_length =
|
||||
util::coordinate_calculation::greatCircleDistance(from, to);
|
||||
const auto id = static_cast<std::uint16_t>(entry_class_hash.size());
|
||||
entry_class_hash[entry_class] = id;
|
||||
return id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return entry_class_hash.find(entry_class)->second;
|
||||
}
|
||||
}(turn_classification.first);
|
||||
|
||||
lookup::SegmentBlock nodeblock = {
|
||||
to.node_id, segment_length, target_node.weight};
|
||||
const auto bearing_class_id =
|
||||
[&](const util::guidance::BearingClass bearing_class) {
|
||||
if (0 == bearing_class_hash.count(bearing_class))
|
||||
{
|
||||
const auto id = static_cast<std::uint32_t>(bearing_class_hash.size());
|
||||
bearing_class_hash[bearing_class] = id;
|
||||
return id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return bearing_class_hash.find(bearing_class)->second;
|
||||
}
|
||||
}(turn_classification.second);
|
||||
bearing_class_by_node_based_node[node_at_center_of_intersection] = bearing_class_id;
|
||||
|
||||
edge_segment_file.write(reinterpret_cast<const char *>(&nodeblock),
|
||||
sizeof(nodeblock));
|
||||
previous = target_node.node_id;
|
||||
for (const auto &turn : intersection)
|
||||
{
|
||||
// only keep valid turns
|
||||
if (!turn.entry_allowed)
|
||||
continue;
|
||||
|
||||
// only add an edge if turn is not prohibited
|
||||
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(incoming_edge);
|
||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
|
||||
|
||||
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
||||
BOOST_ASSERT(!edge_data1.reversed);
|
||||
BOOST_ASSERT(!edge_data2.reversed);
|
||||
|
||||
// the following is the core of the loop.
|
||||
unsigned distance = edge_data1.distance;
|
||||
if (m_traffic_lights.find(node_at_center_of_intersection) !=
|
||||
m_traffic_lights.end())
|
||||
{
|
||||
distance += profile_properties.traffic_signal_penalty;
|
||||
}
|
||||
|
||||
// We also now write out the mapping between the edge-expanded edges and the
|
||||
// original nodes. Since each edge represents a possible maneuver, external
|
||||
// programs can use this to quickly perform updates to edge weights in order
|
||||
// to penalize certain turns.
|
||||
const int32_t turn_penalty =
|
||||
scripting_environment.GetTurnPenalty(180. - turn.angle);
|
||||
|
||||
// If this edge is 'trivial' -- where the compressed edge corresponds
|
||||
// exactly to an original OSM segment -- we can pull the turn's preceding
|
||||
// node ID directly with `node_along_road_entering`; otherwise, we need to look
|
||||
// up the node
|
||||
// immediately preceding the turn from the compressed edge container.
|
||||
const bool isTrivial = m_compressed_edge_container.IsTrivial(incoming_edge);
|
||||
const auto turn_instruction = turn.instruction;
|
||||
if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
|
||||
{
|
||||
distance += profile_properties.u_turn_penalty;
|
||||
}
|
||||
|
||||
const auto &from_node =
|
||||
isTrivial
|
||||
? m_node_info_list[node_along_road_entering]
|
||||
: m_node_info_list[m_compressed_edge_container.GetLastEdgeSourceID(
|
||||
incoming_edge)];
|
||||
const auto &via_node =
|
||||
m_node_info_list[m_compressed_edge_container.GetLastEdgeTargetID(
|
||||
incoming_edge)];
|
||||
const auto &to_node =
|
||||
m_node_info_list[m_compressed_edge_container.GetFirstEdgeTargetID(
|
||||
turn.eid)];
|
||||
// don't add turn penalty if it is not an actual turn. This heuristic is
|
||||
// necessary
|
||||
// since OSRM cannot handle looping roads/parallel roads
|
||||
if (turn_instruction.type != guidance::TurnType::NoTurn)
|
||||
distance += turn_penalty;
|
||||
|
||||
const unsigned fixed_penalty = distance - edge_data1.distance;
|
||||
lookup::PenaltyBlock penaltyblock = {
|
||||
fixed_penalty, from_node.node_id, via_node.node_id, to_node.node_id};
|
||||
edge_penalty_file.write(reinterpret_cast<const char *>(&penaltyblock),
|
||||
sizeof(penaltyblock));
|
||||
const bool is_encoded_forwards =
|
||||
m_compressed_edge_container.HasZippedEntryForForwardID(incoming_edge);
|
||||
const bool is_encoded_backwards =
|
||||
m_compressed_edge_container.HasZippedEntryForReverseID(incoming_edge);
|
||||
BOOST_ASSERT(is_encoded_forwards || is_encoded_backwards);
|
||||
if (is_encoded_forwards)
|
||||
{
|
||||
original_edge_data_vector.emplace_back(
|
||||
GeometryID{m_compressed_edge_container.GetZippedPositionForForwardID(
|
||||
incoming_edge),
|
||||
true},
|
||||
edge_data1.name_id,
|
||||
turn.lane_data_id,
|
||||
turn_instruction,
|
||||
entry_class_id,
|
||||
edge_data1.travel_mode,
|
||||
util::guidance::TurnBearing(intersection[0].bearing),
|
||||
util::guidance::TurnBearing(turn.bearing));
|
||||
}
|
||||
else if (is_encoded_backwards)
|
||||
{
|
||||
original_edge_data_vector.emplace_back(
|
||||
GeometryID{m_compressed_edge_container.GetZippedPositionForReverseID(
|
||||
incoming_edge),
|
||||
false},
|
||||
edge_data1.name_id,
|
||||
turn.lane_data_id,
|
||||
turn_instruction,
|
||||
entry_class_id,
|
||||
edge_data1.travel_mode,
|
||||
util::guidance::TurnBearing(intersection[0].bearing),
|
||||
util::guidance::TurnBearing(turn.bearing));
|
||||
}
|
||||
|
||||
++original_edges_counter;
|
||||
|
||||
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
|
||||
{
|
||||
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
|
||||
|
||||
// NOTE: potential overflow here if we hit 2^32 routable edges
|
||||
BOOST_ASSERT(m_edge_based_edge_list.size() <=
|
||||
std::numeric_limits<NodeID>::max());
|
||||
m_edge_based_edge_list.emplace_back(edge_data1.edge_id,
|
||||
edge_data2.edge_id,
|
||||
m_edge_based_edge_list.size(),
|
||||
distance,
|
||||
true,
|
||||
false);
|
||||
BOOST_ASSERT(original_edges_counter == m_edge_based_edge_list.size());
|
||||
|
||||
// Here is where we write out the mapping between the edge-expanded edges, and
|
||||
// the node-based edges that are originally used to calculate the `distance`
|
||||
// for the edge-expanded edges. About 40 lines back, there is:
|
||||
//
|
||||
// unsigned distance = edge_data1.distance;
|
||||
//
|
||||
// This tells us that the weight for an edge-expanded-edge is based on the
|
||||
// weight
|
||||
// of the *source* node-based edge. Therefore, we will look up the individual
|
||||
// segments of the source node-based edge, and write out a mapping between
|
||||
// those and the edge-based-edge ID.
|
||||
// External programs can then use this mapping to quickly perform
|
||||
// updates to the edge-expanded-edge based directly on its ID.
|
||||
if (generate_edge_lookup)
|
||||
{
|
||||
const auto node_based_edges =
|
||||
m_compressed_edge_container.GetBucketReference(incoming_edge);
|
||||
NodeID previous = node_along_road_entering;
|
||||
|
||||
const unsigned node_count = node_based_edges.size() + 1;
|
||||
const QueryNode &first_node = m_node_info_list[previous];
|
||||
|
||||
lookup::SegmentHeaderBlock header = {node_count, first_node.node_id};
|
||||
|
||||
edge_segment_file.write(reinterpret_cast<const char *>(&header),
|
||||
sizeof(header));
|
||||
|
||||
for (auto target_node : node_based_edges)
|
||||
{
|
||||
const QueryNode &from = m_node_info_list[previous];
|
||||
const QueryNode &to = m_node_info_list[target_node.node_id];
|
||||
const double segment_length =
|
||||
util::coordinate_calculation::greatCircleDistance(from, to);
|
||||
|
||||
lookup::SegmentBlock nodeblock = {
|
||||
to.node_id, segment_length, target_node.weight};
|
||||
|
||||
edge_segment_file.write(reinterpret_cast<const char *>(&nodeblock),
|
||||
sizeof(nodeblock));
|
||||
previous = target_node.node_id;
|
||||
}
|
||||
|
||||
// We also now write out the mapping between the edge-expanded edges and the
|
||||
// original nodes. Since each edge represents a possible maneuver, external
|
||||
// programs can use this to quickly perform updates to edge weights in order
|
||||
// to penalize certain turns.
|
||||
|
||||
// If this edge is 'trivial' -- where the compressed edge corresponds
|
||||
// exactly to an original OSM segment -- we can pull the turn's preceding
|
||||
// node ID directly with `node_along_road_entering`; otherwise, we need to
|
||||
// look
|
||||
// up the node
|
||||
// immediately preceding the turn from the compressed edge container.
|
||||
const bool isTrivial = m_compressed_edge_container.IsTrivial(incoming_edge);
|
||||
|
||||
const auto &from_node =
|
||||
isTrivial
|
||||
? m_node_info_list[node_along_road_entering]
|
||||
: m_node_info_list[m_compressed_edge_container.GetLastEdgeSourceID(
|
||||
incoming_edge)];
|
||||
const auto &via_node =
|
||||
m_node_info_list[m_compressed_edge_container.GetLastEdgeTargetID(
|
||||
incoming_edge)];
|
||||
const auto &to_node =
|
||||
m_node_info_list[m_compressed_edge_container.GetFirstEdgeTargetID(
|
||||
turn.eid)];
|
||||
|
||||
const unsigned fixed_penalty = distance - edge_data1.distance;
|
||||
lookup::PenaltyBlock penaltyblock = {
|
||||
fixed_penalty, from_node.node_id, via_node.node_id, to_node.node_id};
|
||||
edge_penalty_file.write(reinterpret_cast<const char *>(&penaltyblock),
|
||||
sizeof(penaltyblock));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write() << "Created " << entry_class_hash.size() << " entry classes and "
|
||||
<< bearing_class_hash.size() << " Bearing Classes";
|
||||
util::Log() << "Created " << entry_class_hash.size() << " entry classes and "
|
||||
<< bearing_class_hash.size() << " Bearing Classes";
|
||||
|
||||
util::SimpleLogger().Write() << "Writing Turn Lane Data to File...";
|
||||
util::Log() << "Writing Turn Lane Data to File...";
|
||||
std::ofstream turn_lane_data_file(turn_lane_data_filename.c_str(), std::ios::binary);
|
||||
std::vector<util::guidance::LaneTupleIdPair> lane_data(lane_data_map.size());
|
||||
// extract lane data sorted by ID
|
||||
@@ -630,7 +646,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
turn_lane_data_file.write(reinterpret_cast<const char *>(&lane_data[0]),
|
||||
sizeof(util::guidance::LaneTupleIdPair) * lane_data.size());
|
||||
|
||||
util::SimpleLogger().Write() << "done.";
|
||||
util::Log() << "done.";
|
||||
|
||||
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
||||
|
||||
@@ -642,18 +658,15 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
edge_data_file.write(reinterpret_cast<const char *>(&length_prefix), sizeof(length_prefix));
|
||||
|
||||
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
|
||||
<< " edge based nodes";
|
||||
util::SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter
|
||||
<< " edges";
|
||||
util::SimpleLogger().Write() << "Edge-expanded graph ...";
|
||||
util::SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
|
||||
util::SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
|
||||
"defined by "
|
||||
<< m_restriction_map->size() << " restrictions";
|
||||
util::SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
|
||||
util::SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter
|
||||
<< " turns over barriers";
|
||||
util::Log() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
|
||||
util::Log() << "Node-based graph contains " << node_based_edge_counter << " edges";
|
||||
util::Log() << "Edge-expanded graph ...";
|
||||
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
|
||||
util::Log() << " skips " << restricted_turns_counter << " turns, "
|
||||
"defined by "
|
||||
<< m_restriction_map->size() << " restrictions";
|
||||
util::Log() << " skips " << skipped_uturns_counter << " U turns";
|
||||
util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
|
||||
}
|
||||
|
||||
std::vector<util::guidance::BearingClass> EdgeBasedGraphFactory::GetBearingClasses() const
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+53
-61
@@ -10,12 +10,13 @@
|
||||
|
||||
#include "extractor/raster_source.hpp"
|
||||
#include "storage/io.hpp"
|
||||
#include "storage/io.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/graph_loader.hpp"
|
||||
#include "util/io.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/range_table.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
@@ -43,7 +44,6 @@
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
@@ -119,12 +119,12 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
tbb::task_scheduler_init init(number_of_threads);
|
||||
|
||||
{
|
||||
util::SimpleLogger().Write() << "Input file: " << config.input_path.filename().string();
|
||||
util::Log() << "Input file: " << config.input_path.filename().string();
|
||||
if (!config.profile_path.empty())
|
||||
{
|
||||
util::SimpleLogger().Write() << "Profile: " << config.profile_path.filename().string();
|
||||
util::Log() << "Profile: " << config.profile_path.filename().string();
|
||||
}
|
||||
util::SimpleLogger().Write() << "Threads: " << number_of_threads;
|
||||
util::Log() << "Threads: " << number_of_threads;
|
||||
|
||||
ExtractionContainers extraction_containers;
|
||||
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(extraction_containers);
|
||||
@@ -137,7 +137,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
unsigned number_of_ways = 0;
|
||||
unsigned number_of_relations = 0;
|
||||
|
||||
util::SimpleLogger().Write() << "Parsing in progress..";
|
||||
util::Log() << "Parsing in progress..";
|
||||
TIMER_START(parsing);
|
||||
|
||||
// setup raster sources
|
||||
@@ -148,7 +148,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
{
|
||||
generator = "unknown tool";
|
||||
}
|
||||
util::SimpleLogger().Write() << "input file generated by " << generator;
|
||||
util::Log() << "input file generated by " << generator;
|
||||
|
||||
// write .timestamp data file
|
||||
std::string timestamp = header.get("osmosis_replication_timestamp");
|
||||
@@ -156,7 +156,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
{
|
||||
timestamp = "n/a";
|
||||
}
|
||||
util::SimpleLogger().Write() << "timestamp: " << timestamp;
|
||||
util::Log() << "timestamp: " << timestamp;
|
||||
|
||||
boost::filesystem::ofstream timestamp_out(config.timestamp_file_name);
|
||||
timestamp_out.write(timestamp.c_str(), timestamp.length());
|
||||
@@ -210,12 +210,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
}
|
||||
}
|
||||
TIMER_STOP(parsing);
|
||||
util::SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing)
|
||||
<< " seconds";
|
||||
util::Log() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
|
||||
|
||||
util::SimpleLogger().Write() << "Raw input contains " << number_of_nodes << " nodes, "
|
||||
<< number_of_ways << " ways, and " << number_of_relations
|
||||
<< " relations";
|
||||
util::Log() << "Raw input contains " << number_of_nodes << " nodes, " << number_of_ways
|
||||
<< " ways, and " << number_of_relations << " relations";
|
||||
|
||||
// take control over the turn lane map
|
||||
turn_lane_map = extractor_callbacks->moveOutLaneDescriptionMap();
|
||||
@@ -224,8 +222,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
|
||||
if (extraction_containers.all_edges_list.empty())
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
|
||||
return 1;
|
||||
throw util::exception(std::string("There are no edges remaining after parsing.") +
|
||||
SOURCE_REF);
|
||||
}
|
||||
|
||||
extraction_containers.PrepareData(scripting_environment,
|
||||
@@ -237,15 +235,14 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
scripting_environment.GetProfileProperties());
|
||||
|
||||
TIMER_STOP(extracting);
|
||||
util::SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting)
|
||||
<< "s";
|
||||
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
||||
}
|
||||
|
||||
{
|
||||
// Transform the node-based graph that OSM is based on into an edge-based graph
|
||||
// that is better for routing. Every edge becomes a node, and every valid
|
||||
// movement (e.g. turn from A->B, and B->A) becomes an edge
|
||||
util::SimpleLogger().Write() << "Generating edge-expanded graph representation";
|
||||
util::Log() << "Generating edge-expanded graph representation";
|
||||
|
||||
TIMER_START(expansion);
|
||||
|
||||
@@ -267,17 +264,16 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
|
||||
TIMER_STOP(expansion);
|
||||
|
||||
util::SimpleLogger().Write() << "Saving edge-based node weights to file.";
|
||||
util::Log() << "Saving edge-based node weights to file.";
|
||||
TIMER_START(timer_write_node_weights);
|
||||
util::serializeVector(config.edge_based_node_weights_output_path, edge_based_node_weights);
|
||||
TIMER_STOP(timer_write_node_weights);
|
||||
util::SimpleLogger().Write() << "Done writing. (" << TIMER_SEC(timer_write_node_weights)
|
||||
<< ")";
|
||||
util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")";
|
||||
|
||||
util::SimpleLogger().Write() << "Computing strictly connected components ...";
|
||||
util::Log() << "Computing strictly connected components ...";
|
||||
FindComponents(max_edge_id, edge_based_edge_list, edge_based_node_list);
|
||||
|
||||
util::SimpleLogger().Write() << "Building r-tree ...";
|
||||
util::Log() << "Building r-tree ...";
|
||||
TIMER_START(rtree);
|
||||
BuildRTree(std::move(edge_based_node_list),
|
||||
std::move(node_is_startpoint),
|
||||
@@ -285,7 +281,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
|
||||
TIMER_STOP(rtree);
|
||||
|
||||
util::SimpleLogger().Write() << "Writing node map ...";
|
||||
util::Log() << "Writing node map ...";
|
||||
WriteNodeMapping(internal_to_external_node_map);
|
||||
|
||||
WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list);
|
||||
@@ -295,10 +291,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
const auto edges_per_second =
|
||||
static_cast<std::uint64_t>((max_edge_id + 1) / TIMER_SEC(expansion));
|
||||
|
||||
util::SimpleLogger().Write() << "Expansion: " << nodes_per_second << " nodes/sec and "
|
||||
<< edges_per_second << " edges/sec";
|
||||
util::SimpleLogger().Write() << "To prepare the data for routing, run: "
|
||||
<< "./osrm-contract " << config.output_file_name << std::endl;
|
||||
util::Log() << "Expansion: " << nodes_per_second << " nodes/sec and " << edges_per_second
|
||||
<< " edges/sec";
|
||||
util::Log() << "To prepare the data for routing, run: "
|
||||
<< "./osrm-contract " << config.output_file_name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -310,7 +306,7 @@ void Extractor::WriteProfileProperties(const std::string &output_path,
|
||||
boost::filesystem::ofstream out_stream(output_path);
|
||||
if (!out_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + output_path + " for writing.");
|
||||
throw util::exception("Could not open " + output_path + " for writing." + SOURCE_REF);
|
||||
}
|
||||
|
||||
out_stream.write(reinterpret_cast<const char *>(&properties), sizeof(properties));
|
||||
@@ -406,7 +402,7 @@ std::shared_ptr<RestrictionMap> Extractor::LoadRestrictionMap()
|
||||
|
||||
util::loadRestrictionsFromFile(file_reader, restriction_list);
|
||||
|
||||
util::SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
|
||||
util::Log() << " - " << restriction_list.size() << " restrictions.";
|
||||
|
||||
return std::make_shared<RestrictionMap>(restriction_list);
|
||||
}
|
||||
@@ -428,16 +424,16 @@ Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barriers,
|
||||
NodeID number_of_node_based_nodes = util::loadNodesFromFile(
|
||||
file_reader, barriers_iter, traffic_signals_iter, internal_to_external_node_map);
|
||||
|
||||
util::SimpleLogger().Write() << " - " << barriers.size() << " bollard nodes, "
|
||||
<< traffic_signals.size() << " traffic lights";
|
||||
util::Log() << " - " << barriers.size() << " bollard nodes, " << traffic_signals.size()
|
||||
<< " traffic lights";
|
||||
|
||||
std::vector<NodeBasedEdge> edge_list;
|
||||
util::loadEdgesFromFile(file_reader, edge_list);
|
||||
|
||||
if (edge_list.empty())
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
|
||||
return std::shared_ptr<util::NodeBasedDynamicGraph>();
|
||||
throw util::exception("Node-based-graph (" + config.output_file_name +
|
||||
") contains no edges." + SOURCE_REF);
|
||||
}
|
||||
|
||||
return util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
|
||||
@@ -541,9 +537,9 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
|
||||
std::vector<bool> node_is_startpoint,
|
||||
const std::vector<QueryNode> &internal_to_external_node_map)
|
||||
{
|
||||
util::SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size()
|
||||
<< " edge elements build on-top of "
|
||||
<< internal_to_external_node_map.size() << " coordinates";
|
||||
util::Log() << "constructing r-tree of " << node_based_edge_list.size()
|
||||
<< " edge elements build on-top of " << internal_to_external_node_map.size()
|
||||
<< " coordinates";
|
||||
|
||||
BOOST_ASSERT(node_is_startpoint.size() == node_based_edge_list.size());
|
||||
|
||||
@@ -564,7 +560,8 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
|
||||
if (new_size == 0)
|
||||
{
|
||||
throw util::exception("There are no snappable edges left after processing. Are you "
|
||||
"setting travel modes correctly in the profile? Cannot continue.");
|
||||
"setting travel modes correctly in the profile? Cannot continue." +
|
||||
SOURCE_REF);
|
||||
}
|
||||
node_based_edge_list.resize(new_size);
|
||||
|
||||
@@ -575,8 +572,7 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
|
||||
internal_to_external_node_map);
|
||||
|
||||
TIMER_STOP(construction);
|
||||
util::SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
|
||||
<< " seconds";
|
||||
util::Log() << "finished r-tree construction in " << TIMER_SEC(construction) << " seconds";
|
||||
}
|
||||
|
||||
void Extractor::WriteEdgeBasedGraph(
|
||||
@@ -590,8 +586,7 @@ void Extractor::WriteEdgeBasedGraph(
|
||||
const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
|
||||
file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
|
||||
|
||||
util::SimpleLogger().Write() << "[extractor] Writing edge-based-graph edges ... "
|
||||
<< std::flush;
|
||||
util::Log() << "Writing edge-based-graph edges ... " << std::flush;
|
||||
TIMER_START(write_edges);
|
||||
|
||||
std::uint64_t number_of_used_edges = edge_based_edge_list.size();
|
||||
@@ -604,9 +599,9 @@ void Extractor::WriteEdgeBasedGraph(
|
||||
}
|
||||
|
||||
TIMER_STOP(write_edges);
|
||||
util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
|
||||
util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s";
|
||||
|
||||
util::SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
|
||||
util::Log() << "Processed " << number_of_used_edges << " edges";
|
||||
}
|
||||
|
||||
void Extractor::WriteIntersectionClassificationData(
|
||||
@@ -618,12 +613,11 @@ void Extractor::WriteIntersectionClassificationData(
|
||||
std::ofstream file_out_stream(output_file_name.c_str(), std::ios::binary);
|
||||
if (!file_out_stream)
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "Failed to open " << output_file_name
|
||||
<< " for writing";
|
||||
util::Log(logERROR) << "Failed to open " << output_file_name << " for writing";
|
||||
return;
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write() << "Writing Intersection Classification Data";
|
||||
util::Log() << "Writing Intersection Classification Data";
|
||||
TIMER_START(write_edges);
|
||||
util::writeFingerprint(file_out_stream);
|
||||
util::serializeVector(file_out_stream, node_based_intersection_classes);
|
||||
@@ -652,16 +646,15 @@ void Extractor::WriteIntersectionClassificationData(
|
||||
|
||||
if (!static_cast<bool>(file_out_stream))
|
||||
{
|
||||
throw util::exception("Failed to write to " + output_file_name + ".");
|
||||
throw util::exception("Failed to write to " + output_file_name + "." + SOURCE_REF);
|
||||
}
|
||||
|
||||
util::serializeVector(file_out_stream, entry_classes);
|
||||
TIMER_STOP(write_edges);
|
||||
util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s for "
|
||||
<< node_based_intersection_classes.size() << " Indices into "
|
||||
<< bearing_classes.size() << " bearing classes and "
|
||||
<< entry_classes.size() << " entry classes and " << total_bearings
|
||||
<< " bearing values." << std::endl;
|
||||
util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s for "
|
||||
<< node_based_intersection_classes.size() << " Indices into "
|
||||
<< bearing_classes.size() << " bearing classes and " << entry_classes.size()
|
||||
<< " entry classes and " << total_bearings << " bearing values.";
|
||||
}
|
||||
|
||||
void Extractor::WriteTurnLaneData(const std::string &turn_lane_file) const
|
||||
@@ -671,27 +664,26 @@ void Extractor::WriteTurnLaneData(const std::string &turn_lane_file) const
|
||||
std::vector<guidance::TurnLaneType::Mask> turn_lane_masks;
|
||||
std::tie(turn_lane_offsets, turn_lane_masks) = transformTurnLaneMapIntoArrays(turn_lane_map);
|
||||
|
||||
util::SimpleLogger().Write() << "Writing turn lane masks...";
|
||||
util::Log() << "Writing turn lane masks...";
|
||||
TIMER_START(turn_lane_timer);
|
||||
|
||||
std::ofstream ofs(turn_lane_file, std::ios::binary);
|
||||
if (!ofs)
|
||||
throw osrm::util::exception("Failed to open " + turn_lane_file + " for writing.");
|
||||
throw osrm::util::exception("Failed to open " + turn_lane_file + " for writing." +
|
||||
SOURCE_REF);
|
||||
|
||||
if (!util::serializeVector(ofs, turn_lane_offsets))
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "Error while writing.";
|
||||
return;
|
||||
throw util::exception("Error while writing to " + turn_lane_file + SOURCE_REF);
|
||||
}
|
||||
|
||||
if (!util::serializeVector(ofs, turn_lane_masks))
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "Error while writing.";
|
||||
return;
|
||||
throw util::exception("Error while writing to " + turn_lane_file + SOURCE_REF);
|
||||
}
|
||||
|
||||
TIMER_STOP(turn_lane_timer);
|
||||
util::SimpleLogger().Write() << "done (" << TIMER_SEC(turn_lane_timer) << ")";
|
||||
util::Log() << "done (" << TIMER_SEC(turn_lane_timer) << ")";
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "util/for_each_pair.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
#include <boost/optional/optional.hpp>
|
||||
@@ -62,7 +62,7 @@ void ExtractorCallbacks::ProcessRestriction(
|
||||
if (restriction)
|
||||
{
|
||||
external_memory.restrictions_list.push_back(restriction.get());
|
||||
// util::SimpleLogger().Write() << "from: " << restriction.get().restriction.from.node <<
|
||||
// util::Log() << "from: " << restriction.get().restriction.from.node <<
|
||||
// ",via: " << restriction.get().restriction.via.node <<
|
||||
// ", to: " << restriction.get().restriction.to.node <<
|
||||
// ", only: " << (restriction.get().restriction.flags.is_only ?
|
||||
@@ -96,8 +96,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
|
||||
if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id())
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id()
|
||||
<< " of size " << input_way.nodes().size();
|
||||
util::Log(logDEBUG) << "found bogus way with id: " << input_way.id() << " of size "
|
||||
<< input_way.nodes().size();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,8 +135,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID &&
|
||||
backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: "
|
||||
<< input_way.id();
|
||||
util::Log(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -196,8 +195,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
if (translated_mask == TurnLaneType::empty)
|
||||
{
|
||||
// if we have unsupported tags, don't handle them
|
||||
util::SimpleLogger().Write(logDEBUG) << "Unsupported lane tag found: \""
|
||||
<< *token_itr << "\"";
|
||||
util::Log(logDEBUG) << "Unsupported lane tag found: \"" << *token_itr << "\"";
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -328,7 +326,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
false,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_access_restricted,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_travel_mode,
|
||||
false,
|
||||
@@ -361,7 +358,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
!forward_only,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_access_restricted,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.forward_travel_mode,
|
||||
split_edge,
|
||||
@@ -384,7 +380,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
true,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_access_restricted,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_travel_mode,
|
||||
true,
|
||||
|
||||
@@ -14,7 +14,9 @@ IntersectionPrinter::IntersectionPrinter(
|
||||
const std::vector<extractor::QueryNode> &node_coordinates,
|
||||
const extractor::guidance::CoordinateExtractor &coordinate_extractor)
|
||||
: node_based_graph(node_based_graph), node_coordinates(node_coordinates),
|
||||
coordinate_extractor(coordinate_extractor){};
|
||||
coordinate_extractor(coordinate_extractor)
|
||||
{
|
||||
}
|
||||
|
||||
util::json::Array IntersectionPrinter::
|
||||
operator()(const NodeID intersection_node,
|
||||
|
||||
+166
-158
@@ -6,7 +6,7 @@
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/percent.hpp"
|
||||
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -22,175 +22,185 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
|
||||
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
|
||||
|
||||
util::Percent progress(original_number_of_nodes);
|
||||
|
||||
for (const NodeID node_v : util::irange(0u, original_number_of_nodes))
|
||||
{
|
||||
progress.PrintStatus(node_v);
|
||||
util::UnbufferedLog log;
|
||||
util::Percent progress(log, original_number_of_nodes);
|
||||
|
||||
// only contract degree 2 vertices
|
||||
if (2 != graph.GetOutDegree(node_v))
|
||||
for (const NodeID node_v : util::irange(0u, original_number_of_nodes))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
progress.PrintStatus(node_v);
|
||||
|
||||
// don't contract barrier node
|
||||
if (barrier_nodes.end() != barrier_nodes.find(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
|
||||
if (restriction_map.IsViaNode(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// reverse_e2 forward_e2
|
||||
// u <---------- v -----------> w
|
||||
// ----------> <-----------
|
||||
// forward_e1 reverse_e1
|
||||
//
|
||||
// Will be compressed to:
|
||||
//
|
||||
// reverse_e1
|
||||
// u <---------- w
|
||||
// ---------->
|
||||
// forward_e1
|
||||
//
|
||||
// If the edges are compatible.
|
||||
const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
|
||||
const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
|
||||
BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) && forward_e2 < graph.EndEdges(node_v));
|
||||
const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
|
||||
BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) && reverse_e2 < graph.EndEdges(node_v));
|
||||
|
||||
const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
|
||||
const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);
|
||||
|
||||
const NodeID node_w = graph.GetTarget(forward_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_w);
|
||||
BOOST_ASSERT(node_v != node_w);
|
||||
const NodeID node_u = graph.GetTarget(reverse_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_u);
|
||||
BOOST_ASSERT(node_u != node_v);
|
||||
|
||||
const EdgeID forward_e1 = graph.FindEdge(node_u, node_v);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
|
||||
BOOST_ASSERT(node_v == graph.GetTarget(forward_e1));
|
||||
const EdgeID reverse_e1 = graph.FindEdge(node_w, node_v);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
|
||||
BOOST_ASSERT(node_v == graph.GetTarget(reverse_e1));
|
||||
|
||||
const EdgeData &fwd_edge_data1 = graph.GetEdgeData(forward_e1);
|
||||
const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1);
|
||||
|
||||
if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// this case can happen if two ways with different names overlap
|
||||
if (fwd_edge_data1.name_id != rev_edge_data1.name_id ||
|
||||
fwd_edge_data2.name_id != rev_edge_data2.name_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fwd_edge_data1.CanCombineWith(fwd_edge_data2) &&
|
||||
rev_edge_data1.CanCombineWith(rev_edge_data2))
|
||||
{
|
||||
BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
|
||||
graph.GetEdgeData(reverse_e1).name_id);
|
||||
BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
|
||||
graph.GetEdgeData(reverse_e2).name_id);
|
||||
|
||||
// Do not compress edge if it crosses a traffic signal.
|
||||
// This can't be done in CanCombineWith, becase we only store the
|
||||
// traffic signals in the `traffic_lights` list, which EdgeData
|
||||
// doesn't have access to.
|
||||
const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
|
||||
if (has_node_penalty)
|
||||
// only contract degree 2 vertices
|
||||
if (2 != graph.GetOutDegree(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get distances before graph is modified
|
||||
const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
|
||||
const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;
|
||||
// don't contract barrier node
|
||||
if (barrier_nodes.end() != barrier_nodes.find(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(0 != forward_weight1);
|
||||
BOOST_ASSERT(0 != forward_weight2);
|
||||
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
|
||||
if (restriction_map.IsViaNode(node_v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const int reverse_weight1 = graph.GetEdgeData(reverse_e1).distance;
|
||||
const int reverse_weight2 = graph.GetEdgeData(reverse_e2).distance;
|
||||
// reverse_e2 forward_e2
|
||||
// u <---------- v -----------> w
|
||||
// ----------> <-----------
|
||||
// forward_e1 reverse_e1
|
||||
//
|
||||
// Will be compressed to:
|
||||
//
|
||||
// reverse_e1
|
||||
// u <---------- w
|
||||
// ---------->
|
||||
// forward_e1
|
||||
//
|
||||
// If the edges are compatible.
|
||||
const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
|
||||
const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
|
||||
BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) &&
|
||||
forward_e2 < graph.EndEdges(node_v));
|
||||
const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
|
||||
BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) &&
|
||||
reverse_e2 < graph.EndEdges(node_v));
|
||||
|
||||
BOOST_ASSERT(0 != reverse_weight1);
|
||||
BOOST_ASSERT(0 != reverse_weight2);
|
||||
const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
|
||||
const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);
|
||||
|
||||
// add weight of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
|
||||
graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
|
||||
const NodeID node_w = graph.GetTarget(forward_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_w);
|
||||
BOOST_ASSERT(node_v != node_w);
|
||||
const NodeID node_u = graph.GetTarget(reverse_e2);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_u);
|
||||
BOOST_ASSERT(node_u != node_v);
|
||||
|
||||
// extend e1's to targets of e2's
|
||||
graph.SetTarget(forward_e1, node_w);
|
||||
graph.SetTarget(reverse_e1, node_u);
|
||||
const EdgeID forward_e1 = graph.FindEdge(node_u, node_v);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
|
||||
BOOST_ASSERT(node_v == graph.GetTarget(forward_e1));
|
||||
const EdgeID reverse_e1 = graph.FindEdge(node_w, node_v);
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
|
||||
BOOST_ASSERT(node_v == graph.GetTarget(reverse_e1));
|
||||
|
||||
/*
|
||||
* Remember Lane Data for compressed parts. This handles scenarios where lane-data is
|
||||
* only kept up until a traffic light.
|
||||
*
|
||||
* | |
|
||||
* ---------------- |
|
||||
* -^ | |
|
||||
* ----------- |
|
||||
* -v | |
|
||||
* --------------- |
|
||||
* | |
|
||||
*
|
||||
* u ------- v ---- w
|
||||
*
|
||||
* Since the edge is compressable, we can transfer:
|
||||
* "left|right" (uv) and "" (uw) into a string with "left|right" (uw) for the compressed
|
||||
* edge.
|
||||
* Doing so, we might mess up the point from where the lanes are shown. It should be
|
||||
* reasonable, since the announcements have to come early anyhow. So there is a
|
||||
* potential danger in here, but it saves us from adding a lot of additional edges for
|
||||
* turn-lanes. Without this,we would have to treat any turn-lane beginning/ending just
|
||||
* like a barrier.
|
||||
*/
|
||||
const auto selectLaneID = [](const LaneDescriptionID front,
|
||||
const LaneDescriptionID back) {
|
||||
// A lane has tags: u - (front) - v - (back) - w
|
||||
// During contraction, we keep only one of the tags. Usually the one closer to the
|
||||
// intersection is preferred. If its empty, however, we keep the non-empty one
|
||||
if (back == INVALID_LANE_DESCRIPTIONID)
|
||||
return front;
|
||||
return back;
|
||||
};
|
||||
graph.GetEdgeData(forward_e1).lane_description_id =
|
||||
selectLaneID(graph.GetEdgeData(forward_e1).lane_description_id,
|
||||
fwd_edge_data2.lane_description_id);
|
||||
graph.GetEdgeData(reverse_e1).lane_description_id =
|
||||
selectLaneID(graph.GetEdgeData(reverse_e1).lane_description_id,
|
||||
rev_edge_data2.lane_description_id);
|
||||
const EdgeData &fwd_edge_data1 = graph.GetEdgeData(forward_e1);
|
||||
const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1);
|
||||
|
||||
// remove e2's (if bidir, otherwise only one)
|
||||
graph.DeleteEdge(node_v, forward_e2);
|
||||
graph.DeleteEdge(node_v, reverse_e2);
|
||||
if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// update any involved turn restrictions
|
||||
restriction_map.FixupStartingTurnRestriction(node_u, node_v, node_w);
|
||||
restriction_map.FixupArrivingTurnRestriction(node_u, node_v, node_w, graph);
|
||||
// this case can happen if two ways with different names overlap
|
||||
if (fwd_edge_data1.name_id != rev_edge_data1.name_id ||
|
||||
fwd_edge_data2.name_id != rev_edge_data2.name_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
restriction_map.FixupStartingTurnRestriction(node_w, node_v, node_u);
|
||||
restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);
|
||||
if (fwd_edge_data1.CanCombineWith(fwd_edge_data2) &&
|
||||
rev_edge_data1.CanCombineWith(rev_edge_data2))
|
||||
{
|
||||
BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
|
||||
graph.GetEdgeData(reverse_e1).name_id);
|
||||
BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
|
||||
graph.GetEdgeData(reverse_e2).name_id);
|
||||
|
||||
// store compressed geometry in container
|
||||
geometry_compressor.CompressEdge(
|
||||
forward_e1, forward_e2, node_v, node_w, forward_weight1, forward_weight2);
|
||||
geometry_compressor.CompressEdge(
|
||||
reverse_e1, reverse_e2, node_v, node_u, reverse_weight1, reverse_weight2);
|
||||
// Do not compress edge if it crosses a traffic signal.
|
||||
// This can't be done in CanCombineWith, becase we only store the
|
||||
// traffic signals in the `traffic_lights` list, which EdgeData
|
||||
// doesn't have access to.
|
||||
const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
|
||||
if (has_node_penalty)
|
||||
continue;
|
||||
|
||||
// Get distances before graph is modified
|
||||
const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
|
||||
const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;
|
||||
|
||||
BOOST_ASSERT(0 != forward_weight1);
|
||||
BOOST_ASSERT(0 != forward_weight2);
|
||||
|
||||
const int reverse_weight1 = graph.GetEdgeData(reverse_e1).distance;
|
||||
const int reverse_weight2 = graph.GetEdgeData(reverse_e2).distance;
|
||||
|
||||
BOOST_ASSERT(0 != reverse_weight1);
|
||||
BOOST_ASSERT(0 != reverse_weight2);
|
||||
|
||||
// add weight of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
|
||||
graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
|
||||
|
||||
// extend e1's to targets of e2's
|
||||
graph.SetTarget(forward_e1, node_w);
|
||||
graph.SetTarget(reverse_e1, node_u);
|
||||
|
||||
/*
|
||||
* Remember Lane Data for compressed parts. This handles scenarios where lane-data
|
||||
* is
|
||||
* only kept up until a traffic light.
|
||||
*
|
||||
* | |
|
||||
* ---------------- |
|
||||
* -^ | |
|
||||
* ----------- |
|
||||
* -v | |
|
||||
* --------------- |
|
||||
* | |
|
||||
*
|
||||
* u ------- v ---- w
|
||||
*
|
||||
* Since the edge is compressable, we can transfer:
|
||||
* "left|right" (uv) and "" (uw) into a string with "left|right" (uw) for the
|
||||
* compressed
|
||||
* edge.
|
||||
* Doing so, we might mess up the point from where the lanes are shown. It should be
|
||||
* reasonable, since the announcements have to come early anyhow. So there is a
|
||||
* potential danger in here, but it saves us from adding a lot of additional edges
|
||||
* for
|
||||
* turn-lanes. Without this,we would have to treat any turn-lane beginning/ending
|
||||
* just
|
||||
* like a barrier.
|
||||
*/
|
||||
const auto selectLaneID = [](const LaneDescriptionID front,
|
||||
const LaneDescriptionID back) {
|
||||
// A lane has tags: u - (front) - v - (back) - w
|
||||
// During contraction, we keep only one of the tags. Usually the one closer to
|
||||
// the
|
||||
// intersection is preferred. If its empty, however, we keep the non-empty one
|
||||
if (back == INVALID_LANE_DESCRIPTIONID)
|
||||
return front;
|
||||
return back;
|
||||
};
|
||||
graph.GetEdgeData(forward_e1).lane_description_id =
|
||||
selectLaneID(graph.GetEdgeData(forward_e1).lane_description_id,
|
||||
fwd_edge_data2.lane_description_id);
|
||||
graph.GetEdgeData(reverse_e1).lane_description_id =
|
||||
selectLaneID(graph.GetEdgeData(reverse_e1).lane_description_id,
|
||||
rev_edge_data2.lane_description_id);
|
||||
|
||||
// remove e2's (if bidir, otherwise only one)
|
||||
graph.DeleteEdge(node_v, forward_e2);
|
||||
graph.DeleteEdge(node_v, reverse_e2);
|
||||
|
||||
// update any involved turn restrictions
|
||||
restriction_map.FixupStartingTurnRestriction(node_u, node_v, node_w);
|
||||
restriction_map.FixupArrivingTurnRestriction(node_u, node_v, node_w, graph);
|
||||
|
||||
restriction_map.FixupStartingTurnRestriction(node_w, node_v, node_u);
|
||||
restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);
|
||||
|
||||
// store compressed geometry in container
|
||||
geometry_compressor.CompressEdge(
|
||||
forward_e1, forward_e2, node_v, node_w, forward_weight1, forward_weight2);
|
||||
geometry_compressor.CompressEdge(
|
||||
reverse_e1, reverse_e2, node_v, node_u, reverse_weight1, reverse_weight2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,10 +236,8 @@ void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
|
||||
new_edge_count += (graph.EndEdges(i) - graph.BeginEdges(i));
|
||||
}
|
||||
}
|
||||
util::SimpleLogger().Write() << "Node compression ratio: "
|
||||
<< new_node_count / (double)original_number_of_nodes;
|
||||
util::SimpleLogger().Write() << "Edge compression ratio: "
|
||||
<< new_edge_count / (double)original_number_of_edges;
|
||||
util::Log() << "Node compression ratio: " << new_node_count / (double)original_number_of_nodes;
|
||||
util::Log() << "Edge compression ratio: " << new_edge_count / (double)original_number_of_edges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/range/algorithm/transform.hpp>
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
using osrm::util::angularDeviation;
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -55,7 +55,7 @@ double GetOffsetCorrectionFactor(const RoadClassification &road_classification)
|
||||
default:
|
||||
return 1.0;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CoordinateExtractor::CoordinateExtractor(
|
||||
@@ -125,14 +125,14 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
|
||||
// due to repeated coordinates / smaller offset errors we skip over the very first parts of the
|
||||
// coordinate set to add a small level of fault tolerance
|
||||
const constexpr double distance_to_skip_over_due_to_coordinate_inaccuracies = 2;
|
||||
const constexpr double skipping_inaccuracies_distance = 2;
|
||||
|
||||
// fallback, mostly necessary for dead ends
|
||||
if (intersection_node == to_node)
|
||||
{
|
||||
const auto result = ExtractCoordinateAtLength(
|
||||
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates);
|
||||
BOOST_ASSERT(is_valid_result(coordinates.back()));
|
||||
skipping_inaccuracies_distance, coordinates);
|
||||
BOOST_ASSERT(is_valid_result(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
if (turn_edge_data.roundabout || turn_edge_data.circular)
|
||||
{
|
||||
const auto result = ExtractCoordinateAtLength(
|
||||
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates);
|
||||
skipping_inaccuracies_distance, coordinates);
|
||||
BOOST_ASSERT(is_valid_result(result));
|
||||
return result;
|
||||
}
|
||||
@@ -235,7 +235,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
|
||||
// if we are now left with two, well than we don't have to worry, or the segment is very small
|
||||
if (coordinates.size() == 2 ||
|
||||
total_distance <= distance_to_skip_over_due_to_coordinate_inaccuracies)
|
||||
total_distance <= skipping_inaccuracies_distance)
|
||||
{
|
||||
BOOST_ASSERT(is_valid_result(coordinates.back()));
|
||||
return coordinates.back();
|
||||
@@ -253,7 +253,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
if (coordinates.front() == coordinates.back())
|
||||
{
|
||||
const auto result = ExtractCoordinateAtLength(
|
||||
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates);
|
||||
skipping_inaccuracies_distance, coordinates);
|
||||
BOOST_ASSERT(is_valid_result(result));
|
||||
return result;
|
||||
}
|
||||
@@ -337,38 +337,9 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
return result;
|
||||
}
|
||||
|
||||
if (IsCurve(coordinates,
|
||||
segment_distances,
|
||||
total_distance,
|
||||
considered_lanes * 0.5 * ASSUMED_LANE_WIDTH,
|
||||
turn_edge_data))
|
||||
{
|
||||
if (total_distance <= distance_to_skip_over_due_to_coordinate_inaccuracies)
|
||||
return coordinates.back();
|
||||
/*
|
||||
* In curves we now have to distinguish between larger curves and tiny curves modelling the
|
||||
* actual turn in the beginnig.
|
||||
*
|
||||
* We distinguish between turns that simply model the initial way of getting onto the
|
||||
* destination lanes and the ones that performa a larger turn.
|
||||
*/
|
||||
const double offset =
|
||||
std::min(0.5 * considered_lanes * ASSUMED_LANE_WIDTH, 0.2 * segment_distances.back());
|
||||
coordinates = TrimCoordinatesToLength(std::move(coordinates), offset, segment_distances);
|
||||
BOOST_ASSERT(coordinates.size() >= 2);
|
||||
segment_distances.resize(coordinates.size());
|
||||
segment_distances.back() = util::coordinate_calculation::haversineDistance(
|
||||
*(coordinates.end() - 2), coordinates.back());
|
||||
const auto vector_head = coordinates.back();
|
||||
coordinates =
|
||||
TrimCoordinatesToLength(std::move(coordinates), 0.5 * offset, segment_distances);
|
||||
BOOST_ASSERT(coordinates.size() >= 2);
|
||||
const auto result =
|
||||
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
|
||||
BOOST_ASSERT(is_valid_result(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// We check offsets before curves to avoid detecting lane offsets due to large roads as curves
|
||||
// (think major highway here). If the road is wide, it can have quite a few coordinates in the
|
||||
// beginning.
|
||||
if (IsDirectOffset(coordinates,
|
||||
straight_index,
|
||||
straight_distance,
|
||||
@@ -387,6 +358,40 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
return result;
|
||||
}
|
||||
|
||||
if (IsCurve(coordinates,
|
||||
segment_distances,
|
||||
total_distance,
|
||||
considered_lanes * 0.5 * ASSUMED_LANE_WIDTH,
|
||||
turn_edge_data))
|
||||
{
|
||||
if (total_distance <= skipping_inaccuracies_distance)
|
||||
return coordinates.back();
|
||||
/*
|
||||
* In curves we now have to distinguish between larger curves and tiny curves modelling the
|
||||
* actual turn in the beginnig.
|
||||
*
|
||||
* We distinguish between turns that simply model the initial way of getting onto the
|
||||
* destination lanes and the ones that performa a larger turn.
|
||||
*/
|
||||
coordinates =
|
||||
TrimCoordinatesToLength(std::move(coordinates),
|
||||
2 * skipping_inaccuracies_distance,
|
||||
segment_distances);
|
||||
BOOST_ASSERT(coordinates.size() >= 2);
|
||||
segment_distances.resize(coordinates.size());
|
||||
segment_distances.back() = util::coordinate_calculation::haversineDistance(
|
||||
*(coordinates.end() - 2), coordinates.back());
|
||||
const auto vector_head = coordinates.back();
|
||||
coordinates = TrimCoordinatesToLength(std::move(coordinates),
|
||||
skipping_inaccuracies_distance,
|
||||
segment_distances);
|
||||
BOOST_ASSERT(coordinates.size() >= 2);
|
||||
const auto result =
|
||||
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
|
||||
BOOST_ASSERT(is_valid_result(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
{
|
||||
// skip over the first coordinates, in specific the assumed lane count. We add a small
|
||||
// safety factor, to not overshoot on the regression
|
||||
@@ -447,18 +452,17 @@ CoordinateExtractor::ExtractCoordinateAtLength(const double distance,
|
||||
|
||||
// find the beginning fo the segment (begin here and above for the length cache need to match
|
||||
// up!)
|
||||
const auto coordinate_base =
|
||||
std::find_if(coordinates.begin() + 1, coordinates.end(), find_coordinate_at_distance) - 1;
|
||||
const auto coordinate_after =
|
||||
std::find_if(coordinates.begin() + 1, coordinates.end(), find_coordinate_at_distance);
|
||||
|
||||
if (static_cast<std::size_t>(std::distance(coordinates.begin(), coordinate_base) + 1) >=
|
||||
coordinates.size())
|
||||
if (coordinate_after == coordinates.end())
|
||||
return coordinates.back();
|
||||
|
||||
const auto interpolation_factor =
|
||||
ComputeInterpolationFactor(distance - accumulated_distance, 0, *length_cache_itr);
|
||||
|
||||
return util::coordinate_calculation::interpolateLinear(
|
||||
interpolation_factor, *coordinate_base, *(coordinate_base + 1));
|
||||
interpolation_factor, *std::prev(coordinate_after), *coordinate_after);
|
||||
}
|
||||
|
||||
util::Coordinate CoordinateExtractor::ExtractCoordinateAtLength(
|
||||
@@ -475,26 +479,29 @@ util::Coordinate CoordinateExtractor::ExtractCoordinateAtLength(
|
||||
util::coordinate_calculation::haversineDistance(last_coordinate, coordinate);
|
||||
const auto result = (accumulated_distance + segment_distance) >= distance;
|
||||
if (!result)
|
||||
{
|
||||
accumulated_distance += segment_distance;
|
||||
last_coordinate = coordinate;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// find the begin of the segment containing the coordinate
|
||||
const auto coordinate_base =
|
||||
std::find_if(coordinates.begin() + 1, coordinates.end(), coordinate_at_distance) - 1;
|
||||
const auto coordinate_after =
|
||||
std::find_if(coordinates.begin() + 1, coordinates.end(), coordinate_at_distance);
|
||||
|
||||
if (static_cast<std::size_t>(std::distance(coordinates.begin(), coordinate_base) + 1) >=
|
||||
coordinates.size())
|
||||
if (coordinate_after == coordinates.end())
|
||||
return coordinates.back();
|
||||
|
||||
const auto interpolation_factor = ComputeInterpolationFactor(
|
||||
distance - accumulated_distance,
|
||||
0,
|
||||
util::coordinate_calculation::haversineDistance(*coordinate_base, *(coordinate_base + 1)));
|
||||
const auto interpolation_factor =
|
||||
ComputeInterpolationFactor(distance - accumulated_distance,
|
||||
0,
|
||||
util::coordinate_calculation::haversineDistance(
|
||||
*std::prev(coordinate_after), *coordinate_after));
|
||||
|
||||
return util::coordinate_calculation::interpolateLinear(
|
||||
interpolation_factor, *coordinate_base, *(coordinate_base + 1));
|
||||
interpolation_factor, *std::prev(coordinate_after), *coordinate_after);
|
||||
}
|
||||
|
||||
util::Coordinate CoordinateExtractor::GetCoordinateCloseToTurn(const NodeID from_node,
|
||||
@@ -598,6 +605,9 @@ CoordinateExtractor::GetCoordinatesAlongRoad(const NodeID intersection_node,
|
||||
std::back_inserter(result),
|
||||
compressedGeometryToCoordinate);
|
||||
}
|
||||
// filter duplicated coordinates
|
||||
auto end = std::unique(result.begin(), result.end());
|
||||
result.erase(end, result.end());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -691,12 +701,12 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
std::tie(has_up_down_deviation, maximum_deviation_index, maximum_deviation) =
|
||||
[&coordinates, get_deviation]() -> std::tuple<bool, std::size_t, double> {
|
||||
const auto increasing = [&](const util::Coordinate lhs, const util::Coordinate rhs) {
|
||||
return get_deviation(coordinates.front(), coordinates.back(), lhs) <=
|
||||
return get_deviation(coordinates.front(), coordinates.back(), lhs) <
|
||||
get_deviation(coordinates.front(), coordinates.back(), rhs);
|
||||
};
|
||||
|
||||
const auto decreasing = [&](const util::Coordinate lhs, const util::Coordinate rhs) {
|
||||
return get_deviation(coordinates.front(), coordinates.back(), lhs) >=
|
||||
return get_deviation(coordinates.front(), coordinates.back(), lhs) >
|
||||
get_deviation(coordinates.front(), coordinates.back(), rhs);
|
||||
};
|
||||
|
||||
@@ -707,16 +717,17 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
return std::make_tuple(
|
||||
true, 1, get_deviation(coordinates.front(), coordinates.back(), coordinates[1]));
|
||||
|
||||
const auto maximum_itr =
|
||||
const auto one_past_maximum_iter =
|
||||
std::is_sorted_until(coordinates.begin() + 1, coordinates.end(), increasing);
|
||||
|
||||
if (maximum_itr == coordinates.end())
|
||||
if (one_past_maximum_iter == coordinates.end())
|
||||
return std::make_tuple(true, coordinates.size() - 1, 0.);
|
||||
else if (std::is_sorted(maximum_itr, coordinates.end(), decreasing))
|
||||
return std::make_tuple(
|
||||
true,
|
||||
std::distance(coordinates.begin(), maximum_itr),
|
||||
get_deviation(coordinates.front(), coordinates.back(), *maximum_itr));
|
||||
else if (std::is_sorted(one_past_maximum_iter, coordinates.end(), decreasing))
|
||||
return std::make_tuple(true,
|
||||
std::distance(coordinates.begin(), one_past_maximum_iter) - 1,
|
||||
get_deviation(coordinates.front(),
|
||||
coordinates.back(),
|
||||
*(one_past_maximum_iter - 1)));
|
||||
else
|
||||
return std::make_tuple(false, 0, 0.);
|
||||
}();
|
||||
@@ -729,7 +740,7 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
// if the maximum deviation is at a quarter of the total curve, we are probably looking at a
|
||||
// normal turn
|
||||
const auto distance_to_max_deviation = std::accumulate(
|
||||
segment_distances.begin(), segment_distances.begin() + maximum_deviation_index, 0.);
|
||||
segment_distances.begin(), segment_distances.begin() + maximum_deviation_index + 1, 0.);
|
||||
|
||||
if ((distance_to_max_deviation <= 0.35 * segment_length ||
|
||||
maximum_deviation < std::max(0.3 * considered_lane_width, 0.5 * ASSUMED_LANE_WIDTH)) &&
|
||||
@@ -928,11 +939,15 @@ CoordinateExtractor::TrimCoordinatesToLength(std::vector<util::Coordinate> coord
|
||||
const auto distance_between_last_coordinates =
|
||||
util::coordinate_calculation::haversineDistance(*(coordinates.end() - 2),
|
||||
*(coordinates.end() - 1));
|
||||
const auto interpolation_factor =
|
||||
ComputeInterpolationFactor(length_cache.back(), 0, distance_between_last_coordinates);
|
||||
|
||||
coordinates.back() = util::coordinate_calculation::interpolateLinear(
|
||||
interpolation_factor, *(coordinates.end() - 2), coordinates.back());
|
||||
if (distance_between_last_coordinates > 0)
|
||||
{
|
||||
const auto interpolation_factor = ComputeInterpolationFactor(
|
||||
length_cache.back(), 0, distance_between_last_coordinates);
|
||||
|
||||
coordinates.back() = util::coordinate_calculation::interpolateLinear(
|
||||
interpolation_factor, *(coordinates.end() - 2), coordinates.back());
|
||||
}
|
||||
return coordinates;
|
||||
}
|
||||
else
|
||||
@@ -1138,7 +1153,8 @@ CoordinateExtractor::RegressionLine(const std::vector<util::Coordinate> &coordin
|
||||
return {coordinates.front(), coordinates.back()};
|
||||
|
||||
// compute the regression vector based on the sum of least squares
|
||||
const auto regression_line = leastSquareRegression(sampled_coordinates);
|
||||
const auto regression_line =
|
||||
util::coordinate_calculation::leastSquareRegression(sampled_coordinates);
|
||||
const auto coord_between_front =
|
||||
util::coordinate_calculation::projectPointOnSegment(
|
||||
regression_line.first, regression_line.second, coordinates.front())
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user