Compare commits

...

37 Commits

Author SHA1 Message Date
Daniel Patterson b58329104a Bump version field and update CHANGELOG. 2016-12-16 13:58:21 -08:00
Patrick Niklaus d188e8e2a8 Fix changing shared memory in multi-process setup (#3462)
This change fixes two bugs:

1. A dead-lock that occurs between osrm-datastore and libosrm when an
   old dataset is free during a data update. This happened because the
   mutexes where acquired in a different order.

2. A region is deleted eventhough it is still in use. This happens when
   libosrm gets overtaken by osrm-datastore, so the new dataset is in
   the same region the old one was.
2016-12-16 13:54:57 -08:00
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 6232 additions and 3945 deletions
+8
View File
@@ -1,3 +1,8 @@
# 5.5.1
- Changes from 5.5.0
- Bugfixes
- Fixes #3455 where a deadlock could occur if re-loading new data under heavy load with multiple consumers osrm-datastore
# 5.5.0 # 5.5.0
- Changes from 5.4.0 - Changes from 5.4.0
- API: - API:
@@ -19,6 +24,7 @@
- Improved turn angle calculation, detecting offsets due to lanes / minor variations due to inaccuracies - Improved turn angle calculation, detecting offsets due to lanes / minor variations due to inaccuracies
- Corrected the bearings returned for intermediate steps - requires reprocessing - Corrected the bearings returned for intermediate steps - requires reprocessing
- Improved turn locations for collapsed turns - Improved turn locations for collapsed turns
- Sliproad classification refinements: the situations we detect as Sliproads now resemble more closely the reality
- Trip Plugin - Trip Plugin
- changed internal behaviour to prefer the smallest lexicographic result over the largest one - changed internal behaviour to prefer the smallest lexicographic result over the largest one
- Bugfixes - Bugfixes
@@ -27,6 +33,8 @@
- fixed a bug that could result in inconsistent behaviour when collapsing instructions - 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 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 - 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 - Debug Tiles
- Added support for turn penalties - Added support for turn penalties
- Internals - Internals
+6 -4
View File
@@ -53,9 +53,11 @@ endif()
project(OSRM C CXX) project(OSRM C CXX)
set(OSRM_VERSION_MAJOR 5) set(OSRM_VERSION_MAJOR 5)
set(OSRM_VERSION_MINOR 5) set(OSRM_VERSION_MINOR 5)
set(OSRM_VERSION_PATCH 0) set(OSRM_VERSION_PATCH 1)
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}") 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: # these two functions build up custom variables:
# DEPENDENCIES_INCLUDE_DIRS and OSRM_DEFINES # DEPENDENCIES_INCLUDE_DIRS and OSRM_DEFINES
# These variables we want to pass to # 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_BINARY_DIR}/include/)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_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} add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}" "-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-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
set_property(TARGET osrm-routed 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 LibraryGlob include/osrm/*.hpp)
file(GLOB ParametersGlob include/engine/api/*_parameters.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) 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 ${ContractorHeader} DESTINATION include/osrm/contractor)
install(FILES ${LibraryGlob} DESTINATION include/osrm) install(FILES ${LibraryGlob} DESTINATION include/osrm)
install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api) 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-extract DESTINATION bin)
install(TARGETS osrm-contract DESTINATION bin) install(TARGETS osrm-contract DESTINATION bin)
install(TARGETS osrm-datastore 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 | | 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 | | 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. - `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. - `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 | | | | no | yes | x |
| | | yes | no | | | | | 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 Scenario: Car - Access tag hierarchy on nodes
Then routability should be Then routability should be
| node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw | | node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
@@ -149,6 +178,7 @@ Feature: Car - Restricted access
| runway | | | | yes | | | runway | | | | yes | |
| primary | | | | no | x | | primary | | | | no | x |
@hov
Scenario: Car - only designated HOV ways are ignored by default Scenario: Car - only designated HOV ways are ignored by default
Then routability should be Then routability should be
| highway | hov | bothw | | highway | hov | bothw |
@@ -156,6 +186,7 @@ Feature: Car - Restricted access
| primary | yes | x | | primary | yes | x |
| primary | no | x | | primary | no | x |
@hov
Scenario: Car - a way with all lanes HOV-designated is inaccessible by default (similar to hov=designated) Scenario: Car - a way with all lanes HOV-designated is inaccessible by default (similar to hov=designated)
Then routability should be Then routability should be
| highway | hov:lanes:forward | hov:lanes:backward | hov:lanes | oneway | forw | backw | | 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 | designated\|no | designated\|no | | | x | x |
| primary | yes\|no | yes\|no | | | x | x | | primary | yes\|no | yes\|no | | | x | x |
| primary | | | | | x | x | | primary | | | | | x | x |
| primary | designated | | | -1 | | | | primary | designated | | | -1 | | x |
| primary | | designated | | -1 | | x | | primary | | designated | | -1 | | |
| primary | | | designated | yes | | | | primary | | | designated | yes | | |
| primary | | | designated | -1 | | | | primary | | | designated | -1 | | |
| primary | | | designated\| | yes | x | | | primary | | | designated\| | yes | x | |
@@ -189,3 +220,15 @@ Feature: Car - Restricted access
Then routability should be Then routability should be
| highway | toll | bothw | | highway | toll | bothw |
| primary | yes | | | 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 | -1 | | 23 km/h |
| primary | 30 | 1 | | 15 km/h | 15 km/h | | primary | 30 | 1 | | 15 km/h | 15 km/h |
| primary | 30 | 2 | | 23 km/h | 23 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 Scenario: Inner city expressway with on road
Given the node map Given the node map
""" """
a b c g a b . . . c g
f `f .
`
.
.
d d
.
.
.
e e
""" """
And the ways And the ways
| nodes | highway | name | name:pronunciation | | nodes | highway | name | name:pronunciation | oneway |
| abc | primary | road | roooaad | | abc | primary | road | roooaad | |
| cg | primary | road | roooaad | | cg | primary | road | roooaad | |
| bfd | trunk_link | | | | bfd | trunk_link | sliproad | | yes |
| cde | trunk | trunk | truank | | cde | trunk | trunk | truank | yes |
And the relations And the relations
| type | way:from | way:to | node:via | restriction | | 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 the profile "car"
Given a grid size of 3 meters Given a grid size of 3 meters
@sliproads @sliproads
Scenario: Separate Turn Lanes Scenario: Separate Turn Lanes
Given the node map Given the node map
""" """
e e
a b c g .
d a ... b ..... c . g
` .
`... d
.
f f
""" """
@@ -41,8 +45,10 @@ Feature: Turn Lane Guidance
Given the node map Given the node map
""" """
e e
a b c g a . . b . . . c g
d ` .
` .
` d
f 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,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, | | a,f | in,cross,cross | depart,turn right,arrive | ,left:false straight:false right:true, |
@sliproads @sliproads
Scenario: Separate Turn Lanes Next to other turns Scenario: Separate Turn Lanes Next to other turns
Given the node map Given the node map
""" """
e . e
a - - b.-.- - c-g a . . b . . . c g
| ' 'd . ` .
| f . ` .
| . d
| . f
| .
| .
| .
| .
i - - h - - - j i . . h . . . j
""" """
And the ways 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,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, | | a,i | in,turn,other,other | depart,turn right,turn right,arrive | ,,left:false right:true, |
@todo @2654 @none @todo @2654 @none
#https://github.com/Project-OSRM/osrm-backend/issues/2645 #https://github.com/Project-OSRM/osrm-backend/issues/2645
#http://www.openstreetmap.org/export#map=19/52.56054/13.32152 #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,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, | | 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 Scenario: Check sliproad handler loop's exit condition, Issue #2896
# http://www.openstreetmap.org/way/198481519 # http://www.openstreetmap.org/way/198481519
Given the node locations Given the node locations
+35
View File
@@ -55,3 +55,38 @@ Feature: Collapse
| waypoints | route | turns | | waypoints | route | turns |
| a,g | road,road,road | depart,continue uturn,arrive | | a,g | road,road,road | depart,continue uturn,arrive |
| d,c | 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 Given the node map
""" """
g g
.
c c
a b a . . b .'
d ` d.
f e 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 And the ways
| nodes | name | oneway | highway | | nodes | name | oneway | highway |
@@ -725,10 +728,9 @@ Feature: Collapse
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive | | a,g | road,cross,cross | depart,fork left,arrive |
| a,e | road,road,road | depart,continue straight,arrive | | a,e | road,road,road | depart,fork slight right,arrive |
# We should discuss whether the next item should be collapsed to depart,turn right,arrive. | a,f | road,road,cross,cross | depart,fork slight right,turn right,arrive |
| a,f | road,road,cross,cross | depart,continue straight,turn right,arrive |
Scenario: On-Off on Highway Scenario: On-Off on Highway
Given the node map Given the node map
+389 -38
View File
@@ -9,23 +9,23 @@ Feature: Slipways and Dedicated Turn Lanes
Given the node map Given the node map
""" """
e e
a b c d a b . . c d
h `h .
`
1 1 `
.
f f
.
g g
""" """
And the ways And the ways
| nodes | highway | name | | nodes | highway | name | oneway |
| abc | trunk | first | | abc | trunk | first | |
| cd | trunk | first | | cd | trunk | first | |
| bhf | trunk_link | | | bhf | trunk_link | | yes |
| cfg | primary | second | | cfg | primary | second | yes |
| ec | primary | second | | ec | primary | second | |
And the relations And the relations
| type | way:from | way:to | node:via | restriction | | type | way:from | way:to | node:via | restriction |
@@ -51,12 +51,12 @@ Feature: Slipways and Dedicated Turn Lanes
""" """
And the ways And the ways
| nodes | highway | name | maxspeed | | nodes | highway | name | maxspeed | oneway |
| abc | trunk | first | 70 | | abc | trunk | first | 70 | |
| cd | trunk | first | 2 | | cd | trunk | first | 2 | |
| bhf | trunk_link | | 2 | | bhf | trunk_link | | 2 | yes |
| cfg | primary | second | 50 | | cfg | primary | second | 50 | yes |
| ec | primary | second | 50 | | ec | primary | second | 50 | |
And the relations And the relations
| type | way:from | way:to | node:via | restriction | | 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 Scenario: Inner city expressway with on road
Given the node map Given the node map
""" """
a b c g a b . . . c g
f `f .
`
.
.
d d
.
.
.
e e
""" """
And the ways And the ways
| nodes | highway | name | | nodes | highway | name | oneway |
| abc | primary | road | | abc | primary | road | |
| cg | primary | road | | cg | primary | road | |
| bfd | trunk_link | | | bfd | trunk_link | | yes |
| cde | trunk | trunk | | cde | trunk | trunk | yes |
And the relations And the relations
| type | way:from | way:to | node:via | restriction | | type | way:from | way:to | node:via | restriction |
@@ -240,8 +240,8 @@ Feature: Slipways and Dedicated Turn Lanes
| qe | secondary_link | Ettlinger Allee | | yes | | qe | secondary_link | Ettlinger Allee | | yes |
When I route I should get When I route I should get
| waypoints | route | turns | ref | | waypoints | route | turns | ref |
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, | | a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
Scenario: Traffic Lights everywhere 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 #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 | | jcghf | primary | Brauerstrasse | yes |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive | | a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive | | a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive | | a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
| a,1 | Ebertstrasse,, | depart,turn right,arrive | | a,1 | Ebertstrasse,, | depart,turn slight right,arrive |
#2839 #2839
Scenario: Self-Loop Scenario: Self-Loop
@@ -431,3 +431,354 @@ Feature: Slipways and Dedicated Turn Lanes
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,i | road,road,road | depart,fork slight left,arrive | | 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 Scenario: Curved Turn At Cross
Given the node map Given the node map
""" """
h h
| |
| |
| |
| |
| . b - - - - - - - - - - - - - - - - - - a | . b - - - - - - - - - - - - - - - - - - - - - - - a
| . | .
| . | .
| c | c
| |
| |
| |
d d
| |
| |
| |
e | e |
. | . |
. | . |
g - - - - - - - - - - - - - f | g - - - - - - - - - - - - - - - - - - f |
| |
| |
| |
i i
""" """
And the ways And the ways
@@ -443,9 +443,9 @@ Feature: Simple Turns
| ef | residential | road | 2 | yes | | ef | residential | road | 2 | yes |
When I route I should get When I route I should get
| waypoints | route | turns | locations | | waypoints | route | turns | locations | # |
| g,f | turn,road,road | depart,turn left,arrive | g,e,f | | 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 | | 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 #http://www.openstreetmap.org/search?query=52.479264%2013.295617#map=19/52.47926/13.29562
Scenario: Splitting Roads with curved split Scenario: Splitting Roads with curved split
@@ -627,12 +627,14 @@ Feature: Simple Turns
| 1,h | ,allee,allee | depart,turn left,arrive | | 1,h | ,allee,allee | depart,turn left,arrive |
| 2,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 #http://www.openstreetmap.org/#map=18/52.56251/13.32650
@todo
Scenario: Curved Turn on Separated Directions Scenario: Curved Turn on Separated Directions
Given the node map Given the node map
""" """
e d e d
f - - - - - - - - - - - - - - - c - - - - - - - - - - - j f c - - - - - - - - - - - j
| l ' | | l ' |
| ' | | ' |
| ' | | ' |
@@ -680,6 +682,58 @@ Feature: Simple Turns
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive | | j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
| a,i | Kurt,Kurt,Kurt | 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 #http://www.openstreetmap.org/#map=19/52.53731/13.36033
Scenario: Splitting Road to Left Scenario: Splitting Road to Left
Given the node map Given the node map
@@ -1112,8 +1166,9 @@ Feature: Simple Turns
""" """
And the ways And the ways
| nodes | name | highway | lanes | | nodes | name | highway | lanes | oneway |
| abcdefghijklmnopc | circled | residential | 1 | | abc | circled | residential | 1 | no |
| cdefghijklmnopc | circled | residential | 1 | yes |
When I route I should get When I route I should get
| waypoints | bearings | route | turns | | waypoints | bearings | route | turns |
@@ -1168,3 +1223,40 @@ Feature: Simple Turns
When I route I should get When I route I should get
| waypoints | route | | waypoints | route |
| a,e | ab,bcde,bcde | | 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: Background:
Given the profile "testbot" 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 Scenario: osrm-contract - Non-existing option
When I try to run "osrm-contract --fly-me-to-the-moon" 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 "option"
And stderr should contain "fly-me-to-the-moon" And stderr should contain "fly-me-to-the-moon"
And it should exit with an error 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 EdgeID
LoadEdgeExpandedGraph(const std::string &edge_based_graph_path, LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list, util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
const std::string &edge_segment_lookup_path, const std::string &edge_segment_lookup_path,
const std::string &edge_penalty_path, const std::string &edge_penalty_path,
const std::vector<std::string> &segment_speed_path, const std::vector<std::string> &segment_speed_path,
+23 -21
View File
@@ -6,8 +6,8 @@
#include "util/deallocating_vector.hpp" #include "util/deallocating_vector.hpp"
#include "util/dynamic_graph.hpp" #include "util/dynamic_graph.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/percent.hpp" #include "util/percent.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp" #include "util/timing_util.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include "util/xor_fast_hash.hpp" #include "util/xor_fast_hash.hpp"
@@ -156,11 +156,10 @@ class GraphContractor
#ifndef NDEBUG #ifndef NDEBUG
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10) if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
{ {
util::SimpleLogger().Write(logWARNING) util::Log(logWARNING) << "Edge weight large -> "
<< "Edge weight large -> " << static_cast<unsigned int>(std::max(diter->weight, 1))
<< static_cast<unsigned int>(std::max(diter->weight, 1)) << " : " << " : " << static_cast<unsigned int>(diter->source) << " -> "
<< static_cast<unsigned int>(diter->source) << " -> " << static_cast<unsigned int>(diter->target);
<< static_cast<unsigned int>(diter->target);
} }
#endif #endif
edges.emplace_back(diter->source, edges.emplace_back(diter->source,
@@ -245,15 +244,14 @@ class GraphContractor
} }
} }
} }
util::SimpleLogger().Write() << "merged " << edges.size() - edge << " edges out of " util::Log() << "merged " << edges.size() - edge << " edges out of " << edges.size();
<< edges.size();
edges.resize(edge); edges.resize(edge);
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges); contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
edges.clear(); edges.clear();
edges.shrink_to_fit(); edges.shrink_to_fit();
BOOST_ASSERT(0 == edges.capacity()); BOOST_ASSERT(0 == edges.capacity());
util::SimpleLogger().Write() << "contractor finished initalization"; util::Log() << "contractor finished initalization";
} }
void Run(double core_factor = 1.0) void Run(double core_factor = 1.0)
@@ -270,7 +268,6 @@ class GraphContractor
const constexpr size_t DeleteGrainSize = 1; const constexpr size_t DeleteGrainSize = 1;
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes(); const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
util::Percent p(number_of_nodes);
ThreadDataContainer thread_data_list(number_of_nodes); ThreadDataContainer thread_data_list(number_of_nodes);
@@ -292,9 +289,10 @@ class GraphContractor
bool use_cached_node_priorities = !node_levels.empty(); bool use_cached_node_priorities = !node_levels.empty();
if (use_cached_node_priorities) 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); node_priorities.swap(node_levels);
std::cout << "ok" << std::endl; log << "ok";
} }
else else
{ {
@@ -302,7 +300,8 @@ class GraphContractor
node_priorities.resize(number_of_nodes); node_priorities.resize(number_of_nodes);
node_levels.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), tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
[this, &node_priorities, &node_depth, &thread_data_list]( [this, &node_priorities, &node_depth, &thread_data_list](
const tbb::blocked_range<int> &range) { const tbb::blocked_range<int> &range) {
@@ -313,11 +312,14 @@ class GraphContractor
this->EvaluateNodePriority(data, node_depth[x], x); this->EvaluateNodePriority(data, node_depth[x], x);
} }
}); });
std::cout << "ok" << std::endl; log << "ok";
} }
BOOST_ASSERT(node_priorities.size() == number_of_nodes); 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; unsigned current_level = 0;
bool flushed_contractor = false; bool flushed_contractor = false;
@@ -331,7 +333,7 @@ class GraphContractor
new_edge_set; // this one is not explicitely new_edge_set; // this one is not explicitely
// cleared since it goes out of // cleared since it goes out of
// scope anywa // 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 // Delete old heap data to free memory that we need for the coming operations
thread_data_list.data.clear(); thread_data_list.data.clear();
@@ -599,9 +601,8 @@ class GraphContractor
is_core_node.clear(); is_core_node.clear();
} }
util::SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes " util::Log() << "[core] " << remaining_nodes.size() << " nodes "
<< contractor_graph->GetNumberOfEdges() << " edges." << contractor_graph->GetNumberOfEdges() << " edges.";
<< std::endl;
thread_data_list.data.clear(); thread_data_list.data.clear();
} }
@@ -618,8 +619,9 @@ class GraphContractor
template <class Edge> inline void GetEdges(util::DeallocatingVector<Edge> &edges) template <class Edge> inline void GetEdges(util::DeallocatingVector<Edge> &edges)
{ {
util::Percent p(contractor_graph->GetNumberOfNodes()); util::UnbufferedLog log;
util::SimpleLogger().Write() << "Getting edges of minimized graph"; log << "Getting edges of minimized graph ";
util::Percent p(log, contractor_graph->GetNumberOfNodes());
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes(); const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
if (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); auto num_coordinates = std::distance(begin, end);
BOOST_ASSERT(num_coordinates != 0); BOOST_ASSERT(num_coordinates != 0);
util::json::Object geojson; util::json::Object geojson;
geojson.values["type"] = "LineString";
util::json::Array coordinates;
if (num_coordinates > 1) if (num_coordinates > 1)
{ {
geojson.values["type"] = "LineString";
util::json::Array coordinates;
coordinates.values.reserve(num_coordinates); coordinates.values.reserve(num_coordinates);
std::transform( auto into = std::back_inserter(coordinates.values);
begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat); std::transform(begin, end, into, &detail::coordinateToLonLat);
geojson.values["coordinates"] = std::move(coordinates);
} }
else if (num_coordinates > 0) else if (num_coordinates > 0)
{ {
geojson.values["type"] = "Point"; // For a single location we create a [location, location] LineString
util::json::Array coordinates; // instead of a single Point making the GeoJSON output consistent.
coordinates.values.push_back(detail::coordinateToLonLat(*begin)); coordinates.values.reserve(2);
geojson.values["coordinates"] = std::move(coordinates); auto location = detail::coordinateToLonLat(*begin);
coordinates.values.push_back(location);
coordinates.values.push_back(location);
} }
geojson.values["coordinates"] = std::move(coordinates);
return geojson; return geojson;
} }
@@ -12,11 +12,13 @@
#include "util/guidance/turn_lanes.hpp" #include "util/guidance/turn_lanes.hpp"
#include "engine/geospatial_query.hpp" #include "engine/geospatial_query.hpp"
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/guidance/turn_bearing.hpp" #include "util/guidance/turn_bearing.hpp"
#include "util/log.hpp"
#include "util/packed_vector.hpp" #include "util/packed_vector.hpp"
#include "util/range_table.hpp" #include "util/range_table.hpp"
#include "util/rectangle.hpp" #include "util/rectangle.hpp"
#include "util/simple_logger.hpp"
#include "util/static_graph.hpp" #include "util/static_graph.hpp"
#include "util/static_rtree.hpp" #include "util/static_rtree.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
@@ -116,7 +118,7 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
{ {
m_check_sum = m_check_sum =
*data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::HSGR_CHECKSUM); *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) 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); file_index_path = boost::filesystem::path(file_index_ptr);
if (!boost::filesystem::exists(file_index_path)) 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() + 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 = auto tree_ptr =
@@ -38,31 +38,39 @@ class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
// used anymore. We crash hard here if something goes wrong (noexcept). // used anymore. We crash hard here if something goes wrong (noexcept).
virtual ~SharedMemoryDataFacade() noexcept virtual ~SharedMemoryDataFacade() noexcept
{ {
// Now check if this is still the newest dataset
boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
current_regions_lock(shared_barriers->current_regions_mutex,
boost::interprocess::defer_lock);
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock( boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
: shared_barriers->regions_2_mutex, : shared_barriers->regions_2_mutex,
boost::interprocess::defer_lock); boost::interprocess::defer_lock);
// if this returns false this is still in use // if this returns false this is still in use
if (exclusive_lock.try_lock()) if (current_regions_lock.try_lock() && exclusive_lock.try_lock())
{ {
// Now check if this is still the newest dataset if (storage::SharedMemory::RegionExists(data_region))
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::SimpleLogger().Write(logDEBUG) << "Retaining data with shared timestamp " BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
<< shared_timestamp;
} auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
else const auto current_timestamp =
{ static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
storage::SharedMemory::Remove(data_region);
storage::SharedMemory::Remove(layout_region); // check if the memory region referenced by this facade needs cleanup
if (current_timestamp->data == data_region)
{
BOOST_ASSERT(current_timestamp->layout == layout_region);
util::Log(logDEBUG) << "Retaining data with shared timestamp "
<< shared_timestamp;
}
else
{
storage::SharedMemory::Remove(data_region);
storage::SharedMemory::Remove(layout_region);
}
} }
} }
} }
@@ -74,8 +82,7 @@ class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
: shared_barriers(shared_barriers_), layout_region(layout_region_), : shared_barriers(shared_barriers_), layout_region(layout_region_),
data_region(data_region_), shared_timestamp(shared_timestamp_) data_region(data_region_), shared_timestamp(shared_timestamp_)
{ {
util::SimpleLogger().Write(logDEBUG) << "Loading new data with shared timestamp " util::Log(logDEBUG) << "Loading new data with shared timestamp " << shared_timestamp;
<< shared_timestamp;
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region)); BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
m_layout_memory = storage::makeSharedMemory(layout_region); m_layout_memory = storage::makeSharedMemory(layout_region);
+2
View File
@@ -18,6 +18,8 @@
#include "engine/plugins/trip.hpp" #include "engine/plugins/trip.hpp"
#include "engine/plugins/viaroute.hpp" #include "engine/plugins/viaroute.hpp"
#include "engine/status.hpp" #include "engine/status.hpp"
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/json_container.hpp" #include "util/json_container.hpp"
#include <memory> #include <memory>
@@ -6,7 +6,6 @@
#include "engine/datafacade/datafacade_base.hpp" #include "engine/datafacade/datafacade_base.hpp"
#include "engine/guidance/leg_geometry.hpp" #include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_step.hpp" #include "engine/guidance/route_step.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/internal_route_result.hpp" #include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp" #include "engine/phantom_node.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
+8 -11
View File
@@ -8,14 +8,12 @@
#include "engine/guidance/leg_geometry.hpp" #include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_step.hpp" #include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp" #include "engine/guidance/step_maneuver.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/internal_route_result.hpp" #include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp" #include "engine/phantom_node.hpp"
#include "util/bearing.hpp" #include "util/bearing.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
#include "util/guidance/entry_class.hpp" #include "util/guidance/entry_class.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/guidance/turn_lanes.hpp" #include "util/guidance/turn_lanes.hpp"
#include "util/typedefs.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)); intersection.entry.push_back(entry_class.allowsEntry(idx));
} }
std::int16_t bearing_in_driving_direction = std::int16_t bearing_in_driving_direction =
util::bearing::reverseBearing(std::round(bearings.first)); util::reverseBearing(std::round(bearings.first));
maneuver = {intersection.location, maneuver = {intersection.location,
bearing_in_driving_direction, bearing_in_driving_direction,
bearings.second, bearings.second,
@@ -216,14 +214,13 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
BOOST_ASSERT(segment_index == number_of_segments - 1); BOOST_ASSERT(segment_index == number_of_segments - 1);
bearings = detail::getArriveBearings(leg_geometry); bearings = detail::getArriveBearings(leg_geometry);
intersection = { intersection = {target_node.location,
target_node.location, std::vector<short>({static_cast<short>(util::reverseBearing(bearings.first))}),
std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}), std::vector<bool>({true}),
std::vector<bool>({true}), 0,
0, Intersection::NO_INDEX,
Intersection::NO_INDEX, util::guidance::LaneTuple(),
util::guidance::LaneTuple(), {}};
{}};
// This step has length zero, the only reason we need it is the target location // This step has length zero, the only reason we need it is the target location
maneuver = {intersection.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 "util/guidance/turn_lanes.hpp"
#include <cstddef> #include <cstddef>
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/range/iterator_range.hpp>
namespace osrm namespace osrm
{ {
namespace engine namespace engine
@@ -71,6 +72,33 @@ struct RouteStep
std::size_t geometry_begin; std::size_t geometry_begin;
std::size_t geometry_end; std::size_t geometry_end;
std::vector<Intersection> intersections; 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() 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() << " // forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
// nodes"; // 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() << " // reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
// nodes"; // nodes";
@@ -601,7 +601,7 @@ class AlternativeRouting final
// //compute forward sharing // //compute forward sharing
// while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) && // while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
// (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) { // (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] << ")"; // packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex], // EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
// packed_alternate_path[aindex+1]); // packed_alternate_path[aindex+1]);
@@ -640,7 +640,7 @@ class AlternativeRouting final
const NodeID node = forward_heap.DeleteMin(); const NodeID node = forward_heap.DeleteMin();
const int weight = forward_heap.GetKey(node); const int weight = forward_heap.GetKey(node);
// const NodeID parentnode = forward_heap.GetData(node).parent; // 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 (" // edge ("
// << parentnode << "," << node << "), dist: " << weight; // << parentnode << "," << node << "), dist: " << weight;
@@ -665,11 +665,11 @@ class AlternativeRouting final
{ {
*middle_node = node; *middle_node = node;
*upper_bound_to_shortest_path_weight = new_weight; *upper_bound_to_shortest_path_weight = new_weight;
// util::SimpleLogger().Write() << "accepted middle_node " << *middle_node // util::Log() << "accepted middle_node " << *middle_node
// << " at // << " at
// weight " << new_weight; // weight " << new_weight;
// } else { // } else {
// util::SimpleLogger().Write() << "discarded middle_node " << *middle_node // util::Log() << "discarded middle_node " << *middle_node
// << " // << "
// at weight " << new_weight; // at weight " << new_weight;
} }
+1 -1
View File
@@ -2,7 +2,7 @@
#define TRIP_BRUTE_FORCE_HPP #define TRIP_BRUTE_FORCE_HPP
#include "util/dist_table_wrapper.hpp" #include "util/dist_table_wrapper.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include "osrm/json_container.hpp" #include "osrm/json_container.hpp"
@@ -3,7 +3,6 @@
#include "util/dist_table_wrapper.hpp" #include "util/dist_table_wrapper.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include "util/typedefs.hpp"
#include "osrm/json_container.hpp" #include "osrm/json_container.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
@@ -2,7 +2,7 @@
#define TRIP_NEAREST_NEIGHBOUR_HPP #define TRIP_NEAREST_NEIGHBOUR_HPP
#include "util/dist_table_wrapper.hpp" #include "util/dist_table_wrapper.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include "osrm/json_container.hpp" #include "osrm/json_container.hpp"
@@ -29,7 +29,6 @@
#include <memory> #include <memory>
#include <queue> #include <queue>
#include <string> #include <string>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
@@ -12,7 +12,7 @@
#include <limits> #include <limits>
#include <string> #include <string>
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/parsing_toolkit.hpp"
namespace osrm namespace osrm
{ {
@@ -109,13 +109,13 @@ inline unsigned parseDuration(const std::string &s)
inline std::string inline std::string
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right) 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, inline std::string applyAccessTokens(const std::string &lane_string,
const std::string &access_tokens) 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. // Takes a string representing a list separated by delim and canonicalizes containing spaces.
-2
View File
@@ -46,7 +46,6 @@ struct ExtractionWay
roundabout = false; roundabout = false;
circular = false; circular = false;
is_startpoint = true; is_startpoint = true;
is_access_restricted = false;
name.clear(); name.clear();
ref.clear(); ref.clear();
pronunciation.clear(); pronunciation.clear();
@@ -96,7 +95,6 @@ struct ExtractionWay
std::string turn_lanes_backward; std::string turn_lanes_backward;
bool roundabout; bool roundabout;
bool circular; bool circular;
bool is_access_restricted;
bool is_startpoint; bool is_startpoint;
TravelMode forward_travel_mode : 4; TravelMode forward_travel_mode : 4;
TravelMode backward_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/coordinate_extractor.hpp"
#include "extractor/guidance/intersection.hpp" #include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include <boost/optional.hpp>
namespace osrm namespace osrm
{ {
@@ -9,7 +9,6 @@
#include "util/attributes.hpp" #include "util/attributes.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
namespace osrm namespace osrm
+123 -39
View File
@@ -1,15 +1,23 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_ #ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_ #define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
#include <algorithm>
#include <functional>
#include <limits>
#include <string> #include <string>
#include <type_traits>
#include <vector> #include <vector>
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "util/bearing.hpp" #include "util/bearing.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
#include "util/typedefs.hpp" // EdgeID #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 osrm
{ {
namespace extractor namespace extractor
@@ -27,11 +35,18 @@ struct IntersectionShapeData
inline auto makeCompareShapeDataByBearing(const double base_bearing) inline auto makeCompareShapeDataByBearing(const double base_bearing)
{ {
return [base_bearing](const IntersectionShapeData &lhs, const IntersectionShapeData &rhs) { return [base_bearing](const auto &lhs, const auto &rhs) {
return util::bearing::angleBetweenBearings(base_bearing, lhs.bearing) < return util::angleBetweenBearings(base_bearing, lhs.bearing) <
util::bearing::angleBetweenBearings(base_bearing, rhs.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 // 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 // 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 // A Connected Road is the internal representation of a potential turn. Internally, we require
// full list of all connected roads to determine the outcome. // 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 // 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 // aaa(2)aa
// a - bbbbb // 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). // 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 // In addition, they can influence whether a turn is obvious or not. b->(2) would also be no
// turn-operation, // turn-operation, but rather a name change.
// but rather a name change.
// //
// If this were a normal intersection with // 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 // small helper function to print the content of a connected road
std::string toString(const ConnectedRoad &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>; 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>; 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>; 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 guidance
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm
@@ -35,6 +35,12 @@ class IntersectionGenerator
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const CompressedEdgeContainer &compressed_edge_container); 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; 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 * The shape also only comes with turn bearings, not with turn angles. All turn angles will be
* set to zero * set to zero
*/ */
OSRM_ATTR_WARN_UNUSED
IntersectionShape IntersectionShape
ComputeIntersectionShape(const NodeID center_node, ComputeIntersectionShape(const NodeID center_node,
const boost::optional<NodeID> sorting_base = boost::none, 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 // 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. // 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 // Here we follow the road until we either reach a dead end or find the next intersection with
// more than a single next road. // more than a single next road. This function skips over degree two nodes to find coorect input
IntersectionView GetActualNextIntersection(const NodeID starting_node, // for GetConnectedRoads.
const EdgeID via_edge, OSRM_ATTR_WARN_UNUSED
NodeID *resulting_from_node, std::pair<NodeID, EdgeID> SkipDegreeTwoNodes(const NodeID starting_node,
EdgeID *resulting_via_edge) const; const EdgeID via_edge) const;
// Allow access to the coordinate extractor for all owners // Allow access to the coordinate extractor for all owners
const CoordinateExtractor &GetCoordinateExtractor() const; const CoordinateExtractor &GetCoordinateExtractor() const;
@@ -3,15 +3,22 @@
#include "extractor/guidance/intersection.hpp" #include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp" #include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/node_based_graph_walker.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp" #include "extractor/suffix_table.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/name_announcements.hpp"
#include "util/name_table.hpp" #include "util/name_table.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
#include <algorithm>
#include <cstddef> #include <cstddef>
#include <utility>
#include <vector> #include <vector>
#include <boost/optional.hpp>
namespace osrm namespace osrm
{ {
namespace extractor namespace extractor
@@ -48,9 +55,7 @@ class IntersectionHandler
const util::NameTable &name_table; const util::NameTable &name_table;
const SuffixTable &street_name_suffix_table; const SuffixTable &street_name_suffix_table;
const IntersectionGenerator &intersection_generator; const IntersectionGenerator &intersection_generator;
const NodeBasedGraphWalker graph_walker; // for skipping traffic signal, distances etc.
// counts the number on allowed entry roads
std::size_t countValid(const Intersection &intersection) const;
// Decide on a basic turn types // Decide on a basic turn types
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const; 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 // 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 // other possible turns. The function will consider road categories and other inputs like the
// turn angles. // 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 // 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. // 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 begin,
const std::size_t end) const; 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; 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 guidance
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm
@@ -57,16 +57,17 @@ class IntersectionNormalizer
const IntersectionGenerator &intersection_generator; const IntersectionGenerator &intersection_generator;
// check if two indices in an intersection can be seen as a single road in the perceived /* 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 * intersection representation. See below for an example. Utility function for
// MergeSegregatedRoads. It also checks for neighboring merges. * MergeSegregatedRoads. It also checks for neighboring merges.
// This is due possible segments where multiple roads could end up being merged into one. * 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. * We only support merging two roads, not three or more, though.
// c c * c c
// / / * / /
// a - b -> a - b - (c,d) but not a - b d -> a,b,(cde) * a - b -> a - b - (c,d) but not a - b d -> a,b,(cde)
// \ \ * \ \
// d e * d e
*/
bool CanMerge(const NodeID intersection_node, bool CanMerge(const NodeID intersection_node,
const IntersectionShape &intersection, const IntersectionShape &intersection,
std::size_t first_index, std::size_t first_index,
@@ -3,9 +3,8 @@
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection_generator.hpp" #include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
@@ -43,7 +42,7 @@ class NodeBasedGraphWalker
boost::optional<std::pair<NodeID, EdgeID>> TraverseRoad(NodeID starting_at_node_id, boost::optional<std::pair<NodeID, EdgeID>> TraverseRoad(NodeID starting_at_node_id,
EdgeID following_edge_id, EdgeID following_edge_id,
accumulator_type &accumulator, accumulator_type &accumulator,
const selector_type &selector); const selector_type &selector) const;
private: private:
const util::NodeBasedDynamicGraph &node_based_graph; const util::NodeBasedDynamicGraph &node_based_graph;
@@ -141,7 +140,7 @@ boost::optional<std::pair<NodeID, EdgeID>>
NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id, NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
EdgeID current_edge_id, EdgeID current_edge_id,
accumulator_type &accumulator, 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 * 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 {}; 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 guidance
} // namespace extractor } // namespace extractor
} // namespace osrm } // 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 <cmath>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <unordered_map>
#include <osmium/osm.hpp> #include "extractor/guidance/constants.hpp"
namespace osrm namespace osrm
{ {
@@ -126,6 +125,22 @@ inline bool canBeSeenAsFork(const RoadClassification first, const RoadClassifica
return std::abs(static_cast<int>(first.GetPriority()) - return std::abs(static_cast<int>(first.GetPriority()) -
static_cast<int>(second.GetPriority())) <= 1; 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 guidance
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm
@@ -15,7 +15,6 @@
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include <unordered_set> #include <unordered_set>
#include <utility>
#include <vector> #include <vector>
namespace osrm namespace osrm
@@ -9,10 +9,10 @@
#include "util/name_table.hpp" #include "util/name_table.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
#include <cstddef>
#include <utility>
#include <vector> #include <vector>
#include <boost/optional.hpp>
namespace osrm namespace osrm
{ {
namespace extractor namespace extractor
@@ -22,7 +22,7 @@ namespace guidance
// Intersection handlers deal with all issues related to intersections. // Intersection handlers deal with all issues related to intersections.
// They assign appropriate turn operations to the TurnOperations. // They assign appropriate turn operations to the TurnOperations.
class SliproadHandler : public IntersectionHandler class SliproadHandler final : public IntersectionHandler
{ {
public: public:
SliproadHandler(const IntersectionGenerator &intersection_generator, SliproadHandler(const IntersectionGenerator &intersection_generator,
@@ -42,6 +42,37 @@ class SliproadHandler : public IntersectionHandler
Intersection operator()(const NodeID nid, Intersection operator()(const NodeID nid,
const EdgeID via_eid, const EdgeID via_eid,
Intersection intersection) const override final; 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 } // 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/motorway_handler.hpp"
#include "extractor/guidance/roundabout_handler.hpp" #include "extractor/guidance/roundabout_handler.hpp"
#include "extractor/guidance/sliproad_handler.hpp" #include "extractor/guidance/sliproad_handler.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_classification.hpp" #include "extractor/guidance/turn_classification.hpp"
#include "extractor/guidance/turn_handler.hpp" #include "extractor/guidance/turn_handler.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
@@ -1,21 +1,12 @@
#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_ #ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
#define 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/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/bearing_class.hpp"
#include "util/guidance/entry_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 <utility>
#include <vector>
namespace osrm namespace osrm
{ {
@@ -5,8 +5,6 @@
#include "extractor/guidance/intersection_generator.hpp" #include "extractor/guidance/intersection_generator.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include <string>
namespace osrm namespace osrm
{ {
namespace extractor namespace extractor
+158 -2
View File
@@ -1,11 +1,11 @@
#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_ #ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_ #define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
#include <algorithm>
#include <cstdint> #include <cstdint>
#include <boost/assert.hpp>
#include "extractor/guidance/roundabout_type.hpp" #include "extractor/guidance/roundabout_type.hpp"
#include "util/attributes.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
namespace osrm 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; 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 guidance
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm
@@ -4,7 +4,6 @@
#include "extractor/guidance/turn_lane_types.hpp" #include "extractor/guidance/turn_lane_types.hpp"
#include "util/attributes.hpp" #include "util/attributes.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include <string>
#include <vector> #include <vector>
namespace osrm namespace osrm
@@ -2,7 +2,6 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_HANDLER_HPP_ #define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp" #include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_analysis.hpp" #include "extractor/guidance/turn_analysis.hpp"
#include "extractor/guidance/turn_lane_data.hpp" #include "extractor/guidance/turn_lane_data.hpp"
#include "extractor/guidance/turn_lane_types.hpp" #include "extractor/guidance/turn_lane_types.hpp"
@@ -74,7 +73,7 @@ class TurnLaneHandler
std::vector<TurnLaneType::Mask> &turn_lane_masks, std::vector<TurnLaneType::Mask> &turn_lane_masks,
LaneDescriptionMap &lane_description_map, LaneDescriptionMap &lane_description_map,
const TurnAnalysis &turn_analysis, const TurnAnalysis &turn_analysis,
LaneDataIdMap &id_map); util::guidance::LaneDataIdMap &id_map);
~TurnLaneHandler(); ~TurnLaneHandler();
@@ -91,7 +90,7 @@ class TurnLaneHandler
std::vector<TurnLaneType::Mask> &turn_lane_masks; std::vector<TurnLaneType::Mask> &turn_lane_masks;
LaneDescriptionMap &lane_description_map; LaneDescriptionMap &lane_description_map;
const TurnAnalysis &turn_analysis; const TurnAnalysis &turn_analysis;
LaneDataIdMap &id_map; util::guidance::LaneDataIdMap &id_map;
// Find out which scenario we have to handle // Find out which scenario we have to handle
TurnLaneScenario deduceScenario(const NodeID at, TurnLaneScenario deduceScenario(const NodeID at,
@@ -2,7 +2,6 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_MATCHER_HPP_ #define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_MATCHER_HPP_
#include "extractor/guidance/intersection.hpp" #include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "extractor/guidance/turn_lane_data.hpp" #include "extractor/guidance/turn_lane_data.hpp"
@@ -10,8 +9,6 @@
#include "util/guidance/turn_lanes.hpp" #include "util/guidance/turn_lanes.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
#include <unordered_map>
namespace osrm namespace osrm
{ {
namespace extractor namespace extractor
@@ -47,7 +44,7 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
const LaneDataVector &lane_data, const LaneDataVector &lane_data,
const util::NodeBasedDynamicGraph &node_based_graph, const util::NodeBasedDynamicGraph &node_based_graph,
const LaneDescriptionID lane_string_id, const LaneDescriptionID lane_string_id,
LaneDataIdMap &lane_data_to_id); util::guidance::LaneDataIdMap &lane_data_to_id);
} // namespace lanes } // namespace lanes
} // namespace guidance } // namespace guidance
@@ -8,11 +8,9 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <boost/assert.hpp>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include "util/json_container.hpp" #include "util/json_container.hpp"
#include "util/simple_logger.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
namespace osrm namespace osrm
@@ -47,7 +47,6 @@ struct InternalExtractorEdge
false, // backward false, // backward
false, // roundabout false, // roundabout
false, // circular false, // circular
false, // access restricted
true, // can be startpoint true, // can be startpoint
TRAVEL_MODE_INACCESSIBLE, TRAVEL_MODE_INACCESSIBLE,
false, false,
@@ -64,7 +63,6 @@ struct InternalExtractorEdge
bool backward, bool backward,
bool roundabout, bool roundabout,
bool circular, bool circular,
bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split, bool is_split,
@@ -78,7 +76,6 @@ struct InternalExtractorEdge
backward, backward,
roundabout, roundabout,
circular, circular,
access_restricted,
startpoint, startpoint,
travel_mode, travel_mode,
is_split, is_split,
@@ -106,7 +103,6 @@ struct InternalExtractorEdge
false, // backward false, // backward
false, // roundabout false, // roundabout
false, // circular false, // circular
false, // access restricted
true, // can be startpoint true, // can be startpoint
TRAVEL_MODE_INACCESSIBLE, TRAVEL_MODE_INACCESSIBLE,
false, false,
@@ -123,7 +119,6 @@ struct InternalExtractorEdge
false, // backward false, // backward
false, // roundabout false, // roundabout
false, // circular false, // circular
false, // access restricted
true, // can be startpoint true, // can be startpoint
TRAVEL_MODE_INACCESSIBLE, TRAVEL_MODE_INACCESSIBLE,
false, false,
+4 -12
View File
@@ -23,7 +23,6 @@ struct NodeBasedEdge
bool backward, bool backward,
bool roundabout, bool roundabout,
bool circular, bool circular,
bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split, bool is_split,
@@ -40,7 +39,6 @@ struct NodeBasedEdge
bool backward : 1; bool backward : 1;
bool roundabout : 1; bool roundabout : 1;
bool circular : 1; bool circular : 1;
bool access_restricted : 1;
bool startpoint : 1; bool startpoint : 1;
bool is_split : 1; bool is_split : 1;
TravelMode travel_mode : 4; TravelMode travel_mode : 4;
@@ -58,7 +56,6 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
bool backward, bool backward,
bool roundabout, bool roundabout,
bool circular, bool circular,
bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split, bool is_split,
@@ -73,9 +70,8 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
inline NodeBasedEdge::NodeBasedEdge() inline NodeBasedEdge::NodeBasedEdge()
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false), : source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
backward(false), roundabout(false), circular(false), access_restricted(false), backward(false), roundabout(false), circular(false), startpoint(true), is_split(false),
startpoint(true), is_split(false), travel_mode(false), travel_mode(false), lane_description_id(INVALID_LANE_DESCRIPTIONID)
lane_description_id(INVALID_LANE_DESCRIPTIONID)
{ {
} }
@@ -87,16 +83,14 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
bool backward, bool backward,
bool roundabout, bool roundabout,
bool circular, bool circular,
bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split, bool is_split,
const LaneDescriptionID lane_description_id, const LaneDescriptionID lane_description_id,
guidance::RoadClassification road_classification) guidance::RoadClassification road_classification)
: source(source), target(target), name_id(name_id), weight(weight), forward(forward), : source(source), target(target), name_id(name_id), weight(weight), forward(forward),
backward(backward), roundabout(roundabout), circular(circular), backward(backward), roundabout(roundabout), circular(circular), startpoint(startpoint),
access_restricted(access_restricted), startpoint(startpoint), is_split(is_split), is_split(is_split), travel_mode(travel_mode), lane_description_id(lane_description_id),
travel_mode(travel_mode), lane_description_id(lane_description_id),
road_classification(std::move(road_classification)) road_classification(std::move(road_classification))
{ {
} }
@@ -126,7 +120,6 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
bool backward, bool backward,
bool roundabout, bool roundabout,
bool circular, bool circular,
bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split, bool is_split,
@@ -140,7 +133,6 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
backward, backward,
roundabout, roundabout,
circular, circular,
access_restricted,
startpoint, startpoint,
travel_mode, travel_mode,
is_split, is_split,
+4 -3
View File
@@ -66,13 +66,14 @@ class RasterGrid
} }
catch (std::exception const &ex) catch (std::exception const &ex)
{ {
throw util::exception( throw util::exception("Failed to read from raster source " + filepath.string() + ": " +
std::string("Failed to read from raster source with exception: ") + ex.what()); ex.what() + SOURCE_REF);
} }
if (!r || itr != end) 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/typedefs.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include "util/std_hash.hpp" #include "util/std_hash.hpp"
#include "util/timing_util.hpp" #include "util/timing_util.hpp"
@@ -146,8 +146,8 @@ template <typename GraphT> class TarjanSCC
if (size_of_current_component > 1000) if (size_of_current_component > 1000)
{ {
util::SimpleLogger().Write() << "large component [" << component_index util::Log() << "large component [" << component_index
<< "]=" << size_of_current_component; << "]=" << size_of_current_component;
} }
++component_index; ++component_index;
@@ -158,7 +158,7 @@ template <typename GraphT> class TarjanSCC
} }
TIMER_STOP(SCC_RUN); 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(), size_one_counter = std::count_if(component_size_vector.begin(),
component_size_vector.end(), component_size_vector.end(),
+3 -4
View File
@@ -6,7 +6,7 @@
#include "server/service_handler.hpp" #include "server/service_handler.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
@@ -36,8 +36,7 @@ class Server
static std::shared_ptr<Server> static std::shared_ptr<Server>
CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads) CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
{ {
util::SimpleLogger().Write() << "http 1.1 compression handled by zlib version " util::Log() << "http 1.1 compression handled by zlib version " << zlibVersion();
<< zlibVersion();
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency()); const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads); const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
return std::make_shared<Server>(ip_address, ip_port, real_num_threads); return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
@@ -62,7 +61,7 @@ class Server
acceptor.bind(endpoint); acceptor.bind(endpoint);
acceptor.listen(); acceptor.listen();
util::SimpleLogger().Write() << "Listening on: " << acceptor.local_endpoint(); util::Log() << "Listening on: " << acceptor.local_endpoint();
acceptor.async_accept( acceptor.async_accept(
new_connection->socket(), new_connection->socket(),
+1 -1
View File
@@ -5,7 +5,7 @@
#include "osrm/osrm.hpp" #include "osrm/osrm.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include <variant/variant.hpp> #include <mapbox/variant.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
+84 -12
View File
@@ -2,13 +2,13 @@
#define OSRM_STORAGE_IO_HPP_ #define OSRM_STORAGE_IO_HPP_
#include "util/exception.hpp" #include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/fingerprint.hpp" #include "util/fingerprint.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#include <boost/iostreams/seek.hpp> #include <boost/iostreams/seek.hpp>
#include <cerrno>
#include <cstring> #include <cstring>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
@@ -23,7 +23,7 @@ namespace io
class FileReader class FileReader
{ {
private: private:
const std::string filename; const boost::filesystem::path filepath;
boost::filesystem::ifstream input_stream; boost::filesystem::ifstream input_stream;
public: public:
@@ -47,16 +47,16 @@ class FileReader
{ {
} }
FileReader(const boost::filesystem::path &filename_, const FingerprintFlag flag) FileReader(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
: filename(filename_.string()) : filepath(filepath_)
{ {
input_stream.open(filename_, std::ios::binary); input_stream.open(filepath, std::ios::binary);
if (!input_stream) if (!input_stream)
throw util::exception("Error opening " + filename + ":" + std::strerror(errno)); throw util::exception("Error opening " + filepath.string());
if (flag == VerifyFingerprint && !ReadAndCheckFingerprint()) 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()) if (result.eof())
{ {
throw util::exception("Error reading from " + filename + throw util::exception("Error reading from " + filepath.string() +
": Unexpected end of file"); ": 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); 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 // EOF is OK here, everything else, re-throw
if (!input_stream.eof()) if (!input_stream.eof())
@@ -170,6 +170,78 @@ class FileReader
return thisline; 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 "storage/io.hpp"
#include "util/exception.hpp" #include "util/exception.hpp"
#include "util/fingerprint.hpp" #include "util/fingerprint.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include "util/static_graph.hpp" #include "util/static_graph.hpp"
#include <boost/filesystem/fstream.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>(); const auto fingerprint_loaded = input_file.ReadOne<util::FingerPrint>();
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid)) if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
{ {
util::SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n" util::Log(logWARNING) << ".hsgr was prepared with different build.\n"
"Reprocess to get rid of this warning."; "Reprocess to get rid of this warning.";
} }
HSGRHeader header; HSGRHeader header;
+6 -5
View File
@@ -2,7 +2,8 @@
#define SHARED_DATA_TYPE_HPP #define SHARED_DATA_TYPE_HPP
#include "util/exception.hpp" #include "util/exception.hpp"
#include "util/simple_logger.hpp" #include "util/exception_utils.hpp"
#include "util/log.hpp"
#include <array> #include <array>
#include <cstdint> #include <cstdint>
@@ -175,13 +176,13 @@ struct DataLayout
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr); bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
if (!start_canary_alive) if (!start_canary_alive)
{ {
throw util::exception(std::string("Start canary of block corrupted. (") + throw util::exception("Start canary of block corrupted. (" +
block_id_to_name[bid] + ")"); std::string(block_id_to_name[bid]) + ")" + SOURCE_REF);
} }
if (!end_canary_alive) if (!end_canary_alive)
{ {
throw util::exception(std::string("End canary of block corrupted. (") + throw util::exception("End canary of block corrupted. (" +
block_id_to_name[bid] + ")"); std::string(block_id_to_name[bid]) + ")" + SOURCE_REF);
} }
} }
+13 -14
View File
@@ -2,7 +2,8 @@
#define SHARED_MEMORY_HPP #define SHARED_MEMORY_HPP
#include "util/exception.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.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
@@ -62,8 +63,7 @@ class SharedMemory
{ {
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key); shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key);
util::SimpleLogger().Write(logDEBUG) << "opening " << shm.get_shmid() << " from id " util::Log(logDEBUG) << "opening " << shm.get_shmid() << " from id " << id;
<< id;
region = boost::interprocess::mapped_region(shm, access); region = boost::interprocess::mapped_region(shm, access);
} }
@@ -72,14 +72,14 @@ class SharedMemory
{ {
shm = boost::interprocess::xsi_shared_memory( shm = boost::interprocess::xsi_shared_memory(
boost::interprocess::open_or_create, key, size); boost::interprocess::open_or_create, key, size);
util::SimpleLogger().Write(logDEBUG) << "opening/creating " << shm.get_shmid() util::Log(logDEBUG) << "opening/creating " << shm.get_shmid() << " from id " << id
<< " from id " << id << " with size " << size; << " with size " << size;
#ifdef __linux__ #ifdef __linux__
if (-1 == shmctl(shm.get_shmid(), SHM_LOCK, nullptr)) if (-1 == shmctl(shm.get_shmid(), SHM_LOCK, nullptr))
{ {
if (ENOMEM == errno) 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 #endif
@@ -133,7 +133,7 @@ class SharedMemory
static bool Remove(const boost::interprocess::xsi_key &key) static bool Remove(const boost::interprocess::xsi_key &key)
{ {
boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, 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()); return boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
} }
@@ -173,8 +173,7 @@ class SharedMemory
shm.truncate(size); shm.truncate(size);
region = boost::interprocess::mapped_region(shm, access); region = boost::interprocess::mapped_region(shm, access);
util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size util::Log(logDEBUG) << "writeable memory allocated " << size << " bytes";
<< " bytes";
} }
} }
@@ -221,7 +220,7 @@ class SharedMemory
static bool Remove(char *key) 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); 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) if (0 == size)
{ {
throw util::exception("lock file does not exist, exiting"); throw util::exception("lock file does not exist, exiting" + SOURCE_REF);
} }
else else
{ {
@@ -253,9 +252,9 @@ makeSharedMemory(const IdentifierT &id, const uint64_t size = 0, bool read_write
} }
catch (const boost::interprocess::interprocess_exception &e) catch (const boost::interprocess::interprocess_exception &e)
{ {
util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code " util::Log(logERROR) << "Error while attempting to allocate shared memory: " << e.what()
<< e.get_error_code(); << ", code " << e.get_error_code();
throw util::exception(e.what()); throw util::exception(e.what() + SOURCE_REF);
} }
} }
} }
+10 -1
View File
@@ -1,7 +1,9 @@
#ifndef BEARING_HPP #ifndef BEARING_HPP
#define BEARING_HPP #define BEARING_HPP
#include <algorithm>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <cmath>
#include <string> #include <string>
namespace osrm 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; return normalized_B - range <= normalized_A && normalized_A <= normalized_B + range;
} }
} }
} // namespace bearing
inline double reverseBearing(const double 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; 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 util
} // namespace osrm } // namespace osrm
+3
View File
@@ -136,6 +136,9 @@ bool isCCW(const Coordinate first_coordinate,
const Coordinate second_coordinate, const Coordinate second_coordinate,
const Coordinate third_coordinate); const Coordinate third_coordinate);
std::pair<util::Coordinate, util::Coordinate>
leastSquareRegression(const std::vector<util::Coordinate> &coordinates);
} // ns coordinate_calculation } // ns coordinate_calculation
} // ns util } // ns util
} // ns osrm } // 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.hpp"
#include "util/exception_utils.hpp"
#include <boost/uuid/name_generator.hpp> #include <boost/uuid/name_generator.hpp>
#include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_generators.hpp>
@@ -57,7 +58,7 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
{ {
if (!IsMagicNumberOK(other)) 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); 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)) 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); 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)) 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); 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)) 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); 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_container.hpp"
#include "util/json_renderer.hpp" #include "util/json_renderer.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
namespace osrm namespace osrm
{ {
@@ -63,11 +63,11 @@ class GeojsonLogger
// make sure to syncronize logging output, our writing should be sequential // make sure to syncronize logging output, our writing should be sequential
std::lock_guard<std::mutex> guard(lock); 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)) if (!ofs.is_open() || (nullptr == policy))
{ {
// this can only happend between two guards when concurrent writing occurs throw util::exception("Trying to use the geojson printer without an open logger.");
return false;
} }
// use our policy to convert the arguments into geojson, this can be done in parallel // 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 // out on log output. Such a sad life
if (ofs.is_open()) if (ofs.is_open())
{ {
util::SimpleLogger().Write(logWARNING) util::Log(logWARNING)
<< "Overwriting " << logfile << "Overwriting " << logfile
<< ". Is this desired behaviour? If this message occurs more than once rethink the " << ". Is this desired behaviour? If this message occurs more than once rethink the "
"location of your Logger Guard."; "location of your Logger Guard.";
+5 -5
View File
@@ -8,7 +8,7 @@
#include "storage/io.hpp" #include "storage/io.hpp"
#include "util/exception.hpp" #include "util/exception.hpp"
#include "util/fingerprint.hpp" #include "util/fingerprint.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
@@ -60,7 +60,7 @@ NodeID loadNodesFromFile(storage::io::FileReader &file_reader,
std::vector<extractor::QueryNode> &node_array) std::vector<extractor::QueryNode> &node_array)
{ {
NodeID number_of_nodes = file_reader.ReadElementCount32(); 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); 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)); BOOST_ASSERT(sizeof(EdgeID) == sizeof(number_of_edges));
edge_list.resize(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); file_reader.ReadInto(edge_list.data(), number_of_edges);
BOOST_ASSERT(edge_list.size() > 0); BOOST_ASSERT(edge_list.size() > 0);
#ifndef NDEBUG #ifndef NDEBUG
SimpleLogger().Write() << "Validating loaded edges..."; Log() << "Validating loaded edges...";
tbb::parallel_sort( tbb::parallel_sort(
edge_list.begin(), edge_list.begin(),
edge_list.end(), edge_list.end(),
@@ -129,7 +129,7 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
} }
#endif #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; return number_of_edges;
} }
@@ -1,26 +1,20 @@
#ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ #ifndef OSRM_UTIL_GUIDANCE_NAME_ANNOUNCEMENT_HPP_
#define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ #define OSRM_UTIL_GUIDANCE_NAME_ANNOUNCEMENT_HPP_
/* A set of tools required for guidance in both pre and post-processing */ /* 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 "extractor/suffix_table.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/phantom_node.hpp"
#include "util/attributes.hpp" #include "util/attributes.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/name_table.hpp" #include "util/name_table.hpp"
#include "util/simple_logger.hpp" #include "util/typedefs.hpp"
#include <algorithm> #include <algorithm>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
namespace osrm namespace osrm
{ {
@@ -29,122 +23,6 @@ namespace util
namespace guidance 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 // Name Change Logic
// Used both during Extraction as well as during Post-Processing // 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 util
} // namespace osrm } // 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 <cstddef>
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
#include <unordered_map>
#include <vector> #include <vector>
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
@@ -96,6 +97,8 @@ class LaneTupleIdPair
} }
}; };
using LaneDataIdMap = std::unordered_map<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
} // namespace guidance } // namespace guidance
} // namespace util } // namespace util
} // namespace osrm } // namespace osrm
+17 -11
View File
@@ -1,7 +1,7 @@
#ifndef OSRM_INCLUDE_UTIL_IO_HPP_ #ifndef OSRM_INCLUDE_UTIL_IO_HPP_
#define 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/filesystem.hpp>
#include <boost/numeric/conversion/cast.hpp> #include <boost/numeric/conversion/cast.hpp>
@@ -54,7 +54,8 @@ template <typename simple_type>
bool serializeVectorIntoAdjacencyArray(const std::string &filename, bool serializeVectorIntoAdjacencyArray(const std::string &filename,
const std::vector<std::vector<simple_type>> &data) 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; std::vector<std::uint32_t> offsets;
offsets.reserve(data.size() + 1); offsets.reserve(data.size() + 1);
std::uint64_t current_offset = 0; std::uint64_t current_offset = 0;
@@ -64,18 +65,23 @@ bool serializeVectorIntoAdjacencyArray(const std::string &filename,
current_offset += vec.size(); current_offset += vec.size();
offsets.push_back(boost::numeric_cast<std::uint32_t>(current_offset)); offsets.push_back(boost::numeric_cast<std::uint32_t>(current_offset));
} }
if (!serializeVector(out_stream, offsets))
return false;
std::vector<simple_type> all_data; std::vector<simple_type> all_data;
all_data.reserve(offsets.back()); all_data.reserve(offsets.back());
for (auto const &vec : data) for (auto const &vec : data)
all_data.insert(all_data.end(), vec.begin(), vec.end()); all_data.insert(all_data.end(), vec.begin(), vec.end());
if (!serializeVector(out_stream, all_data)) if (!file.SerializeVector(offsets))
{
return false; 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> 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 // offsets have to match up with the size of the data
if (offsets.empty() || (offsets.back() != boost::numeric_cast<std::uint32_t>(data.size()))) if (offsets.empty() || (offsets.back() != boost::numeric_cast<std::uint32_t>(data.size())))
throw util::exception("Error in " + filename + (offsets.empty() throw util::exception(
? "Offsets are empty" "Error in " + filename +
: "Offset and data size do not match")); (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) 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; ++chunk_count;
flag_stream.write(reinterpret_cast<const char *>(&chunk), sizeof(chunk)); flag_stream.write(reinterpret_cast<const char *>(&chunk), sizeof(chunk));
} }
SimpleLogger().Write() << "Wrote " << number_of_bits << " bits in " << chunk_count Log() << "Wrote " << number_of_bits << " bits in " << chunk_count << " chunks (Flags).";
<< " chunks (Flags).";
return static_cast<bool>(flag_stream); 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 #ifndef JSON_CONTAINER_HPP
#define JSON_CONTAINER_HPP #define JSON_CONTAINER_HPP
#include <variant/variant.hpp> #include <mapbox/variant.hpp>
#include <string> #include <string>
#include <unordered_map> #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() NodeBasedEdgeData()
: distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID), : distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
name_id(std::numeric_limits<unsigned>::max()), access_restricted(false), reversed(false), name_id(std::numeric_limits<unsigned>::max()), reversed(false), roundabout(false),
roundabout(false), circular(false), travel_mode(TRAVEL_MODE_INACCESSIBLE), circular(false), travel_mode(TRAVEL_MODE_INACCESSIBLE),
lane_description_id(INVALID_LANE_DESCRIPTIONID) lane_description_id(INVALID_LANE_DESCRIPTIONID)
{ {
} }
@@ -28,24 +28,21 @@ struct NodeBasedEdgeData
NodeBasedEdgeData(int distance, NodeBasedEdgeData(int distance,
unsigned edge_id, unsigned edge_id,
unsigned name_id, unsigned name_id,
bool access_restricted,
bool reversed, bool reversed,
bool roundabout, bool roundabout,
bool circular, bool circular,
bool startpoint, bool startpoint,
extractor::TravelMode travel_mode, extractor::TravelMode travel_mode,
const LaneDescriptionID lane_description_id) const LaneDescriptionID lane_description_id)
: distance(distance), edge_id(edge_id), name_id(name_id), : distance(distance), edge_id(edge_id), name_id(name_id), reversed(reversed),
access_restricted(access_restricted), reversed(reversed), roundabout(roundabout), roundabout(roundabout), circular(circular), startpoint(startpoint),
circular(circular), startpoint(startpoint), travel_mode(travel_mode), travel_mode(travel_mode), lane_description_id(lane_description_id)
lane_description_id(lane_description_id)
{ {
} }
int distance; int distance;
unsigned edge_id; unsigned edge_id;
unsigned name_id; unsigned name_id;
bool access_restricted : 1;
bool reversed : 1; bool reversed : 1;
bool roundabout : 1; bool roundabout : 1;
bool circular : 1; bool circular : 1;
@@ -58,7 +55,6 @@ struct NodeBasedEdgeData
{ {
return (reversed == other.reversed) && (roundabout == other.roundabout) && return (reversed == other.reversed) && (roundabout == other.roundabout) &&
(circular == other.circular) && (startpoint == other.startpoint) && (circular == other.circular) && (startpoint == other.startpoint) &&
(access_restricted == other.access_restricted) &&
(travel_mode == other.travel_mode) && (travel_mode == other.travel_mode) &&
(road_classification == other.road_classification); (road_classification == other.road_classification);
} }
@@ -88,7 +84,6 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
output_edge.data.roundabout = input_edge.roundabout; output_edge.data.roundabout = input_edge.roundabout;
output_edge.data.circular = input_edge.circular; output_edge.data.circular = input_edge.circular;
output_edge.data.name_id = input_edge.name_id; 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.travel_mode = input_edge.travel_mode;
output_edge.data.startpoint = input_edge.startpoint; output_edge.data.startpoint = input_edge.startpoint;
output_edge.data.road_classification = input_edge.road_classification; output_edge.data.road_classification = input_edge.road_classification;
+11 -7
View File
@@ -5,6 +5,7 @@
#include <iostream> #include <iostream>
#include "util/isatty.hpp" #include "util/isatty.hpp"
#include "util/log.hpp"
namespace osrm namespace osrm
{ {
@@ -13,8 +14,13 @@ namespace util
class Percent class Percent
{ {
Log &log;
public: 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 // Reinitializes
void Reinit(unsigned max_value, unsigned step = 5) void Reinit(unsigned max_value, unsigned step = 5)
@@ -36,7 +42,7 @@ class Percent
PrintPercent(current_value / static_cast<double>(m_max_value) * 100.); PrintPercent(current_value / static_cast<double>(m_max_value) * 100.);
} }
if (current_value + 1 == m_max_value) if (current_value + 1 == m_max_value)
std::cout << " 100%" << std::endl; log << " 100%";
} }
void PrintIncrement() void PrintIncrement()
@@ -67,19 +73,17 @@ class Percent
m_last_percent += m_step; m_last_percent += m_step;
if (m_last_percent % 10 == 0) if (m_last_percent % 10 == 0)
{ {
std::cout << " " << m_last_percent << "% "; log << " " << m_last_percent << "% ";
} }
else else
{ {
std::cout << "."; log << ".";
} }
// When not on a TTY, print newlines after each progress indicator so // When not on a TTY, print newlines after each progress indicator so
// so that progress is visible to line-buffered logging systems // so that progress is visible to line-buffered logging systems
if (!IsStdoutATTY()) if (!IsStdoutATTY())
std::cout << std::endl; log << "" << std::endl;
std::cout.flush();
} }
} }
}; };
@@ -3,7 +3,7 @@
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include <cstddef> #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) catch (const std::exception &exc)
{ {
throw exception(boost::str(boost::format("Leaf file %1% mapping failed: %2%") % 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 } 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_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = 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" } 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 } 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" } restrictions = { "bicycle" }
unsafe_highway_list = { ["primary"] = true, ["secondary"] = true, ["tertiary"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true} 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 get_turn_lanes = require("lib/guidance").get_turn_lanes
local Set = require('lib/set') local Set = require('lib/set')
local Sequence = require('lib/sequence') local Sequence = require('lib/sequence')
local Directional = require('lib/directional')
-- Begin of globals -- Begin of globals
barrier_whitelist = Set { barrier_whitelist = Set {
@@ -39,11 +40,6 @@ access_tag_blacklist = Set {
'delivery' 'delivery'
} }
access_tag_restricted = Set {
'destination',
'delivery'
}
access_tags_hierarchy = Sequence { access_tags_hierarchy = Sequence {
'motorcar', 'motorcar',
'motor_vehicle', 'motor_vehicle',
@@ -51,11 +47,6 @@ access_tags_hierarchy = Sequence {
'access' 'access'
} }
service_tag_restricted = Set {
'parking_aisle',
'parking'
}
service_tag_forbidden = Set { service_tag_forbidden = Set {
'emergency_access' 'emergency_access'
} }
@@ -287,69 +278,51 @@ end
-- abort early if this way is obviouslt not routable -- abort early if this way is obviouslt not routable
function initial_routability_check(way,result,data) 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('route') ~= nil or
way:get_value_by_key('bridge') ~= nil way:get_value_by_key('bridge') ~= nil
end end
-- handle high occupancy vehicle tags -- all lanes restricted to hov vehicles?
function handle_hov(way,result) local function has_all_designated_hov_lanes(lanes)
-- respect user-preference for HOV-only ways if not lanes then
if ignore_hov_ways then return false
local hov = way:get_value_by_key("hov") end
if "designated" == hov then -- 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 return false
end end
end
return true
end
-- also respect user-preference for HOV-only ways when all lanes are HOV-designated -- handle high occupancy vehicle tags
local function has_all_designated_hov_lanes(lanes) function handle_hov(way,result,data)
local all = true -- respect user-preference for HOV
-- This gmatch call effectively splits the string on | chars. if not ignore_hov_ways then
-- we append an extra | to the end so that we can match the final part return
for lane in (lanes .. '|'):gmatch("([^|]*)|") do end
if lane and lane ~= "designated" then
all = false
break
end
end
return all
end
local hov_lanes = way:get_value_by_key("hov:lanes") -- check if way is hov only
local hov_lanes_forward = way:get_value_by_key("hov:lanes:forward") local hov = way:get_value_by_key("hov")
local hov_lanes_backward = way:get_value_by_key("hov:lanes:backward") if "designated" == hov then
return false
end
local hov_all_designated = hov_lanes and -- check if all lanes are hov only
has_all_designated_hov_lanes(hov_lanes) 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 hov_all_designated_forward = hov_lanes_forward and local inaccessible_backward = has_all_designated_hov_lanes(hov_lanes_backward)
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
if inaccessible_forward then
result.forward_mode = mode.inaccessible
end
if inaccessible_backward then
result.backward_mode = mode.inaccessible
end end
end end
@@ -394,8 +367,18 @@ end
-- check accessibility by traversing our acces tag hierarchy -- check accessibility by traversing our acces tag hierarchy
function handle_access(way,result,data) function handle_access(way,result,data)
data.access = find_access_tag(way, access_tags_hierarchy) data.forward_access, data.backward_access =
if access_tag_blacklist[data.access] then 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 return false
end end
end end
@@ -440,30 +423,21 @@ end
-- handle speed (excluding maxspeed) -- handle speed (excluding maxspeed)
function handle_speed(way,result,data) function handle_speed(way,result,data)
if result.forward_speed == -1 then if result.forward_speed == -1 then
local highway_speed = speed_profile[way:get_value_by_key("highway")] local highway_speed = speed_profile[data.highway]
local max_speed = parse_maxspeed( way:get_value_by_key("maxspeed") )
-- Set the avg speed on the way if it is accessible by road class -- Set the avg speed on the way if it is accessible by road class
if highway_speed then if highway_speed then
if max_speed and max_speed > highway_speed then result.forward_speed = highway_speed
result.forward_speed = max_speed result.backward_speed = highway_speed
result.backward_speed = max_speed
-- max_speed = math.huge
else
result.forward_speed = highway_speed
result.backward_speed = highway_speed
end
else else
-- Set the avg speed on ways that are marked accessible -- 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"] result.forward_speed = speed_profile["default"]
end
if access_tag_whitelist[data.backward_access] then
result.backward_speed = speed_profile["default"] result.backward_speed = speed_profile["default"]
end end
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 end
if -1 == result.forward_speed and -1 == result.backward_speed then 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_side_roads(way,result) == false then return false end
if handle_surface(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_speed_scaling(way,result) == false then return false end
if handle_alternating_speed(way,result) == false then return false end if handle_alternating_speed(way,result) == false then return false end
end end
@@ -529,23 +503,15 @@ function handle_names(way,result)
end end
-- handle turn lanes -- handle turn lanes
function handle_turn_lanes(way,result) function handle_turn_lanes(way,result,data)
local turn_lanes = '' local forward, backward = get_turn_lanes(way,data)
local turn_lanes_forward = ''
local turn_lanes_backward = ''
turn_lanes, turn_lanes_forward, turn_lanes_backward = get_turn_lanes(way) if forward then
if turn_lanes and turn_lanes ~= '' then result.turn_lanes_forward = forward
result.turn_lanes_forward = turn_lanes; end
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 turn_lanes_backward and turn_lanes_backward ~= '' then if backward then
result.turn_lanes_backward = turn_lanes_backward; result.turn_lanes_backward = backward
end
end end
end end
@@ -565,22 +531,10 @@ function handle_roundabouts(way,result)
end end
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 -- service roads
function handle_service(way,result) function handle_service(way,result)
local service = way:get_value_by_key("service") local service = way:get_value_by_key("service")
if service then 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 -- Set don't allow access to certain service roads
if service_tag_forbidden[service] then if service_tag_forbidden[service] then
result.forward_mode = mode.inaccessible result.forward_mode = mode.inaccessible
@@ -633,69 +587,55 @@ function handle_speed_scaling(way,result)
end end
end end
-- oneways -- handle oneways tags
function handle_oneway(way,result) function handle_oneway(way,result,data)
local oneway = way:get_value_by_key("oneway") local oneway = way:get_value_by_key("oneway")
data.oneway = oneway
if obey_oneway then if obey_oneway then
if oneway == "-1" then if oneway == "-1" then
data.is_reverse_oneway = true
result.forward_mode = mode.inaccessible result.forward_mode = mode.inaccessible
local is_forward = false
local destination = get_destination(way, is_forward)
result.destinations = canonicalizeStringList(destination, ",")
elseif oneway == "yes" or elseif oneway == "yes" or
oneway == "1" or oneway == "1" or
oneway == "true" or oneway == "true" then
way:get_value_by_key("junction") == "roundabout" or data.is_forward_oneway = true
way:get_value_by_key("junction") == "circular" or
(way:get_value_by_key("highway") == "motorway" and oneway ~= "no") then
result.backward_mode = mode.inaccessible result.backward_mode = mode.inaccessible
else
local is_forward = true local junction = way:get_value_by_key("junction")
local destination = get_destination(way, is_forward) if data.highway == "motorway" or
result.destinations = canonicalizeStringList(destination, ",") 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 end
end end
-- maxspeed and advisory maxspeed -- handle destination tags
function handle_maxspeed(way,result) function handle_destinations(way,result,data)
-- Override speed settings if explicit forward/backward maxspeeds are given if data.is_forward_oneway or data.is_reverse_oneway then
local maxspeed_forward = parse_maxspeed(way:get_value_by_key("maxspeed:forward")) local destination = get_destination(way, data.is_forward_oneway)
local maxspeed_backward = parse_maxspeed(way:get_value_by_key("maxspeed:backward")) result.destinations = canonicalizeStringList(destination, ",")
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
end end
if maxspeed_backward and maxspeed_backward > 0 then end
result.backward_speed = maxspeed_backward
-- 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 end
-- Override speed settings if advisory forward/backward maxspeeds are given if backward and backward > 0 then
local advisory_speed = parse_maxspeed(way:get_value_by_key("maxspeed:advisory")) result.backward_speed = backward
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
end end
end end
@@ -713,6 +653,7 @@ function handle_alternating_speed(way,result)
end end
end end
-- determine if this way can be used as a start/end point for routing -- determine if this way can be used as a start/end point for routing
function handle_startpoint(way,result) function handle_startpoint(way,result)
-- only allow this road as start point if it not a ferry -- only allow this road as start point if it not a ferry
@@ -721,8 +662,8 @@ function handle_startpoint(way,result)
end end
-- set the road classification based on guidance globals configuration -- set the road classification based on guidance globals configuration
function handle_classification(way,result) function handle_classification(way,result,data)
set_classification(way:get_value_by_key("highway"),result,way) set_classification(data.highway,result,way)
end end
-- main entry point for processsing a way -- main entry point for processsing a way
@@ -754,8 +695,11 @@ function way_function(way, result)
-- access tags, e.g: motorcar, motor_vehicle, vehicle -- access tags, e.g: motorcar, motor_vehicle, vehicle
if handle_access(way,result,data) == false then return end if handle_access(way,result,data) == false then return end
-- check high occupancy vehicle restrictions -- check whether forward/backward directons are routable
if handle_hov(way,result) == false then return end 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 -- check whether we're using a special transport mode
if handle_ferries(way,result) == false then return end if handle_ferries(way,result) == false then return end
@@ -764,27 +708,19 @@ function way_function(way, result)
-- handle service road restrictions -- handle service road restrictions
if handle_service(way,result) == false then return end if handle_service(way,result) == false then return end
-- check whether forward/backward directons are routable -- check high occupancy vehicle restrictions
if handle_oneway(way,result) == false then return end if handle_hov(way,result,data) == false then return end
-- compute speed taking into account way type, maxspeed tags, etc. -- compute speed taking into account way type, maxspeed tags, etc.
if handle_speed(way,result,data) == false then return end if handle_speed(way,result,data) == false then return end
-- handle turn lanes and road classification, used for guidance -- handle turn lanes and road classification, used for guidance
if handle_turn_lanes(way,result) == false then return end if handle_turn_lanes(way,result,data) == false then return end
if handle_classification(way,result) == false then return end if handle_classification(way,result,data) == false then return end
-- handle various other flags -- handle various other flags
if handle_roundabouts(way,result) == false then return end if handle_roundabouts(way,result) == false then return end
if handle_startpoint(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 -- set name, ref and pronunciation
if handle_names(way,result) == false then return end 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 -- input tags, normally extracted from OSM data
local way = { local way = {
highway = 'motorway', highway = 'primary',
name = 'Main Street', name = 'Main Street',
--access = 'no'
["access:forward"] = 'no'
--width = '3', --width = '3',
--maxspeed = '30', --maxspeed = '30',
--['maxspeed:advisory'] = '25', --['maxspeed:advisory'] = '25',
@@ -56,13 +58,32 @@ local way = {
--route = 'ferry', --route = 'ferry',
--duration = '00:01:00', --duration = '00:01:00',
--hov = 'designated', --hov = 'designated',
--access = 'no' --hov:lanes:forward"] = 'designated',
--destination = 'Berlin', --destination = 'Berlin',
["destination:ref"] = 'Nuremberg', --["destination:ref"] = 'Nuremberg',
--["destination:ref:forward"] = 'Hamburg;Dresden', --["destination:ref:forward"] = 'Hamburg;Dresden',
} }
-- tag function normally provided via C++ -- tag function normally provided via C++
function way:get_value_by_key(k) 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] return self[k]
end end
@@ -83,6 +104,27 @@ function canonicalizeStringList(str)
return str return str
end 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++ -- start state of result table, normally set form C++
local result = { local result = {
road_classification = {}, road_classification = {},
@@ -100,3 +142,9 @@ way_function(way,result)
pprint(way) pprint(way)
print("=>") print("=>")
pprint(result) 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} 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_whitelist = { ["yes"] = true, ["foot"] = true, ["permissive"] = true, ["designated"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = 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" } access_tags_hierarchy = { "foot", "access" }
service_tag_restricted = { ["parking_aisle"] = true }
ignore_in_grid = { ["ferry"] = true } ignore_in_grid = { ["ferry"] = true }
restrictions = { "foot" } 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 = {} local Guidance = {}
-- Guidance: Default Mapping from roads to types/priorities -- Guidance: Default Mapping from roads to types/priorities
highway_classes = { ["motorway"] = road_priority_class.motorway, highway_classes = {
["motorway_link"] = road_priority_class.link_road, motorway = road_priority_class.motorway,
["trunk"] = road_priority_class.trunk, motorway_link = road_priority_class.link_road,
["trunk_link"] = road_priority_class.link_road, trunk = road_priority_class.trunk,
["primary"] = road_priority_class.primary, trunk_link = road_priority_class.link_road,
["primary_link"] = road_priority_class.link_road, primary = road_priority_class.primary,
["secondary"] = road_priority_class.secondary, primary_link = road_priority_class.link_road,
["secondary_link"] = road_priority_class.link_road, secondary = road_priority_class.secondary,
["tertiary"] = road_priority_class.tertiary, secondary_link = road_priority_class.link_road,
["tertiary_link"] = road_priority_class.link_road, tertiary = road_priority_class.tertiary,
["unclassified"] = road_priority_class.side_residential, tertiary_link = road_priority_class.link_road,
["residential"] = road_priority_class.side_residential, unclassified = road_priority_class.side_residential,
["service"] = road_priority_class.connectivity, residential = road_priority_class.side_residential,
["living_street"] = road_priority_class.main_residential, service = road_priority_class.connectivity,
["track"] = road_priority_class.bike_path, living_street = road_priority_class.main_residential,
["path"] = road_priority_class.bike_path, track = road_priority_class.bike_path,
["footway"] = road_priority_class.foot_path, path = road_priority_class.bike_path,
["pedestrian"] = road_priority_class.foot_path, footway = road_priority_class.foot_path,
["steps"] = road_priority_class.foot_path} pedestrian = road_priority_class.foot_path,
steps = road_priority_class.foot_path
}
default_highway_class = road_priority_class.connectivity; 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 -- these road types are set with a car in mind. For bicycle/walk we probably need different ones
road_types = { ["motorway"] = true, road_types = Set {
["motorway_link"] = true, 'motorway',
["trunk"] = true, 'motorway_link',
["trunk_link"] = true, 'trunk',
["primary"] = true, 'trunk_link',
["primary_link"] = true, 'primary',
["secondary"] = true, 'primary_link',
["secondary_link"] = true, 'secondary',
["tertiary"] = true, 'secondary_link',
["tertiary_link"] = true, 'tertiary',
["unclassified"] = true, 'tertiary_link',
["residential"] = true, 'unclassified',
["living_street"] = true } '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) function Guidance.set_classification (highway, result, input_way)
if motorway_types[highway] then if motorway_types[highway] then
result.road_classification.motorway_class = true; result.road_classification.motorway_class = true;
end end
if link_types[highway] then if link_types[highway] then
result.road_classification.link_class = true; result.road_classification.link_class = true;
end end
if highway_classes[highway] ~= nil then if highway_classes[highway] ~= nil then
result.road_classification.road_priority_class = highway_classes[highway] result.road_classification.road_priority_class = highway_classes[highway]
else else
result.road_classification.road_priority_class = default_highway_class result.road_classification.road_priority_class = default_highway_class
end end
if road_types[highway] then if road_types[highway] then
result.road_classification.may_be_ignored = false; result.road_classification.may_be_ignored = false;
else else
result.road_classification.may_be_ignored = true; result.road_classification.may_be_ignored = true;
end end
local lane_count = input_way:get_value_by_key("lanes") local lane_count = input_way:get_value_by_key("lanes")
if lane_count then if lane_count then
local lc = tonumber(lane_count) local lc = tonumber(lane_count)
if lc ~= nil then if lc ~= nil then
result.road_classification.num_lanes = lc 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
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 end
-- returns forward,backward psv lane count -- returns forward,backward psv lane count
local function get_psv_counts(way) local function get_psv_counts(way,data)
local psv = way:get_value_by_key("lanes:psv") local psv_forward, psv_backward = Directional.get_values_by_key(way,data,'lanes:psv')
local psv_forward = way:get_value_by_key("lanes:psv:forward"); if psv_forward then
local psv_backward = way:get_value_by_key("lanes:psv:backward"); psv_forward = tonumber(psv_forward)
end
local fw = 0; if psv_backward then
local bw = 0; psv_backward = tonumber(psv_backward)
if psv then end
fw = tonumber(psv) return psv_forward or 0,
if( fw == nil ) then psv_backward or 0
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
end end
-- trims lane string with regard to supported lanes -- trims lane string with regard to supported lanes
local function process_lanes(turn_lane,vehicle_lane,first_count,second_count) local function process_lanes(turn_lanes,vehicle_lanes,first_count,second_count)
if turn_lane then if turn_lanes then
if vehicle_lane then if vehicle_lanes then
turn_lane = applyAccessTokens(turn_lane,vehicle_lane) return applyAccessTokens(turn_lanes,vehicle_lanes)
elseif first_count ~= 0 or second_count ~= 0 then elseif first_count ~= 0 or second_count ~= 0 then
turn_lane = trimLaneString(turn_lane, first_count, second_count) return trimLaneString(turn_lanes, first_count, second_count)
end else
return turn_lanes
end end
return turn_lane; end
end end
-- this is broken for left-sided driving. It needs to switch left and right in case of left-sided driving -- 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) function Guidance.get_turn_lanes(way,data)
local fw_psv = 0 local psv_fw, psv_bw = get_psv_counts(way,data)
local bw_psv = 0 local turn_lanes_fw, turn_lanes_bw = Directional.get_values_by_key(way,data,'turn:lanes')
fw_psv, bw_psv = get_psv_counts(way) local vehicle_lanes_fw, vehicle_lanes_bw = Directional.get_values_by_key(way,data,'vehicle:lanes')
local turn_lanes = way:get_value_by_key("turn:lanes") --note: backward lanes swap psv_bw and psv_fw
local turn_lanes_fw = way:get_value_by_key("turn:lanes:forward") return process_lanes(turn_lanes_fw,vehicle_lanes_fw,psv_bw,psv_fw) or turn_lanes,
local turn_lanes_bw = way:get_value_by_key("turn:lanes:backward") process_lanes(turn_lanes_bw,vehicle_lanes_bw,psv_fw,psv_bw) or turn_lanes
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
end end
return Guidance return Guidance
+13 -6
View File
@@ -1,11 +1,18 @@
#!/usr/bin/env bash #!/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 NODE_HOME=$HOME/node
# This is done manually so that the build works the same on OS X export NODE_HOME
rm -rf ~/.nvm/ && git clone --depth 1 --branch v0.30.1 https://github.com/creationix/nvm.git ~/.nvm mkdir ${NODE_HOME}
source ~/.nvm/nvm.sh if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
nvm install $1 curl https://s3.amazonaws.com/mapbox/apps/install-node/v2.0.0/run | NV=4.4.2 NP=darwin-x64 OD=${NODE_HOME} sh
nvm use $1 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 node --version
npm --version npm --version
which node which node
+7 -3
View File
@@ -7,12 +7,16 @@ set -o nounset
# Runs the Clang Tidy Tool in parallel on the code base. # Runs the Clang Tidy Tool in parallel on the code base.
# Requires a compilation database in the build directory. # 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 \ | xargs \
-0 \
-I{} \ -I{} \
-P $(nproc) \ -n 1 \
clang-tidy \ ./clang+llvm-3.9.0-x86_64-apple-darwin/bin/clang-tidy \
-p build \ -p build \
-header-filter='.*' \ -header-filter='.*' \
{} {}
+122 -79
View File
@@ -6,13 +6,13 @@
#include "extractor/edge_based_graph_factory.hpp" #include "extractor/edge_based_graph_factory.hpp"
#include "extractor/node_based_edge.hpp" #include "extractor/node_based_edge.hpp"
#include "storage/io.hpp"
#include "storage/io.hpp" #include "storage/io.hpp"
#include "util/exception.hpp" #include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/graph_loader.hpp" #include "util/graph_loader.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/io.hpp" #include "util/io.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include "util/static_graph.hpp" #include "util/static_graph.hpp"
#include "util/static_rtree.hpp" #include "util/static_rtree.hpp"
#include "util/string_util.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)) if (old_weight >= (new_segment_weight * log_edge_updates_factor))
{ {
auto speed_file = segment_speed_filenames.at(speed_iter->speed_source.source - 1); auto speed_file = segment_speed_filenames.at(speed_iter->speed_source.source - 1);
util::SimpleLogger().Write(logWARNING) util::Log(logWARNING) << "[weight updates] Edge weight update from " << old_secs
<< "[weight updates] Edge weight update from " << old_secs << "s to " << new_secs << "s to " << new_secs
<< "s New speed: " << speed_iter->speed_source.speed << " kph" << "s New speed: " << speed_iter->speed_source.speed << " kph"
<< ". Old speed: " << approx_original_speed << " kph" << ". Old speed: " << approx_original_speed << " kph"
<< ". Segment length: " << segment_length << " m" << ". Segment length: " << segment_length << " m"
<< ". Segment: " << speed_iter->segment.from << "," << speed_iter->segment.to << ". Segment: " << speed_iter->segment.from << ","
<< " based on " << speed_file; << 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) 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); 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; util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;
EdgeID max_edge_id = LoadEdgeExpandedGraph(config.edge_based_graph_path, EdgeID max_edge_id = LoadEdgeExpandedGraph(config.edge_based_graph_path,
edge_based_edge_list, edge_based_edge_list,
node_weights,
config.edge_segment_lookup_path, config.edge_segment_lookup_path,
config.edge_penalty_path, config.edge_penalty_path,
config.segment_speed_lookup_paths, config.segment_speed_lookup_paths,
@@ -163,17 +175,6 @@ int Contractor::Run()
ReadNodeLevels(node_levels); 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; util::DeallocatingVector<QueryEdge> contracted_edge_list;
ContractGraph(max_edge_id, ContractGraph(max_edge_id,
edge_based_edge_list, edge_based_edge_list,
@@ -183,7 +184,7 @@ int Contractor::Run()
node_levels); node_levels);
TIMER_STOP(contraction); 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); std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
WriteCoreNodeMarker(std::move(is_core_node)); WriteCoreNodeMarker(std::move(is_core_node));
@@ -199,11 +200,11 @@ int Contractor::Run()
const auto edges_per_second = const auto edges_per_second =
static_cast<std::uint64_t>(number_of_used_edges / TIMER_SEC(contraction)); static_cast<std::uint64_t>(number_of_used_edges / TIMER_SEC(contraction));
util::SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds"; util::Log() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
util::SimpleLogger().Write() << "Contraction: " << nodes_per_second << " nodes/sec and " util::Log() << "Contraction: " << nodes_per_second << " nodes/sec and " << edges_per_second
<< edges_per_second << " edges/sec"; << " edges/sec";
util::SimpleLogger().Write() << "finished preprocessing"; util::Log() << "finished preprocessing";
return 0; 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{}; std::uint64_t to_node_id{};
unsigned speed{}; unsigned speed{};
std::size_t line_number = 0;
std::for_each( std::for_each(
segment_speed_file_reader.GetLineIteratorBegin(), segment_speed_file_reader.GetLineIteratorBegin(),
segment_speed_file_reader.GetLineIteratorEnd(), segment_speed_file_reader.GetLineIteratorEnd(),
[&](const std::string &line) { [&](const std::string &line) {
++line_number;
using namespace boost::spirit::qi; using namespace boost::spirit::qi;
@@ -329,7 +333,11 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
speed); // speed); //
if (!ok || it != last) 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}}, SegmentSpeedSource val{{OSMNodeID{from_node_id}, OSMNodeID{to_node_id}},
{speed, static_cast<std::uint8_t>(file_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)); local.push_back(std::move(val));
}); });
util::SimpleLogger().Write() << "Loaded speed file " << filename << " with " << local.size() util::Log() << "Loaded speed file " << filename << " with " << local.size() << " speeds";
<< " speeds";
{ {
Mutex::scoped_lock _{flatten_mutex}; 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 // 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 // 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)); flatten.erase(it, end(flatten));
util::SimpleLogger().Write() << "In total loaded " << segment_speed_filenames.size() util::Log() << "In total loaded " << segment_speed_filenames.size()
<< " speed file(s) with a total of " << flatten.size() << " speed file(s) with a total of " << flatten.size() << " unique values";
<< " unique values";
return flatten; 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{}; std::uint64_t to_node_id{};
double penalty{}; double penalty{};
std::size_t line_number = 0;
std::for_each( std::for_each(
turn_penalty_file_reader.GetLineIteratorBegin(), turn_penalty_file_reader.GetLineIteratorBegin(),
turn_penalty_file_reader.GetLineIteratorEnd(), turn_penalty_file_reader.GetLineIteratorEnd(),
[&](const std::string &line) { [&](const std::string &line) {
++line_number;
using namespace boost::spirit::qi; using namespace boost::spirit::qi;
@@ -420,7 +436,11 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
penalty); // penalty); //
if (!ok || it != last) 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{ TurnPenaltySource val{
{OSMNodeID{from_node_id}, OSMNodeID{via_node_id}, OSMNodeID{to_node_id}}, {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)); local.push_back(std::move(val));
}); });
util::SimpleLogger().Write() << "Loaded penalty file " << filename << " with " util::Log() << "Loaded penalty file " << filename << " with " << local.size()
<< local.size() << " turn penalties"; << " turn penalties";
{ {
Mutex::scoped_lock _{flatten_mutex}; 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 // 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 // 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)); map.erase(it, end(map));
util::SimpleLogger().Write() << "In total loaded " << turn_penalty_filenames.size() util::Log() << "In total loaded " << turn_penalty_filenames.size()
<< " turn penalty file(s) with a total of " << map.size() << " turn penalty file(s) with a total of " << map.size() << " unique values";
<< " unique values";
return map; return map;
} }
@@ -474,6 +500,7 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
EdgeID Contractor::LoadEdgeExpandedGraph( EdgeID Contractor::LoadEdgeExpandedGraph(
std::string const &edge_based_graph_filename, std::string const &edge_based_graph_filename,
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list, util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
const std::string &edge_segment_lookup_filename, const std::string &edge_segment_lookup_filename,
const std::string &edge_penalty_filename, const std::string &edge_penalty_filename,
const std::vector<std::string> &segment_speed_filenames, const std::vector<std::string> &segment_speed_filenames,
@@ -486,19 +513,28 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
const double log_edge_updates_factor) const double log_edge_updates_factor)
{ {
if (segment_speed_filenames.size() > 255 || turn_penalty_filenames.size() > 255) 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) { auto mmap_file = [](const std::string &filename) {
using boost::interprocess::file_mapping; using boost::interprocess::file_mapping;
using boost::interprocess::mapped_region; using boost::interprocess::mapped_region;
using boost::interprocess::read_only; using boost::interprocess::read_only;
const file_mapping mapping{filename.c_str(), read_only}; try
mapped_region region{mapping, read_only}; {
region.advise(mapped_region::advice_sequential); const file_mapping mapping{filename.c_str(), read_only};
return region; 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); 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); graph_header.fingerprint.TestContractor(fingerprint_valid);
edge_based_edge_list.resize(graph_header.number_of_edges); edge_based_edge_list.resize(graph_header.number_of_edges);
util::SimpleLogger().Write() << "Reading " << graph_header.number_of_edges util::Log() << "Reading " << graph_header.number_of_edges << " edges from the edge based graph";
<< " edges from the edge based graph";
SegmentSpeedSourceFlatMap segment_speed_lookup; SegmentSpeedSourceFlatMap segment_speed_lookup;
TurnPenaltySourceFlatMap turn_penalty_lookup; TurnPenaltySourceFlatMap turn_penalty_lookup;
@@ -735,15 +770,15 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
{ {
if (i == LUA_SOURCE) if (i == LUA_SOURCE)
{ {
util::SimpleLogger().Write() << "Used " << merged_counters[LUA_SOURCE] util::Log() << "Used " << merged_counters[LUA_SOURCE]
<< " speeds from LUA profile or input map"; << " speeds from LUA profile or input map";
} }
else else
{ {
// segments_speeds_counters has 0 as LUA, segment_speed_filenames not, thus we need // segments_speeds_counters has 0 as LUA, segment_speed_filenames not, thus we need
// to susbstract 1 to avoid off-by-one error // to susbstract 1 to avoid off-by-one error
util::SimpleLogger().Write() << "Used " << merged_counters[i] << " speeds from " util::Log() << "Used " << merged_counters[i] << " speeds from "
<< segment_speed_filenames[i - 1]; << segment_speed_filenames[i - 1];
} }
} }
} }
@@ -756,7 +791,8 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
std::ofstream geometry_stream(geometry_filename, std::ios::binary); std::ofstream geometry_stream(geometry_filename, std::ios::binary);
if (!geometry_stream) 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_indices = m_geometry_indices.size();
const unsigned number_of_compressed_geometries = m_geometry_node_list.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); std::ofstream datasource_stream(datasource_indexes_filename, std::ios::binary);
if (!datasource_stream) 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(); std::uint64_t number_of_datasource_entries = m_geometry_datasource.size();
datasource_stream.write(reinterpret_cast<const char *>(&number_of_datasource_entries), 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); std::ofstream datasource_stream(datasource_names_filename, std::ios::binary);
if (!datasource_stream) 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; datasource_stream << "lua profile" << std::endl;
for (auto const &name : segment_speed_filenames) for (auto const &name : segment_speed_filenames)
@@ -876,6 +916,11 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
previous_osm_node_id = segmentblocks[i].this_osm_node_id; 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 // We found a zero-speed edge, so we'll skip this whole edge-based-edge which
// effectively removes it from the routing network. // effectively removes it from the routing network.
if (skip_this_edge) if (skip_this_edge)
@@ -894,11 +939,11 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
if (new_turn_weight + new_weight < compressed_edge_nodes) if (new_turn_weight + new_weight < compressed_edge_nodes)
{ {
util::SimpleLogger().Write(logWARNING) util::Log(logWARNING) << "turn penalty " << turn_iter->penalty_source.penalty
<< "turn penalty " << turn_iter->penalty_source.penalty << " for turn " << " for turn " << penaltyblock->from_id << ", "
<< penaltyblock->from_id << ", " << penaltyblock->via_id << ", " << penaltyblock->via_id << ", " << penaltyblock->to_id
<< penaltyblock->to_id << " is too negative: clamping turn weight to " << " is too negative: clamping turn weight to "
<< compressed_edge_nodes; << compressed_edge_nodes;
} }
inbuffer.weight = std::max(new_turn_weight + new_weight, 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)); 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; 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. // 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()); tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
const std::uint64_t contracted_edge_count = contracted_edge_list.size(); const std::uint64_t contracted_edge_count = contracted_edge_list.size();
util::SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count util::Log() << "Serializing compacted graph of " << contracted_edge_count << " edges";
<< " edges";
const util::FingerPrint fingerprint = util::FingerPrint::GetValid(); const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary); 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; return tmp_max;
}(); }();
util::SimpleLogger().Write(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes"; util::Log(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
util::SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1) util::Log(logDEBUG) << "contracted graph has " << (max_used_node_id + 1) << " nodes";
<< " nodes";
std::vector<util::StaticGraph<EdgeData>::NodeArrayEntry> node_array; std::vector<util::StaticGraph<EdgeData>::NodeArrayEntry> node_array;
// make sure we have at least one sentinel // make sure we have at least one sentinel
node_array.resize(max_node_id + 2); 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 edge = 0;
util::StaticGraph<EdgeData>::EdgeIterator position = 0; util::StaticGraph<EdgeData>::EdgeIterator position = 0;
util::StaticGraph<EdgeData>::EdgeIterator last_edge; 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; node_array[sentinel_counter].first_edge = contracted_edge_count;
} }
util::SimpleLogger().Write() << "Serializing node array"; util::Log() << "Serializing node array";
RangebasedCRC32 crc32_calculator; RangebasedCRC32 crc32_calculator;
const unsigned edges_crc32 = crc32_calculator(contracted_edge_list); 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(); const std::uint64_t node_array_size = node_array.size();
// serialize crc32, aka checksum // serialize crc32, aka checksum
@@ -1036,7 +1079,7 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
} }
// serialize all edges // serialize all edges
util::SimpleLogger().Write() << "Building edge array"; util::Log() << "Building edge array";
std::size_t number_of_used_edges = 0; std::size_t number_of_used_edges = 0;
util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge; util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
@@ -1055,15 +1098,15 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
#ifndef NDEBUG #ifndef NDEBUG
if (current_edge.data.weight <= 0) if (current_edge.data.weight <= 0)
{ {
util::SimpleLogger().Write(logWARNING) util::Log(logWARNING) << "Edge: " << edge
<< "Edge: " << edge << ",source: " << contracted_edge_list[edge].source << ",source: " << contracted_edge_list[edge].source
<< ", target: " << contracted_edge_list[edge].target << ", target: " << contracted_edge_list[edge].target
<< ", weight: " << current_edge.data.weight; << ", weight: " << current_edge.data.weight;
util::SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node " util::Log(logWARNING) << "Failed at adjacency list of node "
<< contracted_edge_list[edge].source << "/" << contracted_edge_list[edge].source << "/"
<< node_array.size() - 1; << node_array.size() - 1;
return 1; throw util::exception("Edge weight is <= 0" + SOURCE_REF);
} }
#endif #endif
hsgr_output_stream.write((char *)&current_edge, hsgr_output_stream.write((char *)&current_edge,
-1
View File
@@ -6,7 +6,6 @@
#include "util/guidance/bearing_class.hpp" #include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp" #include "util/guidance/entry_class.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
+5 -3
View File
@@ -7,7 +7,7 @@
#include "engine/datafacade/shared_memory_datafacade.hpp" #include "engine/datafacade/shared_memory_datafacade.hpp"
#include "storage/shared_barriers.hpp" #include "storage/shared_barriers.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/interprocess/sync/named_condition.hpp> #include <boost/interprocess/sync/named_condition.hpp>
@@ -68,7 +68,9 @@ Engine::Engine(const EngineConfig &config)
if (!DataWatchdog::TryConnect()) if (!DataWatchdog::TryConnect())
{ {
throw util::exception( 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>(); watchdog = std::make_unique<DataWatchdog>();
@@ -78,7 +80,7 @@ Engine::Engine(const EngineConfig &config)
{ {
if (!config.storage_config.IsValid()) if (!config.storage_config.IsValid())
{ {
throw util::exception("Invalid file paths given!"); throw util::exception("Invalid file paths given!" + SOURCE_REF);
} }
immutable_data_facade = immutable_data_facade =
std::make_shared<datafacade::ProcessMemoryDataFacade>(config.storage_config); std::make_shared<datafacade::ProcessMemoryDataFacade>(config.storage_config);
+4 -6
View File
@@ -1,10 +1,8 @@
#include "util/for_each_pair.hpp" #include "util/for_each_pair.hpp"
#include "util/group_by.hpp" #include "util/group_by.hpp"
#include "util/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/post_processing.hpp" #include "engine/guidance/post_processing.hpp"
#include "engine/guidance/toolkit.hpp"
#include <iterator> #include <iterator>
#include <unordered_set> #include <unordered_set>
@@ -14,8 +12,8 @@ using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
namespace TurnType = osrm::extractor::guidance::TurnType; namespace TurnType = osrm::extractor::guidance::TurnType;
namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier; namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier;
using osrm::util::guidance::isLeftTurn; using osrm::extractor::guidance::isLeftTurn;
using osrm::util::guidance::isRightTurn; using osrm::extractor::guidance::isRightTurn;
namespace osrm 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 // 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 // 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. // 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_right_of_turn = current.numLanesToTheRight();
const LaneID current_num_lanes_left_of_turn = numLanesToTheLeft(current); const LaneID current_num_lanes_left_of_turn = current.numLanesToTheLeft();
const LaneID num_shared_lanes = std::min(current_lanes.lanes_in_turn, // const LaneID num_shared_lanes = std::min(current_lanes.lanes_in_turn, //
previous_lanes.lanes_in_turn); // previous_lanes.lanes_in_turn); //
+37 -41
View File
@@ -1,14 +1,12 @@
#include "engine/guidance/post_processing.hpp" #include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/guidance/assemble_steps.hpp" #include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/lane_processing.hpp" #include "engine/guidance/lane_processing.hpp"
#include "engine/guidance/toolkit.hpp"
#include "util/bearing.hpp" #include "util/bearing.hpp"
#include "util/guidance/toolkit.hpp" #include "util/guidance/name_announcements.hpp"
#include "util/guidance/turn_lanes.hpp" #include "util/guidance/turn_lanes.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
@@ -25,8 +23,11 @@
using TurnInstruction = osrm::extractor::guidance::TurnInstruction; using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
namespace TurnType = osrm::extractor::guidance::TurnType; namespace TurnType = osrm::extractor::guidance::TurnType;
namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier; namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier;
using osrm::util::guidance::angularDeviation; using osrm::util::angularDeviation;
using osrm::util::guidance::getTurnDirection; using osrm::extractor::guidance::getTurnDirection;
using osrm::extractor::guidance::hasRampType;
using osrm::extractor::guidance::mirrorDirectionModifier;
using osrm::extractor::guidance::bearingToDirectionModifier;
namespace osrm namespace osrm
{ {
@@ -299,14 +300,13 @@ void closeOffRoundabout(const bool on_roundabout,
TurnType::EnterRoundaboutIntersectionAtExit) TurnType::EnterRoundaboutIntersectionAtExit)
{ {
BOOST_ASSERT(!propagation_step.intersections.empty()); BOOST_ASSERT(!propagation_step.intersections.empty());
const double angle = util::bearing::angleBetweenBearings( const double angle = util::angleBetweenBearings(
util::bearing::reverseBearing( util::reverseBearing(entry_intersection.bearings[entry_intersection.in]),
entry_intersection.bearings[entry_intersection.in]),
exit_bearing); exit_bearing);
auto bearings = propagation_step.intersections.front().bearings; auto bearings = propagation_step.intersections.front().bearings;
propagation_step.maneuver.instruction.direction_modifier = propagation_step.maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(angle); getTurnDirection(angle);
} }
forwardStepSignage(propagation_step, destination_copy); 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 && (isLinkroad(in_step) && out_step.name_id != EMPTY_NAMEID &&
pre_in_step.name_id != EMPTY_NAMEID && !isNoticeableNameChange(pre_in_step, out_step)); pre_in_step.name_id != EMPTY_NAMEID && !isNoticeableNameChange(pre_in_step, out_step));
const bool takes_u_turn = bearingsAreReversed( const bool takes_u_turn = bearingsAreReversed(
util::bearing::reverseBearing( util::reverseBearing(
in_step.intersections.front().bearings[in_step.intersections.front().in]), in_step.intersections.front().bearings[in_step.intersections.front().in]),
out_step.intersections.front().bearings[out_step.intersections.front().out]); 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_intersection = exit_step.intersections.front();
const auto exit_step_exit_bearing = exit_intersection.bearings[exit_intersection.out]; const auto exit_step_exit_bearing = exit_intersection.bearings[exit_intersection.out];
const auto exit_step_entry_bearing = 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_intersection = entry_step.intersections.front();
const auto entry_step_entry_bearing = 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 entry_step_exit_bearing = entry_intersection.bearings[entry_intersection.out];
const auto exit_angle = 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 = 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 = 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 // We allow for minor deviations from a straight line
if (((entry_step.distance < MAX_COLLAPSE_DISTANCE && exit_step.intersections.size() == 1) || if (((entry_step.distance < MAX_COLLAPSE_DISTANCE && exit_step.intersections.size() == 1) ||
(entry_angle <= 185 && exit_angle <= 185) || (entry_angle >= 175 && exit_angle >= 175)) && (entry_angle <= 185 && exit_angle <= 185) || (entry_angle >= 175 && exit_angle >= 175)) &&
@@ -521,8 +521,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
// tagged late // tagged late
const auto is_delayed_turn_onto_a_ramp = const auto is_delayed_turn_onto_a_ramp =
opening_turn.distance <= 4 * MAX_COLLAPSE_DISTANCE && without_choice && opening_turn.distance <= 4 * MAX_COLLAPSE_DISTANCE && without_choice &&
util::guidance::hasRampType(finishing_turn.maneuver.instruction); hasRampType(finishing_turn.maneuver.instruction);
return !util::guidance::hasRampType(opening_turn.maneuver.instruction) && return !hasRampType(opening_turn.maneuver.instruction) &&
(is_short_and_collapsable || is_not_too_long_and_choiceless || (is_short_and_collapsable || is_not_too_long_and_choiceless ||
isLinkroad(opening_turn) || is_delayed_turn_onto_a_ramp); 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) if (TurnType::Merge == current_step.maneuver.instruction.type)
{ {
steps[step_index].maneuver.instruction.direction_modifier = steps[step_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier( mirrorDirectionModifier(steps[step_index].maneuver.instruction.direction_modifier);
steps[step_index].maneuver.instruction.direction_modifier);
steps[step_index].maneuver.instruction.type = TurnType::Turn; steps[step_index].maneuver.instruction.type = TurnType::Turn;
} }
else else
@@ -573,18 +572,18 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
if (continue_or_suppressed || turning_name) if (continue_or_suppressed || turning_name)
{ {
const auto in_bearing = [](const RouteStep &step) { const auto in_bearing = [](const RouteStep &step) {
return util::bearing::reverseBearing( return util::reverseBearing(
step.intersections.front().bearings[step.intersections.front().in]); step.intersections.front().bearings[step.intersections.front().in]);
}; };
const auto out_bearing = [](const RouteStep &step) { const auto out_bearing = [](const RouteStep &step) {
return step.intersections.front().bearings[step.intersections.front().out]; return step.intersections.front().bearings[step.intersections.front().out];
}; };
const auto first_angle = util::bearing::angleBetweenBearings( const auto first_angle = util::angleBetweenBearings(in_bearing(one_back_step),
in_bearing(one_back_step), out_bearing(one_back_step)); out_bearing(one_back_step));
const auto second_angle = util::bearing::angleBetweenBearings( const auto second_angle =
in_bearing(current_step), out_bearing(current_step)); util::angleBetweenBearings(in_bearing(current_step), out_bearing(current_step));
const auto bearing_turn_angle = util::bearing::angleBetweenBearings( const auto bearing_turn_angle = util::angleBetweenBearings(
in_bearing(one_back_step), out_bearing(current_step)); in_bearing(one_back_step), out_bearing(current_step));
// When looking at an intersection, some angles, even though present, feel more like // 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; DirectionModifier::Straight;
else else
steps[step_index].maneuver.instruction.direction_modifier = 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 // 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. // 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 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))) getBearing(false, current_step)))
{ {
steps[one_back_index].maneuver.instruction.direction_modifier = 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 // need a highway-suppressed to get the turn onto a
// highway... // highway...
{ {
steps[one_back_index].maneuver.instruction.direction_modifier = steps[one_back_index].maneuver.instruction.direction_modifier = mirrorDirectionModifier(
util::guidance::mirrorDirectionModifier( steps[one_back_index].maneuver.instruction.direction_modifier);
steps[one_back_index].maneuver.instruction.direction_modifier);
} }
// on non merge-types, we check for a combined turn angle // on non merge-types, we check for a combined turn angle
else if (TurnType::Merge != one_back_step.maneuver.instruction.type) 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); steps[one_back_index] = elongate(std::move(steps[one_back_index]), current_step);
const auto angle = findTotalTurnAngle(one_back_step, current_step); const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier = steps[one_back_index].maneuver.instruction.direction_modifier = getTurnDirection(angle);
util::guidance::getTurnDirection(angle);
invalidateStep(steps[step_index]); 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] = elongate(std::move(steps[one_back_index]), current_step);
steps[one_back_index].maneuver.instruction.type = TurnType::OnRamp; steps[one_back_index].maneuver.instruction.type = TurnType::OnRamp;
const auto angle = findTotalTurnAngle(one_back_step, current_step); const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier = steps[one_back_index].maneuver.instruction.direction_modifier = getTurnDirection(angle);
util::guidance::getTurnDirection(angle);
forwardStepSignage(steps[one_back_index], current_step); forwardStepSignage(steps[one_back_index], current_step);
invalidateStep(steps[step_index]); invalidateStep(steps[step_index]);
@@ -806,7 +802,7 @@ bool isStaggeredIntersection(const std::vector<RouteStep> &steps,
const auto &intersection = step.intersections.front(); const auto &intersection = step.intersections.front();
const auto entry_bearing = intersection.bearings[intersection.in]; const auto entry_bearing = intersection.bearings[intersection.in];
const auto exit_bearing = intersection.bearings[intersection.out]; 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. // 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); const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier = steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(angle); getTurnDirection(angle);
invalidateStep(steps[step_index]); invalidateStep(steps[step_index]);
} }
else else
@@ -1462,7 +1458,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
geometry.locations[next_to_last_step.geometry_end - 2], geometry.locations[next_to_last_step.geometry_end - 2],
geometry.locations[last_step.geometry_begin])); geometry.locations[last_step.geometry_begin]));
last_step.maneuver.bearing_before = bearing; 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()); 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 = const auto initial_modifier =
distance_to_start >= MINIMAL_RELATIVE_DISTANCE && distance_to_start >= MINIMAL_RELATIVE_DISTANCE &&
distance_to_start <= MAXIMAL_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])) source_node.input_location, leg_geometry.locations[0], leg_geometry.locations[1]))
: extractor::guidance::DirectionModifier::UTurn; : extractor::guidance::DirectionModifier::UTurn;
@@ -1505,7 +1501,7 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
const auto final_modifier = const auto final_modifier =
distance_from_end >= MINIMAL_RELATIVE_DISTANCE && distance_from_end >= MINIMAL_RELATIVE_DISTANCE &&
distance_from_end <= MAXIMAL_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() - 2],
leg_geometry.locations[leg_geometry.locations.size() - 1], leg_geometry.locations[leg_geometry.locations.size() - 1],
target_node.input_location)) 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. // the lane description is given left to right, lanes are counted from the right.
// Therefore we access the lane description using the reverse iterator // 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(), if (!right_most_lanes.empty() && containsTag(right_most_lanes.front(),
(extractor::guidance::TurnLaneType::straight | (extractor::guidance::TurnLaneType::straight |
extractor::guidance::TurnLaneType::none))) extractor::guidance::TurnLaneType::none)))
return false; return false;
auto left_most_lanes = lanesToTheLeft(step); auto left_most_lanes = step.lanesToTheLeft();
if (!left_most_lanes.empty() && containsTag(left_most_lanes.back(), if (!left_most_lanes.empty() && containsTag(left_most_lanes.back(),
(extractor::guidance::TurnLaneType::straight | (extractor::guidance::TurnLaneType::straight |
extractor::guidance::TurnLaneType::none))) extractor::guidance::TurnLaneType::none)))
+42 -8
View File
@@ -357,6 +357,26 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
return offset; 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 // 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. // really cramped, so we don't bother including the data for tiles that span a large area.
if (parameters.z >= MIN_ZOOM_FOR_TURNS) 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 // Build an adjacency list for all the road segments visible in
// the tile // 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) if (edge.forward_segment_id.enabled)
{ {
// operator[] will construct an empty vector at [edge.u] if there is no value. // 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" // vw is the "exit"
std::vector<contractor::QueryEdge::EdgeData> unpacked_shortcut; std::vector<contractor::QueryEdge::EdgeData> unpacked_shortcut;
std::vector<EdgeWeight> approach_weight_vector; 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) 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 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 // If the target of this edge doesn't exist in our directed
// graph, it's probably outside the tile, so we can skip it // 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; continue;
// Skip u-turns // Skip u-turns
if (startnode.first == exit_edge.target_node) if (startnode == exit_edge.target_node)
continue; continue;
// Find the connection between our source road and the target node // 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; const auto turn_cost = data.weight - sum_node_weight;
// Find the three nodes that make up the turn movement) // 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_via = approachedge.target_node;
const auto node_to = exit_edge.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 // 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 // can then encode the features, and we'll know the indexes that feature properties
// need to refer to. // 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 = const auto forward_datasource_vector =
facade->GetUncompressedForwardDatasources(edge.packed_geometry_id); 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, // 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 // we need to do an initial pass over the data and create the complete
// index of used values. // 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 = const auto forward_weight_vector =
facade->GetUncompressedForwardWeights(edge.packed_geometry_id); facade->GetUncompressedForwardWeights(edge.packed_geometry_id);
const auto reverse_weight_vector = 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 // Each feature gets a unique id, starting at 1
unsigned id = 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) // Get coordinates for start/end nodes of segment (NodeIDs u and v)
const auto a = facade->GetCoordinateOfNode(edge.u); const auto a = facade->GetCoordinateOfNode(edge.u);
const auto b = facade->GetCoordinateOfNode(edge.v); const auto b = facade->GetCoordinateOfNode(edge.v);
+39 -30
View File
@@ -2,6 +2,7 @@
#include <algorithm> #include <algorithm>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <climits>
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
#include <cstdlib> #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> decodePolyline(const std::string &geometry_string)
{ {
std::vector<util::Coordinate> new_coordinates; // https://developers.google.com/maps/documentation/utilities/polylinealgorithm
int index = 0, len = geometry_string.size(); auto decode_polyline_integer = [](auto &first, auto last) {
int lat = 0, lng = 0; // 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; const auto dlat = decode_polyline_integer(first, last);
do const auto dlon = decode_polyline_integer(first, last);
{
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;
shift = 0; latitude += dlat;
result = 0; longitude += dlon;
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;
util::Coordinate p; coordinates.emplace_back(
p.lat = util::Coordinate{util::FixedLongitude{polyline_to_coordinate(longitude)},
util::FixedLatitude{static_cast<std::int32_t>(lat * detail::POLYLINE_TO_COORDINATE)}; util::FixedLatitude{polyline_to_coordinate(latitude)}});
p.lon =
util::FixedLongitude{static_cast<std::int32_t>(lng * detail::POLYLINE_TO_COORDINATE)};
new_coordinates.push_back(p);
} }
return new_coordinates; return coordinates;
} }
} }
} }
+8 -9
View File
@@ -1,5 +1,5 @@
#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_edge_container.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/filesystem.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()); longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
} }
util::SimpleLogger().Write() util::Log() << "Geometry successfully removed:"
<< "Geometry successfully removed:" "\n compressed edges: "
"\n compressed edges: " << compressed_edges << "\n compressed geometries: " << compressed_geometries
<< compressed_edges << "\n compressed geometries: " << compressed_geometries << "\n longest chain length: " << longest_chain_length << "\n cmpr ratio: "
<< "\n longest chain length: " << longest_chain_length << "\n cmpr ratio: " << ((float)compressed_edges / std::max(compressed_geometries, (uint64_t)1))
<< ((float)compressed_edges / std::max(compressed_geometries, (uint64_t)1)) << "\n avg chain length: "
<< "\n avg chain length: " << (float)compressed_geometries / std::max((uint64_t)1, compressed_edges);
<< (float)compressed_geometries / std::max((uint64_t)1, compressed_edges);
} }
const CompressedEdgeContainer::OnewayEdgeBucket & const CompressedEdgeContainer::OnewayEdgeBucket &
+292 -279
View File
@@ -6,11 +6,10 @@
#include "util/exception.hpp" #include "util/exception.hpp"
#include "util/guidance/turn_bearing.hpp" #include "util/guidance/turn_bearing.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/percent.hpp" #include "util/percent.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp" #include "util/timing_util.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_analysis.hpp" #include "extractor/guidance/turn_analysis.hpp"
#include "extractor/guidance/turn_lane_handler.hpp" #include "extractor/guidance/turn_lane_handler.hpp"
#include "extractor/scripting_environment.hpp" #include "extractor/scripting_environment.hpp"
@@ -213,10 +212,10 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
TIMER_STOP(generate_edges); TIMER_STOP(generate_edges);
util::SimpleLogger().Write() << "Timing statistics for edge-expanded graph:"; util::Log() << "Timing statistics for edge-expanded graph:";
util::SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s"; util::Log() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
util::SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s"; util::Log() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
util::SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s"; util::Log() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
} }
/// Renumbers all _forward_ edges and sets the edge_id. /// 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. /// Creates the nodes in the edge expanded graph from edges in the node-based graph.
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes() void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
{ {
util::Percent progress(m_node_based_graph->GetNumberOfNodes()); util::Log() << "Generating edge expanded nodes ... ";
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()))
{ {
BOOST_ASSERT(node_u != SPECIAL_NODEID); util::UnbufferedLog log;
BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes()); util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
progress.PrintStatus(node_u);
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u)) 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(node_u != SPECIAL_NODEID);
BOOST_ASSERT(e1 != SPECIAL_EDGEID); BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
const NodeID node_v = m_node_based_graph->GetTarget(e1); progress.PrintStatus(node_u);
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
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; 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 BOOST_ASSERT(node_u < node_v);
if (edge_data.edge_id == SPECIAL_NODEID)
{ // if we found a non-forward edge reverse and try again
InsertEdgeBasedNode(node_v, node_u); if (edge_data.edge_id == SPECIAL_NODEID)
} {
else InsertEdgeBasedNode(node_v, node_u);
{ }
InsertEdgeBasedNode(node_u, node_v); 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_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()); BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size());
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() util::Log() << "Generated " << m_edge_based_node_list.size() << " nodes in edge-expanded graph";
<< " nodes in edge-expanded graph";
} }
/// Actually it also generates OriginalEdgeData and serializes them... /// Actually it also generates OriginalEdgeData and serializes them...
@@ -312,7 +314,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const std::string &edge_fixed_penalties_filename, const std::string &edge_fixed_penalties_filename,
const bool generate_edge_lookup) 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 node_based_edge_counter = 0;
std::size_t original_edges_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. // Loop over all turns and generate new set of edges.
// Three nested loop look super-linear, but we are dealing with a (kind of) // Three nested loop look super-linear, but we are dealing with a (kind of)
// linear number of turns only. // linear number of turns only.
util::Percent progress(m_node_based_graph->GetNumberOfNodes());
SuffixTable street_name_suffix_table(scripting_environment); SuffixTable street_name_suffix_table(scripting_environment);
guidance::TurnAnalysis turn_analysis(*m_node_based_graph, guidance::TurnAnalysis turn_analysis(*m_node_based_graph,
m_node_info_list, m_node_info_list,
@@ -352,7 +353,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
street_name_suffix_table, street_name_suffix_table,
profile_properties); profile_properties);
guidance::LaneDataIdMap lane_data_map; util::guidance::LaneDataIdMap lane_data_map;
guidance::lanes::TurnLaneHandler turn_lane_handler(*m_node_based_graph, guidance::lanes::TurnLaneHandler turn_lane_handler(*m_node_based_graph,
turn_lane_offsets, turn_lane_offsets,
turn_lane_masks, turn_lane_masks,
@@ -363,260 +364,275 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(), bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(),
std::numeric_limits<std::uint32_t>::max()); 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 = util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
turn_analysis.ComputeIntersectionShapes(node_at_center_of_intersection); // going over all nodes (which form the center of an intersection), we compute all
// possible turns along these intersections.
// all nodes in the graph are connected in both directions. We check all outgoing nodes to for (const auto node_at_center_of_intersection :
// find the incoming edge. This is a larger search overhead, but the cost we need to pay to util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
// 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))
{ {
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, const auto shape_result =
node_at_center_of_intersection); turn_analysis.ComputeIntersectionShapes(node_at_center_of_intersection);
if (m_node_based_graph->GetEdgeData(incoming_edge).reversed) // all nodes in the graph are connected in both directions. We check all outgoing nodes
continue; // to
// find the incoming edge. This is a larger search overhead, but the cost we need to pay
++node_based_edge_counter; // to
// generate edges here is worth the additional search overhead.
auto intersection_with_flags_and_angles = //
turn_analysis.GetIntersectionGenerator().TransformIntersectionShapeIntoView( // a -> b <-> c
node_along_road_entering, // |
incoming_edge, // v
shape_result.normalised_intersection_shape, // d
shape_result.intersection_shape, //
shape_result.merging_map); // will have:
// a: b,rev=0
auto intersection = turn_analysis.AssignTurnTypes( // b: a,rev=1 c,rev=0 d,rev=0
node_along_road_entering, incoming_edge, intersection_with_flags_and_angles); // c: b,rev=0
//
BOOST_ASSERT(intersection.valid()); // From the flags alone, we cannot determine which nodes are connected to `b` by an
// outgoing
intersection = turn_lane_handler.assignTurnLanes( // edge. Therefore, we have to search all connected edges for edges entering `b`
node_along_road_entering, incoming_edge, std::move(intersection)); for (const EdgeID outgoing_edge :
m_node_based_graph->GetAdjacentEdgeRange(node_at_center_of_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)
{ {
// only keep valid turns const NodeID node_along_road_entering =
if (!turn.entry_allowed) 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; continue;
// only add an edge if turn is not prohibited ++node_based_edge_counter;
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); auto intersection_with_flags_and_angles =
BOOST_ASSERT(!edge_data1.reversed); turn_analysis.GetIntersectionGenerator().TransformIntersectionShapeIntoView(
BOOST_ASSERT(!edge_data2.reversed); 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. auto intersection = turn_analysis.AssignTurnTypes(
unsigned distance = edge_data1.distance; node_along_road_entering, incoming_edge, intersection_with_flags_and_angles);
if (m_traffic_lights.find(node_at_center_of_intersection) != m_traffic_lights.end())
{
distance += profile_properties.traffic_signal_penalty;
}
const int32_t turn_penalty = BOOST_ASSERT(intersection.valid());
scripting_environment.GetTurnPenalty(180. - turn.angle);
const auto turn_instruction = turn.instruction; intersection = turn_lane_handler.assignTurnLanes(
if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn) node_along_road_entering, incoming_edge, std::move(intersection));
{
distance += profile_properties.u_turn_penalty;
}
// don't add turn penalty if it is not an actual turn. This heuristic is necessary // the entry class depends on the turn, so we have to classify the interesction for
// since OSRM cannot handle looping roads/parallel roads // every edge
if (turn_instruction.type != guidance::TurnType::NoTurn) const auto turn_classification = classifyIntersection(intersection);
distance += turn_penalty;
const bool is_encoded_forwards = const auto entry_class_id = [&](const util::guidance::EntryClass entry_class) {
m_compressed_edge_container.HasZippedEntryForForwardID(incoming_edge); if (0 == entry_class_hash.count(entry_class))
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 auto id = static_cast<std::uint16_t>(entry_class_hash.size());
const QueryNode &to = m_node_info_list[target_node.node_id]; entry_class_hash[entry_class] = id;
const double segment_length = return id;
util::coordinate_calculation::greatCircleDistance(from, to); }
else
{
return entry_class_hash.find(entry_class)->second;
}
}(turn_classification.first);
lookup::SegmentBlock nodeblock = { const auto bearing_class_id =
to.node_id, segment_length, target_node.weight}; [&](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), for (const auto &turn : intersection)
sizeof(nodeblock)); {
previous = target_node.node_id; // 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 const int32_t turn_penalty =
// original nodes. Since each edge represents a possible maneuver, external scripting_environment.GetTurnPenalty(180. - turn.angle);
// 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 const auto turn_instruction = turn.instruction;
// exactly to an original OSM segment -- we can pull the turn's preceding if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
// node ID directly with `node_along_road_entering`; otherwise, we need to look {
// up the node distance += profile_properties.u_turn_penalty;
// immediately preceding the turn from the compressed edge container. }
const bool isTrivial = m_compressed_edge_container.IsTrivial(incoming_edge);
const auto &from_node = // don't add turn penalty if it is not an actual turn. This heuristic is
isTrivial // necessary
? m_node_info_list[node_along_road_entering] // since OSRM cannot handle looping roads/parallel roads
: m_node_info_list[m_compressed_edge_container.GetLastEdgeSourceID( if (turn_instruction.type != guidance::TurnType::NoTurn)
incoming_edge)]; distance += turn_penalty;
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; const bool is_encoded_forwards =
lookup::PenaltyBlock penaltyblock = { m_compressed_edge_container.HasZippedEntryForForwardID(incoming_edge);
fixed_penalty, from_node.node_id, via_node.node_id, to_node.node_id}; const bool is_encoded_backwards =
edge_penalty_file.write(reinterpret_cast<const char *>(&penaltyblock), m_compressed_edge_container.HasZippedEntryForReverseID(incoming_edge);
sizeof(penaltyblock)); 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 " util::Log() << "Created " << entry_class_hash.size() << " entry classes and "
<< bearing_class_hash.size() << " Bearing Classes"; << 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::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()); std::vector<util::guidance::LaneTupleIdPair> lane_data(lane_data_map.size());
// extract lane data sorted by ID // 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]), turn_lane_data_file.write(reinterpret_cast<const char *>(&lane_data[0]),
sizeof(util::guidance::LaneTupleIdPair) * lane_data.size()); sizeof(util::guidance::LaneTupleIdPair) * lane_data.size());
util::SimpleLogger().Write() << "done."; util::Log() << "done.";
FlushVectorToStream(edge_data_file, original_edge_data_vector); 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)); edge_data_file.write(reinterpret_cast<const char *>(&length_prefix), sizeof(length_prefix));
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() util::Log() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
<< " edge based nodes"; util::Log() << "Node-based graph contains " << node_based_edge_counter << " edges";
util::SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter util::Log() << "Edge-expanded graph ...";
<< " edges"; util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
util::SimpleLogger().Write() << "Edge-expanded graph ..."; util::Log() << " skips " << restricted_turns_counter << " turns, "
util::SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges"; "defined by "
util::SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, " << m_restriction_map->size() << " restrictions";
"defined by " util::Log() << " skips " << skipped_uturns_counter << " U turns";
<< m_restriction_map->size() << " restrictions"; util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
util::SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
util::SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter
<< " turns over barriers";
} }
std::vector<util::guidance::BearingClass> EdgeBasedGraphFactory::GetBearingClasses() const 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 "extractor/raster_source.hpp"
#include "storage/io.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/graph_loader.hpp"
#include "util/io.hpp" #include "util/io.hpp"
#include "util/log.hpp"
#include "util/name_table.hpp" #include "util/name_table.hpp"
#include "util/range_table.hpp" #include "util/range_table.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp" #include "util/timing_util.hpp"
#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_edge_container.hpp"
@@ -43,7 +44,6 @@
#include <atomic> #include <atomic>
#include <bitset> #include <bitset>
#include <chrono> #include <chrono>
#include <chrono>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
@@ -119,12 +119,12 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
tbb::task_scheduler_init init(number_of_threads); 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()) 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; ExtractionContainers extraction_containers;
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(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_ways = 0;
unsigned number_of_relations = 0; unsigned number_of_relations = 0;
util::SimpleLogger().Write() << "Parsing in progress.."; util::Log() << "Parsing in progress..";
TIMER_START(parsing); TIMER_START(parsing);
// setup raster sources // setup raster sources
@@ -148,7 +148,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
{ {
generator = "unknown tool"; generator = "unknown tool";
} }
util::SimpleLogger().Write() << "input file generated by " << generator; util::Log() << "input file generated by " << generator;
// write .timestamp data file // write .timestamp data file
std::string timestamp = header.get("osmosis_replication_timestamp"); std::string timestamp = header.get("osmosis_replication_timestamp");
@@ -156,7 +156,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
{ {
timestamp = "n/a"; timestamp = "n/a";
} }
util::SimpleLogger().Write() << "timestamp: " << timestamp; util::Log() << "timestamp: " << timestamp;
boost::filesystem::ofstream timestamp_out(config.timestamp_file_name); boost::filesystem::ofstream timestamp_out(config.timestamp_file_name);
timestamp_out.write(timestamp.c_str(), timestamp.length()); timestamp_out.write(timestamp.c_str(), timestamp.length());
@@ -210,12 +210,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
} }
} }
TIMER_STOP(parsing); TIMER_STOP(parsing);
util::SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) util::Log() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
<< " seconds";
util::SimpleLogger().Write() << "Raw input contains " << number_of_nodes << " nodes, " util::Log() << "Raw input contains " << number_of_nodes << " nodes, " << number_of_ways
<< number_of_ways << " ways, and " << number_of_relations << " ways, and " << number_of_relations << " relations";
<< " relations";
// take control over the turn lane map // take control over the turn lane map
turn_lane_map = extractor_callbacks->moveOutLaneDescriptionMap(); turn_lane_map = extractor_callbacks->moveOutLaneDescriptionMap();
@@ -224,8 +222,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
if (extraction_containers.all_edges_list.empty()) if (extraction_containers.all_edges_list.empty())
{ {
util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting."; throw util::exception(std::string("There are no edges remaining after parsing.") +
return 1; SOURCE_REF);
} }
extraction_containers.PrepareData(scripting_environment, extraction_containers.PrepareData(scripting_environment,
@@ -237,15 +235,14 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
scripting_environment.GetProfileProperties()); scripting_environment.GetProfileProperties());
TIMER_STOP(extracting); TIMER_STOP(extracting);
util::SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
<< "s";
} }
{ {
// Transform the node-based graph that OSM is based on into an edge-based graph // Transform the node-based graph that OSM is based on into an edge-based graph
// that is better for routing. Every edge becomes a node, and every valid // 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 // 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); TIMER_START(expansion);
@@ -267,17 +264,16 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
TIMER_STOP(expansion); 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); TIMER_START(timer_write_node_weights);
util::serializeVector(config.edge_based_node_weights_output_path, edge_based_node_weights); util::serializeVector(config.edge_based_node_weights_output_path, edge_based_node_weights);
TIMER_STOP(timer_write_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); 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); TIMER_START(rtree);
BuildRTree(std::move(edge_based_node_list), BuildRTree(std::move(edge_based_node_list),
std::move(node_is_startpoint), std::move(node_is_startpoint),
@@ -285,7 +281,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
TIMER_STOP(rtree); TIMER_STOP(rtree);
util::SimpleLogger().Write() << "Writing node map ..."; util::Log() << "Writing node map ...";
WriteNodeMapping(internal_to_external_node_map); WriteNodeMapping(internal_to_external_node_map);
WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list); 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 = const auto edges_per_second =
static_cast<std::uint64_t>((max_edge_id + 1) / TIMER_SEC(expansion)); static_cast<std::uint64_t>((max_edge_id + 1) / TIMER_SEC(expansion));
util::SimpleLogger().Write() << "Expansion: " << nodes_per_second << " nodes/sec and " util::Log() << "Expansion: " << nodes_per_second << " nodes/sec and " << edges_per_second
<< edges_per_second << " edges/sec"; << " edges/sec";
util::SimpleLogger().Write() << "To prepare the data for routing, run: " util::Log() << "To prepare the data for routing, run: "
<< "./osrm-contract " << config.output_file_name << std::endl; << "./osrm-contract " << config.output_file_name;
} }
return 0; return 0;
@@ -310,7 +306,7 @@ void Extractor::WriteProfileProperties(const std::string &output_path,
boost::filesystem::ofstream out_stream(output_path); boost::filesystem::ofstream out_stream(output_path);
if (!out_stream) 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)); 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::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); 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( NodeID number_of_node_based_nodes = util::loadNodesFromFile(
file_reader, barriers_iter, traffic_signals_iter, internal_to_external_node_map); file_reader, barriers_iter, traffic_signals_iter, internal_to_external_node_map);
util::SimpleLogger().Write() << " - " << barriers.size() << " bollard nodes, " util::Log() << " - " << barriers.size() << " bollard nodes, " << traffic_signals.size()
<< traffic_signals.size() << " traffic lights"; << " traffic lights";
std::vector<NodeBasedEdge> edge_list; std::vector<NodeBasedEdge> edge_list;
util::loadEdgesFromFile(file_reader, edge_list); util::loadEdgesFromFile(file_reader, edge_list);
if (edge_list.empty()) if (edge_list.empty())
{ {
util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting."; throw util::exception("Node-based-graph (" + config.output_file_name +
return std::shared_ptr<util::NodeBasedDynamicGraph>(); ") contains no edges." + SOURCE_REF);
} }
return util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list); 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, std::vector<bool> node_is_startpoint,
const std::vector<QueryNode> &internal_to_external_node_map) const std::vector<QueryNode> &internal_to_external_node_map)
{ {
util::SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size() util::Log() << "constructing r-tree of " << node_based_edge_list.size()
<< " edge elements build on-top of " << " edge elements build on-top of " << internal_to_external_node_map.size()
<< internal_to_external_node_map.size() << " coordinates"; << " coordinates";
BOOST_ASSERT(node_is_startpoint.size() == node_based_edge_list.size()); 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) if (new_size == 0)
{ {
throw util::exception("There are no snappable edges left after processing. Are you " 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); 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); internal_to_external_node_map);
TIMER_STOP(construction); TIMER_STOP(construction);
util::SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction) util::Log() << "finished r-tree construction in " << TIMER_SEC(construction) << " seconds";
<< " seconds";
} }
void Extractor::WriteEdgeBasedGraph( void Extractor::WriteEdgeBasedGraph(
@@ -590,8 +586,7 @@ void Extractor::WriteEdgeBasedGraph(
const util::FingerPrint fingerprint = util::FingerPrint::GetValid(); const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint)); file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
util::SimpleLogger().Write() << "[extractor] Writing edge-based-graph edges ... " util::Log() << "Writing edge-based-graph edges ... " << std::flush;
<< std::flush;
TIMER_START(write_edges); TIMER_START(write_edges);
std::uint64_t number_of_used_edges = edge_based_edge_list.size(); std::uint64_t number_of_used_edges = edge_based_edge_list.size();
@@ -604,9 +599,9 @@ void Extractor::WriteEdgeBasedGraph(
} }
TIMER_STOP(write_edges); 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( void Extractor::WriteIntersectionClassificationData(
@@ -618,12 +613,11 @@ void Extractor::WriteIntersectionClassificationData(
std::ofstream file_out_stream(output_file_name.c_str(), std::ios::binary); std::ofstream file_out_stream(output_file_name.c_str(), std::ios::binary);
if (!file_out_stream) if (!file_out_stream)
{ {
util::SimpleLogger().Write(logWARNING) << "Failed to open " << output_file_name util::Log(logERROR) << "Failed to open " << output_file_name << " for writing";
<< " for writing";
return; return;
} }
util::SimpleLogger().Write() << "Writing Intersection Classification Data"; util::Log() << "Writing Intersection Classification Data";
TIMER_START(write_edges); TIMER_START(write_edges);
util::writeFingerprint(file_out_stream); util::writeFingerprint(file_out_stream);
util::serializeVector(file_out_stream, node_based_intersection_classes); util::serializeVector(file_out_stream, node_based_intersection_classes);
@@ -652,16 +646,15 @@ void Extractor::WriteIntersectionClassificationData(
if (!static_cast<bool>(file_out_stream)) 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); util::serializeVector(file_out_stream, entry_classes);
TIMER_STOP(write_edges); TIMER_STOP(write_edges);
util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s for " util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s for "
<< node_based_intersection_classes.size() << " Indices into " << node_based_intersection_classes.size() << " Indices into "
<< bearing_classes.size() << " bearing classes and " << bearing_classes.size() << " bearing classes and " << entry_classes.size()
<< entry_classes.size() << " entry classes and " << total_bearings << " entry classes and " << total_bearings << " bearing values.";
<< " bearing values." << std::endl;
} }
void Extractor::WriteTurnLaneData(const std::string &turn_lane_file) const 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::vector<guidance::TurnLaneType::Mask> turn_lane_masks;
std::tie(turn_lane_offsets, turn_lane_masks) = transformTurnLaneMapIntoArrays(turn_lane_map); 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); TIMER_START(turn_lane_timer);
std::ofstream ofs(turn_lane_file, std::ios::binary); std::ofstream ofs(turn_lane_file, std::ios::binary);
if (!ofs) 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)) if (!util::serializeVector(ofs, turn_lane_offsets))
{ {
util::SimpleLogger().Write(logWARNING) << "Error while writing."; throw util::exception("Error while writing to " + turn_lane_file + SOURCE_REF);
return;
} }
if (!util::serializeVector(ofs, turn_lane_masks)) if (!util::serializeVector(ofs, turn_lane_masks))
{ {
util::SimpleLogger().Write(logWARNING) << "Error while writing."; throw util::exception("Error while writing to " + turn_lane_file + SOURCE_REF);
return;
} }
TIMER_STOP(turn_lane_timer); TIMER_STOP(turn_lane_timer);
util::SimpleLogger().Write() << "done (" << TIMER_SEC(turn_lane_timer) << ")"; util::Log() << "done (" << TIMER_SEC(turn_lane_timer) << ")";
} }
} // namespace extractor } // namespace extractor
+6 -11
View File
@@ -8,7 +8,7 @@
#include "util/for_each_pair.hpp" #include "util/for_each_pair.hpp"
#include "util/guidance/turn_lanes.hpp" #include "util/guidance/turn_lanes.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
#include <boost/numeric/conversion/cast.hpp> #include <boost/numeric/conversion/cast.hpp>
#include <boost/optional/optional.hpp> #include <boost/optional/optional.hpp>
@@ -62,7 +62,7 @@ void ExtractorCallbacks::ProcessRestriction(
if (restriction) if (restriction)
{ {
external_memory.restrictions_list.push_back(restriction.get()); 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 << // ",via: " << restriction.get().restriction.via.node <<
// ", to: " << restriction.get().restriction.to.node << // ", to: " << restriction.get().restriction.to.node <<
// ", only: " << (restriction.get().restriction.flags.is_only ? // ", 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()) if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id())
{ {
util::SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id() util::Log(logDEBUG) << "found bogus way with id: " << input_way.id() << " of size "
<< " of size " << input_way.nodes().size(); << input_way.nodes().size();
return; return;
} }
@@ -135,8 +135,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID && if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID &&
backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID) backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
{ {
util::SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " util::Log(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
<< input_way.id();
return; return;
} }
@@ -196,8 +195,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (translated_mask == TurnLaneType::empty) if (translated_mask == TurnLaneType::empty)
{ {
// if we have unsupported tags, don't handle them // if we have unsupported tags, don't handle them
util::SimpleLogger().Write(logDEBUG) << "Unsupported lane tag found: \"" util::Log(logDEBUG) << "Unsupported lane tag found: \"" << *token_itr << "\"";
<< *token_itr << "\"";
return {}; return {};
} }
@@ -328,7 +326,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
false, false,
parsed_way.roundabout, parsed_way.roundabout,
parsed_way.circular, parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint, parsed_way.is_startpoint,
parsed_way.backward_travel_mode, parsed_way.backward_travel_mode,
false, false,
@@ -361,7 +358,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
!forward_only, !forward_only,
parsed_way.roundabout, parsed_way.roundabout,
parsed_way.circular, parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint, parsed_way.is_startpoint,
parsed_way.forward_travel_mode, parsed_way.forward_travel_mode,
split_edge, split_edge,
@@ -384,7 +380,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
true, true,
parsed_way.roundabout, parsed_way.roundabout,
parsed_way.circular, parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint, parsed_way.is_startpoint,
parsed_way.backward_travel_mode, parsed_way.backward_travel_mode,
true, true,
+3 -1
View File
@@ -14,7 +14,9 @@ IntersectionPrinter::IntersectionPrinter(
const std::vector<extractor::QueryNode> &node_coordinates, const std::vector<extractor::QueryNode> &node_coordinates,
const extractor::guidance::CoordinateExtractor &coordinate_extractor) const extractor::guidance::CoordinateExtractor &coordinate_extractor)
: node_based_graph(node_based_graph), node_coordinates(node_coordinates), : node_based_graph(node_based_graph), node_coordinates(node_coordinates),
coordinate_extractor(coordinate_extractor){}; coordinate_extractor(coordinate_extractor)
{
}
util::json::Array IntersectionPrinter:: util::json::Array IntersectionPrinter::
operator()(const NodeID intersection_node, operator()(const NodeID intersection_node,
+166 -158
View File
@@ -6,7 +6,7 @@
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
#include "util/percent.hpp" #include "util/percent.hpp"
#include "util/simple_logger.hpp" #include "util/log.hpp"
namespace osrm 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_nodes = graph.GetNumberOfNodes();
const unsigned original_number_of_edges = graph.GetNumberOfEdges(); 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 for (const NodeID node_v : util::irange(0u, original_number_of_nodes))
if (2 != graph.GetOutDegree(node_v))
{ {
continue; progress.PrintStatus(node_v);
}
// don't contract barrier node // only contract degree 2 vertices
if (barrier_nodes.end() != barrier_nodes.find(node_v)) if (2 != graph.GetOutDegree(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)
continue; continue;
}
// Get distances before graph is modified // don't contract barrier node
const int forward_weight1 = graph.GetEdgeData(forward_e1).distance; if (barrier_nodes.end() != barrier_nodes.find(node_v))
const int forward_weight2 = graph.GetEdgeData(forward_e2).distance; {
continue;
}
BOOST_ASSERT(0 != forward_weight1); // check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
BOOST_ASSERT(0 != forward_weight2); if (restriction_map.IsViaNode(node_v))
{
continue;
}
const int reverse_weight1 = graph.GetEdgeData(reverse_e1).distance; // reverse_e2 forward_e2
const int reverse_weight2 = graph.GetEdgeData(reverse_e2).distance; // 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); const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
BOOST_ASSERT(0 != reverse_weight2); const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);
// add weight of e2's to e1 const NodeID node_w = graph.GetTarget(forward_e2);
graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance; BOOST_ASSERT(SPECIAL_NODEID != node_w);
graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance; 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 const EdgeID forward_e1 = graph.FindEdge(node_u, node_v);
graph.SetTarget(forward_e1, node_w); BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
graph.SetTarget(reverse_e1, node_u); 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);
* Remember Lane Data for compressed parts. This handles scenarios where lane-data is const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1);
* 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) if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
graph.DeleteEdge(node_v, forward_e2); {
graph.DeleteEdge(node_v, reverse_e2); continue;
}
// update any involved turn restrictions // this case can happen if two ways with different names overlap
restriction_map.FixupStartingTurnRestriction(node_u, node_v, node_w); if (fwd_edge_data1.name_id != rev_edge_data1.name_id ||
restriction_map.FixupArrivingTurnRestriction(node_u, node_v, node_w, graph); fwd_edge_data2.name_id != rev_edge_data2.name_id)
{
continue;
}
restriction_map.FixupStartingTurnRestriction(node_w, node_v, node_u); if (fwd_edge_data1.CanCombineWith(fwd_edge_data2) &&
restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph); 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 // Do not compress edge if it crosses a traffic signal.
geometry_compressor.CompressEdge( // This can't be done in CanCombineWith, becase we only store the
forward_e1, forward_e2, node_v, node_w, forward_weight1, forward_weight2); // traffic signals in the `traffic_lights` list, which EdgeData
geometry_compressor.CompressEdge( // doesn't have access to.
reverse_e1, reverse_e2, node_v, node_u, reverse_weight1, reverse_weight2); 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)); new_edge_count += (graph.EndEdges(i) - graph.BeginEdges(i));
} }
} }
util::SimpleLogger().Write() << "Node compression ratio: " util::Log() << "Node compression ratio: " << new_node_count / (double)original_number_of_nodes;
<< new_node_count / (double)original_number_of_nodes; util::Log() << "Edge compression ratio: " << new_edge_count / (double)original_number_of_edges;
util::SimpleLogger().Write() << "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/coordinate_extractor.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/toolkit.hpp"
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <iomanip>
#include <limits>
#include <numeric> #include <numeric>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <boost/range/algorithm/transform.hpp> #include "util/bearing.hpp"
#include "util/coordinate_calculation.hpp"
using osrm::util::angularDeviation;
namespace osrm namespace osrm
{ {
@@ -55,7 +55,7 @@ double GetOffsetCorrectionFactor(const RoadClassification &road_classification)
default: default:
return 1.0; return 1.0;
}; };
}; }
} }
CoordinateExtractor::CoordinateExtractor( 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 // 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 // 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 // fallback, mostly necessary for dead ends
if (intersection_node == to_node) if (intersection_node == to_node)
{ {
const auto result = ExtractCoordinateAtLength( const auto result = ExtractCoordinateAtLength(
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates); skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(coordinates.back())); BOOST_ASSERT(is_valid_result(result));
return result; return result;
} }
@@ -147,7 +147,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
if (turn_edge_data.roundabout || turn_edge_data.circular) if (turn_edge_data.roundabout || turn_edge_data.circular)
{ {
const auto result = ExtractCoordinateAtLength( const auto result = ExtractCoordinateAtLength(
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates); skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result)); BOOST_ASSERT(is_valid_result(result));
return 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 we are now left with two, well than we don't have to worry, or the segment is very small
if (coordinates.size() == 2 || 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())); BOOST_ASSERT(is_valid_result(coordinates.back()));
return coordinates.back(); return coordinates.back();
@@ -253,7 +253,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
if (coordinates.front() == coordinates.back()) if (coordinates.front() == coordinates.back())
{ {
const auto result = ExtractCoordinateAtLength( const auto result = ExtractCoordinateAtLength(
distance_to_skip_over_due_to_coordinate_inaccuracies, coordinates); skipping_inaccuracies_distance, coordinates);
BOOST_ASSERT(is_valid_result(result)); BOOST_ASSERT(is_valid_result(result));
return result; return result;
} }
@@ -337,38 +337,9 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
return result; return result;
} }
if (IsCurve(coordinates, // We check offsets before curves to avoid detecting lane offsets due to large roads as curves
segment_distances, // (think major highway here). If the road is wide, it can have quite a few coordinates in the
total_distance, // beginning.
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;
}
if (IsDirectOffset(coordinates, if (IsDirectOffset(coordinates,
straight_index, straight_index,
straight_distance, straight_distance,
@@ -387,6 +358,40 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
return result; 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 // skip over the first coordinates, in specific the assumed lane count. We add a small
// safety factor, to not overshoot on the regression // 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 // find the beginning fo the segment (begin here and above for the length cache need to match
// up!) // up!)
const auto coordinate_base = const auto coordinate_after =
std::find_if(coordinates.begin() + 1, coordinates.end(), find_coordinate_at_distance) - 1; 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) >= if (coordinate_after == coordinates.end())
coordinates.size())
return coordinates.back(); return coordinates.back();
const auto interpolation_factor = const auto interpolation_factor =
ComputeInterpolationFactor(distance - accumulated_distance, 0, *length_cache_itr); ComputeInterpolationFactor(distance - accumulated_distance, 0, *length_cache_itr);
return util::coordinate_calculation::interpolateLinear( return util::coordinate_calculation::interpolateLinear(
interpolation_factor, *coordinate_base, *(coordinate_base + 1)); interpolation_factor, *std::prev(coordinate_after), *coordinate_after);
} }
util::Coordinate CoordinateExtractor::ExtractCoordinateAtLength( util::Coordinate CoordinateExtractor::ExtractCoordinateAtLength(
@@ -475,26 +479,29 @@ util::Coordinate CoordinateExtractor::ExtractCoordinateAtLength(
util::coordinate_calculation::haversineDistance(last_coordinate, coordinate); util::coordinate_calculation::haversineDistance(last_coordinate, coordinate);
const auto result = (accumulated_distance + segment_distance) >= distance; const auto result = (accumulated_distance + segment_distance) >= distance;
if (!result) if (!result)
{
accumulated_distance += segment_distance; accumulated_distance += segment_distance;
last_coordinate = coordinate;
}
return result; return result;
}; };
// find the begin of the segment containing the coordinate // find the begin of the segment containing the coordinate
const auto coordinate_base = const auto coordinate_after =
std::find_if(coordinates.begin() + 1, coordinates.end(), coordinate_at_distance) - 1; std::find_if(coordinates.begin() + 1, coordinates.end(), coordinate_at_distance);
if (static_cast<std::size_t>(std::distance(coordinates.begin(), coordinate_base) + 1) >= if (coordinate_after == coordinates.end())
coordinates.size())
return coordinates.back(); return coordinates.back();
const auto interpolation_factor = ComputeInterpolationFactor( const auto interpolation_factor =
distance - accumulated_distance, ComputeInterpolationFactor(distance - accumulated_distance,
0, 0,
util::coordinate_calculation::haversineDistance(*coordinate_base, *(coordinate_base + 1))); util::coordinate_calculation::haversineDistance(
*std::prev(coordinate_after), *coordinate_after));
return util::coordinate_calculation::interpolateLinear( 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, util::Coordinate CoordinateExtractor::GetCoordinateCloseToTurn(const NodeID from_node,
@@ -598,6 +605,9 @@ CoordinateExtractor::GetCoordinatesAlongRoad(const NodeID intersection_node,
std::back_inserter(result), std::back_inserter(result),
compressedGeometryToCoordinate); compressedGeometryToCoordinate);
} }
// filter duplicated coordinates
auto end = std::unique(result.begin(), result.end());
result.erase(end, result.end());
return result; 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) = std::tie(has_up_down_deviation, maximum_deviation_index, maximum_deviation) =
[&coordinates, get_deviation]() -> std::tuple<bool, std::size_t, double> { [&coordinates, get_deviation]() -> std::tuple<bool, std::size_t, double> {
const auto increasing = [&](const util::Coordinate lhs, const util::Coordinate rhs) { 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); get_deviation(coordinates.front(), coordinates.back(), rhs);
}; };
const auto decreasing = [&](const util::Coordinate lhs, const util::Coordinate 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); get_deviation(coordinates.front(), coordinates.back(), rhs);
}; };
@@ -707,16 +717,17 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
return std::make_tuple( return std::make_tuple(
true, 1, get_deviation(coordinates.front(), coordinates.back(), coordinates[1])); 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); 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.); return std::make_tuple(true, coordinates.size() - 1, 0.);
else if (std::is_sorted(maximum_itr, coordinates.end(), decreasing)) else if (std::is_sorted(one_past_maximum_iter, coordinates.end(), decreasing))
return std::make_tuple( return std::make_tuple(true,
true, std::distance(coordinates.begin(), one_past_maximum_iter) - 1,
std::distance(coordinates.begin(), maximum_itr), get_deviation(coordinates.front(),
get_deviation(coordinates.front(), coordinates.back(), *maximum_itr)); coordinates.back(),
*(one_past_maximum_iter - 1)));
else else
return std::make_tuple(false, 0, 0.); 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 // if the maximum deviation is at a quarter of the total curve, we are probably looking at a
// normal turn // normal turn
const auto distance_to_max_deviation = std::accumulate( 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 || if ((distance_to_max_deviation <= 0.35 * segment_length ||
maximum_deviation < std::max(0.3 * considered_lane_width, 0.5 * ASSUMED_LANE_WIDTH)) && 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 = const auto distance_between_last_coordinates =
util::coordinate_calculation::haversineDistance(*(coordinates.end() - 2), util::coordinate_calculation::haversineDistance(*(coordinates.end() - 2),
*(coordinates.end() - 1)); *(coordinates.end() - 1));
const auto interpolation_factor =
ComputeInterpolationFactor(length_cache.back(), 0, distance_between_last_coordinates);
coordinates.back() = util::coordinate_calculation::interpolateLinear( if (distance_between_last_coordinates > 0)
interpolation_factor, *(coordinates.end() - 2), coordinates.back()); {
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; return coordinates;
} }
else else
@@ -1138,7 +1153,8 @@ CoordinateExtractor::RegressionLine(const std::vector<util::Coordinate> &coordin
return {coordinates.front(), coordinates.back()}; return {coordinates.front(), coordinates.back()};
// compute the regression vector based on the sum of least squares // 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 = const auto coord_between_front =
util::coordinate_calculation::projectPointOnSegment( util::coordinate_calculation::projectPointOnSegment(
regression_line.first, regression_line.second, coordinates.front()) regression_line.first, regression_line.second, coordinates.front())

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