Compare commits

...

35 Commits

Author SHA1 Message Date
Daniel Patterson f88f51fd98 Log some memory usage statistics after preprocessing tasks. 2016-12-13 21:59:12 +01:00
Daniel J. Hofmann 98659fb0a0 Adds failing tests for directional access overrides, discovered in #3345 2016-12-13 17:37:42 +01:00
Daniel J. Hofmann 8a1afe456f Works around Unreachable Warning for Debug Build 2016-12-13 12:41:25 +01:00
Patrick Niklaus f1384f5e44 Merge pull request #3434 from Project-OSRM/fix/invalid-assertions
fix invalid assertion in coordinate_extractor
2016-12-12 19:19:47 +01:00
Moritz Kobitzsch 1cd5394a16 fix invalid assertion in coordinate_extractor 2016-12-12 10:12:32 +01:00
Daniel Patterson 8c7f744b1a Update node weights if traffic data is applied. 2016-12-11 16:02:58 +01:00
Patrick Niklaus 896445a337 Fix path to node binaries 2016-12-09 16:43:32 +00:00
Patrick Niklaus 8c21e1267e nvm -> install_node 2016-12-09 16:30:14 +00:00
Patrick Niklaus ad3fd46da5 Try to use mapbox node mirror 2016-12-09 15:28:28 +00:00
Huyen Chau Nguyen 62f0e11bfa assert that there is an open logger file when trying to log geojson output (#3417) 2016-12-09 14:58:20 +01:00
Patrick Niklaus 03d653c0bb Fix removing shared memory segments in a multi-process setup 2016-12-09 12:18:05 +01:00
Daniel J. Hofmann cbfb055f81 Changes Single Coordinate Geoms from Point to LineString, closes #3425. 2016-12-09 11:53:06 +01:00
Moritz Kobitzsch 2288704bb5 don't assign unused name to exception 2016-12-08 13:35:28 +01:00
Daniel J. Hofmann 97dcf4eef9 Fixes Compiler Crashes on Windows 2016-12-08 13:23:21 +01:00
Daniel Patterson 17e15033e1 Log helpful error message if mmap fails. 2016-12-07 22:03:49 +01:00
Daniel J. Hofmann 875f482203 Refactors and improves the Sliproad Handler, resolves #3109 2016-12-07 19:22:03 +01:00
Moritz Kobitzsch df3c39cef5 clean-up guidance code/code in general
removes duplicated includes
removes unused includes
eliminates dedicated toolkits that resulted in circular dependencies
moves functionality close to data, where possible
2016-12-07 12:10:56 +01:00
Moritz Kobitzsch a28a20a1ba fix errors in coordinate extractor due to duplicated coordinates
fix offset calculation in curve detection
2016-12-07 11:33:58 +01:00
Daniel Patterson 17a18b5c7c Revert "Add simple code review checklist to PR template."
This reverts commit 3f07a830e6.
2016-12-06 17:21:38 -08:00
Daniel Patterson 423c083038 Refactor logging, improve error handling workflow, clang-format. (#3385) 2016-12-06 12:31:13 -08:00
Daniel Patterson 468d8c0031 Refactor logging, improve error handling workflow, clang-format. (#3385) 2016-12-06 12:30:46 -08:00
Pepijn Schoen 6f4c6e84ae Handle file output through a FileWriter, align interfaces for FileWriter and FileReader 2016-12-06 15:59:12 +01:00
Michael Krasnyk 4b1aae40af Decoding should not fail for incomplete polyline strings (#3404)
Possible fails in
1) correct lattitude, longitude is missing
2) no end-of-number (0 5th bit) marker in the last character
2016-12-06 14:09:18 +01:00
Daniel J. Hofmann 0e6863aec1 Removes access and service restriction list from bike and foot profile 2016-12-05 14:15:47 +01:00
Daniel J. Hofmann 949d505783 Removes access_restricted flag internally 2016-12-05 14:15:47 +01:00
Emil Tin d11927046f car profile: remove use of is_access_restricted flag 2016-12-05 14:15:47 +01:00
Emil Tin 9461c83511 car profile: handle forward/backward access 2016-12-05 14:15:47 +01:00
Emil Tin 532cbfce13 profiles: Directional helper, some car refactoring 2016-12-05 14:15:47 +01:00
Michael Krasnyk 0fbd18b0dd Make absolute fixtures path 2016-12-04 16:34:42 +01:00
Daniel Patterson 3f07a830e6 Add simple code review checklist to PR template.
Add some checkboxes for common, mechanical parts that we should aim to hit for all PRs.
2016-12-02 23:18:57 -08:00
Moritz Kobitzsch 24b01fae00 fix extraction of coordinate along a way (#3397)
Also fix interpolation when coordinates are duplicated at the end of the vector
2016-12-02 13:11:04 -08:00
Daniel Patterson 0817cd6dfd Enforce iteration order so that tiles are encoded consistently on all platforms (#3393) 2016-12-02 08:59:39 -08:00
Daniel J. Hofmann 9d8b92f418 Abstracts away over differences in IntersectionView and Intersection.
Usage:

    struct MyIntersection : EnableIntersectionOps<MyIntersection> {

    };

Done.

We require MyIntersection having at least the member attributes from
IntersectionViewData but don't enforce a inheritance hierarchy.
2016-12-02 12:32:07 +01:00
Daniel Patterson 928a6f0c7d Variant got re-packaged, need to update search paths. (#3392) 2016-12-01 16:59:29 -08:00
Daniel Patterson 29b3caf529 Upgrade to mapbox/variant 1.1.4 2016-12-01 15:44:27 -08:00
188 changed files with 6221 additions and 3943 deletions
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+45 -2
View File
@@ -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 |
+11
View File
@@ -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
View File
@@ -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 |
+24 -15
View File
@@ -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
+35
View File
@@ -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 |
+9 -7
View File
@@ -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
+389 -38
View File
@@ -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&center=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 |
+122 -30
View File
@@ -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 |
+16
View File
@@ -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
+1
View File
@@ -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,
+23 -21
View File
@@ -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())
{
+12 -9
View File
@@ -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);
+2
View File
@@ -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 -11
View File
@@ -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_ */
+29 -1
View File
@@ -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()
-108
View File
@@ -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;
}
+1 -1
View File
@@ -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.
-2
View File
@@ -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;
+2 -1
View File
@@ -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
+123 -39
View File
@@ -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
-241
View File
@@ -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
+158 -2
View File
@@ -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,
+4 -12
View File
@@ -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,
+4 -3
View File
@@ -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);
}
}
+4 -4
View File
@@ -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(),
+3 -4
View File
@@ -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(),
+1 -1
View File
@@ -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
View File
@@ -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);
}
};
}
}
}
+3 -3
View File
@@ -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;
+6 -5
View File
@@ -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);
}
}
+13 -14
View File
@@ -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);
}
}
}
+10 -1
View File
@@ -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
+3
View File
@@ -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
+15
View File
@@ -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
+5 -4
View File
@@ -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);
}
+5 -5
View File
@@ -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.";
+5 -5
View File
@@ -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_ */
+3
View File
@@ -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
View File
@@ -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);
}
+1 -1
View File
@@ -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>
+70
View File
@@ -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 */
+43
View File
@@ -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
+5 -10
View File
@@ -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;
+11 -7
View File
@@ -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>
-55
View File
@@ -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 */
+2 -1
View File
@@ -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);
}
}
-2
View File
@@ -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
View File
@@ -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
View File
@@ -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')
-2
View File
@@ -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" }
+59
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 *)&current_edge,
-1
View File
@@ -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>
+5 -3
View File
@@ -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);
+4 -6
View File
@@ -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); //
+37 -41
View File
@@ -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)))
+42 -8
View File
@@ -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);
+39 -30
View File
@@ -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;
}
}
}
+8 -9
View File
@@ -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 &
+292 -279
View File
@@ -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
View File
@@ -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
+6 -11
View File
@@ -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,
+3 -1
View File
@@ -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
View File
@@ -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;
}
}
}
+88 -72
View File
@@ -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