Compare commits

..

50 Commits

Author SHA1 Message Date
Daniel Patterson a0b1a5df8c Update version and CHANGELOG for 5.5.3. 2017-01-11 17:14:18 -08:00
Daniel Patterson 411313f666 Backport NumLanesToTheRight/NumLanesToTheLeft to support 6ea9f9fdf1 2017-01-11 16:44:25 -08:00
Moritz Kobitzsch ada0a1e8f8 fix coordinate assertion for walking profile with steps 2017-01-11 21:57:11 +00:00
Moritz Kobitzsch 74611f94fa Remove assertions that could be triggered by bad data. (#3469)
When two consecutive nodes have identical coordinates, there is no valid
bearing.  For now, make equal nodes have bearing 0.

Full fix still needs to be done via https://github.com/Project-OSRM/osrm-backend/issues/3470.
2017-01-11 21:55:29 +00:00
Michael Krasnyk eaff3b4210 Make a hard reset of named barrier mutexes on signal 2017-01-11 21:43:01 +00:00
Jihyun Yu 1fb9f3e1eb Fix copying vector on std::sort comparator (#3504) 2017-01-11 21:41:17 +00:00
Daniel J. Hofmann 6ea9f9fdf1 Consider number of lanes to cross, resolves #3025.
Lane Anticipation currently triggers on quick steps with lanes. This
changeset makes the "quick" part more dynamic by taking lanes left and
right of the turn into account. The reasoning for this is as follows.

The user can drive on the leftmost or rightmost lane and has to cross
all lanes left or right of the turn, respecitvely.

We scale our threshold appropriately, which now means the threshold
describes the duration the user needs for crossing _a single lane_.

Note: this is a heuristic and assumes the worst case. Which in my
opinion is fine to do since triggering Lane Anticipation in complex
scenarios is desirable.
2017-01-11 21:37:17 +00:00
Daniel Patterson 434a3a638a Make Travis buildit. 2016-12-21 15:31:03 -08:00
Daniel Patterson 6305f4a529 Update changelog and version. 2016-12-21 15:18:30 -08:00
Patrick Niklaus 646b1631ab Revert "Smarter search radius formula for map matching"
This reverts commit b73c59088c.
2016-12-21 15:14:33 -08:00
Patrick Niklaus a852ab1c43 Revert "Fix capture"
This reverts commit 4f81e31d63.
2016-12-21 15:14:33 -08:00
Patrick Niklaus ff25fc70f0 Revert "Hardcode search radius parameters"
This reverts commit 2c9e18d5a9.
2016-12-21 15:14:33 -08:00
Patrick Niklaus b34ed587d0 Revert "Fix call to std::min"
This reverts commit 8bb183bc8c.
2016-12-21 15:14:33 -08:00
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
192 changed files with 6511 additions and 3998 deletions
+1
View File
@@ -13,6 +13,7 @@ notifications:
branches:
only:
- master
- 5.5
cache:
ccache: true
+22
View File
@@ -1,3 +1,22 @@
# 5.5.3
- Changes from 5.5.2
- Bugfixes:
- PR #3504 - debug tiles were very slow to generate due to unnecessarily copying data in a hot loop.
- PR #3556 - fix an assertion in the walking profile triggered by tight spiral stairwells
- PR #3469 - don't assert when identical coordinates are supplied to some calculations - OSM data contains these, we shouldn't crash.
- Enhancements:
- backported 6ea9f9fdf19 - when anticipating upcoming lanes, consider how many lanes need to be crossed to get there.
- when using osrm-datastore, it will attempt to clean up locks if it crashes.
# 5.5.2
- Changes from 5.5.1
- Revert smarter map-matching search radius. The increased radius causes performance degredation when map-matching against non-car road networks with more edges.
# 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
- Changes from 5.4.0
- API:
@@ -19,6 +38,7 @@
- Improved turn angle calculation, detecting offsets due to lanes / minor variations due to inaccuracies
- Corrected the bearings returned for intermediate steps - requires reprocessing
- Improved turn locations for collapsed turns
- Sliproad classification refinements: the situations we detect as Sliproads now resemble more closely the reality
- Trip Plugin
- changed internal behaviour to prefer the smallest lexicographic result over the largest one
- Bugfixes
@@ -27,6 +47,8 @@
- fixed a bug that could result in inconsistent behaviour when collapsing instructions
- fixed a bug that could result in crashes when leaving a ferry directly onto a motorway ramp
- fixed a bug in the tile plugin that resulted in discovering invalid edges for connections
- improved error messages when missing files during traffic updates (#3114)
- For single coordinate geometries the GeoJSON `Point` encoding was broken. We now always emit `LineString`s even in the one-coordinate-case (backwards compatible) (#3425)
- Debug Tiles
- Added support for turn penalties
- Internals
+6 -4
View File
@@ -53,9 +53,11 @@ endif()
project(OSRM C CXX)
set(OSRM_VERSION_MAJOR 5)
set(OSRM_VERSION_MINOR 5)
set(OSRM_VERSION_PATCH 0)
set(OSRM_VERSION_PATCH 3)
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
# these two functions build up custom variables:
# DEPENDENCIES_INCLUDE_DIRS and OSRM_DEFINES
# These variables we want to pass to
@@ -92,7 +94,7 @@ endif()
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/variant/include)
add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
@@ -637,7 +639,7 @@ set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
file(GLOB VariantGlob third_party/variant/*.hpp)
file(GLOB VariantGlob third_party/variant/include/mapbox/*.hpp)
file(GLOB LibraryGlob include/osrm/*.hpp)
file(GLOB ParametersGlob include/engine/api/*_parameters.hpp)
set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/phantom_node.hpp)
@@ -652,7 +654,7 @@ install(FILES ${ExtractorHeader} DESTINATION include/osrm/extractor)
install(FILES ${ContractorHeader} DESTINATION include/osrm/contractor)
install(FILES ${LibraryGlob} DESTINATION include/osrm)
install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api)
install(FILES ${VariantGlob} DESTINATION include/variant)
install(FILES ${VariantGlob} DESTINATION include/mapbox)
install(TARGETS osrm-extract DESTINATION bin)
install(TARGETS osrm-contract DESTINATION bin)
install(TARGETS osrm-datastore DESTINATION bin)
+1 -1
View File
@@ -519,7 +519,7 @@ step.
|------------|--------------------------------------------------------------------|
| polyline | [polyline](https://www.npmjs.com/package/polyline) with precision 5 in [latitude,longitude] encoding |
| polyline6 | [polyline](https://www.npmjs.com/package/polyline) with precision 6 in [latitude,longitude] encoding |
| geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) or [GeoJSON `Point`](http://geojson.org/geojson-spec.html#point) if it is only one coordinate (not wrapped by a GeoJSON feature)|
| geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) |
- `name`: The name of the way along which travel proceeds.
- `ref`: A reference number or code for the way. Optionally included, if ref data is available for the given way.
+45 -2
View File
@@ -30,6 +30,35 @@ Feature: Car - Restricted access
| | | no | yes | x |
| | | yes | no | |
Scenario: Car - Access tag hierarchy and forward/backward
Then routability should be
| access | access:forward | access:backward | motorcar | motorcar:forward | motorcar:backward | forw | backw |
| | | | | | | x | x |
| yes | | | | | | x | x |
| yes | no | | | | | | x |
| yes | yes | | no | | | | |
| yes | yes | | yes | no | | | x |
| yes | | | | | | x | x |
| yes | | no | | | | x | |
| yes | | yes | no | | | | |
| yes | | yes | yes | | no | x | |
| no | | | | | | | |
| no | yes | | | | | x | |
| no | no | | yes | | | x | x |
| no | no | | no | yes | | x | |
| no | | | | | | | |
| no | | yes | | | | | x |
| no | | no | yes | | | x | x |
| no | | no | no | | yes | | x |
| | no | | | no | | | x |
| | | no | | | no | x | |
| | no | | | | no | | |
| | | no | no | | | | |
| | no | | | yes | | x | x |
| | | no | | | yes | x | x |
| | yes | | | no | | | x |
| | | yes | | | no | x | |
Scenario: Car - Access tag hierarchy on nodes
Then routability should be
| node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
@@ -149,6 +178,7 @@ Feature: Car - Restricted access
| runway | | | | yes | |
| primary | | | | no | x |
@hov
Scenario: Car - only designated HOV ways are ignored by default
Then routability should be
| highway | hov | bothw |
@@ -156,6 +186,7 @@ Feature: Car - Restricted access
| primary | yes | x |
| primary | no | x |
@hov
Scenario: Car - a way with all lanes HOV-designated is inaccessible by default (similar to hov=designated)
Then routability should be
| highway | hov:lanes:forward | hov:lanes:backward | hov:lanes | oneway | forw | backw |
@@ -166,8 +197,8 @@ Feature: Car - Restricted access
| primary | designated\|no | designated\|no | | | x | x |
| primary | yes\|no | yes\|no | | | x | x |
| primary | | | | | x | x |
| primary | designated | | | -1 | | |
| primary | | designated | | -1 | | x |
| primary | designated | | | -1 | | x |
| primary | | designated | | -1 | | |
| primary | | | designated | yes | | |
| primary | | | designated | -1 | | |
| primary | | | designated\| | yes | x | |
@@ -189,3 +220,15 @@ Feature: Car - Restricted access
Then routability should be
| highway | toll | bothw |
| primary | yes | |
Scenario: Car - directional access tags
Then routability should be
| highway | access | access:forward | access:backward | forw | backw |
| primary | yes | yes | yes | x | x |
| primary | yes | | no | x | |
| primary | yes | no | | | x |
| primary | yes | no | no | | |
| primary | no | no | no | | |
| primary | no | | yes | | x |
| primary | no | yes | | x | |
| primary | no | yes | yes | x | x |
+11
View File
@@ -123,3 +123,14 @@ OSRM will use 4/5 of the projected free-flow speed.
| primary | 30 | 1 | -1 | | 23 km/h |
| primary | 30 | 1 | | 15 km/h | 15 km/h |
| primary | 30 | 2 | | 23 km/h | 23 km/h |
Scenario: Car - Forwward/backward maxspeed on reverse oneways
Then routability should be
| highway | maxspeed | maxspeed:forward | maxspeed:backward | oneway | forw | backw |
| primary | | | | -1 | | 52 km/h |
| primary | 30 | | | -1 | | 23 km/h |
| primary | | 30 | | -1 | | 52 km/h |
| primary | | | 30 | -1 | | 23 km/h |
| primary | 20 | 30 | | -1 | | 16 km/h |
| primary | 20 | | 30 | -1 | | 23 km/h |
+13 -13
View File
@@ -78,24 +78,24 @@ Feature: Car - Street names in instructions
Scenario: Inner city expressway with on road
Given the node map
"""
a b c g
f
a b . . . c g
`f .
`
.
.
d
.
.
.
e
"""
And the ways
| nodes | highway | name | name:pronunciation |
| abc | primary | road | roooaad |
| cg | primary | road | roooaad |
| bfd | trunk_link | | |
| cde | trunk | trunk | truank |
| nodes | highway | name | name:pronunciation | oneway |
| abc | primary | road | roooaad | |
| cg | primary | road | roooaad | |
| bfd | trunk_link | sliproad | | yes |
| cde | trunk | trunk | truank | yes |
And the relations
| type | way:from | way:to | node:via | restriction |
+24 -15
View File
@@ -5,13 +5,17 @@ Feature: Turn Lane Guidance
Given the profile "car"
Given a grid size of 3 meters
@sliproads
Scenario: Separate Turn Lanes
Given the node map
"""
e
a b c g
d
.
a ... b ..... c . g
` .
`... d
.
f
"""
@@ -41,8 +45,10 @@ Feature: Turn Lane Guidance
Given the node map
"""
e
a b c g
d
a . . b . . . c g
` .
` .
` d
f
"""
@@ -67,21 +73,22 @@ Feature: Turn Lane Guidance
| a,g | in,straight,straight | depart,new name straight,arrive | ,left:false straight:true right:false, |
| a,f | in,cross,cross | depart,turn right,arrive | ,left:false straight:false right:true, |
@sliproads
Scenario: Separate Turn Lanes Next to other turns
Given the node map
"""
e
a - - b.-.- - c-g
| ' 'd
| f
|
|
|
|
|
|
i - - h - - - j
. e
a . . b . . . c g
. ` .
. ` .
. d
. f
.
.
.
.
i . . h . . . j
"""
And the ways
@@ -109,6 +116,7 @@ Feature: Turn Lane Guidance
| a,j | in,turn,other,other | depart,turn right,turn left,arrive | ,,left:true right:false, |
| a,i | in,turn,other,other | depart,turn right,turn right,arrive | ,,left:false right:true, |
@todo @2654 @none
#https://github.com/Project-OSRM/osrm-backend/issues/2645
#http://www.openstreetmap.org/export#map=19/52.56054/13.32152
@@ -231,6 +239,7 @@ Feature: Turn Lane Guidance
| a,j | ghough,market,market | depart,turn left,arrive | ,none:true straight:false straight:false straight:false, |
| a,f | ghough,ghough,ghough | depart,continue slight left,arrive | ,none:true straight:true straight:false straight:false, |
Scenario: Check sliproad handler loop's exit condition, Issue #2896
# http://www.openstreetmap.org/way/198481519
Given the node locations
@@ -783,3 +783,38 @@ Feature: Turn Lane Guidance
| waypoints | route | turns | lanes |
| a,f | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,turn right,arrive | ,left:false left:true none:false none:false,left:false left:true none:false none:false,left:false left:true none:false none:false,left:false left:false right:true, |
| a,g | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,turn left,arrive | ,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true right:false, |
@anticipate
Scenario: Complex lane scenarios scale threshold for triggering Lane Anticipation
Given the node map
"""
a b x
|
|
|
|
|
|
|
|
|
|
c
|
e d y
"""
# With a grid size of 20m the duration is ~20s but our default threshold for Lane Anticipation is 15s.
# The additional lanes left and right of the turn scale the threshold up so that Lane Anticipation still triggers.
And the ways
| nodes | turn:lanes:forward | name |
| ab | through\|through\|right\|right | MySt |
| bx | | XSt |
| bc | | MySt |
| cd | left\|right | MySt |
| de | | MySt |
| dy | | YSt |
When I route I should get
| waypoints | route | turns | lanes |
| a,e | MySt,MySt,MySt,MySt | depart,continue right,turn right,arrive | ,straight:false straight:false right:false right:true,left:false right:true, |
+35
View File
@@ -55,3 +55,38 @@ Feature: Collapse
| waypoints | route | turns |
| a,g | road,road,road | depart,continue uturn,arrive |
| d,c | road,road,road | depart,continue uturn,arrive |
Scenario: Forking before a turn (forky)
Given the node map
"""
g
.
c
a . . b .'
`d.
f e
"""
# note: check clooapse.feature for a similar test case where we do not
# classify the situation as Sliproad and therefore keep the fork inst.
And the ways
| nodes | name | oneway | highway |
| ab | road | yes | primary |
| bd | road | yes | primary |
| bc | road | yes | primary |
| de | road | yes | primary |
| fd | cross | no | secondary |
| dc | cross | no | secondary |
| cg | cross | no | secondary |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bd | dc | d | no_left_turn |
| restriction | bc | dc | c | no_right_turn |
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road,road | depart,continue right,arrive |
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
| a,f | road,road,cross,cross | depart,continue slight right,turn right,arrive |
+9 -7
View File
@@ -701,12 +701,15 @@ Feature: Collapse
Given the node map
"""
g
.
c
a b
d
a . . b .'
` d.
f e
"""
# as it is right now we don't classify this as a sliproad,
# check collapse-detail.feature for a similar test case
# which removes the fork here due to it being a Sliproad.
And the ways
| nodes | name | oneway | highway |
@@ -725,10 +728,9 @@ Feature: Collapse
When I route I should get
| waypoints | route | turns |
| a,g | road,cross,cross | depart,turn left,arrive |
| a,e | road,road,road | depart,continue straight,arrive |
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
| a,f | road,road,cross,cross | depart,continue straight,turn right,arrive |
| a,g | road,cross,cross | depart,fork left,arrive |
| a,e | road,road,road | depart,fork slight right,arrive |
| a,f | road,road,cross,cross | depart,fork slight right,turn right,arrive |
Scenario: On-Off on Highway
Given the node map
+389 -38
View File
@@ -9,23 +9,23 @@ Feature: Slipways and Dedicated Turn Lanes
Given the node map
"""
e
a b c d
h
1
a b . . c d
`h .
`
1 `
.
f
.
g
"""
And the ways
| nodes | highway | name |
| abc | trunk | first |
| cd | trunk | first |
| bhf | trunk_link | |
| cfg | primary | second |
| ec | primary | second |
| nodes | highway | name | oneway |
| abc | trunk | first | |
| cd | trunk | first | |
| bhf | trunk_link | | yes |
| cfg | primary | second | yes |
| ec | primary | second | |
And the relations
| type | way:from | way:to | node:via | restriction |
@@ -51,12 +51,12 @@ Feature: Slipways and Dedicated Turn Lanes
"""
And the ways
| nodes | highway | name | maxspeed |
| abc | trunk | first | 70 |
| cd | trunk | first | 2 |
| bhf | trunk_link | | 2 |
| cfg | primary | second | 50 |
| ec | primary | second | 50 |
| nodes | highway | name | maxspeed | oneway |
| abc | trunk | first | 70 | |
| cd | trunk | first | 2 | |
| bhf | trunk_link | | 2 | yes |
| cfg | primary | second | 50 | yes |
| ec | primary | second | 50 | |
And the relations
| type | way:from | way:to | node:via | restriction |
@@ -125,24 +125,24 @@ Feature: Slipways and Dedicated Turn Lanes
Scenario: Inner city expressway with on road
Given the node map
"""
a b c g
f
a b . . . c g
`f .
`
.
.
d
.
.
.
e
"""
And the ways
| nodes | highway | name |
| abc | primary | road |
| cg | primary | road |
| bfd | trunk_link | |
| cde | trunk | trunk |
| nodes | highway | name | oneway |
| abc | primary | road | |
| cg | primary | road | |
| bfd | trunk_link | | yes |
| cde | trunk | trunk | yes |
And the relations
| type | way:from | way:to | node:via | restriction |
@@ -240,8 +240,8 @@ Feature: Slipways and Dedicated Turn Lanes
| qe | secondary_link | Ettlinger Allee | | yes |
When I route I should get
| waypoints | route | turns | ref |
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
| waypoints | route | turns | ref |
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
Scenario: Traffic Lights everywhere
#http://map.project-osrm.org/?z=18&center=48.995336%2C8.383813&loc=48.995467%2C8.384548&loc=48.995115%2C8.382761&hl=en&alt=0
@@ -271,11 +271,11 @@ Feature: Slipways and Dedicated Turn Lanes
| jcghf | primary | Brauerstrasse | yes |
When I route I should get
| waypoints | route | turns |
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
| a,1 | Ebertstrasse,, | depart,turn right,arrive |
| waypoints | route | turns |
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
| a,1 | Ebertstrasse,, | depart,turn slight right,arrive |
#2839
Scenario: Self-Loop
@@ -431,3 +431,354 @@ Feature: Slipways and Dedicated Turn Lanes
When I route I should get
| waypoints | route | turns |
| a,i | road,road,road | depart,fork slight left,arrive |
# The following tests are current false positives / false negatives #3199
@sliproads
# http://www.openstreetmap.org/#map=19/52.59847/13.14815
Scenario: Sliproad Detection
Given the node map
"""
a . . .
. .
b . . . . . . c . . . d
` . .
e . .
` . .
f . .
` . .
g i
` h .
"""
And the ways
| nodes | highway | name |
| abefgh | residential | Nachtigallensteig |
| bcd | residential | Kiebitzsteig |
| cg | residential | Haenflingsteig |
| hid | residential | Waldkauzsteig |
When I route I should get
| waypoints | route | turns |
| a,d | Nachtigallensteig,Kiebitzsteig,Kiebitzsteig | depart,turn left,arrive |
| a,h | Nachtigallensteig,Nachtigallensteig | depart,arrive |
@sliproads
Scenario: Not a obvious Sliproad
Given the node map
"""
d
.
s . a . . b . . c
` .
` e
.`
. `
f g
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbef | primary | dbef | yes |
| aeg | primary | aeg | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,aeg,dbef,dbef | depart,turn right,turn right,arrive |
@sliproads
Scenario: Through Street, not a Sliproad although obvious
Given the node map
"""
d
.
s . a . . b . . c
` .
` e
. `
. `
f g
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbef | primary | dbef | yes |
| aeg | primary | aeg | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,aeg,dbef,dbef | depart,turn right,turn right,arrive |
@sliproads
Scenario: Sliproad target turn is restricted
Given the node map
"""
d
.
s . a . . . . b . . c
` .
` .
` .
` .
`.
e
.`
f `
. ` g
"""
And the ways
| nodes | highway | name | oneway |
| sa | primary | sabc | |
| abc | primary | sabc | |
| dbe | primary | dbef | yes |
| ef | primary | dbef | |
| ae | primary | aeg | yes |
| eg | primary | aeg | |
# the reason we have to split ways at e is that otherwise we can't handle restrictions via e
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | ae | ef | e | no_right_turn |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,dbef,dbef | depart,turn right,arrive |
| s,g | sabc,aeg,aeg | depart,turn right,arrive |
@sliproads
Scenario: Not a Sliproad, road not continuing straight
Given the node map
"""
d
.
s . a . . b . . c
` .
` e . . g
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbe | primary | dbe | yes |
| aeg | primary | aeg | yes |
When I route I should get
| waypoints | route | turns |
| s,c | sabc,sabc | depart,arrive |
| s,g | sabc,aeg,aeg | depart,turn right,arrive |
@sliproads
Scenario: Intersection too far away with Traffic Light shortly after initial split
Given the node map
"""
d
.
s . a . . . . . . . . . . . . . t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . b . . c
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . . . . . . . . . . .
` . . .
` e
.
f
.
"""
And the nodes
| node | highway |
| t | traffic_signals |
And the ways
| nodes | highway | name | oneway |
| satbc | primary | sabc | |
| dbef | primary | dbef | yes |
| ae | primary | ae | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,ae,dbef,dbef | depart,turn slight right,turn right,arrive |
@sliproads
Scenario: Traffic Signal on Sliproad
Given the node map
"""
d
.
s . a . . . . . b . . c
` .
` .
` .
t .
` .
e
.
.
f
"""
And the nodes
| node | highway |
| t | traffic_signals |
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbe | primary | dbe | yes |
| ef | primary | ef | |
| ate | primary | ate | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,ef,ef | depart,turn right,arrive |
@sliproads
Scenario: Sliproad tagged as link
Given the node map
"""
d
.
s . a . . . . . b . . c
` .
` .
` .
` .
` .
e
.
.
f
"""
And the ways
| nodes | highway | name | oneway |
| sabc | motorway | sabc | |
| dbef | motorway | dbef | yes |
| ae | motorway_link | ae | yes |
When I route I should get
| waypoints | route | turns |
| s,f | sabc,dbef,dbef | depart,turn right,arrive |
@sliproads
Scenario: Sliproad with same-ish names
Given the node map
"""
d
.
s . a . . b . . c
` .
. e
..
.
f
.
t
"""
And the ways
| nodes | highway | name | ref | oneway |
| sabc | primary | main | | |
| dbe | primary | crossing | r0 | yes |
| eft | primary | crossing | r0;r1 | yes |
| af | primary | sliproad | | yes |
When I route I should get
| waypoints | route | turns |
| s,t | main,crossing,crossing | depart,turn right,arrive |
@sliproads
Scenario: Not a Sliproad, name mismatch
Given the node map
"""
d
.
s . a . . b . . c
` .
. e
. .
..
.
f
.
t
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | main | |
| dbe | primary | top | yes |
| ef | primary | bottom | yes |
| ft | primary | away | yes |
| af | primary | sliproad | yes |
When I route I should get
| waypoints | route | turns |
| s,t | main,away,away | depart,turn right,arrive |
@sliproads
Scenario: Not a Sliproad, low road priority
Given the node map
"""
d
.
s . a . . b . . c
` .
. e
. .
..
.
f
.
t
"""
And the ways
# maxspeed otherwise service road will never be routed over and we won't see instructions
| nodes | highway | name | maxspeed | oneway |
| sabc | primary | main | 30 km/h | |
| dbe | primary | crossing | 30 km/h | yes |
| eft | primary | crossing | 30 km/h | yes |
| ft | primary | away | 30 km/h | yes |
| af | service | sliproad | 30 km/h | yes |
When I route I should get
| waypoints | route | turns |
| s,t | main,away,away | depart,turn right,arrive |
@sliproads
Scenario: Not a Sliproad, more than three roads at target intersection
Given the node map
"""
d
.
s . a . . b . . c
` .
. e
. .
..
. h
f .
. g
t
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | main | |
| dbe | primary | top | yes |
| eft | primary | bottom | yes |
| fh | primary | another | |
| fg | primary | another | |
| af | primary | sliproad | yes |
When I route I should get
| waypoints | route | turns |
| s,g | main,sliproad,another,another | depart,turn right,turn left,arrive |
+179 -30
View File
@@ -317,30 +317,30 @@ Feature: Simple Turns
Scenario: Curved Turn At Cross
Given the node map
"""
h
|
|
|
|
| . b - - - - - - - - - - - - - - - - - - a
| .
| .
| c
|
|
|
d
|
|
|
e |
. |
. |
g - - - - - - - - - - - - - f |
|
|
|
i
h
|
|
|
|
| . b - - - - - - - - - - - - - - - - - - - - - - - a
| .
| .
| c
|
|
|
d
|
|
|
e |
. |
. |
g - - - - - - - - - - - - - - - - - - f |
|
|
|
i
"""
And the ways
@@ -443,9 +443,9 @@ Feature: Simple Turns
| ef | residential | road | 2 | yes |
When I route I should get
| waypoints | route | turns | locations |
| g,f | turn,road,road | depart,turn left,arrive | g,e,f |
| c,f | road,road,road | depart,continue right,arrive | c,b,f |
| waypoints | route | turns | locations | # |
| g,f | turn,road | depart,arrive | g,f | #could offer an additional turn at `e` if you don't detect the turn in between as curve |
| c,f | road,road,road | depart,continue right,arrive | c,b,f | |
#http://www.openstreetmap.org/search?query=52.479264%2013.295617#map=19/52.47926/13.29562
Scenario: Splitting Roads with curved split
@@ -627,12 +627,14 @@ Feature: Simple Turns
| 1,h | ,allee,allee | depart,turn left,arrive |
| 2,h | ,allee,allee | depart,turn left,arrive |
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
@todo
Scenario: Curved Turn on Separated Directions
Given the node map
"""
e d
f - - - - - - - - - - - - - - - c - - - - - - - - - - - j
f c - - - - - - - - - - - j
| l ' |
| ' |
| ' |
@@ -680,6 +682,58 @@ Feature: Simple Turns
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
Scenario: Curved Turn on Separated Directions
Given the node map
"""
e d
f c - - - - - - - - - - - j
| l ' |
| ' |
| ' |
| ' |
| ' |
| n |
| |
| ' |
| |
| ' |
| |
| |
| |
|' |
| |
| |
| |
| |
g |
h - - - - - - - - - - - - - - - b - - - - - - - - - - - o
| |
| |
| |
| |
| |
| |
i a
"""
And the ways
| nodes | name | oneway | lanes | highway |
| jc | Kapweg | yes | 3 | primary |
| clngh | Kapweg | yes | | primary_link |
| hbo | Kapweg | yes | 2 | primary |
| efh | Kurt | yes | 4 | secondary |
| hi | Kurt | yes | 3 | primary |
| ab | Kurt | yes | 4 | primary |
| cd | Kurt | yes | 3 | secondary |
| bc | Kurt | yes | 2 | primary |
When I route I should get
| waypoints | route | turns |
| j,i | Kapweg,Kurt,Kurt | depart,turn left,arrive |
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
#http://www.openstreetmap.org/#map=19/52.53731/13.36033
Scenario: Splitting Road to Left
Given the node map
@@ -1112,8 +1166,9 @@ Feature: Simple Turns
"""
And the ways
| nodes | name | highway | lanes |
| abcdefghijklmnopc | circled | residential | 1 |
| nodes | name | highway | lanes | oneway |
| abc | circled | residential | 1 | no |
| cdefghijklmnopc | circled | residential | 1 | yes |
When I route I should get
| waypoints | bearings | route | turns |
@@ -1168,3 +1223,97 @@ Feature: Simple Turns
When I route I should get
| waypoints | route |
| a,e | ab,bcde,bcde |
@3401
Scenario: Curve With Duplicated Coordinates
Given the node locations
| node | lat | lon | # |
| a | 0.9999280745650984 | 1.0 | |
| b | 0.9999280745650984 | 1.0000179813587253 | |
| c | 0.9999280745650984 | 1.0000359627174509 | |
| d | 0.9999460559238238 | 1.0000674300952204 | |
| e | 0.9999640372825492 | 1.0000809161142643 | |
| f | 0.9999820186412746 | 1.0000854114539457 | |
| g | 1.0 | 1.0000854114539457 | |
| h | 1.0 | 1.0000854114539457 | #same as g |
| z | 0.9999100932063729 | 1.0000179813587253 | |
# g
# |
# f
# '
# e
# '
# d
# '
#a - b - c
# |
# z
And the ways
| nodes | oneway | lanes | # |
| ab | yes | 1 | |
| zb | yes | 1 | |
| bcdefgh | yes | 1 | #intentional duplication |
# we don't care for turn instructions, this is a coordinate extraction bug check
When I route I should get
| waypoints | route | intersections |
| a,g | ab,bcdefgh,bcdefgh | true:90;true:45 false:180 false:270;true:180 |
#https://github.com/Project-OSRM/osrm-backend/pull/3469#issuecomment-270806580
Scenario: Oszillating Lower Priority Road
#Given the node map
# """
# a -db c
# f
# """
Given the node locations
| node | lat | lon | # |
| a | 1.0 | 1.0 | |
| b | 1.0000179813587253 | 1.0 | |
| c | 1.0000204580571323 | 1.0 | |
| d | 1.0000179813587253 | 1.0 | same as b |
| f | 1.0000179813587253 | 1.0000179813587253 | |
And the ways
| nodes | oneway | lanes | highway |
| ab | yes | 1 | primary |
| bf | yes | 1 | primary |
| bcd | yes | 1 | service |
# we don't care for turn instructions, this is a coordinate extraction bug check
When I route I should get
| waypoints | route |
| a,d | ab,ab |
Scenario: Sharp Turn Onto A Bridge
Given the node map
"""
e
|
|
|
|
|
|
|
|
|
|
|
|
|
g a - - -b
f /
d -c
"""
And the ways
| nodes | oneway | lanes |
| gaf | yes | 1 |
| abcde | yes | 1 |
When I route I should get
| waypoints | route |
| g,e | abcde,abcde |
+16
View File
@@ -3,6 +3,14 @@ Feature: osrm-contract command line options: invalid options
Background:
Given the profile "testbot"
And the node map
"""
a b
"""
And the ways
| nodes |
| ab |
And the data has been extracted
Scenario: osrm-contract - Non-existing option
When I try to run "osrm-contract --fly-me-to-the-moon"
@@ -10,3 +18,11 @@ Feature: osrm-contract command line options: invalid options
And stderr should contain "option"
And stderr should contain "fly-me-to-the-moon"
And it should exit with an error
# This tests the error messages when you try to use --segment-speed-file,
# but osrm-extract has not been run with --generate-edge-lookup
Scenario: osrm-contract - Someone forgot --generate-edge-lookup on osrm-extract
When I try to run "osrm-contract --segment-speed-file /dev/null {processed_file}"
Then stderr should contain "Error while trying to mmap"
Then stderr should contain ".osrm.edge_penalties"
And it should exit with an error
+1
View File
@@ -81,6 +81,7 @@ class Contractor
EdgeID
LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
const std::string &edge_segment_lookup_path,
const std::string &edge_penalty_path,
const std::vector<std::string> &segment_speed_path,
+23 -21
View File
@@ -6,8 +6,8 @@
#include "util/deallocating_vector.hpp"
#include "util/dynamic_graph.hpp"
#include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/percent.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp"
#include "util/typedefs.hpp"
#include "util/xor_fast_hash.hpp"
@@ -156,11 +156,10 @@ class GraphContractor
#ifndef NDEBUG
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
{
util::SimpleLogger().Write(logWARNING)
<< "Edge weight large -> "
<< static_cast<unsigned int>(std::max(diter->weight, 1)) << " : "
<< static_cast<unsigned int>(diter->source) << " -> "
<< static_cast<unsigned int>(diter->target);
util::Log(logWARNING) << "Edge weight large -> "
<< static_cast<unsigned int>(std::max(diter->weight, 1))
<< " : " << static_cast<unsigned int>(diter->source) << " -> "
<< static_cast<unsigned int>(diter->target);
}
#endif
edges.emplace_back(diter->source,
@@ -245,15 +244,14 @@ class GraphContractor
}
}
}
util::SimpleLogger().Write() << "merged " << edges.size() - edge << " edges out of "
<< edges.size();
util::Log() << "merged " << edges.size() - edge << " edges out of " << edges.size();
edges.resize(edge);
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
edges.clear();
edges.shrink_to_fit();
BOOST_ASSERT(0 == edges.capacity());
util::SimpleLogger().Write() << "contractor finished initalization";
util::Log() << "contractor finished initalization";
}
void Run(double core_factor = 1.0)
@@ -270,7 +268,6 @@ class GraphContractor
const constexpr size_t DeleteGrainSize = 1;
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
util::Percent p(number_of_nodes);
ThreadDataContainer thread_data_list(number_of_nodes);
@@ -292,9 +289,10 @@ class GraphContractor
bool use_cached_node_priorities = !node_levels.empty();
if (use_cached_node_priorities)
{
std::cout << "using cached node priorities ..." << std::flush;
util::UnbufferedLog log;
log << "using cached node priorities ...";
node_priorities.swap(node_levels);
std::cout << "ok" << std::endl;
log << "ok";
}
else
{
@@ -302,7 +300,8 @@ class GraphContractor
node_priorities.resize(number_of_nodes);
node_levels.resize(number_of_nodes);
std::cout << "initializing elimination PQ ..." << std::flush;
util::UnbufferedLog log;
log << "initializing elimination PQ ...";
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
[this, &node_priorities, &node_depth, &thread_data_list](
const tbb::blocked_range<int> &range) {
@@ -313,11 +312,14 @@ class GraphContractor
this->EvaluateNodePriority(data, node_depth[x], x);
}
});
std::cout << "ok" << std::endl;
log << "ok";
}
BOOST_ASSERT(node_priorities.size() == number_of_nodes);
std::cout << "preprocessing " << number_of_nodes << " nodes ..." << std::flush;
util::Log() << "preprocessing " << number_of_nodes << " nodes ...";
util::UnbufferedLog log;
util::Percent p(log, number_of_nodes);
unsigned current_level = 0;
bool flushed_contractor = false;
@@ -331,7 +333,7 @@ class GraphContractor
new_edge_set; // this one is not explicitely
// cleared since it goes out of
// scope anywa
std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
log << " [flush " << number_of_contracted_nodes << " nodes] ";
// Delete old heap data to free memory that we need for the coming operations
thread_data_list.data.clear();
@@ -599,9 +601,8 @@ class GraphContractor
is_core_node.clear();
}
util::SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes "
<< contractor_graph->GetNumberOfEdges() << " edges."
<< std::endl;
util::Log() << "[core] " << remaining_nodes.size() << " nodes "
<< contractor_graph->GetNumberOfEdges() << " edges.";
thread_data_list.data.clear();
}
@@ -618,8 +619,9 @@ class GraphContractor
template <class Edge> inline void GetEdges(util::DeallocatingVector<Edge> &edges)
{
util::Percent p(contractor_graph->GetNumberOfNodes());
util::SimpleLogger().Write() << "Getting edges of minimized graph";
util::UnbufferedLog log;
log << "Getting edges of minimized graph ";
util::Percent p(log, contractor_graph->GetNumberOfNodes());
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
if (contractor_graph->GetNumberOfNodes())
{
+12 -9
View File
@@ -54,22 +54,25 @@ util::json::Object makeGeoJSONGeometry(ForwardIter begin, ForwardIter end)
auto num_coordinates = std::distance(begin, end);
BOOST_ASSERT(num_coordinates != 0);
util::json::Object geojson;
geojson.values["type"] = "LineString";
util::json::Array coordinates;
if (num_coordinates > 1)
{
geojson.values["type"] = "LineString";
util::json::Array coordinates;
coordinates.values.reserve(num_coordinates);
std::transform(
begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat);
geojson.values["coordinates"] = std::move(coordinates);
auto into = std::back_inserter(coordinates.values);
std::transform(begin, end, into, &detail::coordinateToLonLat);
}
else if (num_coordinates > 0)
{
geojson.values["type"] = "Point";
util::json::Array coordinates;
coordinates.values.push_back(detail::coordinateToLonLat(*begin));
geojson.values["coordinates"] = std::move(coordinates);
// For a single location we create a [location, location] LineString
// instead of a single Point making the GeoJSON output consistent.
coordinates.values.reserve(2);
auto location = detail::coordinateToLonLat(*begin);
coordinates.values.push_back(location);
coordinates.values.push_back(location);
}
geojson.values["coordinates"] = std::move(coordinates);
return geojson;
}
@@ -12,11 +12,13 @@
#include "util/guidance/turn_lanes.hpp"
#include "engine/geospatial_query.hpp"
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/guidance/turn_bearing.hpp"
#include "util/log.hpp"
#include "util/packed_vector.hpp"
#include "util/range_table.hpp"
#include "util/rectangle.hpp"
#include "util/simple_logger.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
#include "util/typedefs.hpp"
@@ -116,7 +118,7 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
{
m_check_sum =
*data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::HSGR_CHECKSUM);
util::SimpleLogger().Write() << "set checksum: " << m_check_sum;
util::Log() << "set checksum: " << m_check_sum;
}
void InitializeProfilePropertiesPointer(storage::DataLayout &data_layout, char *memory_block)
@@ -144,9 +146,9 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
file_index_path = boost::filesystem::path(file_index_ptr);
if (!boost::filesystem::exists(file_index_path))
{
util::SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
util::Log(logDEBUG) << "Leaf file name " << file_index_path.string();
throw util::exception("Could not load " + file_index_path.string() +
"Is any data loaded into shared memory?");
"Is any data loaded into shared memory?" + SOURCE_REF);
}
auto tree_ptr =
@@ -38,31 +38,39 @@ class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
// used anymore. We crash hard here if something goes wrong (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(
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
: shared_barriers->regions_2_mutex,
boost::interprocess::defer_lock);
// 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
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
lock(shared_barriers->current_regions_mutex);
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
const auto current_timestamp =
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
if (current_timestamp->timestamp == shared_timestamp)
if (storage::SharedMemory::RegionExists(data_region))
{
util::SimpleLogger().Write(logDEBUG) << "Retaining data with shared timestamp "
<< shared_timestamp;
}
else
{
storage::SharedMemory::Remove(data_region);
storage::SharedMemory::Remove(layout_region);
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
const auto current_timestamp =
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
// 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_),
data_region(data_region_), shared_timestamp(shared_timestamp_)
{
util::SimpleLogger().Write(logDEBUG) << "Loading new data with shared timestamp "
<< shared_timestamp;
util::Log(logDEBUG) << "Loading new data with shared timestamp " << shared_timestamp;
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
m_layout_memory = storage::makeSharedMemory(layout_region);
+2
View File
@@ -18,6 +18,8 @@
#include "engine/plugins/trip.hpp"
#include "engine/plugins/viaroute.hpp"
#include "engine/status.hpp"
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/json_container.hpp"
#include <memory>
@@ -6,7 +6,6 @@
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "util/coordinate.hpp"
+8 -11
View File
@@ -8,14 +8,12 @@
#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "util/bearing.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/guidance/turn_lanes.hpp"
#include "util/typedefs.hpp"
@@ -156,7 +154,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
intersection.entry.push_back(entry_class.allowsEntry(idx));
}
std::int16_t bearing_in_driving_direction =
util::bearing::reverseBearing(std::round(bearings.first));
util::reverseBearing(std::round(bearings.first));
maneuver = {intersection.location,
bearing_in_driving_direction,
bearings.second,
@@ -216,14 +214,13 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
BOOST_ASSERT(segment_index == number_of_segments - 1);
bearings = detail::getArriveBearings(leg_geometry);
intersection = {
target_node.location,
std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}),
std::vector<bool>({true}),
0,
Intersection::NO_INDEX,
util::guidance::LaneTuple(),
{}};
intersection = {target_node.location,
std::vector<short>({static_cast<short>(util::reverseBearing(bearings.first))}),
std::vector<bool>({true}),
0,
Intersection::NO_INDEX,
util::guidance::LaneTuple(),
{}};
// This step has length zero, the only reason we need it is the target location
maneuver = {intersection.location,
@@ -0,0 +1,53 @@
#ifndef OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_
#define OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/route_step.hpp"
#include <iterator>
#include <utility>
namespace osrm
{
namespace engine
{
namespace guidance
{
// Runs fn on RouteStep sub-ranges determined to be roundabouts.
// The function fn is getting called with a roundabout range as in: [enter, .., leave].
//
// The following situations are taken care for (i.e. we discard them):
// - partial roundabout: enter without exit or exit without enter
// - data issues: no roundabout, exit before enter
template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, Iter last, Fn fn)
{
while (first != last)
{
const auto enter = std::find_if(first, last, [](const RouteStep &step) {
return entersRoundabout(step.maneuver.instruction);
});
// enter has to come before leave, otherwise: faulty data / partial roundabout, skip those
const auto leave = std::find_if(enter, last, [](const RouteStep &step) {
return leavesRoundabout(step.maneuver.instruction);
});
// No roundabouts, or partial one (like start / end inside a roundabout)
if (enter == last || leave == last)
break;
(void)fn(std::make_pair(enter, leave));
// Skip to first step after the currently handled enter / leave pair
first = std::next(leave);
}
return fn;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif /* OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_ */
+29 -1
View File
@@ -11,10 +11,11 @@
#include "util/guidance/turn_lanes.hpp"
#include <cstddef>
#include <string>
#include <vector>
#include <boost/range/iterator_range.hpp>
namespace osrm
{
namespace engine
@@ -71,6 +72,33 @@ struct RouteStep
std::size_t geometry_begin;
std::size_t geometry_end;
std::vector<Intersection> intersections;
LaneID numLanesToTheRight() const
{
return intersections.front().lanes.first_lane_from_the_right;
}
LaneID numLanesToTheLeft() const
{
LaneID const total = intersections.front().lane_description.size();
return total - (intersections.front().lanes.lanes_in_turn +
intersections.front().lanes.first_lane_from_the_right);
}
auto lanesToTheLeft() const
{
const auto &description = intersections.front().lane_description;
LaneID num_lanes_left = numLanesToTheLeft();
return boost::make_iterator_range(description.begin(),
description.begin() + num_lanes_left);
}
auto lanesToTheRight() const
{
const auto &description = intersections.front().lane_description;
LaneID num_lanes_right = numLanesToTheRight();
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
}
};
inline RouteStep getInvalidRouteStep()
-108
View File
@@ -1,108 +0,0 @@
#ifndef OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
#define OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/route_step.hpp"
#include "util/bearing.hpp"
#include "util/guidance/toolkit.hpp"
#include <algorithm>
#include <iterator>
#include <utility>
namespace osrm
{
namespace engine
{
namespace guidance
{
using util::guidance::entersRoundabout;
using util::guidance::leavesRoundabout;
using util::guidance::staysOnRoundabout;
// Silent Turn Instructions are not to be mentioned to the outside world but
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::NoTurn ||
instruction.type == extractor::guidance::TurnType::Suppressed ||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
inline extractor::guidance::DirectionModifier::Enum angleToDirectionModifier(const double bearing)
{
if (bearing < 135)
{
return extractor::guidance::DirectionModifier::Right;
}
if (bearing <= 225)
{
return extractor::guidance::DirectionModifier::Straight;
}
return extractor::guidance::DirectionModifier::Left;
}
// Runs fn on RouteStep sub-ranges determined to be roundabouts.
// The function fn is getting called with a roundabout range as in: [enter, .., leave].
//
// The following situations are taken care for (i.e. we discard them):
// - partial roundabout: enter without exit or exit without enter
// - data issues: no roundabout, exit before enter
template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, Iter last, Fn fn)
{
while (first != last)
{
const auto enter = std::find_if(first, last, [](const RouteStep &step) {
return entersRoundabout(step.maneuver.instruction);
});
// enter has to come before leave, otherwise: faulty data / partial roundabout, skip those
const auto leave = std::find_if(enter, last, [](const RouteStep &step) {
return leavesRoundabout(step.maneuver.instruction);
});
// No roundabouts, or partial one (like start / end inside a roundabout)
if (enter == last || leave == last)
break;
(void)fn(std::make_pair(enter, leave));
// Skip to first step after the currently handled enter / leave pair
first = std::next(leave);
}
return fn;
}
LaneID inline numLanesToTheRight(const engine::guidance::RouteStep &step)
{
return step.intersections.front().lanes.first_lane_from_the_right;
}
LaneID inline numLanesToTheLeft(const engine::guidance::RouteStep &step)
{
LaneID const total = step.intersections.front().lane_description.size();
return total - (step.intersections.front().lanes.lanes_in_turn +
step.intersections.front().lanes.first_lane_from_the_right);
}
auto inline lanesToTheLeft(const engine::guidance::RouteStep &step)
{
const auto &description = step.intersections.front().lane_description;
LaneID num_lanes_left = numLanesToTheLeft(step);
return boost::make_iterator_range(description.begin(), description.begin() + num_lanes_left);
}
auto inline lanesToTheRight(const engine::guidance::RouteStep &step)
{
const auto &description = step.intersections.front().lane_description;
LaneID num_lanes_right = numLanesToTheRight(step);
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif /* OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_ */
@@ -235,10 +235,10 @@ class AlternativeRouting final
}
}
// util::SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
// util::Log(logDEBUG) << "fwd_search_space size: " <<
// forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
// nodes";
// util::SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
// util::Log(logDEBUG) << "rev_search_space size: " <<
// reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
// nodes";
@@ -601,7 +601,7 @@ class AlternativeRouting final
// //compute forward sharing
// while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
// (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
// // util::SimpleLogger().Write() << "retrieving edge (" <<
// // util::Log() << "retrieving edge (" <<
// packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
// packed_alternate_path[aindex+1]);
@@ -640,7 +640,7 @@ class AlternativeRouting final
const NodeID node = forward_heap.DeleteMin();
const int weight = forward_heap.GetKey(node);
// const NodeID parentnode = forward_heap.GetData(node).parent;
// util::SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
// util::Log() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
// edge ("
// << parentnode << "," << node << "), dist: " << weight;
@@ -665,11 +665,11 @@ class AlternativeRouting final
{
*middle_node = node;
*upper_bound_to_shortest_path_weight = new_weight;
// util::SimpleLogger().Write() << "accepted middle_node " << *middle_node
// util::Log() << "accepted middle_node " << *middle_node
// << " at
// weight " << new_weight;
// } else {
// util::SimpleLogger().Write() << "discarded middle_node " << *middle_node
// util::Log() << "discarded middle_node " << *middle_node
// << "
// at weight " << new_weight;
}
+1 -1
View File
@@ -2,7 +2,7 @@
#define TRIP_BRUTE_FORCE_HPP
#include "util/dist_table_wrapper.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include "util/typedefs.hpp"
#include "osrm/json_container.hpp"
@@ -3,7 +3,6 @@
#include "util/dist_table_wrapper.hpp"
#include "util/typedefs.hpp"
#include "util/typedefs.hpp"
#include "osrm/json_container.hpp"
#include <boost/assert.hpp>
@@ -2,7 +2,7 @@
#define TRIP_NEAREST_NEIGHBOUR_HPP
#include "util/dist_table_wrapper.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include "util/typedefs.hpp"
#include "osrm/json_container.hpp"
@@ -29,7 +29,6 @@
#include <memory>
#include <queue>
#include <string>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -12,7 +12,7 @@
#include <limits>
#include <string>
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/parsing_toolkit.hpp"
namespace osrm
{
@@ -109,13 +109,13 @@ inline unsigned parseDuration(const std::string &s)
inline std::string
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
{
return extractor::guidance::trimLaneString(std::move(lane_string), count_left, count_right);
return guidance::trimLaneString(std::move(lane_string), count_left, count_right);
}
inline std::string applyAccessTokens(const std::string &lane_string,
const std::string &access_tokens)
{
return extractor::guidance::applyAccessTokens(lane_string, access_tokens);
return guidance::applyAccessTokens(lane_string, access_tokens);
}
// Takes a string representing a list separated by delim and canonicalizes containing spaces.
-2
View File
@@ -46,7 +46,6 @@ struct ExtractionWay
roundabout = false;
circular = false;
is_startpoint = true;
is_access_restricted = false;
name.clear();
ref.clear();
pronunciation.clear();
@@ -96,7 +95,6 @@ struct ExtractionWay
std::string turn_lanes_backward;
bool roundabout;
bool circular;
bool is_access_restricted;
bool is_startpoint;
TravelMode forward_travel_mode : 4;
TravelMode backward_travel_mode : 4;
+2 -1
View File
@@ -11,7 +11,8 @@
#include "extractor/guidance/coordinate_extractor.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include <boost/optional.hpp>
namespace osrm
{
@@ -9,7 +9,6 @@
#include "util/attributes.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/node_based_graph.hpp"
namespace osrm
@@ -29,7 +28,8 @@ class CoordinateExtractor
/* Find a interpolated coordinate a long the compressed geometries. The desired coordinate
* should be in a certain distance. This method is dedicated to find representative coordinates
* at turns.
* Since we are computing the length of the segment anyhow, we also return it.
* Note: The segment between intersection and turn coordinate can be zero, if the OSM modelling
* is unfortunate. See https://github.com/Project-OSRM/osrm-backend/issues/3470
*/
OSRM_ATTR_WARN_UNUSED
util::Coordinate GetCoordinateAlongRoad(const NodeID intersection_node,
+123 -39
View File
@@ -1,15 +1,23 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
#include <algorithm>
#include <functional>
#include <limits>
#include <string>
#include <type_traits>
#include <vector>
#include "extractor/guidance/turn_instruction.hpp"
#include "util/bearing.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp" // EdgeID
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/assert.hpp>
namespace osrm
{
namespace extractor
@@ -27,11 +35,18 @@ struct IntersectionShapeData
inline auto makeCompareShapeDataByBearing(const double base_bearing)
{
return [base_bearing](const IntersectionShapeData &lhs, const IntersectionShapeData &rhs) {
return util::bearing::angleBetweenBearings(base_bearing, lhs.bearing) <
util::bearing::angleBetweenBearings(base_bearing, rhs.bearing);
return [base_bearing](const auto &lhs, const auto &rhs) {
return util::angleBetweenBearings(base_bearing, lhs.bearing) <
util::angleBetweenBearings(base_bearing, rhs.bearing);
};
};
}
inline auto makeCompareAngularDeviation(const double angle)
{
return [angle](const auto &lhs, const auto &rhs) {
return util::angularDeviation(lhs.angle, angle) < util::angularDeviation(rhs.angle, angle);
};
}
// When viewing an intersection from an incoming edge, we can transform a shape into a view which
// gives additional information on angles and whether a turn is allowed
@@ -53,7 +68,7 @@ struct IntersectionViewData : IntersectionShapeData
// A Connected Road is the internal representation of a potential turn. Internally, we require
// full list of all connected roads to determine the outcome.
// The reasoning behind is that even invalid turns can influence the perceived angles, or even
// instructions themselves. An pososible example can be described like this:
// instructions themselves. An possible example can be described like this:
//
// aaa(2)aa
// a - bbbbb
@@ -61,8 +76,7 @@ struct IntersectionViewData : IntersectionShapeData
//
// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
// In addition, they can influence whether a turn is obvious or not. b->(2) would also be no
// turn-operation,
// but rather a name change.
// turn-operation, but rather a name change.
//
// If this were a normal intersection with
//
@@ -96,47 +110,117 @@ struct ConnectedRoad final : IntersectionViewData
// small helper function to print the content of a connected road
std::string toString(const ConnectedRoad &road);
// Intersections are sorted roads: [0] being the UTurn road, then from sharp right to sharp left.
using IntersectionShape = std::vector<IntersectionShapeData>;
struct IntersectionView final : std::vector<IntersectionViewData>
// Common operations shared among IntersectionView and Intersections.
// Inherit to enable those operations on your compatible type. CRTP pattern.
template <typename Self> struct EnableIntersectionOps
{
// Find the turn whose angle offers the least angular deviation to the specified angle
// For turn angles [0, 90, 260] and a query of 180 we return the 260 degree turn.
auto findClosestTurn(double angle) const
{
auto comp = makeCompareAngularDeviation(angle);
return std::min_element(self()->begin(), self()->end(), comp);
}
// Check validity of the intersection object. We assume a few basic properties every set of
// connected roads should follow throughout guidance pre-processing. This utility function
// allows checking intersections for validity
auto valid() const
{
if (self()->empty())
return false;
auto comp = [](const auto &lhs, const auto &rhs) { return lhs.CompareByAngle(rhs); };
const auto ordered = std::is_sorted(self()->begin(), self()->end(), comp);
if (!ordered)
return false;
const auto uturn = self()->operator[](0).angle < std::numeric_limits<double>::epsilon();
if (!uturn)
return false;
return true;
}
// Given all possible turns which is the highest connected number of lanes per turn.
// This value is used for example during generation of intersections.
auto getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &graph) const
{
const std::function<std::uint8_t(const ConnectedRoad &)> to_lane_count =
[&](const ConnectedRoad &road) {
return graph.GetEdgeData(road.eid).road_classification.GetNumberOfLanes();
};
std::uint8_t max_lanes = 0;
const auto extract_maximal_value = [&max_lanes](std::uint8_t value) {
max_lanes = std::max(max_lanes, value);
return false;
};
const auto view = *self() | boost::adaptors::transformed(to_lane_count);
boost::range::find_if(view, extract_maximal_value);
return max_lanes;
}
// Returns the UTurn road we took to arrive at this intersection.
const auto &getUTurnRoad() const { return self()->operator[](0); }
// Returns the right-most road at this intersection.
const auto &getRightmostRoad() const
{
return self()->size() > 1 ? self()->operator[](1) : self()->getUTurnRoad();
}
// Returns the left-most road at this intersection.
const auto &getLeftmostRoad() const
{
return self()->size() > 1 ? self()->back() : self()->getUTurnRoad();
}
// Can this be skipped over?
auto isTrafficSignalOrBarrier() const { return self()->size() == 2; }
// Checks if there is at least one road available (except UTurn road) on which to continue.
auto isDeadEnd() const
{
auto pred = [](const auto &road) { return road.entry_allowed; };
return !std::any_of(self()->begin() + 1, self()->end(), pred);
}
// Returns the number of roads we can enter at this intersection, respectively.
auto countEnterable() const
{
auto pred = [](const auto &road) { return road.entry_allowed; };
return std::count_if(self()->begin(), self()->end(), pred);
}
// Returns the number of roads we can not enter at this intersection, respectively.
auto countNonEnterable() const { return self()->size() - self()->countEnterable(); }
private:
auto self() { return static_cast<Self *>(this); }
auto self() const { return static_cast<const Self *>(this); }
};
struct IntersectionView final : std::vector<IntersectionViewData>, //
EnableIntersectionOps<IntersectionView> //
{
using Base = std::vector<IntersectionViewData>;
bool valid() const
{
return std::is_sorted(begin(), end(), std::mem_fn(&IntersectionViewData::CompareByAngle));
};
Base::iterator findClosestTurn(double angle);
Base::const_iterator findClosestTurn(double angle) const;
};
struct Intersection final : std::vector<ConnectedRoad>
struct Intersection final : std::vector<ConnectedRoad>, //
EnableIntersectionOps<Intersection> //
{
using Base = std::vector<ConnectedRoad>;
/*
* find the turn whose angle offers the least angularDeviation to the specified angle
* E.g. for turn angles [0,90,260] and a query of 180 we return the 260 degree turn (difference
* 80 over the difference of 90 to the 90 degree turn)
*/
Base::iterator findClosestTurn(double angle);
Base::const_iterator findClosestTurn(double angle) const;
/*
* Check validity of the intersection object. We assume a few basic properties every set of
* connected roads should follow throughout guidance pre-processing. This utility function
* allows checking intersections for validity
*/
bool valid() const;
// given all possible turns, which is the highest connected number of lanes per turn. This value
// is used, for example, during generation of intersections.
std::uint8_t getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &) const;
};
Intersection::const_iterator findClosestTurn(const Intersection &intersection, const double angle);
Intersection::iterator findClosestTurn(Intersection &intersection, const double angle);
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -35,6 +35,12 @@ class IntersectionGenerator
const std::vector<QueryNode> &node_info_list,
const CompressedEdgeContainer &compressed_edge_container);
// For a source node `a` and a via edge `ab` creates an intersection at target `b`.
//
// a . . . b . .
// .
// .
//
IntersectionView operator()(const NodeID nid, const EdgeID via_eid) const;
/*
@@ -43,6 +49,7 @@ class IntersectionGenerator
* The shape also only comes with turn bearings, not with turn angles. All turn angles will be
* set to zero
*/
OSRM_ATTR_WARN_UNUSED
IntersectionShape
ComputeIntersectionShape(const NodeID center_node,
const boost::optional<NodeID> sorting_base = boost::none,
@@ -53,11 +60,11 @@ class IntersectionGenerator
// intermediate intersection, if there is a traffic light in between. If we want to look farther
// down a road, finding the next actual decision requires the look at multiple intersections.
// Here we follow the road until we either reach a dead end or find the next intersection with
// more than a single next road.
IntersectionView GetActualNextIntersection(const NodeID starting_node,
const EdgeID via_edge,
NodeID *resulting_from_node,
EdgeID *resulting_via_edge) const;
// more than a single next road. This function skips over degree two nodes to find coorect input
// for GetConnectedRoads.
OSRM_ATTR_WARN_UNUSED
std::pair<NodeID, EdgeID> SkipDegreeTwoNodes(const NodeID starting_node,
const EdgeID via_edge) const;
// Allow access to the coordinate extractor for all owners
const CoordinateExtractor &GetCoordinateExtractor() const;
@@ -3,15 +3,22 @@
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/node_based_graph_walker.hpp"
#include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/name_announcements.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include <algorithm>
#include <cstddef>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
namespace osrm
{
namespace extractor
@@ -48,9 +55,7 @@ class IntersectionHandler
const util::NameTable &name_table;
const SuffixTable &street_name_suffix_table;
const IntersectionGenerator &intersection_generator;
// counts the number on allowed entry roads
std::size_t countValid(const Intersection &intersection) const;
const NodeBasedGraphWalker graph_walker; // for skipping traffic signal, distances etc.
// Decide on a basic turn types
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
@@ -59,7 +64,8 @@ class IntersectionHandler
// determining whether there is a road that can be seen as obvious turn in the presence of many
// other possible turns. The function will consider road categories and other inputs like the
// turn angles.
std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
template <typename IntersectionType> // works with Intersection and IntersectionView
std::size_t findObviousTurn(const EdgeID via_edge, const IntersectionType &intersection) const;
// Obvious turns can still take multiple forms. This function looks at the turn onto a road
// candidate when coming from a via_edge and determines the best instruction to emit.
@@ -83,9 +89,458 @@ class IntersectionHandler
const std::size_t begin,
const std::size_t end) const;
// Checks the intersection for a through street connected to `intersection[index]`
bool isThroughStreet(const std::size_t index, const Intersection &intersection) const;
// See `getNextIntersection`
struct IntersectionViewAndNode final
{
IntersectionView intersection; // < actual intersection
NodeID node; // < node at this intersection
};
// Skips over artificial intersections i.e. traffic lights, barriers etc.
// Returns the next non-artificial intersection and its node in the node based
// graph if an intersection could be found or none otherwise.
//
// a ... tl ... b .. c
// .
// .
// d
//
// ^ at
// ^ via
//
// For this scenario returns intersection at `b` and `b`.
boost::optional<IntersectionHandler::IntersectionViewAndNode>
getNextIntersection(const NodeID at, const EdgeID via) const;
};
// Impl.
template <typename IntersectionType> // works with Intersection and IntersectionView
std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
const IntersectionType &intersection) const
{
using Road = typename IntersectionType::value_type;
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
using osrm::util::angularDeviation;
// no obvious road
if (intersection.size() == 1)
return 0;
// a single non u-turn is obvious
if (intersection.size() == 2)
return 1;
const EdgeData &in_way_data = node_based_graph.GetEdgeData(via_edge);
// the strategy for picking the most obvious turn involves deciding between
// an overall best candidate and a best candidate that shares the same name
// as the in road, i.e. a continue road
std::size_t best_option = 0;
double best_option_deviation = 180;
std::size_t best_continue = 0;
double best_continue_deviation = 180;
/* helper functions */
const auto IsContinueRoad = [&](const EdgeData &way_data) {
return !util::guidance::requiresNameAnnounced(
in_way_data.name_id, way_data.name_id, name_table, street_name_suffix_table);
};
auto sameOrHigherPriority = [&in_way_data](const auto &way_data) {
return way_data.road_classification.GetPriority() <=
in_way_data.road_classification.GetPriority();
};
auto IsLowPriority = [](const auto &way_data) {
return way_data.road_classification.IsLowPriorityRoadClass();
};
// These two Compare functions are used for sifting out best option and continue
// candidates by evaluating all the ways in an intersection by what they share
// with the in way. Ideal candidates are of similar road class with the in way
// and are require relatively straight turns.
const auto RoadCompare = [&](const auto &lhs, const auto &rhs) {
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
const auto lhs_deviation = angularDeviation(lhs.angle, STRAIGHT_ANGLE);
const auto rhs_deviation = angularDeviation(rhs.angle, STRAIGHT_ANGLE);
const bool rhs_same_classification =
rhs_data.road_classification == in_way_data.road_classification;
const bool lhs_same_classification =
lhs_data.road_classification == in_way_data.road_classification;
const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_data);
const bool rhs_low_priority = IsLowPriority(rhs_data);
const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_data);
const bool lhs_low_priority = IsLowPriority(lhs_data);
auto left_tie = std::tie(lhs.entry_allowed,
lhs_same_or_higher_priority,
rhs_low_priority,
rhs_deviation,
lhs_same_classification);
auto right_tie = std::tie(rhs.entry_allowed,
rhs_same_or_higher_priority,
lhs_low_priority,
lhs_deviation,
rhs_same_classification);
return left_tie > right_tie;
};
const auto RoadCompareSameName = [&](const auto &lhs, const auto &rhs) {
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
const auto lhs_continues = IsContinueRoad(lhs_data);
const auto rhs_continues = IsContinueRoad(rhs_data);
const auto left_tie = std::tie(lhs.entry_allowed, lhs_continues);
const auto right_tie = std::tie(rhs.entry_allowed, rhs_continues);
return left_tie > right_tie || (left_tie == right_tie && RoadCompare(lhs, rhs));
};
auto best_option_it = std::min_element(begin(intersection), end(intersection), RoadCompare);
// min element should only return end() when vector is empty
BOOST_ASSERT(best_option_it != end(intersection));
best_option = std::distance(begin(intersection), best_option_it);
best_option_deviation = angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
const auto &best_option_data = node_based_graph.GetEdgeData(intersection[best_option].eid);
// Unless the in way is also low priority, it is generally undesirable to
// indicate that a low priority road is obvious
if (IsLowPriority(best_option_data) &&
best_option_data.road_classification != in_way_data.road_classification)
{
best_option = 0;
best_option_deviation = 180;
}
// double check if the way with the lowest deviation from straight is still be better choice
const auto straightest = intersection.findClosestTurn(STRAIGHT_ANGLE);
if (straightest != best_option_it)
{
const EdgeData &straightest_data = node_based_graph.GetEdgeData(straightest->eid);
double straightest_data_deviation = angularDeviation(straightest->angle, STRAIGHT_ANGLE);
const auto deviation_diff =
std::abs(best_option_deviation - straightest_data_deviation) > FUZZY_ANGLE_DIFFERENCE;
const auto not_ramp_class = !straightest_data.road_classification.IsRampClass();
const auto not_link_class = !straightest_data.road_classification.IsLinkClass();
if (deviation_diff && !IsLowPriority(straightest_data) && not_ramp_class &&
not_link_class && !IsContinueRoad(best_option_data))
{
best_option = std::distance(begin(intersection), straightest);
best_option_deviation =
angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
}
}
// No non-low priority roads? Declare no obvious turn
if (best_option == 0)
return 0;
auto best_continue_it =
std::min_element(begin(intersection), end(intersection), RoadCompareSameName);
const auto best_continue_data = node_based_graph.GetEdgeData(best_continue_it->eid);
if (IsContinueRoad(best_continue_data) ||
(in_way_data.name_id == EMPTY_NAMEID && best_continue_data.name_id == EMPTY_NAMEID))
{
best_continue = std::distance(begin(intersection), best_continue_it);
best_continue_deviation =
angularDeviation(intersection[best_continue].angle, STRAIGHT_ANGLE);
}
// if the best angle is going straight but the road is turning, declare no obvious turn
if (0 != best_continue && best_option != best_continue &&
best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification ==
best_option_data.road_classification)
{
return 0;
}
// get a count of number of ways from that intersection that qualify to have
// continue instruction because they share a name with the approaching way
const std::int64_t continue_count =
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid));
});
const std::int64_t continue_count_valid =
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid)) && way.entry_allowed;
});
// checks if continue candidates are sharp turns
const bool all_continues_are_narrow = [&]() {
return std::count_if(begin(intersection), end(intersection), [&](const Road &road) {
const EdgeData &road_data = node_based_graph.GetEdgeData(road.eid);
const double &road_angle = angularDeviation(road.angle, STRAIGHT_ANGLE);
return IsContinueRoad(road_data) && (road_angle < NARROW_TURN_ANGLE);
}) == continue_count;
}();
// return true if the best_option candidate is more promising than the best_continue candidate
// otherwise return false, the best_continue candidate is more promising
const auto best_over_best_continue = [&]() {
// no continue road exists
if (best_continue == 0)
return true;
// we have multiple continues and not all are narrow. This suggests that
// the continue candidates are ambiguous
if (!all_continues_are_narrow && (continue_count >= 2 && intersection.size() >= 4))
return true;
// if the best continue is not narrow and we also have at least 2 possible choices, the
// intersection size does not matter anymore
if (continue_count_valid >= 2 && best_continue_deviation >= 2 * NARROW_TURN_ANGLE)
return true;
// continue data now most certainly exists
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
// best_continue is obvious by road class
if (obviousByRoadClass(in_way_data.road_classification,
continue_data.road_classification,
best_option_data.road_classification))
return false;
// best_option is obvious by road class
if (obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
continue_data.road_classification))
return true;
// the best_option deviation is very straight and not a ramp
if (best_option_deviation < best_continue_deviation &&
best_option_deviation < FUZZY_ANGLE_DIFFERENCE &&
!best_option_data.road_classification.IsRampClass())
return true;
// the continue road is of a lower priority, while the road continues on the same priority
// with a better angle
if (best_option_deviation < best_continue_deviation &&
in_way_data.road_classification == best_option_data.road_classification &&
continue_data.road_classification.GetPriority() >
best_option_data.road_classification.GetPriority())
return true;
return false;
}();
if (best_over_best_continue)
{
// Find left/right deviation
// skipping over service roads
const std::size_t left_index = [&]() {
const auto index_candidate = (best_option + 1) % intersection.size();
if (index_candidate == 0)
return index_candidate;
const auto &candidate_data =
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
if (obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
candidate_data.road_classification))
return (index_candidate + 1) % intersection.size();
else
return index_candidate;
}();
const auto right_index = [&]() {
BOOST_ASSERT(best_option > 0);
const auto index_candidate = best_option - 1;
if (index_candidate == 0)
return index_candidate;
const auto candidate_data =
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
if (obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
candidate_data.road_classification))
return index_candidate - 1;
else
return index_candidate;
}();
const double left_deviation =
angularDeviation(intersection[left_index].angle, STRAIGHT_ANGLE);
const double right_deviation =
angularDeviation(intersection[right_index].angle, STRAIGHT_ANGLE);
// return best_option candidate if it is nearly straight and distinct from the nearest other
// out
// way
if (best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
return best_option;
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid);
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid);
const bool obvious_to_left =
left_index == 0 || obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
left_data.road_classification);
const bool obvious_to_right =
right_index == 0 || obviousByRoadClass(in_way_data.road_classification,
best_option_data.road_classification,
right_data.road_classification);
// if the best_option turn isn't narrow, but there is a nearly straight turn, we don't
// consider the
// turn obvious
const auto check_narrow = [&intersection, best_option_deviation](const std::size_t index) {
return angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) <=
FUZZY_ANGLE_DIFFERENCE &&
(best_option_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed);
};
// other narrow turns?
if (check_narrow(right_index) && !obvious_to_right)
return 0;
if (check_narrow(left_index) && !obvious_to_left)
return 0;
// checks if a given way in the intersection is distinct enough from the best_option
// candidate
const auto isDistinct = [&](const std::size_t index, const double deviation) {
/*
If the neighbor is not possible to enter, we allow for a lower
distinction rate. If the road category is smaller, its also adjusted. Only
roads of the same priority require the full distinction ratio.
*/
const auto &best_option_data =
node_based_graph.GetEdgeData(intersection[best_option].eid);
const auto adjusted_distinction_ratio = [&]() {
// not allowed competitors are easily distinct
if (!intersection[index].entry_allowed)
return 0.7 * DISTINCTION_RATIO;
// a bit less obvious are road classes
else if (in_way_data.road_classification == best_option_data.road_classification &&
best_option_data.road_classification.GetPriority() <
node_based_graph.GetEdgeData(intersection[index].eid)
.road_classification.GetPriority())
return 0.8 * DISTINCTION_RATIO;
// if road classes are the same, we use the full ratio
else
return DISTINCTION_RATIO;
}();
return index == 0 || deviation / best_option_deviation >= adjusted_distinction_ratio ||
(deviation <= NARROW_TURN_ANGLE && !intersection[index].entry_allowed);
};
const bool distinct_to_left = isDistinct(left_index, left_deviation);
const bool distinct_to_right = isDistinct(right_index, right_deviation);
// Well distinct turn that is nearly straight
if ((distinct_to_left || obvious_to_left) && (distinct_to_right || obvious_to_right))
return best_option;
}
else
{
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
if (std::abs(best_continue_deviation) < 1)
return best_continue;
// check if any other similar best continues exist
std::size_t i, last = intersection.size();
for (i = 1; i < last; ++i)
{
if (i == best_continue || !intersection[i].entry_allowed)
continue;
const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid);
const bool is_obvious_by_road_class =
obviousByRoadClass(in_way_data.road_classification,
continue_data.road_classification,
turn_data.road_classification);
// if the main road is obvious by class, we ignore the current road as a potential
// prevention of obviousness
if (is_obvious_by_road_class)
continue;
// continuation could be grouped with a straight turn and the turning road is a ramp
if (turn_data.road_classification.IsRampClass() &&
best_continue_deviation < GROUP_ANGLE &&
!continue_data.road_classification.IsRampClass())
continue;
// perfectly straight turns prevent obviousness
const auto turn_deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
if (turn_deviation < FUZZY_ANGLE_DIFFERENCE)
return 0;
const auto deviation_ratio = turn_deviation / best_continue_deviation;
// in comparison to normal deviations, a continue road can offer a smaller distinction
// ratio. Other roads close to the turn angle are not as obvious, if one road continues.
if (deviation_ratio < DISTINCTION_RATIO / 1.5)
return 0;
/* in comparison to another continuing road, we need a better distinction. This prevents
situations where the turn is probably less obvious. An example are places that have a
road with the same name entering/exiting:
d
/
/
a -- b
\
\
c
*/
const auto same_name = !util::guidance::requiresNameAnnounced(
turn_data.name_id, continue_data.name_id, name_table, street_name_suffix_table);
if (same_name && deviation_ratio < 1.5 * DISTINCTION_RATIO)
return 0;
}
// Segregated intersections can result in us finding an obvious turn, even though its only
// obvious due to a very short segment in between. So if the segment coming in is very
// short, we check the previous intersection for other continues in the opposite bearing.
const auto node_at_intersection = node_based_graph.GetTarget(via_edge);
const double constexpr MAX_COLLAPSE_DISTANCE = 30;
const auto distance_at_u_turn = intersection[0].segment_length;
if (distance_at_u_turn < MAX_COLLAPSE_DISTANCE)
{
// this request here actually goes against the direction of the ingoing edgeid. This can
// even reverse the direction. Since we don't want to compute actual turns but simply
// try to find whether there is a turn going to the opposite direction of our obvious
// turn, this should be alright.
NodeID new_node;
const auto previous_intersection = [&]() {
EdgeID turn_edge;
std::tie(new_node, turn_edge) = intersection_generator.SkipDegreeTwoNodes(
node_at_intersection, intersection[0].eid);
return intersection_generator.GetConnectedRoads(new_node, turn_edge);
}();
if (new_node != node_at_intersection)
{
const auto continue_road = intersection[best_continue];
for (const auto &comparison_road : previous_intersection)
{
// since we look at the intersection in the wrong direction, a similar angle
// actually represents a near 180 degree different in bearings between the two
// roads. So if there is a road that is enterable in the opposite direction just
// prior, a turn is not obvious
const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.eid);
if (angularDeviation(comparison_road.angle, STRAIGHT_ANGLE) > GROUP_ANGLE &&
angularDeviation(comparison_road.angle, continue_road.angle) <
FUZZY_ANGLE_DIFFERENCE &&
!turn_data.reversed && continue_data.CanCombineWith(turn_data))
return 0;
}
}
}
return best_continue;
}
return 0;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -57,16 +57,17 @@ class IntersectionNormalizer
const IntersectionGenerator &intersection_generator;
// check if two indices in an intersection can be seen as a single road in the perceived
// intersection representation. See below for an example. Utility function for
// MergeSegregatedRoads. It also checks for neighboring merges.
// This is due possible segments where multiple roads could end up being merged into one.
// We only support merging two roads, not three or more, though.
// c c
// / /
// a - b -> a - b - (c,d) but not a - b d -> a,b,(cde)
// \ \
// d e
/* check if two indices in an intersection can be seen as a single road in the perceived
* intersection representation. See below for an example. Utility function for
* MergeSegregatedRoads. It also checks for neighboring merges.
* This is due possible segments where multiple roads could end up being merged into one.
* We only support merging two roads, not three or more, though.
* c c
* / /
* a - b -> a - b - (c,d) but not a - b d -> a,b,(cde)
* \ \
* d e
*/
bool CanMerge(const NodeID intersection_node,
const IntersectionShape &intersection,
std::size_t first_index,
@@ -3,9 +3,8 @@
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
@@ -43,7 +42,7 @@ class NodeBasedGraphWalker
boost::optional<std::pair<NodeID, EdgeID>> TraverseRoad(NodeID starting_at_node_id,
EdgeID following_edge_id,
accumulator_type &accumulator,
const selector_type &selector);
const selector_type &selector) const;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
@@ -141,7 +140,7 @@ boost::optional<std::pair<NodeID, EdgeID>>
NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
EdgeID current_edge_id,
accumulator_type &accumulator,
const selector_type &selector)
const selector_type &selector) const
{
/*
* since graph hopping is used in many ways, we don't generate an adjusted intersection
@@ -192,6 +191,60 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
return {};
}
struct SkipTrafficSignalBarrierRoadSelector
{
boost::optional<EdgeID> operator()(const NodeID,
const EdgeID,
const IntersectionView &intersection,
const util::NodeBasedDynamicGraph &) const
{
if (intersection.isTrafficSignalOrBarrier())
{
return boost::make_optional(intersection[1].eid);
}
else
{
return boost::none;
}
}
};
struct DistanceToNextIntersectionAccumulator
{
DistanceToNextIntersectionAccumulator(
const extractor::guidance::CoordinateExtractor &extractor_,
const util::NodeBasedDynamicGraph &graph_,
const double threshold)
: extractor{extractor_}, graph{graph_}, threshold{threshold}
{
}
bool terminate()
{
if (distance > threshold)
{
too_far_away = true;
return true;
}
return false;
}
void update(const NodeID start, const EdgeID onto, const NodeID)
{
using namespace util::coordinate_calculation;
const auto coords = extractor.GetForwardCoordinatesAlongRoad(start, onto);
distance += getLength(coords, &haversineDistance);
}
const extractor::guidance::CoordinateExtractor &extractor;
const util::NodeBasedDynamicGraph &graph;
const double threshold;
bool too_far_away = false;
double distance = 0.;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -0,0 +1,112 @@
#ifndef OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
#define OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
#include <cstdint>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include "util/attributes.hpp"
namespace osrm
{
namespace extractor
{
namespace guidance
{
// Public service vehicle lanes and similar can introduce additional lanes into the lane string that
// are not specifically marked for left/right turns. This function can be used from the profile to
// trim the lane string appropriately
//
// left|throught|
// in combination with lanes:psv:forward=1
// will be corrected to left|throught, since the final lane is not drivable.
// This is in contrast to a situation with lanes:psv:forward=0 (or not set) where left|through|
// represents left|through|through
OSRM_ATTR_WARN_UNUSED
inline std::string
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
{
if (count_left)
{
bool sane = count_left < static_cast<std::int32_t>(lane_string.size());
for (std::int32_t i = 0; i < count_left; ++i)
// this is adjusted for our fake pipe. The moment cucumber can handle multiple escaped
// pipes, the '&' part can be removed
if (lane_string[i] != '|')
{
sane = false;
break;
}
if (sane)
{
lane_string.erase(lane_string.begin(), lane_string.begin() + count_left);
}
}
if (count_right)
{
bool sane = count_right < static_cast<std::int32_t>(lane_string.size());
for (auto itr = lane_string.rbegin();
itr != lane_string.rend() && itr != lane_string.rbegin() + count_right;
++itr)
{
if (*itr != '|')
{
sane = false;
break;
}
}
if (sane)
lane_string.resize(lane_string.size() - count_right);
}
return lane_string;
}
// https://github.com/Project-OSRM/osrm-backend/issues/2638
// It can happen that some lanes are not drivable by car. Here we handle this tagging scheme
// (vehicle:lanes) to filter out not-allowed roads
// lanes=3
// turn:lanes=left|through|through|right
// vehicle:lanes=yes|yes|no|yes
// bicycle:lanes=yes|no|designated|yes
OSRM_ATTR_WARN_UNUSED
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
{
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
tokenizer tokens(lane_string, sep);
tokenizer access(access_tokens, sep);
// strings don't match, don't do anything
if (std::distance(std::begin(tokens), std::end(tokens)) !=
std::distance(std::begin(access), std::end(access)))
return lane_string;
std::string result_string = "";
const static std::string yes = "yes";
for (auto token_itr = std::begin(tokens), access_itr = std::begin(access);
token_itr != std::end(tokens);
++token_itr, ++access_itr)
{
if (*access_itr == yes)
{
// we have to add this in front, because the next token could be invalid. Doing this on
// non-empty strings makes sure that the token string will be valid in the end
if (!result_string.empty())
result_string += '|';
result_string += *token_itr;
}
}
return result_string;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif // OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
@@ -4,9 +4,8 @@
#include <cmath>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <osmium/osm.hpp>
#include "extractor/guidance/constants.hpp"
namespace osrm
{
@@ -126,6 +125,22 @@ inline bool canBeSeenAsFork(const RoadClassification first, const RoadClassifica
return std::abs(static_cast<int>(first.GetPriority()) -
static_cast<int>(second.GetPriority())) <= 1;
}
inline bool obviousByRoadClass(const RoadClassification in_classification,
const RoadClassification obvious_candidate,
const RoadClassification compare_candidate)
{
// lower numbers are of higher priority
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
compare_candidate.GetPriority();
const bool continues_on_same_class = in_classification == obvious_candidate;
return (has_high_priority && continues_on_same_class) ||
(!obvious_candidate.IsLowPriorityRoadClass() &&
!in_classification.IsLowPriorityRoadClass() &&
compare_candidate.IsLowPriorityRoadClass());
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -15,7 +15,6 @@
#include "util/typedefs.hpp"
#include <unordered_set>
#include <utility>
#include <vector>
namespace osrm
@@ -9,10 +9,10 @@
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include <cstddef>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
namespace osrm
{
namespace extractor
@@ -22,7 +22,7 @@ namespace guidance
// Intersection handlers deal with all issues related to intersections.
// They assign appropriate turn operations to the TurnOperations.
class SliproadHandler : public IntersectionHandler
class SliproadHandler final : public IntersectionHandler
{
public:
SliproadHandler(const IntersectionGenerator &intersection_generator,
@@ -42,6 +42,37 @@ class SliproadHandler : public IntersectionHandler
Intersection operator()(const NodeID nid,
const EdgeID via_eid,
Intersection intersection) const override final;
private:
boost::optional<std::size_t> getObviousIndexWithSliproads(const EdgeID from,
const Intersection &intersection,
const NodeID at) const;
// Next intersection from `start` onto `onto` is too far away for a Siproad scenario
bool nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const;
// Through street: does a road continue with from's name at the intersection
bool isThroughStreet(const EdgeID from, const IntersectionView &intersection) const;
// Does the road from `current` to `next` continue
bool roadContinues(const EdgeID current, const EdgeID next) const;
// Is the area under the triangle a valid Sliproad triangle
bool isValidSliproadArea(const double max_area, const NodeID, const NodeID, const NodeID) const;
// Is the Sliproad a link the both roads it shortcuts must not be links
bool isValidSliproadLink(const IntersectionViewData &sliproad,
const IntersectionViewData &first,
const IntersectionViewData &second) const;
// Could a Sliproad reach this intersection?
static bool canBeTargetOfSliproad(const IntersectionView &intersection);
// Scales a threshold based on the underlying road classification.
// Example: a 100 m threshold for a highway if different on living streets.
// The return value is guaranteed to not be larger than `threshold`.
static double scaledThresholdByRoadClass(const double max_threshold,
const RoadClassification &classification);
};
} // namespace guidance
-241
View File
@@ -1,241 +0,0 @@
#ifndef OSRM_GUIDANCE_TOOLKIT_HPP_
#define OSRM_GUIDANCE_TOOLKIT_HPP_
#include "util/attributes.hpp"
#include "util/bearing.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/guidance/turn_lanes.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp"
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/road_classification.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/functional/hash.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/tokenizer.hpp>
namespace osrm
{
namespace extractor
{
namespace guidance
{
using util::guidance::LaneTupleIdPair;
using LaneDataIdMap = std::unordered_map<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
using util::guidance::angularDeviation;
using util::guidance::entersRoundabout;
using util::guidance::leavesRoundabout;
// To simplify handling of Left/Right hand turns, we can mirror turns and write an intersection
// handler only for one side. The mirror function turns a left-hand turn in a equivalent right-hand
// turn and vice versa.
inline bool hasRoundaboutType(const TurnInstruction instruction)
{
using namespace extractor::guidance::TurnType;
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
TurnType::EnterAndExitRoundabout,
TurnType::EnterRotary,
TurnType::EnterAndExitRotary,
TurnType::EnterRoundaboutIntersection,
TurnType::EnterAndExitRoundaboutIntersection,
TurnType::EnterRoundaboutAtExit,
TurnType::ExitRoundabout,
TurnType::EnterRotaryAtExit,
TurnType::ExitRotary,
TurnType::EnterRoundaboutIntersectionAtExit,
TurnType::ExitRoundaboutIntersection,
TurnType::StayOnRoundabout};
const auto *first = valid_types;
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
return std::find(first, last, instruction.type) != last;
}
// Public service vehicle lanes and similar can introduce additional lanes into the lane string that
// are not specifically marked for left/right turns. This function can be used from the profile to
// trim the lane string appropriately
//
// left|throught|
// in combination with lanes:psv:forward=1
// will be corrected to left|throught, since the final lane is not drivable.
// This is in contrast to a situation with lanes:psv:forward=0 (or not set) where left|through|
// represents left|through|through
OSRM_ATTR_WARN_UNUSED
inline std::string
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
{
if (count_left)
{
bool sane = count_left < static_cast<std::int32_t>(lane_string.size());
for (std::int32_t i = 0; i < count_left; ++i)
// this is adjusted for our fake pipe. The moment cucumber can handle multiple escaped
// pipes, the '&' part can be removed
if (lane_string[i] != '|')
{
sane = false;
break;
}
if (sane)
{
lane_string.erase(lane_string.begin(), lane_string.begin() + count_left);
}
}
if (count_right)
{
bool sane = count_right < static_cast<std::int32_t>(lane_string.size());
for (auto itr = lane_string.rbegin();
itr != lane_string.rend() && itr != lane_string.rbegin() + count_right;
++itr)
{
if (*itr != '|')
{
sane = false;
break;
}
}
if (sane)
lane_string.resize(lane_string.size() - count_right);
}
return lane_string;
}
// https://github.com/Project-OSRM/osrm-backend/issues/2638
// It can happen that some lanes are not drivable by car. Here we handle this tagging scheme
// (vehicle:lanes) to filter out not-allowed roads
// lanes=3
// turn:lanes=left|through|through|right
// vehicle:lanes=yes|yes|no|yes
// bicycle:lanes=yes|no|designated|yes
OSRM_ATTR_WARN_UNUSED
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
{
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
tokenizer tokens(lane_string, sep);
tokenizer access(access_tokens, sep);
// strings don't match, don't do anything
if (std::distance(std::begin(tokens), std::end(tokens)) !=
std::distance(std::begin(access), std::end(access)))
return lane_string;
std::string result_string = "";
const static std::string yes = "yes";
for (auto token_itr = std::begin(tokens), access_itr = std::begin(access);
token_itr != std::end(tokens);
++token_itr, ++access_itr)
{
if (*access_itr == yes)
{
// we have to add this in front, because the next token could be invalid. Doing this on
// non-empty strings makes sure that the token string will be valid in the end
if (!result_string.empty())
result_string += '|';
result_string += *token_itr;
}
}
return result_string;
}
inline bool obviousByRoadClass(const RoadClassification in_classification,
const RoadClassification obvious_candidate,
const RoadClassification compare_candidate)
{
// lower numbers are of higher priority
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
compare_candidate.GetPriority();
const bool continues_on_same_class = in_classification == obvious_candidate;
return (has_high_priority && continues_on_same_class) ||
(!obvious_candidate.IsLowPriorityRoadClass() &&
!in_classification.IsLowPriorityRoadClass() &&
compare_candidate.IsLowPriorityRoadClass());
}
/* We use the sum of least squares to calculate a linear regression through our
* coordinates.
* This regression gives a good idea of how the road can be perceived and corrects for
* initial and final corrections
*/
inline std::pair<util::Coordinate, util::Coordinate>
leastSquareRegression(const std::vector<util::Coordinate> &coordinates)
{
BOOST_ASSERT(coordinates.size() >= 2);
double sum_lon = 0, sum_lat = 0, sum_lon_lat = 0, sum_lon_lon = 0;
double min_lon = static_cast<double>(toFloating(coordinates.front().lon));
double max_lon = static_cast<double>(toFloating(coordinates.front().lon));
for (const auto coord : coordinates)
{
min_lon = std::min(min_lon, static_cast<double>(toFloating(coord.lon)));
max_lon = std::max(max_lon, static_cast<double>(toFloating(coord.lon)));
sum_lon += static_cast<double>(toFloating(coord.lon));
sum_lon_lon +=
static_cast<double>(toFloating(coord.lon)) * static_cast<double>(toFloating(coord.lon));
sum_lat += static_cast<double>(toFloating(coord.lat));
sum_lon_lat +=
static_cast<double>(toFloating(coord.lon)) * static_cast<double>(toFloating(coord.lat));
}
const auto dividend = coordinates.size() * sum_lon_lat - sum_lon * sum_lat;
const auto divisor = coordinates.size() * sum_lon_lon - sum_lon * sum_lon;
if (std::abs(divisor) < std::numeric_limits<double>::epsilon())
return std::make_pair(coordinates.front(), coordinates.back());
// slope of the regression line
const auto slope = dividend / divisor;
const auto intercept = (sum_lat - slope * sum_lon) / coordinates.size();
const auto GetLatAtLon = [intercept,
slope](const util::FloatLongitude longitude) -> util::FloatLatitude {
return {intercept + slope * static_cast<double>((longitude))};
};
const util::Coordinate regression_first = {
toFixed(util::FloatLongitude{min_lon - 1}),
toFixed(util::FloatLatitude(GetLatAtLon(util::FloatLongitude{min_lon - 1})))};
const util::Coordinate regression_end = {
toFixed(util::FloatLongitude{max_lon + 1}),
toFixed(util::FloatLatitude(GetLatAtLon(util::FloatLongitude{max_lon + 1})))};
return {regression_first, regression_end};
}
inline std::uint8_t getLaneCountAtIntersection(const NodeID intersection_node,
const util::NodeBasedDynamicGraph &node_based_graph)
{
std::uint8_t lanes = 0;
for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(intersection_node))
lanes = std::max(
lanes, node_based_graph.GetEdgeData(onto_edge).road_classification.GetNumberOfLanes());
return lanes;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif // OSRM_GUIDANCE_TOOLKIT_HPP_
@@ -8,7 +8,6 @@
#include "extractor/guidance/motorway_handler.hpp"
#include "extractor/guidance/roundabout_handler.hpp"
#include "extractor/guidance/sliproad_handler.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_classification.hpp"
#include "extractor/guidance/turn_handler.hpp"
#include "extractor/query_node.hpp"
@@ -1,21 +1,12 @@
#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
#define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/query_node.hpp"
#include "util/coordinate.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include <algorithm>
#include <cstddef>
#include <utility>
#include <vector>
namespace osrm
{
@@ -5,8 +5,6 @@
#include "extractor/guidance/intersection_generator.hpp"
#include "util/typedefs.hpp"
#include <string>
namespace osrm
{
namespace extractor
+158 -2
View File
@@ -1,11 +1,11 @@
#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
#include <algorithm>
#include <cstdint>
#include <boost/assert.hpp>
#include "extractor/guidance/roundabout_type.hpp"
#include "util/attributes.hpp"
#include "util/typedefs.hpp"
namespace osrm
@@ -150,6 +150,162 @@ inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs)
return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier;
}
// check if a instruction is associated in any form with a roundabout
inline bool hasRoundaboutType(const TurnInstruction instruction)
{
using namespace extractor::guidance::TurnType;
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
TurnType::EnterAndExitRoundabout,
TurnType::EnterRotary,
TurnType::EnterAndExitRotary,
TurnType::EnterRoundaboutIntersection,
TurnType::EnterAndExitRoundaboutIntersection,
TurnType::EnterRoundaboutAtExit,
TurnType::ExitRoundabout,
TurnType::EnterRotaryAtExit,
TurnType::ExitRotary,
TurnType::EnterRoundaboutIntersectionAtExit,
TurnType::ExitRoundaboutIntersection,
TurnType::StayOnRoundabout};
const auto *first = valid_types;
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
return std::find(first, last, instruction.type) != last;
}
inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterRotary ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersection ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
}
inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
instruction.type == extractor::guidance::TurnType::ExitRotary ||
instruction.type == extractor::guidance::TurnType::ExitRoundaboutIntersection ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
}
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
// Silent Turn Instructions are not to be mentioned to the outside world but
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::NoTurn ||
instruction.type == extractor::guidance::TurnType::Suppressed ||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
inline bool hasRampType(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::OffRamp ||
instruction.type == extractor::guidance::TurnType::OnRamp;
}
inline extractor::guidance::DirectionModifier::Enum getTurnDirection(const double angle)
{
// An angle of zero is a u-turn
// 180 goes perfectly straight
// 0-180 are right turns
// 180-360 are left turns
if (angle > 0 && angle < 60)
return extractor::guidance::DirectionModifier::SharpRight;
if (angle >= 60 && angle < 140)
return extractor::guidance::DirectionModifier::Right;
if (angle >= 140 && angle < 160)
return extractor::guidance::DirectionModifier::SlightRight;
if (angle >= 160 && angle <= 200)
return extractor::guidance::DirectionModifier::Straight;
if (angle > 200 && angle <= 220)
return extractor::guidance::DirectionModifier::SlightLeft;
if (angle > 220 && angle <= 300)
return extractor::guidance::DirectionModifier::Left;
if (angle > 300 && angle < 360)
return extractor::guidance::DirectionModifier::SharpLeft;
return extractor::guidance::DirectionModifier::UTurn;
}
// swaps left <-> right modifier types
OSRM_ATTR_WARN_UNUSED
inline extractor::guidance::DirectionModifier::Enum
mirrorDirectionModifier(const extractor::guidance::DirectionModifier::Enum modifier)
{
const constexpr extractor::guidance::DirectionModifier::Enum results[] = {
extractor::guidance::DirectionModifier::UTurn,
extractor::guidance::DirectionModifier::SharpLeft,
extractor::guidance::DirectionModifier::Left,
extractor::guidance::DirectionModifier::SlightLeft,
extractor::guidance::DirectionModifier::Straight,
extractor::guidance::DirectionModifier::SlightRight,
extractor::guidance::DirectionModifier::Right,
extractor::guidance::DirectionModifier::SharpRight};
return results[modifier];
}
inline bool hasLeftModifier(const extractor::guidance::TurnInstruction instruction)
{
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpLeft ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Left ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightLeft;
}
inline bool hasRightModifier(const extractor::guidance::TurnInstruction instruction)
{
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpRight ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Right ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightRight;
}
inline bool isLeftTurn(const extractor::guidance::TurnInstruction instruction)
{
switch (instruction.type)
{
case TurnType::Merge:
return hasRightModifier(instruction);
default:
return hasLeftModifier(instruction);
}
}
inline bool isRightTurn(const extractor::guidance::TurnInstruction instruction)
{
switch (instruction.type)
{
case TurnType::Merge:
return hasLeftModifier(instruction);
default:
return hasRightModifier(instruction);
}
}
inline DirectionModifier::Enum bearingToDirectionModifier(const double bearing)
{
if (bearing < 135)
{
return extractor::guidance::DirectionModifier::Right;
}
if (bearing <= 225)
{
return extractor::guidance::DirectionModifier::Straight;
}
return extractor::guidance::DirectionModifier::Left;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
@@ -4,7 +4,6 @@
#include "extractor/guidance/turn_lane_types.hpp"
#include "util/attributes.hpp"
#include "util/typedefs.hpp"
#include <string>
#include <vector>
namespace osrm
@@ -2,7 +2,6 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_analysis.hpp"
#include "extractor/guidance/turn_lane_data.hpp"
#include "extractor/guidance/turn_lane_types.hpp"
@@ -74,7 +73,7 @@ class TurnLaneHandler
std::vector<TurnLaneType::Mask> &turn_lane_masks,
LaneDescriptionMap &lane_description_map,
const TurnAnalysis &turn_analysis,
LaneDataIdMap &id_map);
util::guidance::LaneDataIdMap &id_map);
~TurnLaneHandler();
@@ -91,7 +90,7 @@ class TurnLaneHandler
std::vector<TurnLaneType::Mask> &turn_lane_masks;
LaneDescriptionMap &lane_description_map;
const TurnAnalysis &turn_analysis;
LaneDataIdMap &id_map;
util::guidance::LaneDataIdMap &id_map;
// Find out which scenario we have to handle
TurnLaneScenario deduceScenario(const NodeID at,
@@ -2,7 +2,6 @@
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_MATCHER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/guidance/turn_lane_data.hpp"
@@ -10,8 +9,6 @@
#include "util/guidance/turn_lanes.hpp"
#include "util/node_based_graph.hpp"
#include <unordered_map>
namespace osrm
{
namespace extractor
@@ -47,7 +44,7 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
const LaneDataVector &lane_data,
const util::NodeBasedDynamicGraph &node_based_graph,
const LaneDescriptionID lane_string_id,
LaneDataIdMap &lane_data_to_id);
util::guidance::LaneDataIdMap &lane_data_to_id);
} // namespace lanes
} // namespace guidance
@@ -8,11 +8,9 @@
#include <unordered_map>
#include <vector>
#include <boost/assert.hpp>
#include <boost/functional/hash.hpp>
#include "util/json_container.hpp"
#include "util/simple_logger.hpp"
#include "util/typedefs.hpp"
namespace osrm
@@ -47,7 +47,6 @@ struct InternalExtractorEdge
false, // backward
false, // roundabout
false, // circular
false, // access restricted
true, // can be startpoint
TRAVEL_MODE_INACCESSIBLE,
false,
@@ -64,7 +63,6 @@ struct InternalExtractorEdge
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
@@ -78,7 +76,6 @@ struct InternalExtractorEdge
backward,
roundabout,
circular,
access_restricted,
startpoint,
travel_mode,
is_split,
@@ -106,7 +103,6 @@ struct InternalExtractorEdge
false, // backward
false, // roundabout
false, // circular
false, // access restricted
true, // can be startpoint
TRAVEL_MODE_INACCESSIBLE,
false,
@@ -123,7 +119,6 @@ struct InternalExtractorEdge
false, // backward
false, // roundabout
false, // circular
false, // access restricted
true, // can be startpoint
TRAVEL_MODE_INACCESSIBLE,
false,
+4 -12
View File
@@ -23,7 +23,6 @@ struct NodeBasedEdge
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
@@ -40,7 +39,6 @@ struct NodeBasedEdge
bool backward : 1;
bool roundabout : 1;
bool circular : 1;
bool access_restricted : 1;
bool startpoint : 1;
bool is_split : 1;
TravelMode travel_mode : 4;
@@ -58,7 +56,6 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
@@ -73,9 +70,8 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
inline NodeBasedEdge::NodeBasedEdge()
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
backward(false), roundabout(false), circular(false), access_restricted(false),
startpoint(true), is_split(false), travel_mode(false),
lane_description_id(INVALID_LANE_DESCRIPTIONID)
backward(false), roundabout(false), circular(false), startpoint(true), is_split(false),
travel_mode(false), lane_description_id(INVALID_LANE_DESCRIPTIONID)
{
}
@@ -87,16 +83,14 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
const LaneDescriptionID lane_description_id,
guidance::RoadClassification road_classification)
: source(source), target(target), name_id(name_id), weight(weight), forward(forward),
backward(backward), roundabout(roundabout), circular(circular),
access_restricted(access_restricted), startpoint(startpoint), is_split(is_split),
travel_mode(travel_mode), lane_description_id(lane_description_id),
backward(backward), roundabout(roundabout), circular(circular), startpoint(startpoint),
is_split(is_split), travel_mode(travel_mode), lane_description_id(lane_description_id),
road_classification(std::move(road_classification))
{
}
@@ -126,7 +120,6 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
bool backward,
bool roundabout,
bool circular,
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
bool is_split,
@@ -140,7 +133,6 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
backward,
roundabout,
circular,
access_restricted,
startpoint,
travel_mode,
is_split,
+4 -3
View File
@@ -66,13 +66,14 @@ class RasterGrid
}
catch (std::exception const &ex)
{
throw util::exception(
std::string("Failed to read from raster source with exception: ") + ex.what());
throw util::exception("Failed to read from raster source " + filepath.string() + ": " +
ex.what() + SOURCE_REF);
}
if (!r || itr != end)
{
throw util::exception("Failed to parse raster source correctly.");
throw util::exception("Failed to parse raster source: " + filepath.string() +
SOURCE_REF);
}
}
+4 -4
View File
@@ -8,7 +8,7 @@
#include "util/typedefs.hpp"
#include "util/integer_range.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include "util/std_hash.hpp"
#include "util/timing_util.hpp"
@@ -146,8 +146,8 @@ template <typename GraphT> class TarjanSCC
if (size_of_current_component > 1000)
{
util::SimpleLogger().Write() << "large component [" << component_index
<< "]=" << size_of_current_component;
util::Log() << "large component [" << component_index
<< "]=" << size_of_current_component;
}
++component_index;
@@ -158,7 +158,7 @@ template <typename GraphT> class TarjanSCC
}
TIMER_STOP(SCC_RUN);
util::SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
util::Log() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
size_one_counter = std::count_if(component_size_vector.begin(),
component_size_vector.end(),
+3 -4
View File
@@ -6,7 +6,7 @@
#include "server/service_handler.hpp"
#include "util/integer_range.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
@@ -36,8 +36,7 @@ class Server
static std::shared_ptr<Server>
CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
{
util::SimpleLogger().Write() << "http 1.1 compression handled by zlib version "
<< zlibVersion();
util::Log() << "http 1.1 compression handled by zlib version " << zlibVersion();
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
@@ -62,7 +61,7 @@ class Server
acceptor.bind(endpoint);
acceptor.listen();
util::SimpleLogger().Write() << "Listening on: " << acceptor.local_endpoint();
util::Log() << "Listening on: " << acceptor.local_endpoint();
acceptor.async_accept(
new_connection->socket(),
+1 -1
View File
@@ -5,7 +5,7 @@
#include "osrm/osrm.hpp"
#include "util/coordinate.hpp"
#include <variant/variant.hpp>
#include <mapbox/variant.hpp>
#include <string>
#include <vector>
+84 -12
View File
@@ -2,13 +2,13 @@
#define OSRM_STORAGE_IO_HPP_
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/fingerprint.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include <boost/filesystem/fstream.hpp>
#include <boost/iostreams/seek.hpp>
#include <cerrno>
#include <cstring>
#include <tuple>
#include <type_traits>
@@ -23,7 +23,7 @@ namespace io
class FileReader
{
private:
const std::string filename;
const boost::filesystem::path filepath;
boost::filesystem::ifstream input_stream;
public:
@@ -47,16 +47,16 @@ class FileReader
{
}
FileReader(const boost::filesystem::path &filename_, const FingerprintFlag flag)
: filename(filename_.string())
FileReader(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
: filepath(filepath_)
{
input_stream.open(filename_, std::ios::binary);
input_stream.open(filepath, std::ios::binary);
if (!input_stream)
throw util::exception("Error opening " + filename + ":" + std::strerror(errno));
throw util::exception("Error opening " + filepath.string());
if (flag == VerifyFingerprint && !ReadAndCheckFingerprint())
{
throw util::exception("Fingerprint mismatch in " + filename);
throw util::exception("Fingerprint mismatch in " + filepath_.string() + SOURCE_REF);
}
}
@@ -77,10 +77,10 @@ class FileReader
{
if (result.eof())
{
throw util::exception("Error reading from " + filename +
": Unexpected end of file");
throw util::exception("Error reading from " + filepath.string() +
": Unexpected end of file " + SOURCE_REF);
}
throw util::exception("Error reading from " + filename + ": " + std::strerror(errno));
throw util::exception("Error reading from " + filepath.string() + " " + SOURCE_REF);
}
}
@@ -161,7 +161,7 @@ class FileReader
{
std::getline(input_stream, thisline);
}
catch (const std::ios_base::failure &e)
catch (const std::ios_base::failure & /*e*/)
{
// EOF is OK here, everything else, re-throw
if (!input_stream.eof())
@@ -170,6 +170,78 @@ class FileReader
return thisline;
}
};
class FileWriter
{
private:
const boost::filesystem::path filepath;
boost::filesystem::ofstream output_stream;
public:
enum FingerprintFlag
{
GenerateFingerprint,
HasNoFingerprint
};
FileWriter(const std::string &filename, const FingerprintFlag flag)
: FileWriter(boost::filesystem::path(filename), flag)
{
}
FileWriter(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
: filepath(filepath_)
{
output_stream.open(filepath, std::ios::binary);
if (!output_stream)
throw util::exception("Error opening " + filepath.string());
if (flag == GenerateFingerprint)
{
WriteFingerprint();
}
}
/* Write count objects of type T from pointer src to output stream */
template <typename T> bool WriteFrom(T *src, const std::size_t count)
{
#if not defined __GNUC__ or __GNUC__ > 4
static_assert(std::is_trivially_copyable<T>::value,
"bytewise writing requires trivially copyable type");
#endif
if (count == 0)
return true;
const auto &result = output_stream.write(reinterpret_cast<char *>(src), count * sizeof(T));
if (!result)
{
throw util::exception("Error writing to " + filepath.string());
}
return static_cast<bool>(output_stream);
}
template <typename T> bool WriteFrom(T &target) { return WriteFrom(&target, 1); }
template <typename T> bool WriteOne(T tmp) { return WriteFrom(tmp); }
bool WriteElementCount32(const std::uint32_t count) { return WriteOne<std::uint32_t>(count); }
bool WriteElementCount64(const std::uint64_t count) { return WriteOne<std::uint64_t>(count); }
template <typename T> bool SerializeVector(std::vector<T> &data)
{
const auto count = data.size();
WriteElementCount64(count);
return WriteFrom(data.data(), count);
}
bool WriteFingerprint()
{
const auto fingerprint = util::FingerPrint::GetValid();
return WriteOne(fingerprint);
}
};
}
}
}
+3 -3
View File
@@ -8,7 +8,7 @@
#include "storage/io.hpp"
#include "util/exception.hpp"
#include "util/fingerprint.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include "util/static_graph.hpp"
#include <boost/filesystem/fstream.hpp>
@@ -44,8 +44,8 @@ inline HSGRHeader readHSGRHeader(io::FileReader &input_file)
const auto fingerprint_loaded = input_file.ReadOne<util::FingerPrint>();
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
{
util::SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
"Reprocess to get rid of this warning.";
util::Log(logWARNING) << ".hsgr was prepared with different build.\n"
"Reprocess to get rid of this warning.";
}
HSGRHeader header;
+6 -5
View File
@@ -2,7 +2,8 @@
#define SHARED_DATA_TYPE_HPP
#include "util/exception.hpp"
#include "util/simple_logger.hpp"
#include "util/exception_utils.hpp"
#include "util/log.hpp"
#include <array>
#include <cstdint>
@@ -175,13 +176,13 @@ struct DataLayout
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
if (!start_canary_alive)
{
throw util::exception(std::string("Start canary of block corrupted. (") +
block_id_to_name[bid] + ")");
throw util::exception("Start canary of block corrupted. (" +
std::string(block_id_to_name[bid]) + ")" + SOURCE_REF);
}
if (!end_canary_alive)
{
throw util::exception(std::string("End canary of block corrupted. (") +
block_id_to_name[bid] + ")");
throw util::exception("End canary of block corrupted. (" +
std::string(block_id_to_name[bid]) + ")" + SOURCE_REF);
}
}
+13 -14
View File
@@ -2,7 +2,8 @@
#define SHARED_MEMORY_HPP
#include "util/exception.hpp"
#include "util/simple_logger.hpp"
#include "util/exception_utils.hpp"
#include "util/log.hpp"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -62,8 +63,7 @@ class SharedMemory
{
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key);
util::SimpleLogger().Write(logDEBUG) << "opening " << shm.get_shmid() << " from id "
<< id;
util::Log(logDEBUG) << "opening " << shm.get_shmid() << " from id " << id;
region = boost::interprocess::mapped_region(shm, access);
}
@@ -72,14 +72,14 @@ class SharedMemory
{
shm = boost::interprocess::xsi_shared_memory(
boost::interprocess::open_or_create, key, size);
util::SimpleLogger().Write(logDEBUG) << "opening/creating " << shm.get_shmid()
<< " from id " << id << " with size " << size;
util::Log(logDEBUG) << "opening/creating " << shm.get_shmid() << " from id " << id
<< " with size " << size;
#ifdef __linux__
if (-1 == shmctl(shm.get_shmid(), SHM_LOCK, nullptr))
{
if (ENOMEM == errno)
{
util::SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
util::Log(logWARNING) << "could not lock shared memory to RAM";
}
}
#endif
@@ -133,7 +133,7 @@ class SharedMemory
static bool Remove(const boost::interprocess::xsi_key &key)
{
boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory " << xsi.get_shmid();
util::Log(logDEBUG) << "deallocating prev memory " << xsi.get_shmid();
return boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
}
@@ -173,8 +173,7 @@ class SharedMemory
shm.truncate(size);
region = boost::interprocess::mapped_region(shm, access);
util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
<< " bytes";
util::Log(logDEBUG) << "writeable memory allocated " << size << " bytes";
}
}
@@ -221,7 +220,7 @@ class SharedMemory
static bool Remove(char *key)
{
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory for key " << key;
util::Log(logDEBUG) << "deallocating prev memory for key " << key;
return boost::interprocess::shared_memory_object::remove(key);
}
@@ -242,7 +241,7 @@ makeSharedMemory(const IdentifierT &id, const uint64_t size = 0, bool read_write
{
if (0 == size)
{
throw util::exception("lock file does not exist, exiting");
throw util::exception("lock file does not exist, exiting" + SOURCE_REF);
}
else
{
@@ -253,9 +252,9 @@ makeSharedMemory(const IdentifierT &id, const uint64_t size = 0, bool read_write
}
catch (const boost::interprocess::interprocess_exception &e)
{
util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
<< e.get_error_code();
throw util::exception(e.what());
util::Log(logERROR) << "Error while attempting to allocate shared memory: " << e.what()
<< ", code " << e.get_error_code();
throw util::exception(e.what() + SOURCE_REF);
}
}
}
+10 -1
View File
@@ -1,7 +1,9 @@
#ifndef BEARING_HPP
#define BEARING_HPP
#include <algorithm>
#include <boost/assert.hpp>
#include <cmath>
#include <string>
namespace osrm
@@ -89,6 +91,7 @@ inline bool CheckInBounds(const int A, const int B, const int range)
return normalized_B - range <= normalized_A && normalized_A <= normalized_B + range;
}
}
} // namespace bearing
inline double reverseBearing(const double bearing)
{
@@ -128,7 +131,13 @@ inline double angleBetweenBearings(const double entry_bearing, const double exit
return angle >= 360 ? angle - 360 : angle;
}
} // namespace bearing
// minimal difference between two angles/bearings going left or right
inline double angularDeviation(const double angle, const double from)
{
const double deviation = std::abs(angle - from);
return std::min(360 - deviation, deviation);
}
} // namespace util
} // namespace osrm
+3
View File
@@ -136,6 +136,9 @@ bool isCCW(const Coordinate first_coordinate,
const Coordinate second_coordinate,
const Coordinate third_coordinate);
std::pair<util::Coordinate, util::Coordinate>
leastSquareRegression(const std::vector<util::Coordinate> &coordinates);
} // ns coordinate_calculation
} // ns util
} // ns osrm
+15
View File
@@ -0,0 +1,15 @@
#ifndef SOURCE_MACROS_HPP
#define SOURCE_MACROS_HPP
#include <cstring>
// Helper macros, don't use these ones
// STRIP the OSRM_PROJECT_DIR from the front of a filename. Expected to come
// from CMake's CURRENT_SOURCE_DIR, which doesn't have a trailing /, hence the +1
#define _PROJECT_RELATIVE_PATH(x) std::string(x).substr(strlen(OSRM_PROJECT_DIR) + 1)
// Return the path of a file, relative to the OSRM_PROJECT_DIR
#define _OSRM_SOURCE_FILE _PROJECT_RELATIVE_PATH(__FILE__)
// This is the macro to use
#define SOURCE_REF std::string(" (at ") + _OSRM_SOURCE_FILE + ":" + std::to_string(__LINE__) + ")"
#endif // SOURCE_MACROS_HPP
+5 -4
View File
@@ -1,4 +1,5 @@
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include <boost/uuid/name_generator.hpp>
#include <boost/uuid/uuid_generators.hpp>
@@ -57,7 +58,7 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
{
if (!IsMagicNumberOK(other))
{
throw exception("hsgr input file misses magic number. Check or reprocess the file");
throw exception(std::string("hsgr input file misses magic number. Check or reprocess the file") + SOURCE_REF);
}
return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
}
@@ -66,7 +67,7 @@ bool FingerPrint::TestContractor(const FingerPrint &other) const
{
if (!IsMagicNumberOK(other))
{
throw exception("osrm input file misses magic number. Check or reprocess the file");
throw exception(std::string("osrm input file misses magic number. Check or reprocess the file") + SOURCE_REF);
}
return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
}
@@ -75,7 +76,7 @@ bool FingerPrint::TestRTree(const FingerPrint &other) const
{
if (!IsMagicNumberOK(other))
{
throw exception("r-tree input file misses magic number. Check or reprocess the file");
throw exception(std::string("r-tree input file misses magic number. Check or reprocess the file") + SOURCE_REF);
}
return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
}
@@ -84,7 +85,7 @@ bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
{
if (!IsMagicNumberOK(other))
{
throw exception("missing magic number. Check or reprocess the file");
throw exception(std::string("missing magic number. Check or reprocess the file") + SOURCE_REF);
}
return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
}
+5 -5
View File
@@ -7,7 +7,7 @@
#include "util/json_container.hpp"
#include "util/json_renderer.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
namespace osrm
{
@@ -63,11 +63,11 @@ class GeojsonLogger
// make sure to syncronize logging output, our writing should be sequential
std::lock_guard<std::mutex> guard(lock);
// if there is no logfile, we cannot write
// if there is no logfile, we cannot write (possible reason: the guard might be out of scope
// (e.g. if it is anonymous))
if (!ofs.is_open() || (nullptr == policy))
{
// this can only happend between two guards when concurrent writing occurs
return false;
throw util::exception("Trying to use the geojson printer without an open logger.");
}
// use our policy to convert the arguments into geojson, this can be done in parallel
@@ -92,7 +92,7 @@ class GeojsonLogger
// out on log output. Such a sad life
if (ofs.is_open())
{
util::SimpleLogger().Write(logWARNING)
util::Log(logWARNING)
<< "Overwriting " << logfile
<< ". Is this desired behaviour? If this message occurs more than once rethink the "
"location of your Logger Guard.";
+5 -5
View File
@@ -8,7 +8,7 @@
#include "storage/io.hpp"
#include "util/exception.hpp"
#include "util/fingerprint.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include "util/typedefs.hpp"
#include <boost/assert.hpp>
@@ -60,7 +60,7 @@ NodeID loadNodesFromFile(storage::io::FileReader &file_reader,
std::vector<extractor::QueryNode> &node_array)
{
NodeID number_of_nodes = file_reader.ReadElementCount32();
SimpleLogger().Write() << "Importing number_of_nodes new = " << number_of_nodes << " nodes ";
Log() << "Importing number_of_nodes new = " << number_of_nodes << " nodes ";
node_array.resize(number_of_nodes);
@@ -99,14 +99,14 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
BOOST_ASSERT(sizeof(EdgeID) == sizeof(number_of_edges));
edge_list.resize(number_of_edges);
SimpleLogger().Write() << " and " << number_of_edges << " edges ";
Log() << " and " << number_of_edges << " edges ";
file_reader.ReadInto(edge_list.data(), number_of_edges);
BOOST_ASSERT(edge_list.size() > 0);
#ifndef NDEBUG
SimpleLogger().Write() << "Validating loaded edges...";
Log() << "Validating loaded edges...";
tbb::parallel_sort(
edge_list.begin(),
edge_list.end(),
@@ -129,7 +129,7 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
}
#endif
SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
Log() << "Graph loaded ok and has " << edge_list.size() << " edges";
return number_of_edges;
}
@@ -1,26 +1,20 @@
#ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
#define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
#ifndef OSRM_UTIL_GUIDANCE_NAME_ANNOUNCEMENT_HPP_
#define OSRM_UTIL_GUIDANCE_NAME_ANNOUNCEMENT_HPP_
/* A set of tools required for guidance in both pre and post-processing */
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/suffix_table.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/phantom_node.hpp"
#include "util/attributes.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/name_table.hpp"
#include "util/simple_logger.hpp"
#include "util/typedefs.hpp"
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
namespace osrm
{
@@ -29,122 +23,6 @@ namespace util
namespace guidance
{
inline double angularDeviation(const double angle, const double from)
{
const double deviation = std::abs(angle - from);
return std::min(360 - deviation, deviation);
}
inline bool hasRampType(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::OffRamp ||
instruction.type == extractor::guidance::TurnType::OnRamp;
}
inline extractor::guidance::DirectionModifier::Enum getTurnDirection(const double angle)
{
// An angle of zero is a u-turn
// 180 goes perfectly straight
// 0-180 are right turns
// 180-360 are left turns
if (angle > 0 && angle < 60)
return extractor::guidance::DirectionModifier::SharpRight;
if (angle >= 60 && angle < 140)
return extractor::guidance::DirectionModifier::Right;
if (angle >= 140 && angle < 160)
return extractor::guidance::DirectionModifier::SlightRight;
if (angle >= 160 && angle <= 200)
return extractor::guidance::DirectionModifier::Straight;
if (angle > 200 && angle <= 220)
return extractor::guidance::DirectionModifier::SlightLeft;
if (angle > 220 && angle <= 300)
return extractor::guidance::DirectionModifier::Left;
if (angle > 300 && angle < 360)
return extractor::guidance::DirectionModifier::SharpLeft;
return extractor::guidance::DirectionModifier::UTurn;
}
// swaps left <-> right modifier types
OSRM_ATTR_WARN_UNUSED
inline extractor::guidance::DirectionModifier::Enum
mirrorDirectionModifier(const extractor::guidance::DirectionModifier::Enum modifier)
{
const constexpr extractor::guidance::DirectionModifier::Enum results[] = {
extractor::guidance::DirectionModifier::UTurn,
extractor::guidance::DirectionModifier::SharpLeft,
extractor::guidance::DirectionModifier::Left,
extractor::guidance::DirectionModifier::SlightLeft,
extractor::guidance::DirectionModifier::Straight,
extractor::guidance::DirectionModifier::SlightRight,
extractor::guidance::DirectionModifier::Right,
extractor::guidance::DirectionModifier::SharpRight};
return results[modifier];
}
inline bool hasLeftModifier(const extractor::guidance::TurnInstruction instruction)
{
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpLeft ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Left ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightLeft;
}
inline bool hasRightModifier(const extractor::guidance::TurnInstruction instruction)
{
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpRight ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Right ||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightRight;
}
inline bool isLeftTurn(const extractor::guidance::TurnInstruction instruction)
{
switch (instruction.type)
{
case extractor::guidance::TurnType::Merge:
return hasRightModifier(instruction);
default:
return hasLeftModifier(instruction);
}
}
inline bool isRightTurn(const extractor::guidance::TurnInstruction instruction)
{
switch (instruction.type)
{
case extractor::guidance::TurnType::Merge:
return hasLeftModifier(instruction);
default:
return hasRightModifier(instruction);
}
}
inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterRotary ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersection ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
}
inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
instruction.type == extractor::guidance::TurnType::ExitRotary ||
instruction.type == extractor::guidance::TurnType::ExitRoundaboutIntersection ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
}
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
// Name Change Logic
// Used both during Extraction as well as during Post-Processing
@@ -304,4 +182,4 @@ inline bool requiresNameAnnounced(const NameID from_name_id,
} // namespace util
} // namespace osrm
#endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */
#endif /* OSRM_UTIL_GUIDANCE_NAME_ANNOUNCEMENT_HPP_ */
+3
View File
@@ -4,6 +4,7 @@
#include <cstddef>
#include <cstdint>
#include <functional>
#include <unordered_map>
#include <vector>
#include "util/typedefs.hpp"
@@ -96,6 +97,8 @@ class LaneTupleIdPair
}
};
using LaneDataIdMap = std::unordered_map<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
} // namespace guidance
} // namespace util
} // namespace osrm
+17 -11
View File
@@ -1,7 +1,7 @@
#ifndef OSRM_INCLUDE_UTIL_IO_HPP_
#define OSRM_INCLUDE_UTIL_IO_HPP_
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include <boost/filesystem.hpp>
#include <boost/numeric/conversion/cast.hpp>
@@ -54,7 +54,8 @@ template <typename simple_type>
bool serializeVectorIntoAdjacencyArray(const std::string &filename,
const std::vector<std::vector<simple_type>> &data)
{
std::ofstream out_stream(filename, std::ios::binary);
storage::io::FileWriter file(filename, storage::io::FileWriter::HasNoFingerprint);
std::vector<std::uint32_t> offsets;
offsets.reserve(data.size() + 1);
std::uint64_t current_offset = 0;
@@ -64,18 +65,23 @@ bool serializeVectorIntoAdjacencyArray(const std::string &filename,
current_offset += vec.size();
offsets.push_back(boost::numeric_cast<std::uint32_t>(current_offset));
}
if (!serializeVector(out_stream, offsets))
return false;
std::vector<simple_type> all_data;
all_data.reserve(offsets.back());
for (auto const &vec : data)
all_data.insert(all_data.end(), vec.begin(), vec.end());
if (!serializeVector(out_stream, all_data))
if (!file.SerializeVector(offsets))
{
return false;
}
return static_cast<bool>(out_stream);
if (!file.SerializeVector(all_data))
{
return false;
}
return true;
}
template <typename simple_type, std::size_t WRITE_BLOCK_BUFFER_SIZE = 1024>
@@ -119,9 +125,10 @@ void deserializeAdjacencyArray(const std::string &filename,
// offsets have to match up with the size of the data
if (offsets.empty() || (offsets.back() != boost::numeric_cast<std::uint32_t>(data.size())))
throw util::exception("Error in " + filename + (offsets.empty()
? "Offsets are empty"
: "Offset and data size do not match"));
throw util::exception(
"Error in " + filename +
(offsets.empty() ? "Offsets are empty" : "Offset and data size do not match") +
SOURCE_REF);
}
inline bool serializeFlags(const boost::filesystem::path &path, const std::vector<bool> &flags)
@@ -147,8 +154,7 @@ inline bool serializeFlags(const boost::filesystem::path &path, const std::vecto
++chunk_count;
flag_stream.write(reinterpret_cast<const char *>(&chunk), sizeof(chunk));
}
SimpleLogger().Write() << "Wrote " << number_of_bits << " bits in " << chunk_count
<< " chunks (Flags).";
Log() << "Wrote " << number_of_bits << " bits in " << chunk_count << " chunks (Flags).";
return static_cast<bool>(flag_stream);
}
+1 -1
View File
@@ -31,7 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef JSON_CONTAINER_HPP
#define JSON_CONTAINER_HPP
#include <variant/variant.hpp>
#include <mapbox/variant.hpp>
#include <string>
#include <unordered_map>
+70
View File
@@ -0,0 +1,70 @@
#ifndef LOG_HPP
#define LOG_HPP
#include <atomic>
#include <mutex>
#include <sstream>
enum LogLevel
{
logINFO,
logWARNING,
logERROR,
logDEBUG
};
namespace osrm
{
namespace util
{
class LogPolicy
{
public:
void Unmute();
void Mute();
bool IsMute() const;
static LogPolicy &GetInstance();
LogPolicy(const LogPolicy &) = delete;
LogPolicy &operator=(const LogPolicy &) = delete;
private:
LogPolicy() : m_is_mute(true) {}
std::atomic<bool> m_is_mute;
};
class Log
{
public:
Log(LogLevel level_ = logINFO);
Log(LogLevel level_, std::ostream &ostream);
virtual ~Log();
std::mutex &get_mutex();
template <typename T> inline std::ostream &operator<<(const T &data) { return stream << data; }
protected:
LogLevel level;
std::ostringstream buffer;
std::ostream &stream;
};
/**
* Modified logger - this one doesn't buffer - it writes directly to stdout,
* and the final newline is only printed when the object is destructed.
* Useful for logging situations where you don't want to newline right away
*/
class UnbufferedLog : public Log
{
public:
UnbufferedLog(LogLevel level_ = logINFO);
};
}
}
#endif /* LOG_HPP */
+43
View File
@@ -0,0 +1,43 @@
#ifndef MEMINFO_HPP
#define MEMINFO_HPP
#include "util/log.hpp"
#include <stxxl/mng>
#ifndef _WIN32
#include <sys/resource.h>
#endif
namespace osrm
{
namespace util
{
inline void DumpMemoryStats()
{
#if STXXL_VERSION_MAJOR > 1 || (STXXL_VERSION_MAJOR == 1 && STXXL_VERSION_MINOR >= 4)
auto manager = stxxl::block_manager::get_instance();
util::Log() << "STXXL: peak bytes used: " << manager->get_maximum_allocation();
util::Log() << "STXXL: total disk allocated: " << manager->get_total_bytes();
#else
#warning STXXL 1.4+ recommended - STXXL memory summary will not be available
util::Log() << "STXXL: memory summary not available, needs STXXL 1.4 or higher";
#endif
#ifndef _WIN32
rusage usage;
getrusage(RUSAGE_SELF, &usage);
#ifdef __linux__
// Under linux, ru.maxrss is in kb
util::Log() << "RAM: peak bytes used: " << usage.ru_maxrss * 1024;
#else // __linux__
// Under BSD systems (OSX), it's in bytes
util::Log() << "RAM: peak bytes used: " << usage.ru_maxrss;
#endif // __linux__
#else // _WIN32
util::Log() << "RAM: peak bytes used: <not implemented on Windows>";
#endif // _WIN32
}
}
}
#endif
+5 -10
View File
@@ -19,8 +19,8 @@ struct NodeBasedEdgeData
{
NodeBasedEdgeData()
: distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
name_id(std::numeric_limits<unsigned>::max()), access_restricted(false), reversed(false),
roundabout(false), circular(false), travel_mode(TRAVEL_MODE_INACCESSIBLE),
name_id(std::numeric_limits<unsigned>::max()), reversed(false), roundabout(false),
circular(false), travel_mode(TRAVEL_MODE_INACCESSIBLE),
lane_description_id(INVALID_LANE_DESCRIPTIONID)
{
}
@@ -28,24 +28,21 @@ struct NodeBasedEdgeData
NodeBasedEdgeData(int distance,
unsigned edge_id,
unsigned name_id,
bool access_restricted,
bool reversed,
bool roundabout,
bool circular,
bool startpoint,
extractor::TravelMode travel_mode,
const LaneDescriptionID lane_description_id)
: distance(distance), edge_id(edge_id), name_id(name_id),
access_restricted(access_restricted), reversed(reversed), roundabout(roundabout),
circular(circular), startpoint(startpoint), travel_mode(travel_mode),
lane_description_id(lane_description_id)
: distance(distance), edge_id(edge_id), name_id(name_id), reversed(reversed),
roundabout(roundabout), circular(circular), startpoint(startpoint),
travel_mode(travel_mode), lane_description_id(lane_description_id)
{
}
int distance;
unsigned edge_id;
unsigned name_id;
bool access_restricted : 1;
bool reversed : 1;
bool roundabout : 1;
bool circular : 1;
@@ -58,7 +55,6 @@ struct NodeBasedEdgeData
{
return (reversed == other.reversed) && (roundabout == other.roundabout) &&
(circular == other.circular) && (startpoint == other.startpoint) &&
(access_restricted == other.access_restricted) &&
(travel_mode == other.travel_mode) &&
(road_classification == other.road_classification);
}
@@ -88,7 +84,6 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
output_edge.data.roundabout = input_edge.roundabout;
output_edge.data.circular = input_edge.circular;
output_edge.data.name_id = input_edge.name_id;
output_edge.data.access_restricted = input_edge.access_restricted;
output_edge.data.travel_mode = input_edge.travel_mode;
output_edge.data.startpoint = input_edge.startpoint;
output_edge.data.road_classification = input_edge.road_classification;
+11 -7
View File
@@ -5,6 +5,7 @@
#include <iostream>
#include "util/isatty.hpp"
#include "util/log.hpp"
namespace osrm
{
@@ -13,8 +14,13 @@ namespace util
class Percent
{
Log &log;
public:
explicit Percent(unsigned max_value, unsigned step = 5) { Reinit(max_value, step); }
explicit Percent(Log &log_, unsigned max_value, unsigned step = 5) : log{log_}
{
Reinit(max_value, step);
}
// Reinitializes
void Reinit(unsigned max_value, unsigned step = 5)
@@ -36,7 +42,7 @@ class Percent
PrintPercent(current_value / static_cast<double>(m_max_value) * 100.);
}
if (current_value + 1 == m_max_value)
std::cout << " 100%" << std::endl;
log << " 100%";
}
void PrintIncrement()
@@ -67,19 +73,17 @@ class Percent
m_last_percent += m_step;
if (m_last_percent % 10 == 0)
{
std::cout << " " << m_last_percent << "% ";
log << " " << m_last_percent << "% ";
}
else
{
std::cout << ".";
log << ".";
}
// When not on a TTY, print newlines after each progress indicator so
// so that progress is visible to line-buffered logging systems
if (!IsStdoutATTY())
std::cout << std::endl;
std::cout.flush();
log << "" << std::endl;
}
}
};
@@ -3,7 +3,7 @@
#include <boost/assert.hpp>
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include <cstddef>
-55
View File
@@ -1,55 +0,0 @@
#ifndef SIMPLE_LOGGER_HPP
#define SIMPLE_LOGGER_HPP
#include <atomic>
#include <mutex>
#include <sstream>
enum LogLevel
{
logINFO,
logWARNING,
logDEBUG
};
namespace osrm
{
namespace util
{
class LogPolicy
{
public:
void Unmute();
void Mute();
bool IsMute() const;
static LogPolicy &GetInstance();
LogPolicy(const LogPolicy &) = delete;
LogPolicy &operator=(const LogPolicy &) = delete;
private:
LogPolicy() : m_is_mute(true) {}
std::atomic<bool> m_is_mute;
};
class SimpleLogger
{
public:
SimpleLogger();
virtual ~SimpleLogger();
std::mutex &get_mutex();
std::ostringstream &Write(LogLevel l = logINFO) noexcept;
private:
std::ostringstream os;
LogLevel level;
};
}
}
#endif /* SIMPLE_LOGGER_HPP */
+2 -1
View File
@@ -378,7 +378,8 @@ class StaticRTree
catch (const std::exception &exc)
{
throw exception(boost::str(boost::format("Leaf file %1% mapping failed: %2%") %
leaf_file % exc.what()));
leaf_file % exc.what()) +
SOURCE_REF);
}
}
-2
View File
@@ -8,10 +8,8 @@ local set_classification = require("lib/guidance").set_classification
barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["block"] = true }
access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
access_tags_hierarchy = { "bicycle", "vehicle", "access" }
cycleway_tags = {["track"]=true,["lane"]=true,["opposite"]=true,["opposite_lane"]=true,["opposite_track"]=true,["share_busway"]=true,["sharrow"]=true,["shared"]=true }
service_tag_restricted = { ["parking_aisle"] = true }
restrictions = { "bicycle" }
unsafe_highway_list = { ["primary"] = true, ["secondary"] = true, ["tertiary"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true}
+109 -173
View File
@@ -5,6 +5,7 @@ local set_classification = require("lib/guidance").set_classification
local get_turn_lanes = require("lib/guidance").get_turn_lanes
local Set = require('lib/set')
local Sequence = require('lib/sequence')
local Directional = require('lib/directional')
-- Begin of globals
barrier_whitelist = Set {
@@ -39,11 +40,6 @@ access_tag_blacklist = Set {
'delivery'
}
access_tag_restricted = Set {
'destination',
'delivery'
}
access_tags_hierarchy = Sequence {
'motorcar',
'motor_vehicle',
@@ -51,11 +47,6 @@ access_tags_hierarchy = Sequence {
'access'
}
service_tag_restricted = Set {
'parking_aisle',
'parking'
}
service_tag_forbidden = Set {
'emergency_access'
}
@@ -287,69 +278,51 @@ end
-- abort early if this way is obviouslt not routable
function initial_routability_check(way,result,data)
data.speed_type = way:get_value_by_key('highway')
data.highway = way:get_value_by_key('highway')
return data.speed_type ~= nil or
return data.highway ~= nil or
way:get_value_by_key('route') ~= nil or
way:get_value_by_key('bridge') ~= nil
end
-- handle high occupancy vehicle tags
function handle_hov(way,result)
-- respect user-preference for HOV-only ways
if ignore_hov_ways then
local hov = way:get_value_by_key("hov")
if "designated" == hov then
-- all lanes restricted to hov vehicles?
local function has_all_designated_hov_lanes(lanes)
if not lanes then
return false
end
-- This gmatch call effectively splits the string on | chars.
-- we append an extra | to the end so that we can match the final part
for lane in (lanes .. '|'):gmatch("([^|]*)|") do
if lane and lane ~= "designated" then
return false
end
end
return true
end
-- also respect user-preference for HOV-only ways when all lanes are HOV-designated
local function has_all_designated_hov_lanes(lanes)
local all = true
-- This gmatch call effectively splits the string on | chars.
-- we append an extra | to the end so that we can match the final part
for lane in (lanes .. '|'):gmatch("([^|]*)|") do
if lane and lane ~= "designated" then
all = false
break
end
end
return all
end
-- handle high occupancy vehicle tags
function handle_hov(way,result,data)
-- respect user-preference for HOV
if not ignore_hov_ways then
return
end
local hov_lanes = way:get_value_by_key("hov:lanes")
local hov_lanes_forward = way:get_value_by_key("hov:lanes:forward")
local hov_lanes_backward = way:get_value_by_key("hov:lanes:backward")
-- check if way is hov only
local hov = way:get_value_by_key("hov")
if "designated" == hov then
return false
end
local hov_all_designated = hov_lanes and
has_all_designated_hov_lanes(hov_lanes)
local hov_all_designated_forward = hov_lanes_forward and
has_all_designated_hov_lanes(hov_lanes_forward)
local hov_all_designated_backward = hov_lanes_backward and
has_all_designated_hov_lanes(hov_lanes_backward)
-- forward/backward lane depend on a way's direction
local oneway = way:get_value_by_key("oneway")
local reverse = oneway == "-1"
if hov_all_designated or hov_all_designated_forward then
if reverse then
result.backward_mode = mode.inaccessible
else
result.forward_mode = mode.inaccessible
end
end
if hov_all_designated_backward then
if reverse then
result.forward_mode = mode.inaccessible
else
result.backward_mode = mode.inaccessible
end
end
-- check if all lanes are hov only
local hov_lanes_forward, hov_lanes_backward = Directional.get_values_by_key(way,data,'hov:lanes')
local inaccessible_forward = has_all_designated_hov_lanes(hov_lanes_forward)
local inaccessible_backward = has_all_designated_hov_lanes(hov_lanes_backward)
if inaccessible_forward then
result.forward_mode = mode.inaccessible
end
if inaccessible_backward then
result.backward_mode = mode.inaccessible
end
end
@@ -394,8 +367,18 @@ end
-- check accessibility by traversing our acces tag hierarchy
function handle_access(way,result,data)
data.access = find_access_tag(way, access_tags_hierarchy)
if access_tag_blacklist[data.access] then
data.forward_access, data.backward_access =
Directional.get_values_by_set(way,data,access_tags_hierarchy)
if access_tag_blacklist[data.forward_access] then
result.forward_mode = mode.inaccessible
end
if access_tag_blacklist[data.backward_access] then
result.backward_mode = mode.inaccessible
end
if result.forward_mode == mode.inaccessible and result.backward_mode == mode.inaccessible then
return false
end
end
@@ -440,30 +423,21 @@ end
-- handle speed (excluding maxspeed)
function handle_speed(way,result,data)
if result.forward_speed == -1 then
local highway_speed = speed_profile[way:get_value_by_key("highway")]
local max_speed = parse_maxspeed( way:get_value_by_key("maxspeed") )
local highway_speed = speed_profile[data.highway]
-- Set the avg speed on the way if it is accessible by road class
if highway_speed then
if max_speed and max_speed > highway_speed then
result.forward_speed = max_speed
result.backward_speed = max_speed
-- max_speed = math.huge
else
result.forward_speed = highway_speed
result.backward_speed = highway_speed
end
result.forward_speed = highway_speed
result.backward_speed = highway_speed
else
-- Set the avg speed on ways that are marked accessible
if access_tag_whitelist[data.access] then
if access_tag_whitelist[data.forward_access] then
result.forward_speed = speed_profile["default"]
end
if access_tag_whitelist[data.backward_access] then
result.backward_speed = speed_profile["default"]
end
end
if 0 == max_speed then
max_speed = math.huge
end
result.forward_speed = min(result.forward_speed, max_speed)
result.backward_speed = min(result.backward_speed, max_speed)
end
if -1 == result.forward_speed and -1 == result.backward_speed then
@@ -472,7 +446,7 @@ function handle_speed(way,result,data)
if handle_side_roads(way,result) == false then return false end
if handle_surface(way,result) == false then return false end
if handle_maxspeed(way,result) == false then return false end
if handle_maxspeed(way,data,result) == false then return false end
if handle_speed_scaling(way,result) == false then return false end
if handle_alternating_speed(way,result) == false then return false end
end
@@ -529,23 +503,15 @@ function handle_names(way,result)
end
-- handle turn lanes
function handle_turn_lanes(way,result)
local turn_lanes = ''
local turn_lanes_forward = ''
local turn_lanes_backward = ''
function handle_turn_lanes(way,result,data)
local forward, backward = get_turn_lanes(way,data)
turn_lanes, turn_lanes_forward, turn_lanes_backward = get_turn_lanes(way)
if turn_lanes and turn_lanes ~= '' then
result.turn_lanes_forward = turn_lanes;
result.turn_lanes_backward = turn_lanes;
else
if turn_lanes_forward and turn_lanes_forward ~= '' then
result.turn_lanes_forward = turn_lanes_forward;
end
if forward then
result.turn_lanes_forward = forward
end
if turn_lanes_backward and turn_lanes_backward ~= '' then
result.turn_lanes_backward = turn_lanes_backward;
end
if backward then
result.turn_lanes_backward = backward
end
end
@@ -565,22 +531,10 @@ function handle_roundabouts(way,result)
end
end
-- Set access restriction flag if access is allowed under certain restrictions only
function handle_restricted(way,result,data)
if data.access and access_tag_restricted[data.access] then
result.is_access_restricted = true
end
end
-- service roads
function handle_service(way,result)
local service = way:get_value_by_key("service")
if service then
-- Set access restriction flag if service is allowed under certain restrictions only
if service_tag_restricted[service] then
result.is_access_restricted = true
end
-- Set don't allow access to certain service roads
if service_tag_forbidden[service] then
result.forward_mode = mode.inaccessible
@@ -633,69 +587,55 @@ function handle_speed_scaling(way,result)
end
end
-- oneways
function handle_oneway(way,result)
-- handle oneways tags
function handle_oneway(way,result,data)
local oneway = way:get_value_by_key("oneway")
data.oneway = oneway
if obey_oneway then
if oneway == "-1" then
data.is_reverse_oneway = true
result.forward_mode = mode.inaccessible
local is_forward = false
local destination = get_destination(way, is_forward)
result.destinations = canonicalizeStringList(destination, ",")
elseif oneway == "yes" or
oneway == "1" or
oneway == "true" or
way:get_value_by_key("junction") == "roundabout" or
way:get_value_by_key("junction") == "circular" or
(way:get_value_by_key("highway") == "motorway" and oneway ~= "no") then
oneway == "true" then
data.is_forward_oneway = true
result.backward_mode = mode.inaccessible
local is_forward = true
local destination = get_destination(way, is_forward)
result.destinations = canonicalizeStringList(destination, ",")
else
local junction = way:get_value_by_key("junction")
if data.highway == "motorway" or
junction == "roundabout" or
junction == "circular" then
if oneway ~= "no" then
-- implied oneway
data.is_forward_oneway = true
result.backward_mode = mode.inaccessible
end
end
end
end
end
-- maxspeed and advisory maxspeed
function handle_maxspeed(way,result)
-- Override speed settings if explicit forward/backward maxspeeds are given
local maxspeed_forward = parse_maxspeed(way:get_value_by_key("maxspeed:forward"))
local maxspeed_backward = parse_maxspeed(way:get_value_by_key("maxspeed:backward"))
if maxspeed_forward and maxspeed_forward > 0 then
if mode.inaccessible ~= result.forward_mode and
mode.inaccessible ~= result.backward_mode then
result.backward_speed = result.forward_speed
end
result.forward_speed = maxspeed_forward
-- handle destination tags
function handle_destinations(way,result,data)
if data.is_forward_oneway or data.is_reverse_oneway then
local destination = get_destination(way, data.is_forward_oneway)
result.destinations = canonicalizeStringList(destination, ",")
end
if maxspeed_backward and maxspeed_backward > 0 then
result.backward_speed = maxspeed_backward
end
-- maxspeed and advisory maxspeed
function handle_maxspeed(way,data,result)
local keys = Sequence { 'maxspeed:advisory', 'maxspeed' }
local forward, backward = Directional.get_values_by_set(way,data,keys)
forward = parse_maxspeed(forward)
backward = parse_maxspeed(backward)
if forward and forward > 0 then
result.forward_speed = forward
end
-- Override speed settings if advisory forward/backward maxspeeds are given
local advisory_speed = parse_maxspeed(way:get_value_by_key("maxspeed:advisory"))
local advisory_forward = parse_maxspeed(way:get_value_by_key("maxspeed:advisory:forward"))
local advisory_backward = parse_maxspeed(way:get_value_by_key("maxspeed:advisory:backward"))
-- apply bi-directional advisory speed first
if advisory_speed and advisory_speed > 0 then
if mode.inaccessible ~= result.forward_mode then
result.forward_speed = advisory_speed
end
if mode.inaccessible ~= result.backward_mode then
result.backward_speed = advisory_speed
end
end
if advisory_forward and advisory_forward > 0 then
if mode.inaccessible ~= result.forward_mode and mode.inaccessible ~= result.backward_mode then
result.backward_speed = result.forward_speed
end
result.forward_speed = advisory_forward
end
if advisory_backward and advisory_backward > 0 then
result.backward_speed = advisory_backward
if backward and backward > 0 then
result.backward_speed = backward
end
end
@@ -713,6 +653,7 @@ function handle_alternating_speed(way,result)
end
end
-- determine if this way can be used as a start/end point for routing
function handle_startpoint(way,result)
-- only allow this road as start point if it not a ferry
@@ -721,8 +662,8 @@ function handle_startpoint(way,result)
end
-- set the road classification based on guidance globals configuration
function handle_classification(way,result)
set_classification(way:get_value_by_key("highway"),result,way)
function handle_classification(way,result,data)
set_classification(data.highway,result,way)
end
-- main entry point for processsing a way
@@ -754,8 +695,11 @@ function way_function(way, result)
-- access tags, e.g: motorcar, motor_vehicle, vehicle
if handle_access(way,result,data) == false then return end
-- check high occupancy vehicle restrictions
if handle_hov(way,result) == false then return end
-- check whether forward/backward directons are routable
if handle_oneway(way,result,data) == false then return end
-- check whether forward/backward directons are routable
if handle_destinations(way,result,data) == false then return end
-- check whether we're using a special transport mode
if handle_ferries(way,result) == false then return end
@@ -764,27 +708,19 @@ function way_function(way, result)
-- handle service road restrictions
if handle_service(way,result) == false then return end
-- check whether forward/backward directons are routable
if handle_oneway(way,result) == false then return end
-- check high occupancy vehicle restrictions
if handle_hov(way,result,data) == false then return end
-- compute speed taking into account way type, maxspeed tags, etc.
if handle_speed(way,result,data) == false then return end
-- handle turn lanes and road classification, used for guidance
if handle_turn_lanes(way,result) == false then return end
if handle_classification(way,result) == false then return end
if handle_turn_lanes(way,result,data) == false then return end
if handle_classification(way,result,data) == false then return end
-- handle various other flags
if handle_roundabouts(way,result) == false then return end
if handle_startpoint(way,result) == false then return end
if handle_restricted(way,result,data) == false then return end
-- handle roundabout flags
if handle_roundabouts(way,result) == false then return end
-- check if this way can be routed through, but not used as
-- origin or destination
if handle_restricted(way,result,data) == false then return end
-- set name, ref and pronunciation
if handle_names(way,result) == false then return end
+51 -3
View File
@@ -43,8 +43,10 @@ mode = {
-- input tags, normally extracted from OSM data
local way = {
highway = 'motorway',
highway = 'primary',
name = 'Main Street',
--access = 'no'
["access:forward"] = 'no'
--width = '3',
--maxspeed = '30',
--['maxspeed:advisory'] = '25',
@@ -56,13 +58,32 @@ local way = {
--route = 'ferry',
--duration = '00:01:00',
--hov = 'designated',
--access = 'no'
--hov:lanes:forward"] = 'designated',
--destination = 'Berlin',
["destination:ref"] = 'Nuremberg',
--["destination:ref"] = 'Nuremberg',
--["destination:ref:forward"] = 'Hamburg;Dresden',
}
-- tag function normally provided via C++
function way:get_value_by_key(k)
if not self['_debug'] then
self['_debug'] = {
_counts = {}
}
end
if self['_debug']['_total'] then
self['_debug']['_total'] = self['_debug']['_total'] + 1
else
self['_debug']['_total'] = 1
end
if self['_debug']['_counts'][k] then
self['_debug']['_counts'][k] = self['_debug']['_counts'][k] + 1
else
self['_debug']['_counts'][k] = 1
end
return self[k]
end
@@ -83,6 +104,27 @@ function canonicalizeStringList(str)
return str
end
-- helpers for sorting associative array
function get_keys_sorted_by_value(tbl, sortFunction)
local keys = {}
for key in pairs(tbl) do
table.insert(keys, key)
end
table.sort(keys, function(a, b)
return sortFunction(tbl[a], tbl[b])
end)
return keys
end
-- helper for printing sorted array
function print_sorted(sorted,associative)
for _, key in ipairs(sorted) do
print(associative[key], key)
end
end
-- start state of result table, normally set form C++
local result = {
road_classification = {},
@@ -100,3 +142,9 @@ way_function(way,result)
pprint(way)
print("=>")
pprint(result)
print("\n")
print("Tag fetches:")
sorted_counts = get_keys_sorted_by_value(way._debug._counts, function(a, b) return a > b end)
print_sorted(sorted_counts, way._debug._counts)
print(way._debug._total, 'total')
-2
View File
@@ -6,9 +6,7 @@ local find_access_tag = require("lib/access").find_access_tag
barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["block"] = true}
access_tag_whitelist = { ["yes"] = true, ["foot"] = true, ["permissive"] = true, ["designated"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
access_tags_hierarchy = { "foot", "access" }
service_tag_restricted = { ["parking_aisle"] = true }
ignore_in_grid = { ["ferry"] = true }
restrictions = { "foot" }
+59
View File
@@ -0,0 +1,59 @@
local Directional = {}
-- return [forward,backward] values for a specific tag.
-- e.g. for maxspeed search forward:
-- maxspeed:forward
-- maxspeed
-- and backward:
-- maxspeed:backward
-- maxspeed
function Directional.get_values_by_key(way,data,key)
local forward = way:get_value_by_key(key .. ':forward')
local backward = way:get_value_by_key(key .. ':backward')
if forward and backward then
return forward, backward
end
local common = way:get_value_by_key(key)
return forward or common,
backward or common
end
-- return [forward,backward] values, searching a
-- prioritized sequence of tags
-- e.g. for the sequence [maxspeed,advisory] search forward:
-- maxspeed:forward
-- maxspeed
-- advisory:forward
-- advisory
-- and for backward:
-- maxspeed:backward
-- maxspeed
-- advisory:backward
-- advisory
function Directional.get_values_by_set(way,data,keys)
local forward, backward
for i,key in ipairs(keys) do
if not forward then
forward = way:get_value_by_key(key .. ':forward')
end
if not backward then
backward = way:get_value_by_key(key .. ':backward')
end
if not forward or not backward then
local common = way:get_value_by_key(key)
forward = forward or common
backward = backward or common
end
if forward and backward then
break
end
end
return forward, backward
end
return Directional
+120 -128
View File
@@ -1,154 +1,146 @@
local Directional = require('lib/directional')
local Set = require('lib/set')
local Guidance = {}
-- Guidance: Default Mapping from roads to types/priorities
highway_classes = { ["motorway"] = road_priority_class.motorway,
["motorway_link"] = road_priority_class.link_road,
["trunk"] = road_priority_class.trunk,
["trunk_link"] = road_priority_class.link_road,
["primary"] = road_priority_class.primary,
["primary_link"] = road_priority_class.link_road,
["secondary"] = road_priority_class.secondary,
["secondary_link"] = road_priority_class.link_road,
["tertiary"] = road_priority_class.tertiary,
["tertiary_link"] = road_priority_class.link_road,
["unclassified"] = road_priority_class.side_residential,
["residential"] = road_priority_class.side_residential,
["service"] = road_priority_class.connectivity,
["living_street"] = road_priority_class.main_residential,
["track"] = road_priority_class.bike_path,
["path"] = road_priority_class.bike_path,
["footway"] = road_priority_class.foot_path,
["pedestrian"] = road_priority_class.foot_path,
["steps"] = road_priority_class.foot_path}
highway_classes = {
motorway = road_priority_class.motorway,
motorway_link = road_priority_class.link_road,
trunk = road_priority_class.trunk,
trunk_link = road_priority_class.link_road,
primary = road_priority_class.primary,
primary_link = road_priority_class.link_road,
secondary = road_priority_class.secondary,
secondary_link = road_priority_class.link_road,
tertiary = road_priority_class.tertiary,
tertiary_link = road_priority_class.link_road,
unclassified = road_priority_class.side_residential,
residential = road_priority_class.side_residential,
service = road_priority_class.connectivity,
living_street = road_priority_class.main_residential,
track = road_priority_class.bike_path,
path = road_priority_class.bike_path,
footway = road_priority_class.foot_path,
pedestrian = road_priority_class.foot_path,
steps = road_priority_class.foot_path
}
default_highway_class = road_priority_class.connectivity;
motorway_types = { ["motorway"] = true, ["motorway_link"] = true, ["trunk"] = true, ["trunk_link"] = true }
motorway_types = Set {
'motorway',
'motorway_link',
'trunk',
'trunk_link'
}
-- these road types are set with a car in mind. For bicycle/walk we probably need different ones
road_types = { ["motorway"] = true,
["motorway_link"] = true,
["trunk"] = true,
["trunk_link"] = true,
["primary"] = true,
["primary_link"] = true,
["secondary"] = true,
["secondary_link"] = true,
["tertiary"] = true,
["tertiary_link"] = true,
["unclassified"] = true,
["residential"] = true,
["living_street"] = true }
road_types = Set {
'motorway',
'motorway_link',
'trunk',
'trunk_link',
'primary',
'primary_link',
'secondary',
'secondary_link',
'tertiary',
'tertiary_link',
'unclassified',
'residential',
'living_street'
}
link_types = { ["motorway_link"] = true, ["trunk_link"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true }
link_types = Set {
'motorway_link',
'trunk_link',
'primary_link',
'secondary_link',
'tertiary_link'
}
function Guidance.set_classification (highway, result, input_way)
if motorway_types[highway] then
result.road_classification.motorway_class = true;
end
if link_types[highway] then
result.road_classification.link_class = true;
end
if highway_classes[highway] ~= nil then
result.road_classification.road_priority_class = highway_classes[highway]
else
result.road_classification.road_priority_class = default_highway_class
end
if road_types[highway] then
result.road_classification.may_be_ignored = false;
else
result.road_classification.may_be_ignored = true;
end
if motorway_types[highway] then
result.road_classification.motorway_class = true;
end
if link_types[highway] then
result.road_classification.link_class = true;
end
if highway_classes[highway] ~= nil then
result.road_classification.road_priority_class = highway_classes[highway]
else
result.road_classification.road_priority_class = default_highway_class
end
if road_types[highway] then
result.road_classification.may_be_ignored = false;
else
result.road_classification.may_be_ignored = true;
end
local lane_count = input_way:get_value_by_key("lanes")
if lane_count then
local lc = tonumber(lane_count)
if lc ~= nil then
result.road_classification.num_lanes = lc
end
else
local total_count = 0
local forward_count = input_way:get_value_by_key("lanes:forward")
if forward_count then
local fc = tonumber(forward_count)
if fc ~= nil then
total_count = fc
end
end
local backward_count = input_way:get_value_by_key("lanes:backward")
if backward_count then
local bc = tonumber(backward_count)
if bc ~= nil then
total_count = total_count + bc
end
end
if total_count ~= 0 then
result.road_classification.num_lanes = total_count
end
local lane_count = input_way:get_value_by_key("lanes")
if lane_count then
local lc = tonumber(lane_count)
if lc ~= nil then
result.road_classification.num_lanes = lc
end
else
local total_count = 0
local forward_count = input_way:get_value_by_key("lanes:forward")
if forward_count then
local fc = tonumber(forward_count)
if fc ~= nil then
total_count = fc
end
end
local backward_count = input_way:get_value_by_key("lanes:backward")
if backward_count then
local bc = tonumber(backward_count)
if bc ~= nil then
total_count = total_count + bc
end
end
if total_count ~= 0 then
result.road_classification.num_lanes = total_count
end
end
end
-- returns forward,backward psv lane count
local function get_psv_counts(way)
local psv = way:get_value_by_key("lanes:psv")
local psv_forward = way:get_value_by_key("lanes:psv:forward");
local psv_backward = way:get_value_by_key("lanes:psv:backward");
local fw = 0;
local bw = 0;
if psv then
fw = tonumber(psv)
if( fw == nil ) then
fw = 0
end
end
if psv_forward then
fw = tonumber(psv_forward)
if( fw == nil ) then
fw = 0
end
end
if psv_backward then
bw = tonumber(psv_backward);
if( bw == nil ) then
bw = 0
end
end
return fw, bw
local function get_psv_counts(way,data)
local psv_forward, psv_backward = Directional.get_values_by_key(way,data,'lanes:psv')
if psv_forward then
psv_forward = tonumber(psv_forward)
end
if psv_backward then
psv_backward = tonumber(psv_backward)
end
return psv_forward or 0,
psv_backward or 0
end
-- trims lane string with regard to supported lanes
local function process_lanes(turn_lane,vehicle_lane,first_count,second_count)
if turn_lane then
if vehicle_lane then
turn_lane = applyAccessTokens(turn_lane,vehicle_lane)
elseif first_count ~= 0 or second_count ~= 0 then
turn_lane = trimLaneString(turn_lane, first_count, second_count)
end
local function process_lanes(turn_lanes,vehicle_lanes,first_count,second_count)
if turn_lanes then
if vehicle_lanes then
return applyAccessTokens(turn_lanes,vehicle_lanes)
elseif first_count ~= 0 or second_count ~= 0 then
return trimLaneString(turn_lanes, first_count, second_count)
else
return turn_lanes
end
return turn_lane;
end
end
-- this is broken for left-sided driving. It needs to switch left and right in case of left-sided driving
function Guidance.get_turn_lanes(way)
local fw_psv = 0
local bw_psv = 0
fw_psv, bw_psv = get_psv_counts(way)
local turn_lanes = way:get_value_by_key("turn:lanes")
local turn_lanes_fw = way:get_value_by_key("turn:lanes:forward")
local turn_lanes_bw = way:get_value_by_key("turn:lanes:backward")
local vehicle_lanes = way:get_value_by_key("vehicle:lanes");
local vehicle_lanes_fw = way:get_value_by_key("vehicle:lanes:forward");
local vehicle_lanes_bw = way:get_value_by_key("vehicle:lanes:backward");
turn_lanes = process_lanes(turn_lanes,vehicle_lanes,bw_psv,fw_psv)
turn_lanes_fw = process_lanes(turn_lanes_fw,vehicle_lanes_fw,bw_psv,fw_psv)
--backwards turn lanes need to treat bw_psv as fw_psv and vice versa
turn_lanes_bw = process_lanes(turn_lanes_bw,vehicle_lanes_bw,fw_psv,bw_psv)
return turn_lanes, turn_lanes_fw, turn_lanes_bw
function Guidance.get_turn_lanes(way,data)
local psv_fw, psv_bw = get_psv_counts(way,data)
local turn_lanes_fw, turn_lanes_bw = Directional.get_values_by_key(way,data,'turn:lanes')
local vehicle_lanes_fw, vehicle_lanes_bw = Directional.get_values_by_key(way,data,'vehicle:lanes')
--note: backward lanes swap psv_bw and psv_fw
return process_lanes(turn_lanes_fw,vehicle_lanes_fw,psv_bw,psv_fw) or turn_lanes,
process_lanes(turn_lanes_bw,vehicle_lanes_bw,psv_fw,psv_bw) or turn_lanes
end
return Guidance
+13 -6
View File
@@ -1,11 +1,18 @@
#!/usr/bin/env bash
# here we set up the node version on the fly. currently only node 4, but can be used for more values if need be
# This is done manually so that the build works the same on OS X
rm -rf ~/.nvm/ && git clone --depth 1 --branch v0.30.1 https://github.com/creationix/nvm.git ~/.nvm
source ~/.nvm/nvm.sh
nvm install $1
nvm use $1
NODE_HOME=$HOME/node
export NODE_HOME
mkdir ${NODE_HOME}
if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
curl https://s3.amazonaws.com/mapbox/apps/install-node/v2.0.0/run | NV=4.4.2 NP=darwin-x64 OD=${NODE_HOME} sh
else
curl https://s3.amazonaws.com/mapbox/apps/install-node/v2.0.0/run | NV=4.4.2 NP=linux-x64 OD=${NODE_HOME} sh
fi
PATH="${NODE_HOME}/bin:$PATH"
export PATH
node --version
npm --version
which node
+7 -3
View File
@@ -7,12 +7,16 @@ set -o nounset
# Runs the Clang Tidy Tool in parallel on the code base.
# Requires a compilation database in the build directory.
# This works on both OSX and Linux, it's a POSIX thingy
NPROC=$(getconf _NPROCESSORS_ONLN)
find src include unit_tests -type f -name '*.hpp' -o -name '*.cpp' \
find src include unit_tests -type f -name '*.hpp' -o -name '*.cpp' -print0 \
| xargs \
-0 \
-I{} \
-P $(nproc) \
clang-tidy \
-n 1 \
./clang+llvm-3.9.0-x86_64-apple-darwin/bin/clang-tidy \
-p build \
-header-filter='.*' \
{}
+122 -79
View File
@@ -6,13 +6,13 @@
#include "extractor/edge_based_graph_factory.hpp"
#include "extractor/node_based_edge.hpp"
#include "storage/io.hpp"
#include "storage/io.hpp"
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/graph_loader.hpp"
#include "util/integer_range.hpp"
#include "util/io.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
#include "util/string_util.hpp"
@@ -105,13 +105,13 @@ EdgeWeight getNewWeight(IterType speed_iter,
if (old_weight >= (new_segment_weight * log_edge_updates_factor))
{
auto speed_file = segment_speed_filenames.at(speed_iter->speed_source.source - 1);
util::SimpleLogger().Write(logWARNING)
<< "[weight updates] Edge weight update from " << old_secs << "s to " << new_secs
<< "s New speed: " << speed_iter->speed_source.speed << " kph"
<< ". Old speed: " << approx_original_speed << " kph"
<< ". Segment length: " << segment_length << " m"
<< ". Segment: " << speed_iter->segment.from << "," << speed_iter->segment.to
<< " based on " << speed_file;
util::Log(logWARNING) << "[weight updates] Edge weight update from " << old_secs
<< "s to " << new_secs
<< "s New speed: " << speed_iter->speed_source.speed << " kph"
<< ". Old speed: " << approx_original_speed << " kph"
<< ". Segment length: " << segment_length << " m"
<< ". Segment: " << speed_iter->segment.from << ","
<< speed_iter->segment.to << " based on " << speed_file;
}
}
@@ -131,17 +131,29 @@ int Contractor::Run()
if (config.core_factor > 1.0 || config.core_factor < 0)
{
throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)");
throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)" + SOURCE_REF);
}
TIMER_START(preparing);
util::SimpleLogger().Write() << "Loading edge-expanded graph representation";
util::Log() << "Reading node weights.";
std::vector<EdgeWeight> node_weights;
std::string node_file_name = config.osrm_input_path.string() + ".enw";
{
storage::io::FileReader node_file(node_file_name,
storage::io::FileReader::VerifyFingerprint);
node_file.DeserializeVector(node_weights);
}
util::Log() << "Done reading node weights.";
util::Log() << "Loading edge-expanded graph representation";
util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;
EdgeID max_edge_id = LoadEdgeExpandedGraph(config.edge_based_graph_path,
edge_based_edge_list,
node_weights,
config.edge_segment_lookup_path,
config.edge_penalty_path,
config.segment_speed_lookup_paths,
@@ -163,17 +175,6 @@ int Contractor::Run()
ReadNodeLevels(node_levels);
}
util::SimpleLogger().Write() << "Reading node weights.";
std::vector<EdgeWeight> node_weights;
std::string node_file_name = config.osrm_input_path.string() + ".enw";
{
storage::io::FileReader node_file(node_file_name,
storage::io::FileReader::VerifyFingerprint);
node_file.DeserializeVector(node_weights);
}
util::SimpleLogger().Write() << "Done reading node weights.";
util::DeallocatingVector<QueryEdge> contracted_edge_list;
ContractGraph(max_edge_id,
edge_based_edge_list,
@@ -183,7 +184,7 @@ int Contractor::Run()
node_levels);
TIMER_STOP(contraction);
util::SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
util::Log() << "Contraction took " << TIMER_SEC(contraction) << " sec";
std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
WriteCoreNodeMarker(std::move(is_core_node));
@@ -199,11 +200,11 @@ int Contractor::Run()
const auto edges_per_second =
static_cast<std::uint64_t>(number_of_used_edges / TIMER_SEC(contraction));
util::SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
util::SimpleLogger().Write() << "Contraction: " << nodes_per_second << " nodes/sec and "
<< edges_per_second << " edges/sec";
util::Log() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
util::Log() << "Contraction: " << nodes_per_second << " nodes/sec and " << edges_per_second
<< " edges/sec";
util::SimpleLogger().Write() << "finished preprocessing";
util::Log() << "finished preprocessing";
return 0;
}
@@ -309,10 +310,13 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
std::uint64_t to_node_id{};
unsigned speed{};
std::size_t line_number = 0;
std::for_each(
segment_speed_file_reader.GetLineIteratorBegin(),
segment_speed_file_reader.GetLineIteratorEnd(),
[&](const std::string &line) {
++line_number;
using namespace boost::spirit::qi;
@@ -329,7 +333,11 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
speed); //
if (!ok || it != last)
throw util::exception{"Segment speed file " + filename + " malformed"};
{
const std::string message{"Segment speed file " + filename +
" malformed on line " + std::to_string(line_number)};
throw util::exception(message + SOURCE_REF);
}
SegmentSpeedSource val{{OSMNodeID{from_node_id}, OSMNodeID{to_node_id}},
{speed, static_cast<std::uint8_t>(file_id)}};
@@ -337,8 +345,7 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
local.push_back(std::move(val));
});
util::SimpleLogger().Write() << "Loaded speed file " << filename << " with " << local.size()
<< " speeds";
util::Log() << "Loaded speed file " << filename << " with " << local.size() << " speeds";
{
Mutex::scoped_lock _{flatten_mutex};
@@ -349,7 +356,14 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
}
};
tbb::parallel_for(std::size_t{0}, segment_speed_filenames.size(), parse_segment_speed_file);
try
{
tbb::parallel_for(std::size_t{0}, segment_speed_filenames.size(), parse_segment_speed_file);
}
catch (const tbb::captured_exception &e)
{
throw util::exception(e.what() + SOURCE_REF);
}
// With flattened map-ish view of all the files, sort and unique them on from,to,source
// The greater '>' is used here since we want to give files later on higher precedence
@@ -370,9 +384,8 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
flatten.erase(it, end(flatten));
util::SimpleLogger().Write() << "In total loaded " << segment_speed_filenames.size()
<< " speed file(s) with a total of " << flatten.size()
<< " unique values";
util::Log() << "In total loaded " << segment_speed_filenames.size()
<< " speed file(s) with a total of " << flatten.size() << " unique values";
return flatten;
}
@@ -399,10 +412,13 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
std::uint64_t to_node_id{};
double penalty{};
std::size_t line_number = 0;
std::for_each(
turn_penalty_file_reader.GetLineIteratorBegin(),
turn_penalty_file_reader.GetLineIteratorEnd(),
[&](const std::string &line) {
++line_number;
using namespace boost::spirit::qi;
@@ -420,7 +436,11 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
penalty); //
if (!ok || it != last)
throw util::exception{"Turn penalty file " + filename + " malformed"};
{
const std::string message{"Turn penalty file " + filename +
" malformed on line " + std::to_string(line_number)};
throw util::exception(message + SOURCE_REF);
}
TurnPenaltySource val{
{OSMNodeID{from_node_id}, OSMNodeID{via_node_id}, OSMNodeID{to_node_id}},
@@ -428,8 +448,8 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
local.push_back(std::move(val));
});
util::SimpleLogger().Write() << "Loaded penalty file " << filename << " with "
<< local.size() << " turn penalties";
util::Log() << "Loaded penalty file " << filename << " with " << local.size()
<< " turn penalties";
{
Mutex::scoped_lock _{flatten_mutex};
@@ -440,7 +460,14 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
}
};
tbb::parallel_for(std::size_t{0}, turn_penalty_filenames.size(), parse_turn_penalty_file);
try
{
tbb::parallel_for(std::size_t{0}, turn_penalty_filenames.size(), parse_turn_penalty_file);
}
catch (const tbb::captured_exception &e)
{
throw util::exception(e.what() + SOURCE_REF);
}
// With flattened map-ish view of all the files, sort and unique them on from,to,source
// The greater '>' is used here since we want to give files later on higher precedence
@@ -463,9 +490,8 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
map.erase(it, end(map));
util::SimpleLogger().Write() << "In total loaded " << turn_penalty_filenames.size()
<< " turn penalty file(s) with a total of " << map.size()
<< " unique values";
util::Log() << "In total loaded " << turn_penalty_filenames.size()
<< " turn penalty file(s) with a total of " << map.size() << " unique values";
return map;
}
@@ -474,6 +500,7 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_pe
EdgeID Contractor::LoadEdgeExpandedGraph(
std::string const &edge_based_graph_filename,
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
const std::string &edge_segment_lookup_filename,
const std::string &edge_penalty_filename,
const std::vector<std::string> &segment_speed_filenames,
@@ -486,19 +513,28 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
const double log_edge_updates_factor)
{
if (segment_speed_filenames.size() > 255 || turn_penalty_filenames.size() > 255)
throw util::exception("Limit of 255 segment speed and turn penalty files each reached");
throw util::exception("Limit of 255 segment speed and turn penalty files each reached" +
SOURCE_REF);
util::SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
util::Log() << "Opening " << edge_based_graph_filename;
auto mmap_file = [](const std::string &filename) {
using boost::interprocess::file_mapping;
using boost::interprocess::mapped_region;
using boost::interprocess::read_only;
const file_mapping mapping{filename.c_str(), read_only};
mapped_region region{mapping, read_only};
region.advise(mapped_region::advice_sequential);
return region;
try
{
const file_mapping mapping{filename.c_str(), read_only};
mapped_region region{mapping, read_only};
region.advise(mapped_region::advice_sequential);
return region;
}
catch (const std::exception &e)
{
util::Log(logERROR) << "Error while trying to mmap " + filename + ": " + e.what();
throw;
}
};
const auto edge_based_graph_region = mmap_file(edge_based_graph_filename);
@@ -542,8 +578,7 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
graph_header.fingerprint.TestContractor(fingerprint_valid);
edge_based_edge_list.resize(graph_header.number_of_edges);
util::SimpleLogger().Write() << "Reading " << graph_header.number_of_edges
<< " edges from the edge based graph";
util::Log() << "Reading " << graph_header.number_of_edges << " edges from the edge based graph";
SegmentSpeedSourceFlatMap segment_speed_lookup;
TurnPenaltySourceFlatMap turn_penalty_lookup;
@@ -735,15 +770,15 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
{
if (i == LUA_SOURCE)
{
util::SimpleLogger().Write() << "Used " << merged_counters[LUA_SOURCE]
<< " speeds from LUA profile or input map";
util::Log() << "Used " << merged_counters[LUA_SOURCE]
<< " speeds from LUA profile or input map";
}
else
{
// segments_speeds_counters has 0 as LUA, segment_speed_filenames not, thus we need
// to susbstract 1 to avoid off-by-one error
util::SimpleLogger().Write() << "Used " << merged_counters[i] << " speeds from "
<< segment_speed_filenames[i - 1];
util::Log() << "Used " << merged_counters[i] << " speeds from "
<< segment_speed_filenames[i - 1];
}
}
}
@@ -756,7 +791,8 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
std::ofstream geometry_stream(geometry_filename, std::ios::binary);
if (!geometry_stream)
{
throw util::exception("Failed to open " + geometry_filename + " for writing");
const std::string message{"Failed to open " + geometry_filename + " for writing"};
throw util::exception(message + SOURCE_REF);
}
const unsigned number_of_indices = m_geometry_indices.size();
const unsigned number_of_compressed_geometries = m_geometry_node_list.size();
@@ -777,7 +813,9 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
std::ofstream datasource_stream(datasource_indexes_filename, std::ios::binary);
if (!datasource_stream)
{
throw util::exception("Failed to open " + datasource_indexes_filename + " for writing");
const std::string message{"Failed to open " + datasource_indexes_filename +
" for writing"};
throw util::exception(message + SOURCE_REF);
}
std::uint64_t number_of_datasource_entries = m_geometry_datasource.size();
datasource_stream.write(reinterpret_cast<const char *>(&number_of_datasource_entries),
@@ -793,7 +831,9 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
std::ofstream datasource_stream(datasource_names_filename, std::ios::binary);
if (!datasource_stream)
{
throw util::exception("Failed to open " + datasource_names_filename + " for writing");
const std::string message{"Failed to open " + datasource_names_filename +
" for writing"};
throw util::exception(message + SOURCE_REF);
}
datasource_stream << "lua profile" << std::endl;
for (auto const &name : segment_speed_filenames)
@@ -876,6 +916,11 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
previous_osm_node_id = segmentblocks[i].this_osm_node_id;
}
// Update the node-weight cache. This is the weight of the edge-based-node only,
// it doesn't include the turn. We may visit the same node multiple times, but
// we should always assign the same value here.
node_weights[inbuffer.source] = new_weight;
// We found a zero-speed edge, so we'll skip this whole edge-based-edge which
// effectively removes it from the routing network.
if (skip_this_edge)
@@ -894,11 +939,11 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
if (new_turn_weight + new_weight < compressed_edge_nodes)
{
util::SimpleLogger().Write(logWARNING)
<< "turn penalty " << turn_iter->penalty_source.penalty << " for turn "
<< penaltyblock->from_id << ", " << penaltyblock->via_id << ", "
<< penaltyblock->to_id << " is too negative: clamping turn weight to "
<< compressed_edge_nodes;
util::Log(logWARNING) << "turn penalty " << turn_iter->penalty_source.penalty
<< " for turn " << penaltyblock->from_id << ", "
<< penaltyblock->via_id << ", " << penaltyblock->to_id
<< " is too negative: clamping turn weight to "
<< compressed_edge_nodes;
}
inbuffer.weight = std::max(new_turn_weight + new_weight, compressed_edge_nodes);
@@ -915,7 +960,7 @@ EdgeID Contractor::LoadEdgeExpandedGraph(
edge_based_edge_list.emplace_back(std::move(inbuffer));
}
util::SimpleLogger().Write() << "Done reading edges";
util::Log() << "Done reading edges";
return graph_header.max_edge_id;
}
@@ -964,8 +1009,7 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
// Sorting contracted edges in a way that the static query graph can read some in in-place.
tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
const std::uint64_t contracted_edge_count = contracted_edge_list.size();
util::SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
<< " edges";
util::Log() << "Serializing compacted graph of " << contracted_edge_count << " edges";
const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
@@ -982,15 +1026,14 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
return tmp_max;
}();
util::SimpleLogger().Write(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
util::SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1)
<< " nodes";
util::Log(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
util::Log(logDEBUG) << "contracted graph has " << (max_used_node_id + 1) << " nodes";
std::vector<util::StaticGraph<EdgeData>::NodeArrayEntry> node_array;
// make sure we have at least one sentinel
node_array.resize(max_node_id + 2);
util::SimpleLogger().Write() << "Building node array";
util::Log() << "Building node array";
util::StaticGraph<EdgeData>::EdgeIterator edge = 0;
util::StaticGraph<EdgeData>::EdgeIterator position = 0;
util::StaticGraph<EdgeData>::EdgeIterator last_edge;
@@ -1014,11 +1057,11 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
node_array[sentinel_counter].first_edge = contracted_edge_count;
}
util::SimpleLogger().Write() << "Serializing node array";
util::Log() << "Serializing node array";
RangebasedCRC32 crc32_calculator;
const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
util::SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;
util::Log() << "Writing CRC32: " << edges_crc32;
const std::uint64_t node_array_size = node_array.size();
// serialize crc32, aka checksum
@@ -1036,7 +1079,7 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
}
// serialize all edges
util::SimpleLogger().Write() << "Building edge array";
util::Log() << "Building edge array";
std::size_t number_of_used_edges = 0;
util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
@@ -1055,15 +1098,15 @@ Contractor::WriteContractedGraph(unsigned max_node_id,
#ifndef NDEBUG
if (current_edge.data.weight <= 0)
{
util::SimpleLogger().Write(logWARNING)
<< "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
<< ", target: " << contracted_edge_list[edge].target
<< ", weight: " << current_edge.data.weight;
util::Log(logWARNING) << "Edge: " << edge
<< ",source: " << contracted_edge_list[edge].source
<< ", target: " << contracted_edge_list[edge].target
<< ", weight: " << current_edge.data.weight;
util::SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
<< contracted_edge_list[edge].source << "/"
<< node_array.size() - 1;
return 1;
util::Log(logWARNING) << "Failed at adjacency list of node "
<< contracted_edge_list[edge].source << "/"
<< node_array.size() - 1;
throw util::exception("Edge weight is <= 0" + SOURCE_REF);
}
#endif
hsgr_output_stream.write((char *)&current_edge,
-1
View File
@@ -6,7 +6,6 @@
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/typedefs.hpp"
#include <boost/assert.hpp>
+5 -3
View File
@@ -7,7 +7,7 @@
#include "engine/datafacade/shared_memory_datafacade.hpp"
#include "storage/shared_barriers.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include <boost/assert.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
@@ -68,7 +68,9 @@ Engine::Engine(const EngineConfig &config)
if (!DataWatchdog::TryConnect())
{
throw util::exception(
"No shared memory blocks found, have you forgotten to run osrm-datastore?");
std::string(
"No shared memory blocks found, have you forgotten to run osrm-datastore?") +
SOURCE_REF);
}
watchdog = std::make_unique<DataWatchdog>();
@@ -78,7 +80,7 @@ Engine::Engine(const EngineConfig &config)
{
if (!config.storage_config.IsValid())
{
throw util::exception("Invalid file paths given!");
throw util::exception("Invalid file paths given!" + SOURCE_REF);
}
immutable_data_facade =
std::make_shared<datafacade::ProcessMemoryDataFacade>(config.storage_config);
+36 -8
View File
@@ -1,11 +1,10 @@
#include "util/for_each_pair.hpp"
#include "util/group_by.hpp"
#include "util/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/post_processing.hpp"
#include "engine/guidance/toolkit.hpp"
#include <algorithm>
#include <iterator>
#include <unordered_set>
#include <utility>
@@ -14,8 +13,8 @@ using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
namespace TurnType = osrm::extractor::guidance::TurnType;
namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier;
using osrm::util::guidance::isLeftTurn;
using osrm::util::guidance::isRightTurn;
using osrm::extractor::guidance::isLeftTurn;
using osrm::extractor::guidance::isRightTurn;
namespace osrm
{
@@ -29,9 +28,38 @@ std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
{
// Lane anticipation works on contiguous ranges of quick steps that have lane information
const auto is_quick_has_lanes = [&](const RouteStep &step) {
const auto is_quick = step.duration < min_duration_needed_for_lane_change;
const auto has_lanes = step.intersections.front().lanes.lanes_in_turn > 0;
return has_lanes && is_quick;
if (!has_lanes)
return false;
// The more unused lanes to the left and right of the turn there are, the higher
// the chance the user is driving on one of those and has to cross lanes.
// Scale threshold for these cases to be adaptive to the situation's complexity.
//
// Note: what we could do instead: do Lane Anticipation on all step pairs and then scale
// the threshold based on the lanes we're constraining the user to. Would need a re-write
// since at the moment we first group-by and only then do Lane Anticipation selectively.
//
// We do not have a source-target lane mapping, assume worst case for lanes to cross.
// The following two lambda functions are backported from
// https://github.com/Project-OSRM/osrm-backend/pull/3474
const auto NumLanesToTheRight = [](const RouteStep &step) -> LaneID {
return step.intersections.front().lanes.first_lane_from_the_right;
};
const auto NumLanesToTheLeft = [](const RouteStep &step) -> LaneID {
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);
};
const auto to_cross = std::max(NumLanesToTheRight(step), NumLanesToTheLeft(step));
const auto scale = 1 + to_cross;
const auto threshold = scale * min_duration_needed_for_lane_change;
const auto is_quick = step.duration < threshold;
return is_quick;
};
using StepIter = decltype(steps)::iterator;
@@ -80,8 +108,8 @@ std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
// where lanes in the turn fan in but for example the overall lanes at that location
// fan out, we would have to know the asymmetric mapping of lanes. This is currently
// not possible at the moment. In the following we implement a heuristic instead.
const LaneID current_num_lanes_right_of_turn = numLanesToTheRight(current);
const LaneID current_num_lanes_left_of_turn = numLanesToTheLeft(current);
const LaneID current_num_lanes_right_of_turn = current.numLanesToTheRight();
const LaneID current_num_lanes_left_of_turn = current.numLanesToTheLeft();
const LaneID num_shared_lanes = std::min(current_lanes.lanes_in_turn, //
previous_lanes.lanes_in_turn); //
+37 -41
View File
@@ -1,14 +1,12 @@
#include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/lane_processing.hpp"
#include "engine/guidance/toolkit.hpp"
#include "util/bearing.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/guidance/name_announcements.hpp"
#include "util/guidance/turn_lanes.hpp"
#include <boost/assert.hpp>
@@ -25,8 +23,11 @@
using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
namespace TurnType = osrm::extractor::guidance::TurnType;
namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier;
using osrm::util::guidance::angularDeviation;
using osrm::util::guidance::getTurnDirection;
using osrm::util::angularDeviation;
using osrm::extractor::guidance::getTurnDirection;
using osrm::extractor::guidance::hasRampType;
using osrm::extractor::guidance::mirrorDirectionModifier;
using osrm::extractor::guidance::bearingToDirectionModifier;
namespace osrm
{
@@ -299,14 +300,13 @@ void closeOffRoundabout(const bool on_roundabout,
TurnType::EnterRoundaboutIntersectionAtExit)
{
BOOST_ASSERT(!propagation_step.intersections.empty());
const double angle = util::bearing::angleBetweenBearings(
util::bearing::reverseBearing(
entry_intersection.bearings[entry_intersection.in]),
const double angle = util::angleBetweenBearings(
util::reverseBearing(entry_intersection.bearings[entry_intersection.in]),
exit_bearing);
auto bearings = propagation_step.intersections.front().bearings;
propagation_step.maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(angle);
getTurnDirection(angle);
}
forwardStepSignage(propagation_step, destination_copy);
@@ -346,7 +346,7 @@ bool isUTurn(const RouteStep &in_step, const RouteStep &out_step, const RouteSte
(isLinkroad(in_step) && out_step.name_id != EMPTY_NAMEID &&
pre_in_step.name_id != EMPTY_NAMEID && !isNoticeableNameChange(pre_in_step, out_step));
const bool takes_u_turn = bearingsAreReversed(
util::bearing::reverseBearing(
util::reverseBearing(
in_step.intersections.front().bearings[in_step.intersections.front().in]),
out_step.intersections.front().bearings[out_step.intersections.front().out]);
@@ -358,20 +358,20 @@ double findTotalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_ste
const auto exit_intersection = exit_step.intersections.front();
const auto exit_step_exit_bearing = exit_intersection.bearings[exit_intersection.out];
const auto exit_step_entry_bearing =
util::bearing::reverseBearing(exit_intersection.bearings[exit_intersection.in]);
util::reverseBearing(exit_intersection.bearings[exit_intersection.in]);
const auto entry_intersection = entry_step.intersections.front();
const auto entry_step_entry_bearing =
util::bearing::reverseBearing(entry_intersection.bearings[entry_intersection.in]);
util::reverseBearing(entry_intersection.bearings[entry_intersection.in]);
const auto entry_step_exit_bearing = entry_intersection.bearings[entry_intersection.out];
const auto exit_angle =
util::bearing::angleBetweenBearings(exit_step_entry_bearing, exit_step_exit_bearing);
util::angleBetweenBearings(exit_step_entry_bearing, exit_step_exit_bearing);
const auto entry_angle =
util::bearing::angleBetweenBearings(entry_step_entry_bearing, entry_step_exit_bearing);
util::angleBetweenBearings(entry_step_entry_bearing, entry_step_exit_bearing);
const double total_angle =
util::bearing::angleBetweenBearings(entry_step_entry_bearing, exit_step_exit_bearing);
util::angleBetweenBearings(entry_step_entry_bearing, exit_step_exit_bearing);
// We allow for minor deviations from a straight line
if (((entry_step.distance < MAX_COLLAPSE_DISTANCE && exit_step.intersections.size() == 1) ||
(entry_angle <= 185 && exit_angle <= 185) || (entry_angle >= 175 && exit_angle >= 175)) &&
@@ -521,8 +521,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
// tagged late
const auto is_delayed_turn_onto_a_ramp =
opening_turn.distance <= 4 * MAX_COLLAPSE_DISTANCE && without_choice &&
util::guidance::hasRampType(finishing_turn.maneuver.instruction);
return !util::guidance::hasRampType(opening_turn.maneuver.instruction) &&
hasRampType(finishing_turn.maneuver.instruction);
return !hasRampType(opening_turn.maneuver.instruction) &&
(is_short_and_collapsable || is_not_too_long_and_choiceless ||
isLinkroad(opening_turn) || is_delayed_turn_onto_a_ramp);
}
@@ -539,8 +539,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
if (TurnType::Merge == current_step.maneuver.instruction.type)
{
steps[step_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier(
steps[step_index].maneuver.instruction.direction_modifier);
mirrorDirectionModifier(steps[step_index].maneuver.instruction.direction_modifier);
steps[step_index].maneuver.instruction.type = TurnType::Turn;
}
else
@@ -573,18 +572,18 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
if (continue_or_suppressed || turning_name)
{
const auto in_bearing = [](const RouteStep &step) {
return util::bearing::reverseBearing(
return util::reverseBearing(
step.intersections.front().bearings[step.intersections.front().in]);
};
const auto out_bearing = [](const RouteStep &step) {
return step.intersections.front().bearings[step.intersections.front().out];
};
const auto first_angle = util::bearing::angleBetweenBearings(
in_bearing(one_back_step), out_bearing(one_back_step));
const auto second_angle = util::bearing::angleBetweenBearings(
in_bearing(current_step), out_bearing(current_step));
const auto bearing_turn_angle = util::bearing::angleBetweenBearings(
const auto first_angle = util::angleBetweenBearings(in_bearing(one_back_step),
out_bearing(one_back_step));
const auto second_angle =
util::angleBetweenBearings(in_bearing(current_step), out_bearing(current_step));
const auto bearing_turn_angle = util::angleBetweenBearings(
in_bearing(one_back_step), out_bearing(current_step));
// When looking at an intersection, some angles, even though present, feel more like
@@ -669,7 +668,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
DirectionModifier::Straight;
else
steps[step_index].maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(bearing_turn_angle);
getTurnDirection(bearing_turn_angle);
// if the total direction of this turn is now straight, we can keep it suppressed/as
// a new name. Else we have to interpret it as a turn.
@@ -718,7 +717,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
};
// If we Merge onto the same street, we end up with a u-turn in some cases
if (bearingsAreReversed(util::bearing::reverseBearing(getBearing(true, one_back_step)),
if (bearingsAreReversed(util::reverseBearing(getBearing(true, one_back_step)),
getBearing(false, current_step)))
{
steps[one_back_index].maneuver.instruction.direction_modifier =
@@ -737,9 +736,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
// need a highway-suppressed to get the turn onto a
// highway...
{
steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier(
steps[one_back_index].maneuver.instruction.direction_modifier);
steps[one_back_index].maneuver.instruction.direction_modifier = mirrorDirectionModifier(
steps[one_back_index].maneuver.instruction.direction_modifier);
}
// on non merge-types, we check for a combined turn angle
else if (TurnType::Merge != one_back_step.maneuver.instruction.type)
@@ -759,8 +757,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
{
steps[one_back_index] = elongate(std::move(steps[one_back_index]), current_step);
const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(angle);
steps[one_back_index].maneuver.instruction.direction_modifier = getTurnDirection(angle);
invalidateStep(steps[step_index]);
}
@@ -772,8 +769,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
steps[one_back_index] = elongate(std::move(steps[one_back_index]), current_step);
steps[one_back_index].maneuver.instruction.type = TurnType::OnRamp;
const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(angle);
steps[one_back_index].maneuver.instruction.direction_modifier = getTurnDirection(angle);
forwardStepSignage(steps[one_back_index], current_step);
invalidateStep(steps[step_index]);
@@ -806,7 +802,7 @@ bool isStaggeredIntersection(const std::vector<RouteStep> &steps,
const auto &intersection = step.intersections.front();
const auto entry_bearing = intersection.bearings[intersection.in];
const auto exit_bearing = intersection.bearings[intersection.out];
return util::bearing::angleBetweenBearings(entry_bearing, exit_bearing);
return util::angleBetweenBearings(entry_bearing, exit_bearing);
};
// Instead of using turn modifiers (e.g. as in isRightTurn) we want to be more strict here.
@@ -1123,7 +1119,7 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(angle);
getTurnDirection(angle);
invalidateStep(steps[step_index]);
}
else
@@ -1462,7 +1458,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
geometry.locations[next_to_last_step.geometry_end - 2],
geometry.locations[last_step.geometry_begin]));
last_step.maneuver.bearing_before = bearing;
last_step.intersections.front().bearings.front() = util::bearing::reverseBearing(bearing);
last_step.intersections.front().bearings.front() = util::reverseBearing(bearing);
}
BOOST_ASSERT(steps.back().geometry_end == geometry.locations.size());
@@ -1494,7 +1490,7 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
const auto initial_modifier =
distance_to_start >= MINIMAL_RELATIVE_DISTANCE &&
distance_to_start <= MAXIMAL_RELATIVE_DISTANCE
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
? bearingToDirectionModifier(util::coordinate_calculation::computeAngle(
source_node.input_location, leg_geometry.locations[0], leg_geometry.locations[1]))
: extractor::guidance::DirectionModifier::UTurn;
@@ -1505,7 +1501,7 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
const auto final_modifier =
distance_from_end >= MINIMAL_RELATIVE_DISTANCE &&
distance_from_end <= MAXIMAL_RELATIVE_DISTANCE
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
? bearingToDirectionModifier(util::coordinate_calculation::computeAngle(
leg_geometry.locations[leg_geometry.locations.size() - 2],
leg_geometry.locations[leg_geometry.locations.size() - 1],
target_node.input_location))
@@ -1604,13 +1600,13 @@ std::vector<RouteStep> collapseUseLane(std::vector<RouteStep> steps)
// the lane description is given left to right, lanes are counted from the right.
// Therefore we access the lane description using the reverse iterator
auto right_most_lanes = lanesToTheRight(step);
auto right_most_lanes = step.lanesToTheRight();
if (!right_most_lanes.empty() && containsTag(right_most_lanes.front(),
(extractor::guidance::TurnLaneType::straight |
extractor::guidance::TurnLaneType::none)))
return false;
auto left_most_lanes = lanesToTheLeft(step);
auto left_most_lanes = step.lanesToTheLeft();
if (!left_most_lanes.empty() && containsTag(left_most_lanes.back(),
(extractor::guidance::TurnLaneType::straight |
extractor::guidance::TurnLaneType::none)))
+10 -11
View File
@@ -19,14 +19,6 @@
#include <string>
#include <vector>
static double search_radius_for_gps_radius(double gps_radius)
{
// For a given GPS radius, determine the radius we need to search for candidate street segments
// to have a 99.9% chance of finding the correct segment.
// For more detail, see the analysis at https://github.com/Project-OSRM/osrm-backend/pull/3184
return std::min(gps_radius * 3.5 + 45, 200.0);
}
namespace osrm
{
namespace engine
@@ -160,9 +152,16 @@ Status MatchPlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFaca
std::transform(parameters.radiuses.begin(),
parameters.radiuses.end(),
search_radiuses.begin(),
[&](const boost::optional<double> &maybe_radius) {
double gps_radius = maybe_radius ? *maybe_radius : DEFAULT_GPS_PRECISION;
return search_radius_for_gps_radius(gps_radius);
[](const boost::optional<double> &maybe_radius) {
if (maybe_radius)
{
return *maybe_radius * RADIUS_MULTIPLIER;
}
else
{
return DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER;
}
});
}
+42 -8
View File
@@ -357,6 +357,26 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
return offset;
};
// In order to ensure consistent tile encoding, we need to process
// all edges in the same order. Differences in OSX/Linux/Windows
// sorting methods mean that GetEdgesInBox doesn't return the same
// ordered array on all platforms.
// GetEdgesInBox is marked `const`, so we can't sort the array itself,
// instead we create an array of indexes and sort that instead.
std::vector<std::size_t> sorted_edge_indexes(edges.size(), 0);
std::iota(sorted_edge_indexes.begin(), sorted_edge_indexes.end(), 0); // fill with 1,2,3,...N
// Now, sort that array based on the edges list, using the u/v node IDs
// as the sort condition
std::sort(sorted_edge_indexes.begin(),
sorted_edge_indexes.end(),
[&edges](const std::size_t &left, const std::size_t &right) -> bool {
return (edges[left].u != edges[right].u) ? edges[left].u < edges[right].u
: edges[left].v < edges[right].v;
});
// From here on, we'll iterate over the sorted_edge_indexes instead of `edges` directly.
// Note, that we do this because `
// If we're zooming into 16 or higher, include turn data. Why? Because turns make the map
// really cramped, so we don't bother including the data for tiles that span a large area.
if (parameters.z >= MIN_ZOOM_FOR_TURNS)
@@ -386,8 +406,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
// Build an adjacency list for all the road segments visible in
// the tile
for (const auto &edge : edges)
for (const auto &edge_index : sorted_edge_indexes)
{
const auto &edge = edges[edge_index];
if (edge.forward_segment_id.enabled)
{
// operator[] will construct an empty vector at [edge.u] if there is no value.
@@ -435,11 +456,21 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
// vw is the "exit"
std::vector<contractor::QueryEdge::EdgeData> unpacked_shortcut;
std::vector<EdgeWeight> approach_weight_vector;
// Look at every node in the directed graph we created
// Make sure we traverse the startnodes in a consistent order
// to ensure identical PBF encoding on all platforms.
std::vector<NodeID> sorted_startnodes;
sorted_startnodes.reserve(directed_graph.size());
for (const auto &startnode : directed_graph)
sorted_startnodes.push_back(startnode.first);
std::sort(sorted_startnodes.begin(), sorted_startnodes.end());
// Look at every node in the directed graph we created
for (const auto &startnode : sorted_startnodes)
{
const auto &nodedata = directed_graph[startnode];
// For all the outgoing edges from the node
for (const auto &approachedge : startnode.second)
for (const auto &approachedge : nodedata)
{
// If the target of this edge doesn't exist in our directed
// graph, it's probably outside the tile, so we can skip it
@@ -455,7 +486,7 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
continue;
// Skip u-turns
if (startnode.first == exit_edge.target_node)
if (startnode == exit_edge.target_node)
continue;
// Find the connection between our source road and the target node
@@ -528,7 +559,7 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
const auto turn_cost = data.weight - sum_node_weight;
// Find the three nodes that make up the turn movement)
const auto node_from = startnode.first;
const auto node_from = startnode;
const auto node_via = approachedge.target_node;
const auto node_to = exit_edge.target_node;
@@ -584,8 +615,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
// to "pre-loop" over all the edges to create the lookup tables. Once we have those, we
// can then encode the features, and we'll know the indexes that feature properties
// need to refer to.
for (const auto &edge : edges)
for (const auto &edge_index : sorted_edge_indexes)
{
const auto &edge = edges[edge_index];
const auto forward_datasource_vector =
facade->GetUncompressedForwardDatasources(edge.packed_geometry_id);
@@ -636,8 +668,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
// Because we need to know the indexes into the vector tile lookup table,
// we need to do an initial pass over the data and create the complete
// index of used values.
for (const auto &edge : edges)
for (const auto &edge_index : sorted_edge_indexes)
{
const auto &edge = edges[edge_index];
const auto forward_weight_vector =
facade->GetUncompressedForwardWeights(edge.packed_geometry_id);
const auto reverse_weight_vector =
@@ -653,8 +686,9 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
{
// Each feature gets a unique id, starting at 1
unsigned id = 1;
for (const auto &edge : edges)
for (const auto &edge_index : sorted_edge_indexes)
{
const auto &edge = edges[edge_index];
// Get coordinates for start/end nodes of segment (NodeIDs u and v)
const auto a = facade->GetCoordinateOfNode(edge.u);
const auto b = facade->GetCoordinateOfNode(edge.v);
+39 -30
View File
@@ -2,6 +2,7 @@
#include <algorithm>
#include <boost/assert.hpp>
#include <climits>
#include <cmath>
#include <cstddef>
#include <cstdlib>
@@ -55,42 +56,50 @@ std::string encode(std::vector<int> &numbers)
std::vector<util::Coordinate> decodePolyline(const std::string &geometry_string)
{
std::vector<util::Coordinate> new_coordinates;
int index = 0, len = geometry_string.size();
int lat = 0, lng = 0;
// https://developers.google.com/maps/documentation/utilities/polylinealgorithm
auto decode_polyline_integer = [](auto &first, auto last) {
// varint coding parameters
const std::uint32_t bits_in_chunk = 5;
const std::uint32_t continuation_bit = 1 << bits_in_chunk;
const std::uint32_t chunk_mask = (1 << bits_in_chunk) - 1;
while (index < len)
std::uint32_t result = 0;
for (std::uint32_t value = continuation_bit, shift = 0;
(value & continuation_bit) && (shift < CHAR_BIT * sizeof(result) - 1) && first != last;
++first, shift += bits_in_chunk)
{
value = *first - 63; // convert ASCII coding [?..~] to an integer [0..63]
result |= (value & chunk_mask) << shift;
}
// change "zig-zag" sign coding to two's complement
result = ((result & 1) == 1) ? ~(result >> 1) : (result >> 1);
return static_cast<std::int32_t>(result);
};
auto polyline_to_coordinate = [](auto value) {
return static_cast<std::int32_t>(value * detail::POLYLINE_TO_COORDINATE);
};
std::vector<util::Coordinate> coordinates;
std::int32_t latitude = 0, longitude = 0;
std::string::const_iterator first = geometry_string.begin();
const std::string::const_iterator last = geometry_string.end();
while (first != last)
{
int b, shift = 0, result = 0;
do
{
b = geometry_string.at(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20 && index < len);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
const auto dlat = decode_polyline_integer(first, last);
const auto dlon = decode_polyline_integer(first, last);
shift = 0;
result = 0;
do
{
b = geometry_string.at(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20 && index < len);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
latitude += dlat;
longitude += dlon;
util::Coordinate p;
p.lat =
util::FixedLatitude{static_cast<std::int32_t>(lat * detail::POLYLINE_TO_COORDINATE)};
p.lon =
util::FixedLongitude{static_cast<std::int32_t>(lng * detail::POLYLINE_TO_COORDINATE)};
new_coordinates.push_back(p);
coordinates.emplace_back(
util::Coordinate{util::FixedLongitude{polyline_to_coordinate(longitude)},
util::FixedLatitude{polyline_to_coordinate(latitude)}});
}
return new_coordinates;
return coordinates;
}
}
}
+8 -9
View File
@@ -1,5 +1,5 @@
#include "extractor/compressed_edge_container.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -300,14 +300,13 @@ void CompressedEdgeContainer::PrintStatistics() const
longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
}
util::SimpleLogger().Write()
<< "Geometry successfully removed:"
"\n compressed edges: "
<< compressed_edges << "\n compressed geometries: " << compressed_geometries
<< "\n longest chain length: " << longest_chain_length << "\n cmpr ratio: "
<< ((float)compressed_edges / std::max(compressed_geometries, (uint64_t)1))
<< "\n avg chain length: "
<< (float)compressed_geometries / std::max((uint64_t)1, compressed_edges);
util::Log() << "Geometry successfully removed:"
"\n compressed edges: "
<< compressed_edges << "\n compressed geometries: " << compressed_geometries
<< "\n longest chain length: " << longest_chain_length << "\n cmpr ratio: "
<< ((float)compressed_edges / std::max(compressed_geometries, (uint64_t)1))
<< "\n avg chain length: "
<< (float)compressed_geometries / std::max((uint64_t)1, compressed_edges);
}
const CompressedEdgeContainer::OnewayEdgeBucket &
+292 -279
View File
@@ -6,11 +6,10 @@
#include "util/exception.hpp"
#include "util/guidance/turn_bearing.hpp"
#include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/percent.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_analysis.hpp"
#include "extractor/guidance/turn_lane_handler.hpp"
#include "extractor/scripting_environment.hpp"
@@ -213,10 +212,10 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
TIMER_STOP(generate_edges);
util::SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
util::SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
util::SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
util::SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
util::Log() << "Timing statistics for edge-expanded graph:";
util::Log() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
util::Log() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
util::Log() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
}
/// Renumbers all _forward_ edges and sets the edge_id.
@@ -258,40 +257,44 @@ unsigned EdgeBasedGraphFactory::RenumberEdges()
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
{
util::Percent progress(m_node_based_graph->GetNumberOfNodes());
m_compressed_edge_container.InitializeBothwayVector();
// loop over all edges and generate new set of nodes
for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
util::Log() << "Generating edge expanded nodes ... ";
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
progress.PrintStatus(node_u);
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
util::UnbufferedLog log;
util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
m_compressed_edge_container.InitializeBothwayVector();
// loop over all edges and generate new set of nodes
for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
const NodeID node_v = m_node_based_graph->GetTarget(e1);
BOOST_ASSERT(SPECIAL_NODEID != node_v);
// pick only every other edge, since we have every edge as an outgoing
// and incoming egde
if (node_u > node_v)
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
progress.PrintStatus(node_u);
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
{
continue;
}
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
const NodeID node_v = m_node_based_graph->GetTarget(e1);
BOOST_ASSERT(node_u < node_v);
BOOST_ASSERT(SPECIAL_NODEID != node_v);
// pick only every other edge, since we have every edge as an outgoing
// and incoming egde
if (node_u > node_v)
{
continue;
}
// if we found a non-forward edge reverse and try again
if (edge_data.edge_id == SPECIAL_NODEID)
{
InsertEdgeBasedNode(node_v, node_u);
}
else
{
InsertEdgeBasedNode(node_u, node_v);
BOOST_ASSERT(node_u < node_v);
// if we found a non-forward edge reverse and try again
if (edge_data.edge_id == SPECIAL_NODEID)
{
InsertEdgeBasedNode(node_v, node_u);
}
else
{
InsertEdgeBasedNode(node_u, node_v);
}
}
}
}
@@ -299,8 +302,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size());
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
<< " nodes in edge-expanded graph";
util::Log() << "Generated " << m_edge_based_node_list.size() << " nodes in edge-expanded graph";
}
/// Actually it also generates OriginalEdgeData and serializes them...
@@ -312,7 +314,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const std::string &edge_fixed_penalties_filename,
const bool generate_edge_lookup)
{
util::SimpleLogger().Write() << "generating edge-expanded edges";
util::Log() << "Generating edge-expanded edges ";
std::size_t node_based_edge_counter = 0;
std::size_t original_edges_counter = 0;
@@ -341,7 +343,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// Loop over all turns and generate new set of edges.
// Three nested loop look super-linear, but we are dealing with a (kind of)
// linear number of turns only.
util::Percent progress(m_node_based_graph->GetNumberOfNodes());
SuffixTable street_name_suffix_table(scripting_environment);
guidance::TurnAnalysis turn_analysis(*m_node_based_graph,
m_node_info_list,
@@ -352,7 +353,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
street_name_suffix_table,
profile_properties);
guidance::LaneDataIdMap lane_data_map;
util::guidance::LaneDataIdMap lane_data_map;
guidance::lanes::TurnLaneHandler turn_lane_handler(*m_node_based_graph,
turn_lane_offsets,
turn_lane_masks,
@@ -363,260 +364,275 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(),
std::numeric_limits<std::uint32_t>::max());
// going over all nodes (which form the center of an intersection), we compute all
// possible turns along these intersections.
for (const auto node_at_center_of_intersection :
util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
progress.PrintStatus(node_at_center_of_intersection);
util::UnbufferedLog log;
const auto shape_result =
turn_analysis.ComputeIntersectionShapes(node_at_center_of_intersection);
// all nodes in the graph are connected in both directions. We check all outgoing nodes to
// find the incoming edge. This is a larger search overhead, but the cost we need to pay to
// generate edges here is worth the additional search overhead.
//
// a -> b <-> c
// |
// v
// d
//
// will have:
// a: b,rev=0
// b: a,rev=1 c,rev=0 d,rev=0
// c: b,rev=0
//
// From the flags alone, we cannot determine which nodes are connected to `b` by an outgoing
// edge. Therefore, we have to search all connected edges for edges entering `b`
for (const EdgeID outgoing_edge :
m_node_based_graph->GetAdjacentEdgeRange(node_at_center_of_intersection))
util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
// going over all nodes (which form the center of an intersection), we compute all
// possible turns along these intersections.
for (const auto node_at_center_of_intersection :
util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
const NodeID node_along_road_entering = m_node_based_graph->GetTarget(outgoing_edge);
progress.PrintStatus(node_at_center_of_intersection);
const auto incoming_edge = m_node_based_graph->FindEdge(node_along_road_entering,
node_at_center_of_intersection);
const auto shape_result =
turn_analysis.ComputeIntersectionShapes(node_at_center_of_intersection);
if (m_node_based_graph->GetEdgeData(incoming_edge).reversed)
continue;
++node_based_edge_counter;
auto intersection_with_flags_and_angles =
turn_analysis.GetIntersectionGenerator().TransformIntersectionShapeIntoView(
node_along_road_entering,
incoming_edge,
shape_result.normalised_intersection_shape,
shape_result.intersection_shape,
shape_result.merging_map);
auto intersection = turn_analysis.AssignTurnTypes(
node_along_road_entering, incoming_edge, intersection_with_flags_and_angles);
BOOST_ASSERT(intersection.valid());
intersection = turn_lane_handler.assignTurnLanes(
node_along_road_entering, incoming_edge, std::move(intersection));
// the entry class depends on the turn, so we have to classify the interesction for
// every edge
const auto turn_classification = classifyIntersection(intersection);
const auto entry_class_id = [&](const util::guidance::EntryClass entry_class) {
if (0 == entry_class_hash.count(entry_class))
{
const auto id = static_cast<std::uint16_t>(entry_class_hash.size());
entry_class_hash[entry_class] = id;
return id;
}
else
{
return entry_class_hash.find(entry_class)->second;
}
}(turn_classification.first);
const auto bearing_class_id = [&](const util::guidance::BearingClass bearing_class) {
if (0 == bearing_class_hash.count(bearing_class))
{
const auto id = static_cast<std::uint32_t>(bearing_class_hash.size());
bearing_class_hash[bearing_class] = id;
return id;
}
else
{
return bearing_class_hash.find(bearing_class)->second;
}
}(turn_classification.second);
bearing_class_by_node_based_node[node_at_center_of_intersection] = bearing_class_id;
for (const auto &turn : intersection)
// all nodes in the graph are connected in both directions. We check all outgoing nodes
// to
// find the incoming edge. This is a larger search overhead, but the cost we need to pay
// to
// generate edges here is worth the additional search overhead.
//
// a -> b <-> c
// |
// v
// d
//
// will have:
// a: b,rev=0
// b: a,rev=1 c,rev=0 d,rev=0
// c: b,rev=0
//
// From the flags alone, we cannot determine which nodes are connected to `b` by an
// outgoing
// edge. Therefore, we have to search all connected edges for edges entering `b`
for (const EdgeID outgoing_edge :
m_node_based_graph->GetAdjacentEdgeRange(node_at_center_of_intersection))
{
// only keep valid turns
if (!turn.entry_allowed)
const NodeID node_along_road_entering =
m_node_based_graph->GetTarget(outgoing_edge);
const auto incoming_edge = m_node_based_graph->FindEdge(
node_along_road_entering, node_at_center_of_intersection);
if (m_node_based_graph->GetEdgeData(incoming_edge).reversed)
continue;
// only add an edge if turn is not prohibited
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(incoming_edge);
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
++node_based_edge_counter;
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
BOOST_ASSERT(!edge_data1.reversed);
BOOST_ASSERT(!edge_data2.reversed);
auto intersection_with_flags_and_angles =
turn_analysis.GetIntersectionGenerator().TransformIntersectionShapeIntoView(
node_along_road_entering,
incoming_edge,
shape_result.normalised_intersection_shape,
shape_result.intersection_shape,
shape_result.merging_map);
// the following is the core of the loop.
unsigned distance = edge_data1.distance;
if (m_traffic_lights.find(node_at_center_of_intersection) != m_traffic_lights.end())
{
distance += profile_properties.traffic_signal_penalty;
}
auto intersection = turn_analysis.AssignTurnTypes(
node_along_road_entering, incoming_edge, intersection_with_flags_and_angles);
const int32_t turn_penalty =
scripting_environment.GetTurnPenalty(180. - turn.angle);
BOOST_ASSERT(intersection.valid());
const auto turn_instruction = turn.instruction;
if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
{
distance += profile_properties.u_turn_penalty;
}
intersection = turn_lane_handler.assignTurnLanes(
node_along_road_entering, incoming_edge, std::move(intersection));
// don't add turn penalty if it is not an actual turn. This heuristic is necessary
// since OSRM cannot handle looping roads/parallel roads
if (turn_instruction.type != guidance::TurnType::NoTurn)
distance += turn_penalty;
// the entry class depends on the turn, so we have to classify the interesction for
// every edge
const auto turn_classification = classifyIntersection(intersection);
const bool is_encoded_forwards =
m_compressed_edge_container.HasZippedEntryForForwardID(incoming_edge);
const bool is_encoded_backwards =
m_compressed_edge_container.HasZippedEntryForReverseID(incoming_edge);
BOOST_ASSERT(is_encoded_forwards || is_encoded_backwards);
if (is_encoded_forwards)
{
original_edge_data_vector.emplace_back(
GeometryID{m_compressed_edge_container.GetZippedPositionForForwardID(
incoming_edge),
true},
edge_data1.name_id,
turn.lane_data_id,
turn_instruction,
entry_class_id,
edge_data1.travel_mode,
util::guidance::TurnBearing(intersection[0].bearing),
util::guidance::TurnBearing(turn.bearing));
}
else if (is_encoded_backwards)
{
original_edge_data_vector.emplace_back(
GeometryID{m_compressed_edge_container.GetZippedPositionForReverseID(
incoming_edge),
false},
edge_data1.name_id,
turn.lane_data_id,
turn_instruction,
entry_class_id,
edge_data1.travel_mode,
util::guidance::TurnBearing(intersection[0].bearing),
util::guidance::TurnBearing(turn.bearing));
}
++original_edges_counter;
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
{
FlushVectorToStream(edge_data_file, original_edge_data_vector);
}
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
// NOTE: potential overflow here if we hit 2^32 routable edges
BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
m_edge_based_edge_list.emplace_back(edge_data1.edge_id,
edge_data2.edge_id,
m_edge_based_edge_list.size(),
distance,
true,
false);
BOOST_ASSERT(original_edges_counter == m_edge_based_edge_list.size());
// Here is where we write out the mapping between the edge-expanded edges, and
// the node-based edges that are originally used to calculate the `distance`
// for the edge-expanded edges. About 40 lines back, there is:
//
// unsigned distance = edge_data1.distance;
//
// This tells us that the weight for an edge-expanded-edge is based on the weight
// of the *source* node-based edge. Therefore, we will look up the individual
// segments of the source node-based edge, and write out a mapping between
// those and the edge-based-edge ID.
// External programs can then use this mapping to quickly perform
// updates to the edge-expanded-edge based directly on its ID.
if (generate_edge_lookup)
{
const auto node_based_edges =
m_compressed_edge_container.GetBucketReference(incoming_edge);
NodeID previous = node_along_road_entering;
const unsigned node_count = node_based_edges.size() + 1;
const QueryNode &first_node = m_node_info_list[previous];
lookup::SegmentHeaderBlock header = {node_count, first_node.node_id};
edge_segment_file.write(reinterpret_cast<const char *>(&header),
sizeof(header));
for (auto target_node : node_based_edges)
const auto entry_class_id = [&](const util::guidance::EntryClass entry_class) {
if (0 == entry_class_hash.count(entry_class))
{
const QueryNode &from = m_node_info_list[previous];
const QueryNode &to = m_node_info_list[target_node.node_id];
const double segment_length =
util::coordinate_calculation::greatCircleDistance(from, to);
const auto id = static_cast<std::uint16_t>(entry_class_hash.size());
entry_class_hash[entry_class] = id;
return id;
}
else
{
return entry_class_hash.find(entry_class)->second;
}
}(turn_classification.first);
lookup::SegmentBlock nodeblock = {
to.node_id, segment_length, target_node.weight};
const auto bearing_class_id =
[&](const util::guidance::BearingClass bearing_class) {
if (0 == bearing_class_hash.count(bearing_class))
{
const auto id = static_cast<std::uint32_t>(bearing_class_hash.size());
bearing_class_hash[bearing_class] = id;
return id;
}
else
{
return bearing_class_hash.find(bearing_class)->second;
}
}(turn_classification.second);
bearing_class_by_node_based_node[node_at_center_of_intersection] = bearing_class_id;
edge_segment_file.write(reinterpret_cast<const char *>(&nodeblock),
sizeof(nodeblock));
previous = target_node.node_id;
for (const auto &turn : intersection)
{
// only keep valid turns
if (!turn.entry_allowed)
continue;
// only add an edge if turn is not prohibited
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(incoming_edge);
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
BOOST_ASSERT(!edge_data1.reversed);
BOOST_ASSERT(!edge_data2.reversed);
// the following is the core of the loop.
unsigned distance = edge_data1.distance;
if (m_traffic_lights.find(node_at_center_of_intersection) !=
m_traffic_lights.end())
{
distance += profile_properties.traffic_signal_penalty;
}
// We also now write out the mapping between the edge-expanded edges and the
// original nodes. Since each edge represents a possible maneuver, external
// programs can use this to quickly perform updates to edge weights in order
// to penalize certain turns.
const int32_t turn_penalty =
scripting_environment.GetTurnPenalty(180. - turn.angle);
// If this edge is 'trivial' -- where the compressed edge corresponds
// exactly to an original OSM segment -- we can pull the turn's preceding
// node ID directly with `node_along_road_entering`; otherwise, we need to look
// up the node
// immediately preceding the turn from the compressed edge container.
const bool isTrivial = m_compressed_edge_container.IsTrivial(incoming_edge);
const auto turn_instruction = turn.instruction;
if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
{
distance += profile_properties.u_turn_penalty;
}
const auto &from_node =
isTrivial
? m_node_info_list[node_along_road_entering]
: m_node_info_list[m_compressed_edge_container.GetLastEdgeSourceID(
incoming_edge)];
const auto &via_node =
m_node_info_list[m_compressed_edge_container.GetLastEdgeTargetID(
incoming_edge)];
const auto &to_node =
m_node_info_list[m_compressed_edge_container.GetFirstEdgeTargetID(
turn.eid)];
// don't add turn penalty if it is not an actual turn. This heuristic is
// necessary
// since OSRM cannot handle looping roads/parallel roads
if (turn_instruction.type != guidance::TurnType::NoTurn)
distance += turn_penalty;
const unsigned fixed_penalty = distance - edge_data1.distance;
lookup::PenaltyBlock penaltyblock = {
fixed_penalty, from_node.node_id, via_node.node_id, to_node.node_id};
edge_penalty_file.write(reinterpret_cast<const char *>(&penaltyblock),
sizeof(penaltyblock));
const bool is_encoded_forwards =
m_compressed_edge_container.HasZippedEntryForForwardID(incoming_edge);
const bool is_encoded_backwards =
m_compressed_edge_container.HasZippedEntryForReverseID(incoming_edge);
BOOST_ASSERT(is_encoded_forwards || is_encoded_backwards);
if (is_encoded_forwards)
{
original_edge_data_vector.emplace_back(
GeometryID{m_compressed_edge_container.GetZippedPositionForForwardID(
incoming_edge),
true},
edge_data1.name_id,
turn.lane_data_id,
turn_instruction,
entry_class_id,
edge_data1.travel_mode,
util::guidance::TurnBearing(intersection[0].bearing),
util::guidance::TurnBearing(turn.bearing));
}
else if (is_encoded_backwards)
{
original_edge_data_vector.emplace_back(
GeometryID{m_compressed_edge_container.GetZippedPositionForReverseID(
incoming_edge),
false},
edge_data1.name_id,
turn.lane_data_id,
turn_instruction,
entry_class_id,
edge_data1.travel_mode,
util::guidance::TurnBearing(intersection[0].bearing),
util::guidance::TurnBearing(turn.bearing));
}
++original_edges_counter;
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
{
FlushVectorToStream(edge_data_file, original_edge_data_vector);
}
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
// NOTE: potential overflow here if we hit 2^32 routable edges
BOOST_ASSERT(m_edge_based_edge_list.size() <=
std::numeric_limits<NodeID>::max());
m_edge_based_edge_list.emplace_back(edge_data1.edge_id,
edge_data2.edge_id,
m_edge_based_edge_list.size(),
distance,
true,
false);
BOOST_ASSERT(original_edges_counter == m_edge_based_edge_list.size());
// Here is where we write out the mapping between the edge-expanded edges, and
// the node-based edges that are originally used to calculate the `distance`
// for the edge-expanded edges. About 40 lines back, there is:
//
// unsigned distance = edge_data1.distance;
//
// This tells us that the weight for an edge-expanded-edge is based on the
// weight
// of the *source* node-based edge. Therefore, we will look up the individual
// segments of the source node-based edge, and write out a mapping between
// those and the edge-based-edge ID.
// External programs can then use this mapping to quickly perform
// updates to the edge-expanded-edge based directly on its ID.
if (generate_edge_lookup)
{
const auto node_based_edges =
m_compressed_edge_container.GetBucketReference(incoming_edge);
NodeID previous = node_along_road_entering;
const unsigned node_count = node_based_edges.size() + 1;
const QueryNode &first_node = m_node_info_list[previous];
lookup::SegmentHeaderBlock header = {node_count, first_node.node_id};
edge_segment_file.write(reinterpret_cast<const char *>(&header),
sizeof(header));
for (auto target_node : node_based_edges)
{
const QueryNode &from = m_node_info_list[previous];
const QueryNode &to = m_node_info_list[target_node.node_id];
const double segment_length =
util::coordinate_calculation::greatCircleDistance(from, to);
lookup::SegmentBlock nodeblock = {
to.node_id, segment_length, target_node.weight};
edge_segment_file.write(reinterpret_cast<const char *>(&nodeblock),
sizeof(nodeblock));
previous = target_node.node_id;
}
// We also now write out the mapping between the edge-expanded edges and the
// original nodes. Since each edge represents a possible maneuver, external
// programs can use this to quickly perform updates to edge weights in order
// to penalize certain turns.
// If this edge is 'trivial' -- where the compressed edge corresponds
// exactly to an original OSM segment -- we can pull the turn's preceding
// node ID directly with `node_along_road_entering`; otherwise, we need to
// look
// up the node
// immediately preceding the turn from the compressed edge container.
const bool isTrivial = m_compressed_edge_container.IsTrivial(incoming_edge);
const auto &from_node =
isTrivial
? m_node_info_list[node_along_road_entering]
: m_node_info_list[m_compressed_edge_container.GetLastEdgeSourceID(
incoming_edge)];
const auto &via_node =
m_node_info_list[m_compressed_edge_container.GetLastEdgeTargetID(
incoming_edge)];
const auto &to_node =
m_node_info_list[m_compressed_edge_container.GetFirstEdgeTargetID(
turn.eid)];
const unsigned fixed_penalty = distance - edge_data1.distance;
lookup::PenaltyBlock penaltyblock = {
fixed_penalty, from_node.node_id, via_node.node_id, to_node.node_id};
edge_penalty_file.write(reinterpret_cast<const char *>(&penaltyblock),
sizeof(penaltyblock));
}
}
}
}
}
util::SimpleLogger().Write() << "Created " << entry_class_hash.size() << " entry classes and "
<< bearing_class_hash.size() << " Bearing Classes";
util::Log() << "Created " << entry_class_hash.size() << " entry classes and "
<< bearing_class_hash.size() << " Bearing Classes";
util::SimpleLogger().Write() << "Writing Turn Lane Data to File...";
util::Log() << "Writing Turn Lane Data to File...";
std::ofstream turn_lane_data_file(turn_lane_data_filename.c_str(), std::ios::binary);
std::vector<util::guidance::LaneTupleIdPair> lane_data(lane_data_map.size());
// extract lane data sorted by ID
@@ -630,7 +646,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
turn_lane_data_file.write(reinterpret_cast<const char *>(&lane_data[0]),
sizeof(util::guidance::LaneTupleIdPair) * lane_data.size());
util::SimpleLogger().Write() << "done.";
util::Log() << "done.";
FlushVectorToStream(edge_data_file, original_edge_data_vector);
@@ -642,18 +658,15 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
edge_data_file.write(reinterpret_cast<const char *>(&length_prefix), sizeof(length_prefix));
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
<< " edge based nodes";
util::SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter
<< " edges";
util::SimpleLogger().Write() << "Edge-expanded graph ...";
util::SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
util::SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
"defined by "
<< m_restriction_map->size() << " restrictions";
util::SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
util::SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter
<< " turns over barriers";
util::Log() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
util::Log() << "Node-based graph contains " << node_based_edge_counter << " edges";
util::Log() << "Edge-expanded graph ...";
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
util::Log() << " skips " << restricted_turns_counter << " turns, "
"defined by "
<< m_restriction_map->size() << " restrictions";
util::Log() << " skips " << skipped_uturns_counter << " U turns";
util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
}
std::vector<util::guidance::BearingClass> EdgeBasedGraphFactory::GetBearingClasses() const
File diff suppressed because it is too large Load Diff
+53 -61
View File
@@ -10,12 +10,13 @@
#include "extractor/raster_source.hpp"
#include "storage/io.hpp"
#include "storage/io.hpp"
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/graph_loader.hpp"
#include "util/io.hpp"
#include "util/log.hpp"
#include "util/name_table.hpp"
#include "util/range_table.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp"
#include "extractor/compressed_edge_container.hpp"
@@ -43,7 +44,6 @@
#include <atomic>
#include <bitset>
#include <chrono>
#include <chrono>
#include <fstream>
#include <iostream>
#include <iterator>
@@ -119,12 +119,12 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
tbb::task_scheduler_init init(number_of_threads);
{
util::SimpleLogger().Write() << "Input file: " << config.input_path.filename().string();
util::Log() << "Input file: " << config.input_path.filename().string();
if (!config.profile_path.empty())
{
util::SimpleLogger().Write() << "Profile: " << config.profile_path.filename().string();
util::Log() << "Profile: " << config.profile_path.filename().string();
}
util::SimpleLogger().Write() << "Threads: " << number_of_threads;
util::Log() << "Threads: " << number_of_threads;
ExtractionContainers extraction_containers;
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(extraction_containers);
@@ -137,7 +137,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
unsigned number_of_ways = 0;
unsigned number_of_relations = 0;
util::SimpleLogger().Write() << "Parsing in progress..";
util::Log() << "Parsing in progress..";
TIMER_START(parsing);
// setup raster sources
@@ -148,7 +148,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
{
generator = "unknown tool";
}
util::SimpleLogger().Write() << "input file generated by " << generator;
util::Log() << "input file generated by " << generator;
// write .timestamp data file
std::string timestamp = header.get("osmosis_replication_timestamp");
@@ -156,7 +156,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
{
timestamp = "n/a";
}
util::SimpleLogger().Write() << "timestamp: " << timestamp;
util::Log() << "timestamp: " << timestamp;
boost::filesystem::ofstream timestamp_out(config.timestamp_file_name);
timestamp_out.write(timestamp.c_str(), timestamp.length());
@@ -210,12 +210,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
}
}
TIMER_STOP(parsing);
util::SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing)
<< " seconds";
util::Log() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
util::SimpleLogger().Write() << "Raw input contains " << number_of_nodes << " nodes, "
<< number_of_ways << " ways, and " << number_of_relations
<< " relations";
util::Log() << "Raw input contains " << number_of_nodes << " nodes, " << number_of_ways
<< " ways, and " << number_of_relations << " relations";
// take control over the turn lane map
turn_lane_map = extractor_callbacks->moveOutLaneDescriptionMap();
@@ -224,8 +222,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
if (extraction_containers.all_edges_list.empty())
{
util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
return 1;
throw util::exception(std::string("There are no edges remaining after parsing.") +
SOURCE_REF);
}
extraction_containers.PrepareData(scripting_environment,
@@ -237,15 +235,14 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
scripting_environment.GetProfileProperties());
TIMER_STOP(extracting);
util::SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting)
<< "s";
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
}
{
// Transform the node-based graph that OSM is based on into an edge-based graph
// that is better for routing. Every edge becomes a node, and every valid
// movement (e.g. turn from A->B, and B->A) becomes an edge
util::SimpleLogger().Write() << "Generating edge-expanded graph representation";
util::Log() << "Generating edge-expanded graph representation";
TIMER_START(expansion);
@@ -267,17 +264,16 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
TIMER_STOP(expansion);
util::SimpleLogger().Write() << "Saving edge-based node weights to file.";
util::Log() << "Saving edge-based node weights to file.";
TIMER_START(timer_write_node_weights);
util::serializeVector(config.edge_based_node_weights_output_path, edge_based_node_weights);
TIMER_STOP(timer_write_node_weights);
util::SimpleLogger().Write() << "Done writing. (" << TIMER_SEC(timer_write_node_weights)
<< ")";
util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")";
util::SimpleLogger().Write() << "Computing strictly connected components ...";
util::Log() << "Computing strictly connected components ...";
FindComponents(max_edge_id, edge_based_edge_list, edge_based_node_list);
util::SimpleLogger().Write() << "Building r-tree ...";
util::Log() << "Building r-tree ...";
TIMER_START(rtree);
BuildRTree(std::move(edge_based_node_list),
std::move(node_is_startpoint),
@@ -285,7 +281,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
TIMER_STOP(rtree);
util::SimpleLogger().Write() << "Writing node map ...";
util::Log() << "Writing node map ...";
WriteNodeMapping(internal_to_external_node_map);
WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list);
@@ -295,10 +291,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
const auto edges_per_second =
static_cast<std::uint64_t>((max_edge_id + 1) / TIMER_SEC(expansion));
util::SimpleLogger().Write() << "Expansion: " << nodes_per_second << " nodes/sec and "
<< edges_per_second << " edges/sec";
util::SimpleLogger().Write() << "To prepare the data for routing, run: "
<< "./osrm-contract " << config.output_file_name << std::endl;
util::Log() << "Expansion: " << nodes_per_second << " nodes/sec and " << edges_per_second
<< " edges/sec";
util::Log() << "To prepare the data for routing, run: "
<< "./osrm-contract " << config.output_file_name;
}
return 0;
@@ -310,7 +306,7 @@ void Extractor::WriteProfileProperties(const std::string &output_path,
boost::filesystem::ofstream out_stream(output_path);
if (!out_stream)
{
throw util::exception("Could not open " + output_path + " for writing.");
throw util::exception("Could not open " + output_path + " for writing." + SOURCE_REF);
}
out_stream.write(reinterpret_cast<const char *>(&properties), sizeof(properties));
@@ -406,7 +402,7 @@ std::shared_ptr<RestrictionMap> Extractor::LoadRestrictionMap()
util::loadRestrictionsFromFile(file_reader, restriction_list);
util::SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
util::Log() << " - " << restriction_list.size() << " restrictions.";
return std::make_shared<RestrictionMap>(restriction_list);
}
@@ -428,16 +424,16 @@ Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barriers,
NodeID number_of_node_based_nodes = util::loadNodesFromFile(
file_reader, barriers_iter, traffic_signals_iter, internal_to_external_node_map);
util::SimpleLogger().Write() << " - " << barriers.size() << " bollard nodes, "
<< traffic_signals.size() << " traffic lights";
util::Log() << " - " << barriers.size() << " bollard nodes, " << traffic_signals.size()
<< " traffic lights";
std::vector<NodeBasedEdge> edge_list;
util::loadEdgesFromFile(file_reader, edge_list);
if (edge_list.empty())
{
util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
return std::shared_ptr<util::NodeBasedDynamicGraph>();
throw util::exception("Node-based-graph (" + config.output_file_name +
") contains no edges." + SOURCE_REF);
}
return util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
@@ -541,9 +537,9 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
std::vector<bool> node_is_startpoint,
const std::vector<QueryNode> &internal_to_external_node_map)
{
util::SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size()
<< " edge elements build on-top of "
<< internal_to_external_node_map.size() << " coordinates";
util::Log() << "constructing r-tree of " << node_based_edge_list.size()
<< " edge elements build on-top of " << internal_to_external_node_map.size()
<< " coordinates";
BOOST_ASSERT(node_is_startpoint.size() == node_based_edge_list.size());
@@ -564,7 +560,8 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
if (new_size == 0)
{
throw util::exception("There are no snappable edges left after processing. Are you "
"setting travel modes correctly in the profile? Cannot continue.");
"setting travel modes correctly in the profile? Cannot continue." +
SOURCE_REF);
}
node_based_edge_list.resize(new_size);
@@ -575,8 +572,7 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
internal_to_external_node_map);
TIMER_STOP(construction);
util::SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
<< " seconds";
util::Log() << "finished r-tree construction in " << TIMER_SEC(construction) << " seconds";
}
void Extractor::WriteEdgeBasedGraph(
@@ -590,8 +586,7 @@ void Extractor::WriteEdgeBasedGraph(
const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
util::SimpleLogger().Write() << "[extractor] Writing edge-based-graph edges ... "
<< std::flush;
util::Log() << "Writing edge-based-graph edges ... " << std::flush;
TIMER_START(write_edges);
std::uint64_t number_of_used_edges = edge_based_edge_list.size();
@@ -604,9 +599,9 @@ void Extractor::WriteEdgeBasedGraph(
}
TIMER_STOP(write_edges);
util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s";
util::SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
util::Log() << "Processed " << number_of_used_edges << " edges";
}
void Extractor::WriteIntersectionClassificationData(
@@ -618,12 +613,11 @@ void Extractor::WriteIntersectionClassificationData(
std::ofstream file_out_stream(output_file_name.c_str(), std::ios::binary);
if (!file_out_stream)
{
util::SimpleLogger().Write(logWARNING) << "Failed to open " << output_file_name
<< " for writing";
util::Log(logERROR) << "Failed to open " << output_file_name << " for writing";
return;
}
util::SimpleLogger().Write() << "Writing Intersection Classification Data";
util::Log() << "Writing Intersection Classification Data";
TIMER_START(write_edges);
util::writeFingerprint(file_out_stream);
util::serializeVector(file_out_stream, node_based_intersection_classes);
@@ -652,16 +646,15 @@ void Extractor::WriteIntersectionClassificationData(
if (!static_cast<bool>(file_out_stream))
{
throw util::exception("Failed to write to " + output_file_name + ".");
throw util::exception("Failed to write to " + output_file_name + "." + SOURCE_REF);
}
util::serializeVector(file_out_stream, entry_classes);
TIMER_STOP(write_edges);
util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s for "
<< node_based_intersection_classes.size() << " Indices into "
<< bearing_classes.size() << " bearing classes and "
<< entry_classes.size() << " entry classes and " << total_bearings
<< " bearing values." << std::endl;
util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s for "
<< node_based_intersection_classes.size() << " Indices into "
<< bearing_classes.size() << " bearing classes and " << entry_classes.size()
<< " entry classes and " << total_bearings << " bearing values.";
}
void Extractor::WriteTurnLaneData(const std::string &turn_lane_file) const
@@ -671,27 +664,26 @@ void Extractor::WriteTurnLaneData(const std::string &turn_lane_file) const
std::vector<guidance::TurnLaneType::Mask> turn_lane_masks;
std::tie(turn_lane_offsets, turn_lane_masks) = transformTurnLaneMapIntoArrays(turn_lane_map);
util::SimpleLogger().Write() << "Writing turn lane masks...";
util::Log() << "Writing turn lane masks...";
TIMER_START(turn_lane_timer);
std::ofstream ofs(turn_lane_file, std::ios::binary);
if (!ofs)
throw osrm::util::exception("Failed to open " + turn_lane_file + " for writing.");
throw osrm::util::exception("Failed to open " + turn_lane_file + " for writing." +
SOURCE_REF);
if (!util::serializeVector(ofs, turn_lane_offsets))
{
util::SimpleLogger().Write(logWARNING) << "Error while writing.";
return;
throw util::exception("Error while writing to " + turn_lane_file + SOURCE_REF);
}
if (!util::serializeVector(ofs, turn_lane_masks))
{
util::SimpleLogger().Write(logWARNING) << "Error while writing.";
return;
throw util::exception("Error while writing to " + turn_lane_file + SOURCE_REF);
}
TIMER_STOP(turn_lane_timer);
util::SimpleLogger().Write() << "done (" << TIMER_SEC(turn_lane_timer) << ")";
util::Log() << "done (" << TIMER_SEC(turn_lane_timer) << ")";
}
} // namespace extractor
+6 -11
View File
@@ -8,7 +8,7 @@
#include "util/for_each_pair.hpp"
#include "util/guidance/turn_lanes.hpp"
#include "util/simple_logger.hpp"
#include "util/log.hpp"
#include <boost/numeric/conversion/cast.hpp>
#include <boost/optional/optional.hpp>
@@ -62,7 +62,7 @@ void ExtractorCallbacks::ProcessRestriction(
if (restriction)
{
external_memory.restrictions_list.push_back(restriction.get());
// util::SimpleLogger().Write() << "from: " << restriction.get().restriction.from.node <<
// util::Log() << "from: " << restriction.get().restriction.from.node <<
// ",via: " << restriction.get().restriction.via.node <<
// ", to: " << restriction.get().restriction.to.node <<
// ", only: " << (restriction.get().restriction.flags.is_only ?
@@ -96,8 +96,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id())
{
util::SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id()
<< " of size " << input_way.nodes().size();
util::Log(logDEBUG) << "found bogus way with id: " << input_way.id() << " of size "
<< input_way.nodes().size();
return;
}
@@ -135,8 +135,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID &&
backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
{
util::SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: "
<< input_way.id();
util::Log(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
return;
}
@@ -196,8 +195,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (translated_mask == TurnLaneType::empty)
{
// if we have unsupported tags, don't handle them
util::SimpleLogger().Write(logDEBUG) << "Unsupported lane tag found: \""
<< *token_itr << "\"";
util::Log(logDEBUG) << "Unsupported lane tag found: \"" << *token_itr << "\"";
return {};
}
@@ -328,7 +326,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
false,
parsed_way.roundabout,
parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint,
parsed_way.backward_travel_mode,
false,
@@ -361,7 +358,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
!forward_only,
parsed_way.roundabout,
parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint,
parsed_way.forward_travel_mode,
split_edge,
@@ -384,7 +380,6 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
true,
parsed_way.roundabout,
parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint,
parsed_way.backward_travel_mode,
true,

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