Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 72441b271a | |||
| 614ee0a010 | |||
| 4b1a2cea6d | |||
| 31d6bfbf12 | |||
| 607fbce1ef | |||
| 06330a694e | |||
| cbecdf8a4f | |||
| dc26f7d8b9 | |||
| 791f6d02e1 | |||
| 7b7871d5aa | |||
| f7613d77d5 | |||
| c80edef46c | |||
| cfae4a1923 | |||
| fd9d5af7e0 | |||
| c81942c167 | |||
| c5c4a1b4fe | |||
| eb13041784 | |||
| fa1f121b02 | |||
| c26642de6e | |||
| ef1fc8a757 | |||
| 168e313f73 | |||
| 30f910e861 | |||
| e998c1193d | |||
| a8f3474996 | |||
| 55cc06fd8b | |||
| 8883d8cc56 | |||
| 5b2af6ef09 | |||
| 6d801e7086 | |||
| 17eb7052ba | |||
| 330f25eddb | |||
| 08b88bad63 | |||
| 153f9b02a5 | |||
| 0568dca4a3 | |||
| 60ef179d18 | |||
| c64904f5ea | |||
| 4b9e3a8068 | |||
| db7c76d04d | |||
| cc1a5ea78d | |||
| 9c033ff461 | |||
| 3c3322173c | |||
| e805f85407 | |||
| 4d54456f66 | |||
| 7359d0542f | |||
| da4fb13aa3 | |||
| 3649ab4d31 | |||
| 9e9e3fb1e4 | |||
| e73aa01725 | |||
| a5353c7179 | |||
| a5e0d7011b | |||
| 742c32d936 | |||
| 3dec680058 | |||
| 9237430be2 | |||
| 12d1d84b11 | |||
| 6dd029e6ea | |||
| e45d44cb8e | |||
| 84b6ef4340 | |||
| 5af776d963 | |||
| ddf11cc2cc | |||
| c7b1d0c131 | |||
| 423a4ef326 | |||
| ccfbce5300 | |||
| b99d3a0a69 | |||
| 659b470320 | |||
| 9a8ed30e95 | |||
| 4166b1ebbf | |||
| 89080fb2b0 | |||
| 56459d37d1 | |||
| d5232d5f5c | |||
| 3f7b5da683 | |||
| 24562acd30 | |||
| 8bce061691 | |||
| 701c5f853d | |||
| d1e4ba373a | |||
| 8cf8f0d7d6 | |||
| 978350c388 | |||
| 2e97c78181 | |||
| 979ec7fa78 | |||
| 1d7f179374 | |||
| 994fae0ef6 | |||
| 88ee51ba2e | |||
| 25ee26de3b | |||
| 353829a4cc | |||
| 6fd0b56e32 | |||
| c1efefae27 | |||
| 0c96f093ff | |||
| 6f835d57b4 | |||
| e1e53d274b | |||
| d9a03f8365 | |||
| ce5f284ec6 | |||
| 02a2d25a3f |
@@ -4,6 +4,7 @@ What issue is this PR targeting? If there is no issue that addresses the problem
|
|||||||
|
|
||||||
## Tasklist
|
## Tasklist
|
||||||
- [ ] ADD OWN TASKS HERE
|
- [ ] ADD OWN TASKS HERE
|
||||||
|
- [ ] CHANGELOG.md entry ([How to write a changelog entry](http://keepachangelog.com/en/1.0.0/#how))
|
||||||
- [ ] update relevant [Wiki pages](https://github.com/Project-OSRM/osrm-backend/wiki)
|
- [ ] update relevant [Wiki pages](https://github.com/Project-OSRM/osrm-backend/wiki)
|
||||||
- [ ] add regression / cucumber cases (see docs/testing.md)
|
- [ ] add regression / cucumber cases (see docs/testing.md)
|
||||||
- [ ] review
|
- [ ] review
|
||||||
|
|||||||
+2
-2
@@ -12,7 +12,7 @@ notifications:
|
|||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- 5.15
|
||||||
# enable building tags
|
# enable building tags
|
||||||
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||||
|
|
||||||
@@ -422,7 +422,7 @@ install:
|
|||||||
script:
|
script:
|
||||||
- if [[ $TARGET_ARCH == armhf ]] ; then echo "Skip tests for $TARGET_ARCH" && exit 0 ; fi
|
- if [[ $TARGET_ARCH == armhf ]] ; then echo "Skip tests for $TARGET_ARCH" && exit 0 ; fi
|
||||||
- make -C test/data benchmark
|
- make -C test/data benchmark
|
||||||
- ./example/build/osrm-example test/data/ch/monaco.osrm
|
- ./example/build/osrm-example test/data/mld/monaco.osrm
|
||||||
# All tests assume to be run from the build directory
|
# All tests assume to be run from the build directory
|
||||||
- pushd ${OSRM_BUILD_DIR}
|
- pushd ${OSRM_BUILD_DIR}
|
||||||
- ./unit_tests/library-tests
|
- ./unit_tests/library-tests
|
||||||
|
|||||||
+61
-1
@@ -1,4 +1,64 @@
|
|||||||
# UNRELEASED
|
# 5.15.3
|
||||||
|
- Changes from 5.15.2:
|
||||||
|
- Bugfixes: fix deduplication of route steps when waypoints are used [#4909](https://github.com/Project-OSRM/osrm-backend/issues/4909)
|
||||||
|
|
||||||
|
# 5.15.2
|
||||||
|
- Changes from 5.15.1:
|
||||||
|
- Features:
|
||||||
|
- Exposed the waypoints parameter in the node bindings interface
|
||||||
|
- Bugfixes:
|
||||||
|
- Segfault causing bug in leg collapsing map matching when traversing edges in reverse
|
||||||
|
|
||||||
|
# 5.15.1
|
||||||
|
- Changes from 5.15.0:
|
||||||
|
- Bugfixes:
|
||||||
|
- FIXED: Segfault in map matching when RouteLeg collapsing code is run on a match with multiple submatches
|
||||||
|
- Guidance:
|
||||||
|
- Set type of trivial intersections where classes change to Suppressed instead of NoTurn
|
||||||
|
|
||||||
|
# 5.15.0
|
||||||
|
- Changes from 5.14.3:
|
||||||
|
- Bugfixes:
|
||||||
|
- FIXED #4704: Fixed regression in bearings reordering introduced in 5.13 [#4704](https://github.com/Project-OSRM/osrm-backend/issues/4704)
|
||||||
|
- FIXED #4781: Fixed overflow exceptions in percent-encoding parsing
|
||||||
|
- FIXED #4770: Fixed exclude flags for single toll road scenario
|
||||||
|
- FIXED #4283: Fix overflow on zero duration segments
|
||||||
|
- FIXED #4804: Ignore no_*_on_red turn restrictions
|
||||||
|
- Guidance:
|
||||||
|
- CHANGED #4706: Guidance refactoring step to decouple intersection connectivity analysis and turn instructions generation [#4706](https://github.com/Project-OSRM/osrm-backend/pull/4706)
|
||||||
|
- CHANGED #3491: Refactor `isThroughStreet`/Intersection options
|
||||||
|
- Profile:
|
||||||
|
- ADDED: `tunnel` as a new class in car profile so that sections of the route with tunnel tags will be marked as such
|
||||||
|
|
||||||
|
# 5.14.3
|
||||||
|
- Changes from 5.14.2:
|
||||||
|
- Features:
|
||||||
|
- Added a `waypoints` parameter to the match service plugin that accepts indices to input coordinates and treats only those points as waypoints in the response format.
|
||||||
|
- Bugfixes:
|
||||||
|
- FIXED #4754: U-Turn penalties are applied to straight turns.
|
||||||
|
- FIXED #4756: Removed too restrictive road name check in the sliproad handler
|
||||||
|
- FIXED #4731: Use correct weights for edge-based graph duplicated via nodes.
|
||||||
|
- Profile:
|
||||||
|
- CHANGED: added Belarus speed limits
|
||||||
|
- CHANGED: set default urban speed in Ukraine to 50kmh
|
||||||
|
|
||||||
|
# 5.14.2
|
||||||
|
- Changes from 5.14.1:
|
||||||
|
- Bugfixes:
|
||||||
|
- FIXED #4727: Erroring when a old .core file is present.
|
||||||
|
- FIXED #4642: Update checks for EMPTY_NAMEID to check for empty name strings
|
||||||
|
- FIXED #4738: Fix potential segmentation fault
|
||||||
|
- Node.js Bindings:
|
||||||
|
- ADDED: Exposed new `max_radiuses_map_matching` option from `EngingConfig` options
|
||||||
|
- Tools:
|
||||||
|
- ADDED: New osrm-routed `max_radiuses_map_matching` command line flag to optionally set a maximum radius for map matching
|
||||||
|
|
||||||
|
# 5.14.1
|
||||||
|
- Changes from 5.14.0
|
||||||
|
- Bugfixes:
|
||||||
|
- FIXED: don't use removed alternative candidates in `filterPackedPathsByCellSharing`
|
||||||
|
|
||||||
|
# 5.14.0
|
||||||
- Changes from 5.13
|
- Changes from 5.13
|
||||||
- API:
|
- API:
|
||||||
- ADDED: new RouteStep property `driving_side` that has either "left" or "right" for that step
|
- ADDED: new RouteStep property `driving_side` that has either "left" or "right" for that step
|
||||||
|
|||||||
+2
-2
@@ -61,8 +61,8 @@ if (POLICY CMP0048)
|
|||||||
endif()
|
endif()
|
||||||
project(OSRM C CXX)
|
project(OSRM C CXX)
|
||||||
set(OSRM_VERSION_MAJOR 5)
|
set(OSRM_VERSION_MAJOR 5)
|
||||||
set(OSRM_VERSION_MINOR 14)
|
set(OSRM_VERSION_MINOR 15)
|
||||||
set(OSRM_VERSION_PATCH 0)
|
set(OSRM_VERSION_PATCH 3)
|
||||||
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
||||||
|
|
||||||
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Everyone
|
# Everyone
|
||||||
|
|
||||||
Please take some time to review our [code of conduct](CODE_OF_CONDUCT.md) to help guide your interactions with others on this project.
|
Please take some time to review our [code of conduct](CODE-OF-CONDUCT.md) to help guide your interactions with others on this project.
|
||||||
|
|
||||||
# User
|
# User
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ sudo cmake --build . --target install
|
|||||||
|
|
||||||
### Request Against the Demo Server
|
### Request Against the Demo Server
|
||||||
|
|
||||||
Read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Api-usage-policy).
|
Read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Demo-server).
|
||||||
|
|
||||||
Simple query with instructions and alternatives on Berlin:
|
Simple query with instructions and alternatives on Berlin:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
+251
-15
@@ -36,7 +36,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -399,7 +401,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -506,7 +510,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -589,7 +595,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1277,7 +1285,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1308,7 +1318,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1339,7 +1351,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1370,7 +1384,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1529,7 +1545,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1560,7 +1578,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1591,7 +1611,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1622,7 +1644,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1653,7 +1677,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1684,7 +1710,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1715,7 +1743,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Feature",
|
"type": "Feature",
|
||||||
"properties": { "driving_side" : "left" },
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
@@ -1743,6 +1773,212 @@
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Polygon",
|
||||||
|
"coordinates": [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
113.53256464004518,
|
||||||
|
22.17096258989228
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53754281997682,
|
||||||
|
22.16047023983672
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.54106187820436,
|
||||||
|
22.154587822430837
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.54878664016725,
|
||||||
|
22.14703570986906
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.54990243911743,
|
||||||
|
22.141947742446394
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.54792833328247,
|
||||||
|
22.118731558535227
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.54852914810182,
|
||||||
|
22.11006426296891
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.56088876724245,
|
||||||
|
22.105531611874294
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.5914444923401,
|
||||||
|
22.117300298747207
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.60217332839966,
|
||||||
|
22.136303063467075
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.58766794204713,
|
||||||
|
22.183520585503548
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.57015848159791,
|
||||||
|
22.189083895743767
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.56621026992799,
|
||||||
|
22.189163370008256
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.56406450271608,
|
||||||
|
22.190514425625366
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.56380701065065,
|
||||||
|
22.19941517306984
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.56191873550418,
|
||||||
|
22.2050573189853
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.56088876724245,
|
||||||
|
22.21260631441281
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.55256319046022,
|
||||||
|
22.217294433458783
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.54850769042969,
|
||||||
|
22.21683754739093
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.5441303253174,
|
||||||
|
22.217056058304685
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.54318618774415,
|
||||||
|
22.216479983343337
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.5415554046631,
|
||||||
|
22.213242000752253
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.54114770889284,
|
||||||
|
22.213003618712484
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53824019432068,
|
||||||
|
22.213659168347313
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53728532791139,
|
||||||
|
22.21367903343993
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53571891784668,
|
||||||
|
22.213559842841935
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53435635566713,
|
||||||
|
22.213182405280275
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53312253952026,
|
||||||
|
22.212367931293002
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53496789932252,
|
||||||
|
22.20616982803302
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53222131729127,
|
||||||
|
22.19401121511328
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.52681398391725,
|
||||||
|
22.184792218694355
|
||||||
|
],
|
||||||
|
[
|
||||||
|
113.53256464004518,
|
||||||
|
22.17096258989228
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"driving_side": "left"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Polygon",
|
||||||
|
"coordinates": [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
114.1398811340332,
|
||||||
|
22.298308554808454
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.1146469116211,
|
||||||
|
22.295926164040363
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.10280227661133,
|
||||||
|
22.2808367460213
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.1505241394043,
|
||||||
|
22.226342457476385
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.20768737792969,
|
||||||
|
22.188199741518677
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.26794052124023,
|
||||||
|
22.199325771045544
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.26673889160155,
|
||||||
|
22.257008033931445
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.24699783325194,
|
||||||
|
22.278295210101668
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.22657012939453,
|
||||||
|
22.29354373265189
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.20408248901367,
|
||||||
|
22.29973796977008
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.184513092041,
|
||||||
|
22.290843594643704
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.16563034057617,
|
||||||
|
22.28925525380013
|
||||||
|
],
|
||||||
|
[
|
||||||
|
114.1398811340332,
|
||||||
|
22.298308554808454
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -288,6 +288,7 @@ In addition to the [general options](#general-options) the following options are
|
|||||||
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
|
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
|
||||||
|gaps |`split` (default), `ignore` |Allows the input track splitting based on huge timestamp gaps between points. |
|
|gaps |`split` (default), `ignore` |Allows the input track splitting based on huge timestamp gaps between points. |
|
||||||
|tidy |`true`, `false` (default) |Allows the input track modification to obtain better matching quality for noisy tracks. |
|
|tidy |`true`, `false` (default) |Allows the input track modification to obtain better matching quality for noisy tracks. |
|
||||||
|
|waypoints | `{index};{index};{index}...` |Treats input coordinates indicated by given indices as waypoints in returned Match object. Default is to treat all input coordinates as waypoints. |
|
||||||
|
|
||||||
|Parameter |Values |
|
|Parameter |Values |
|
||||||
|------------|-----------------------------------|
|
|------------|-----------------------------------|
|
||||||
@@ -586,7 +587,7 @@ step.
|
|||||||
|
|
||||||
- `name`: The name of the way along which travel proceeds.
|
- `name`: The name of the way along which travel proceeds.
|
||||||
- `ref`: A reference number or code for the way. Optionally included, if ref data is available for the given way.
|
- `ref`: A reference number or code for the way. Optionally included, if ref data is available for the given way.
|
||||||
- `pronunciation`: The pronunciation hint of the way name. Will be `undefined` if there is no pronunciation hit.
|
- `pronunciation`: A string containing an [IPA](https://en.wikipedia.org/wiki/International_Phonetic_Alphabet) phonetic transcription indicating how to pronounce the name in the `name` property. This property is omitted if pronunciation data is unavailable for the step.
|
||||||
- `destinations`: The destinations of the way. Will be `undefined` if there are no destinations.
|
- `destinations`: The destinations of the way. Will be `undefined` if there are no destinations.
|
||||||
- `exits`: The exit numbers or names of the way. Will be `undefined` if there are no exit numbers or names.
|
- `exits`: The exit numbers or names of the way. Will be `undefined` if there are no exit numbers or names.
|
||||||
- `mode`: A string signifying the mode of transportation.
|
- `mode`: A string signifying the mode of transportation.
|
||||||
|
|||||||
+50
-48
@@ -6,7 +6,7 @@ OSRM supports "profiles". Profiles representing routing behavior for different t
|
|||||||
## Available profiles
|
## Available profiles
|
||||||
Out-of-the-box OSRM comes with profiles for car, bicycle and foot. You can easily modify these or create new ones if you like.
|
Out-of-the-box OSRM comes with profiles for car, bicycle and foot. You can easily modify these or create new ones if you like.
|
||||||
|
|
||||||
Profiles have a 'lua' extension, and are places in 'profiles' directory.
|
Profiles have a 'lua' extension, and are placed in 'profiles' directory.
|
||||||
|
|
||||||
When running OSRM preprocessing commands you specify the profile with the --profile (or the shorthand -p) option, for example:
|
When running OSRM preprocessing commands you specify the profile with the --profile (or the shorthand -p) option, for example:
|
||||||
|
|
||||||
@@ -17,8 +17,8 @@ It's important to understand that profiles are used when preprocessing the OSM d
|
|||||||
|
|
||||||
This means that after modifying a profile **you will need to extract, contract and reload the data again** and to see changes in the routing results. See [Processing Flow](https://github.com/Project-OSRM/osrm-backend/wiki/Processing-Flow) for more.
|
This means that after modifying a profile **you will need to extract, contract and reload the data again** and to see changes in the routing results. See [Processing Flow](https://github.com/Project-OSRM/osrm-backend/wiki/Processing-Flow) for more.
|
||||||
|
|
||||||
## Profiles are written in LUA
|
## Profiles are written in Lua
|
||||||
Profiles are not just configuration files. They are scripts written in the [LUA scripting language](http://www.lua.org). The reason for this is that OpenStreetMap data is complex, and it's not possible to simply define tag mappings. LUA scripting offers a powerful way to handle all the possible tag combinations found in OpenStreetMap nodes and ways.
|
Profiles are not just configuration files. They are scripts written in the [Lua scripting language](http://www.lua.org). The reason for this is that OpenStreetMap data is complex, and it's not possible to simply define tag mappings. Lua scripting offers a powerful way to handle all the possible tag combinations found in OpenStreetMap nodes and ways.
|
||||||
|
|
||||||
## Basic structure of profiles
|
## Basic structure of profiles
|
||||||
A profile will process every node and way in the OSM input data to determine what ways are routable in which direction, at what speed, etc.
|
A profile will process every node and way in the OSM input data to determine what ways are routable in which direction, at what speed, etc.
|
||||||
@@ -35,40 +35,40 @@ A profile can also define various local functions it needs.
|
|||||||
|
|
||||||
Looking at [car.lua](../profiles/car.lua) as an example, at the top of the file the api version is defined and then required library files are included.
|
Looking at [car.lua](../profiles/car.lua) as an example, at the top of the file the api version is defined and then required library files are included.
|
||||||
|
|
||||||
Then follows the `setup` functions, which is called once when the profile is loaded. It returns a big hash table of configurations, specifying things like what speed to use for different way types. The configurations are used later in the various processing functions. Many adjustments can be done just be modifying this configuration table.
|
Then follows the `setup` function, which is called once when the profile is loaded. It returns a big hash table of configurations, specifying things like what speed to use for different way types. The configurations are used later in the various processing functions. Many adjustments can be done just by modifying this configuration table.
|
||||||
|
|
||||||
The setup function is also where you can do other setup, like loading elevation data source if you want to consider that when processing ways.
|
The setup function is also where you can do other setup, like loading an elevation data source if you want to consider that when processing ways.
|
||||||
|
|
||||||
Then comes the `process_node` and `process_way` functions, which are called for each OSM node and way when extracting OpenStreetMap data with `osrm-extract`.
|
Then come the `process_node` and `process_way` functions, which are called for each OSM node and way when extracting OpenStreetMap data with `osrm-extract`.
|
||||||
|
|
||||||
The `process_turn` function processes every possible turn in the network, and sets a penalty depending on the angle and turn of the movement.
|
The `process_turn` function processes every possible turn in the network, and sets a penalty depending on the angle and turn of the movement.
|
||||||
|
|
||||||
Profiles can also define a `process_segment` function to handle differences in speed along an OSM way, for example to handle elevation. As you can see, this is not currently used in the car profile.
|
Profiles can also define a `process_segment` function to handle differences in speed along an OSM way, for example to handle elevation. As you can see, this is not currently used in the car profile.
|
||||||
|
|
||||||
At the end of the file, a table if returned with references to the setup and processing functions the profile has defined.
|
At the end of the file, a table is returned with references to the setup and processing functions the profile has defined.
|
||||||
|
|
||||||
## Understanding speed, weight and rate
|
## Understanding speed, weight and rate
|
||||||
When computing a route from A to B there can be different measure of what is the best route. That's why there's a need for different profiles.
|
When computing a route from A to B there can be different measures of what is the best route. That's why there's a need for different profiles.
|
||||||
|
|
||||||
Because speeds very on different types of roads, the shortest and the fastest route are typically different. But there are many other possible preferences. For example a user might prefer a bicycle route that follow parks or other green areas, even though both duration and distance are a bit longer.
|
Because speeds vary on different types of roads, the shortest and the fastest route are typically different. But there are many other possible preferences. For example a user might prefer a bicycle route that follow parks or other green areas, even though both duration and distance are a bit longer.
|
||||||
|
|
||||||
To handle this, OSRM doesn't simply choose the ways with the highest speed. Instead it uses the concept of `weight` and `rate`. The rate is an abstract measure that you can assign to ways as you like to make some ways preferable to others. Routing will prefer ways with high rate.
|
To handle this, OSRM doesn't simply choose the ways with the highest speed. Instead it uses the concepts of `weight` and `rate`. The rate is an abstract measure that you can assign to ways as you like to make some ways preferable to others. Routing will prefer ways with high rate.
|
||||||
|
|
||||||
The weight of a way normally computed as length / rate. The weight can be thought of as the resistance or cost when passing the way. Routing will prefer ways with low weight.
|
The weight of a way is normally computed as length / rate. The weight can be thought of as the resistance or cost when passing the way. Routing will prefer ways with low weight.
|
||||||
|
|
||||||
You can also set the weight of a way to a fixed value, In this case it's not calculated based on the length or rate, and the rate is ignored.
|
You can also set the weight of a way to a fixed value. In this case it's not calculated based on the length or rate, and the rate is ignored.
|
||||||
|
|
||||||
You should set the speed to you best estimate of the actual speed that will be used on a particular way. This will result in the best estimated travel times.
|
You should set the speed to your best estimate of the actual speed that will be used on a particular way. This will result in the best estimated travel times.
|
||||||
|
|
||||||
If you want to prefer certain ways due to other factors than the speed, adjust the rate accordingly. If you adjust the speed, the time time estimation will be skewed.
|
If you want to prefer certain ways due to other factors than the speed, adjust the rate accordingly. If you adjust the speed, the time estimation will be skewed.
|
||||||
|
|
||||||
If you set the same rate on all ways, the result will be shortest path routing.
|
If you set the same rate on all ways, the result will be shortest path routing.
|
||||||
If you set rate = speed on all ways, the result will be fastest path routing.
|
If you set rate = speed on all ways, the result will be fastest path routing.
|
||||||
If you want to prioritize certain street, increase the rate on these.
|
If you want to prioritize certain streets, increase the rate on these.
|
||||||
|
|
||||||
## Elements
|
## Elements
|
||||||
### api_version
|
### api_version
|
||||||
A profile should set api_version at the top of your profile. This is done to ensure that older profiles are still supported when the api changes. If api_version is not defined, 0 will be assumed. The current api version is 2.
|
A profile should set `api_version` at the top of your profile. This is done to ensure that older profiles are still supported when the api changes. If `api_version` is not defined, 0 will be assumed. The current api version is 2.
|
||||||
|
|
||||||
### Library files
|
### Library files
|
||||||
The folder [profiles/lib/](../profiles/lib/) contains LUA library files for handling many common processing tasks.
|
The folder [profiles/lib/](../profiles/lib/) contains LUA library files for handling many common processing tasks.
|
||||||
@@ -81,15 +81,15 @@ set.lua | Defines the Set helper for handling sets of values
|
|||||||
sequence.lua | Defines the Sequence helper for handling sequences of values
|
sequence.lua | Defines the Sequence helper for handling sequences of values
|
||||||
access.lua | Function for finding relevant access tags
|
access.lua | Function for finding relevant access tags
|
||||||
destination.lua | Function for finding relevant destination tags
|
destination.lua | Function for finding relevant destination tags
|
||||||
destination.lua | Function for determining maximum speed
|
maxspeed.lua | Function for determining maximum speed
|
||||||
guidance.lua | Function for processing guidance attributes
|
guidance.lua | Function for processing guidance attributes
|
||||||
|
|
||||||
They all return a table of functions when you use `require` to load them. You can either store this table and reference it's functions later, of if you need only a single you can store that directly.
|
They all return a table of functions when you use `require` to load them. You can either store this table and reference its functions later, or if you need only a single function you can store that directly.
|
||||||
|
|
||||||
### setup()
|
### setup()
|
||||||
The `setup` function is called once when the profile is loaded and must return a table of configurations. It's also where you can do other global setup, like loading data sources that are used during processing.
|
The `setup` function is called once when the profile is loaded and must return a table of configurations. It's also where you can do other global setup, like loading data sources that are used during processing.
|
||||||
|
|
||||||
Note that processing of data is parallelized and several unconnected LUA interpreters will be running at the same time. The `setup` function will be called once for each. Each LUA iinterpreter will have it's own set of globals.
|
Note that processing of data is parallelized and several unconnected LUA interpreters will be running at the same time. The `setup` function will be called once for each. Each LUA iinterpreter will have its own set of globals.
|
||||||
|
|
||||||
The following global properties can be set under `properties` in the hash you return in the `setup` function:
|
The following global properties can be set under `properties` in the hash you return in the `setup` function:
|
||||||
|
|
||||||
@@ -109,8 +109,7 @@ The following additional global properties can be set in the hash you return in
|
|||||||
|
|
||||||
Attribute | Type | Notes
|
Attribute | Type | Notes
|
||||||
-------------------------------------|------------------|----------------------------------------------------------------------------
|
-------------------------------------|------------------|----------------------------------------------------------------------------
|
||||||
excludable | Sequence of Sets | Determines which class-combinations are supported by the `exclude` option at query time.
|
excludable | Sequence of Sets | Determines which class-combinations are supported by the `exclude` option at query time. E.g. `Sequence{Set{"ferry", "motorway"}, Set{"motorway"}}` will allow you to exclude ferries and motorways, or only motorways.
|
||||||
| | E.g. `Sequence{Set{"ferry", "motorway"}, Set{"motorway"}}` will allow you to exclude ferries and motorways, or only motorways.
|
|
||||||
classes | Sequence | Determines the allowed classes that can be referenced using `{forward,backward}_classes` on the way in the `process_way` function.
|
classes | Sequence | Determines the allowed classes that can be referenced using `{forward,backward}_classes` on the way in the `process_way` function.
|
||||||
restrictions | Sequence | Determines which turn restrictions will be used for this profile.
|
restrictions | Sequence | Determines which turn restrictions will be used for this profile.
|
||||||
suffix_list | Set | List of name suffixes needed for determining if "Highway 101 NW" the same road as "Highway 101 ES".
|
suffix_list | Set | List of name suffixes needed for determining if "Highway 101 NW" the same road as "Highway 101 ES".
|
||||||
@@ -147,26 +146,26 @@ Importantly it will set `result.forward_mode` and `result.backward_mode` to indi
|
|||||||
|
|
||||||
It will also set a number of other attributes on `result`.
|
It will also set a number of other attributes on `result`.
|
||||||
|
|
||||||
Using the power of the scripting language you wouldn't typically see something as simple as a `result.forward_speed = 20` line within the `process_way` function. Instead `process_way` will examine the tag set on the way, process this information in various ways, calling other local functions and referencing the configuration in `profile`, etc, before arriving at the result.
|
Using the power of the scripting language you wouldn't typically see something as simple as a `result.forward_speed = 20` line within the `process_way` function. Instead `process_way` will examine the tag set on the way, process this information in various ways, calling other local functions and referencing the configuration in `profile`, etc., before arriving at the result.
|
||||||
|
|
||||||
The following attributes can be set on the result in `process_way`:
|
The following attributes can be set on the result in `process_way`:
|
||||||
|
|
||||||
Attribute | Type | Notes
|
Attribute | Type | Notes
|
||||||
----------------------------------------|----------|--------------------------------------------------------------------------
|
----------------------------------------|----------|--------------------------------------------------------------------------
|
||||||
forward_speed | Float | Speed on this way in km/h. Mandatory.
|
forward_speed | Float | Speed on this way in km/h. Mandatory.
|
||||||
backward_speed | Float | " "
|
backward_speed | Float | ""
|
||||||
forward_rate | Float | Routing weight, expressed as meters/*weight* (e.g. for a fastest-route weighting, you would want this to be meters/second, so set it to forward_speed/3.6)
|
forward_rate | Float | Routing weight, expressed as meters/*weight* (e.g. for a fastest-route weighting, you would want this to be meters/second, so set it to forward_speed/3.6)
|
||||||
backward_rate | Float | " "
|
backward_rate | Float | ""
|
||||||
forward_mode | Enum | Mode of travel (e.g. `car`, `ferry`). Mandatory. Defined in `include/extractor/travel_mode.hpp`.
|
forward_mode | Enum | Mode of travel (e.g. `car`, `ferry`). Mandatory. Defined in `include/extractor/travel_mode.hpp`.
|
||||||
backward_mode | Enum | " "
|
backward_mode | Enum | ""
|
||||||
forward_classes | Table | Mark this way as being of a specific class, e.g. `result.classes["toll"] = true`. This will be exposed in the API as `classes` on each `RouteStep`.
|
forward_classes | Table | Mark this way as being of a specific class, e.g. `result.classes["toll"] = true`. This will be exposed in the API as `classes` on each `RouteStep`.
|
||||||
backward_classes | Table | " "
|
backward_classes | Table | ""
|
||||||
duration | Float | Alternative setter for duration of the whole way in both directions
|
duration | Float | Alternative setter for duration of the whole way in both directions
|
||||||
weight | Float | Alternative setter for weight of the whole way in both directions
|
weight | Float | Alternative setter for weight of the whole way in both directions
|
||||||
turn_lanes_forward | String | Directions for individual lanes (normalized OSM `turn:lanes` value)
|
turn_lanes_forward | String | Directions for individual lanes (normalized OSM `turn:lanes` value)
|
||||||
turn_lanes_backward | String | " "
|
turn_lanes_backward | String | ""
|
||||||
forward_restricted | Boolean | Is this a restricted access road? (e.g. private, or deliveries only; used to enable high turn penalty, so that way is only chosen for start/end of route)
|
forward_restricted | Boolean | Is this a restricted access road? (e.g. private, or deliveries only; used to enable high turn penalty, so that way is only chosen for start/end of route)
|
||||||
backward_restricted | Boolean | " "
|
backward_restricted | Boolean | ""
|
||||||
is_startpoint | Boolean | Can a journey start on this way? (e.g. ferry; if `false`, prevents snapping the start point to this way)
|
is_startpoint | Boolean | Can a journey start on this way? (e.g. ferry; if `false`, prevents snapping the start point to this way)
|
||||||
roundabout | Boolean | Is this part of a roundabout?
|
roundabout | Boolean | Is this part of a roundabout?
|
||||||
circular | Boolean | Is this part of a non-roundabout circular junction?
|
circular | Boolean | Is this part of a non-roundabout circular junction?
|
||||||
@@ -188,18 +187,18 @@ The `process_segment` function is called for every segment of OSM ways. A segmen
|
|||||||
|
|
||||||
On OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However many ways are long. For example, many ways pass hills without any change in tags.
|
On OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However many ways are long. For example, many ways pass hills without any change in tags.
|
||||||
|
|
||||||
Processing each segment of an OSM way makes it possible to have different speeds on different parts of a way based on external data like data about elevation, pollution, noise or scenic value and adjust weight and duration of the segment.
|
Processing each segment of an OSM way makes it possible to have different speeds on different parts of a way based on external data like data about elevation, pollution, noise or scenic value and adjust weight and duration of the segment accordingly.
|
||||||
|
|
||||||
In the `process_segment` you don't have access to OSM tags. Instead you use the geographical location of the start and end point of the way to lookup other data source, like elevation data. See [rasterbot.lua](../profiles/rasterbot.lua) for an example.
|
In the `process_segment` function you don't have access to OSM tags. Instead you use the geographical location of the start and end point of the way to look up information from another data source, like elevation data. See [rasterbot.lua](../profiles/rasterbot.lua) for an example.
|
||||||
|
|
||||||
The following attributes can be read and set on the result in `process_segment`:
|
The following attributes can be read and set on the result in `process_segment`:
|
||||||
|
|
||||||
Attribute | Read/write? | Type | Notes
|
Attribute | Read/write? | Type | Notes
|
||||||
-------------------|-------------|---------|----------------------------------------
|
-------------------|-------------|---------|----------------------------------------
|
||||||
source.lon | Read | Float | Co-ordinates of segment start
|
source.lon | Read | Float | Co-ordinates of segment start
|
||||||
source.lat | Read | Float | " "
|
source.lat | Read | Float | ""
|
||||||
target.lon | Read | Float | Co-ordinates of segment end
|
target.lon | Read | Float | Co-ordinates of segment end
|
||||||
target.lat | Read | Float | " "
|
target.lat | Read | Float | ""
|
||||||
target.distance | Read | Float | Length of segment
|
target.distance | Read | Float | Length of segment
|
||||||
weight | Read/write | Float | Routing weight for this segment
|
weight | Read/write | Float | Routing weight for this segment
|
||||||
duration | Read/write | Float | Duration for this segment
|
duration | Read/write | Float | Duration for this segment
|
||||||
@@ -209,16 +208,19 @@ The `process_turn` function is called for every possible turn in the network. Ba
|
|||||||
|
|
||||||
The following attributes can be read and set on the result in `process_turn`:
|
The following attributes can be read and set on the result in `process_turn`:
|
||||||
|
|
||||||
Attribute | Read/write? | Type | Notes
|
Attribute | Read/write? | Type | Notes
|
||||||
-------------------|-------------|---------|------------------------------------------------------
|
---------------------|-------------|---------|------------------------------------------------------
|
||||||
direction_modifier | Read | Enum | Geometry of turn. Defined in `include/extractor/guidance/turn_instruction.hpp`
|
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
|
||||||
turn_type | Read | Enum | Priority of turn. Defined in `include/extractor/guidance/turn_instruction.hpp`
|
number_of_roads | Read | Integer | Number of ways at the intersection of the turn
|
||||||
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
|
is_u_turn | Read | Boolean | Is the turn a u-turn?
|
||||||
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
|
||||||
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`)
|
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
||||||
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
|
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`)
|
||||||
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
|
is_left_hand_driving | Read | Boolean | Is left-hand traffic?
|
||||||
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
|
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
|
||||||
|
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
|
||||||
|
source_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||||
|
target_mode | Read | Enum | Travel mode after the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||||
|
|
||||||
## Guidance
|
## Guidance
|
||||||
The guidance parameters in profiles are currently a work in progress. They can and will change.
|
The guidance parameters in profiles are currently a work in progress. They can and will change.
|
||||||
@@ -231,7 +233,7 @@ The priority-category influences the decision which road is considered the obvio
|
|||||||
Forks can be emitted between roads of similar priority category only. Obvious choices follow a major priority road, if the priority difference is large.
|
Forks can be emitted between roads of similar priority category only. Obvious choices follow a major priority road, if the priority difference is large.
|
||||||
|
|
||||||
### Using raster data
|
### Using raster data
|
||||||
OSRM has build-in support for loading an interpolating raster data in ASCII format. This can be used e.g. for factoring in elevation when computing routes.
|
OSRM has built-in support for loading an interpolating raster data in ASCII format. This can be used e.g. for factoring in elevation when computing routes.
|
||||||
|
|
||||||
Use `raster:load()` in your `setup` function to load data and store the source in your configuration hash:
|
Use `raster:load()` in your `setup` function to load data and store the source in your configuration hash:
|
||||||
|
|
||||||
@@ -284,8 +286,8 @@ See [rasterbot.lua](../profiles/rasterbot.lua) and [rasterbotinterp.lua](../prof
|
|||||||
### Helper functions
|
### Helper functions
|
||||||
There are a few helper functions defined in the global scope that profiles can use:
|
There are a few helper functions defined in the global scope that profiles can use:
|
||||||
|
|
||||||
durationIsValid
|
- `durationIsValid`
|
||||||
parseDuration
|
- `parseDuration`
|
||||||
trimLaneString
|
- `trimLaneString`
|
||||||
applyAccessTokens
|
- `applyAccessTokens`
|
||||||
canonicalizeStringList
|
- `canonicalizeStringList`
|
||||||
|
|||||||
@@ -30,9 +30,17 @@ int main(int argc, const char *argv[])
|
|||||||
|
|
||||||
// Configure based on a .osrm base path, and no datasets in shared mem from osrm-datastore
|
// Configure based on a .osrm base path, and no datasets in shared mem from osrm-datastore
|
||||||
EngineConfig config;
|
EngineConfig config;
|
||||||
|
|
||||||
config.storage_config = {argv[1]};
|
config.storage_config = {argv[1]};
|
||||||
config.use_shared_memory = false;
|
config.use_shared_memory = false;
|
||||||
|
|
||||||
|
// We support two routing speed up techniques:
|
||||||
|
// - Contraction Hierarchies (CH): requires extract+contract pre-processing
|
||||||
|
// - Multi-Level Dijkstra (MLD): requires extract+partition+customize pre-processing
|
||||||
|
//
|
||||||
|
// config.algorithm = EngineConfig::Algorithm::CH;
|
||||||
|
config.algorithm = EngineConfig::Algorithm::MLD;
|
||||||
|
|
||||||
// Routing machine with several services (such as Route, Table, Nearest, Trip, Match)
|
// Routing machine with several services (such as Route, Table, Nearest, Trip, Match)
|
||||||
const OSRM osrm{config};
|
const OSRM osrm{config};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
@routing @car @way
|
||||||
|
Feature: Car - Avoid defined areas
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given the profile file "car" initialized with
|
||||||
|
"""
|
||||||
|
profile.avoid = Set { 'motorway', 'motorway_link' }
|
||||||
|
profile.speeds = Sequence {
|
||||||
|
highway = {
|
||||||
|
motorway = 90,
|
||||||
|
motorway_link = 45,
|
||||||
|
primary = 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Car - Avoid motorways
|
||||||
|
Then routability should be
|
||||||
|
| highway | bothw |
|
||||||
|
| motorway | |
|
||||||
|
| motorway_link | |
|
||||||
|
| primary | x |
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ Feature: Car - Mode flag
|
|||||||
| from | to | route | turns | classes |
|
| from | to | route | turns | classes |
|
||||||
| a | d | ab,cd | depart,arrive| [(restricted),(motorway,restricted),()],[()] |
|
| a | d | ab,cd | depart,arrive| [(restricted),(motorway,restricted),()],[()] |
|
||||||
|
|
||||||
Scenario: Car - We toll restricted with a class
|
Scenario: Car - We tag toll with a class
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b
|
a b
|
||||||
@@ -99,6 +99,45 @@ Feature: Car - Mode flag
|
|||||||
| from | to | route | turns | classes |
|
| from | to | route | turns | classes |
|
||||||
| a | d | ab,cd | depart,arrive | [(toll),(motorway,toll),()],[()] |
|
| a | d | ab,cd | depart,arrive | [(toll),(motorway,toll),()],[()] |
|
||||||
|
|
||||||
|
Scenario: Car - We tag tunnel with a class
|
||||||
|
Background:
|
||||||
|
Given a grid size of 200 meters
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | tunnel |
|
||||||
|
| ab | no |
|
||||||
|
| bc | yes |
|
||||||
|
| cd | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | turns | classes |
|
||||||
|
| a | d | ab,bc,cd,cd | depart,new name right,new name left,arrive | [()],[(tunnel)],[()],[()] |
|
||||||
|
|
||||||
|
Scenario: Car - We tag classes without intersections
|
||||||
|
Background:
|
||||||
|
Given a grid size of 200 meters
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | name | tunnel |
|
||||||
|
| ab | road | |
|
||||||
|
| bc | road | yes |
|
||||||
|
| cd | road | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | turns | classes |
|
||||||
|
| a | d | road,road | depart,arrive | [(),(tunnel),()],[()] |
|
||||||
|
|
||||||
Scenario: Car - From roundabout on toll road
|
Scenario: Car - From roundabout on toll road
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -124,4 +163,3 @@ Feature: Car - Mode flag
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route | turns | classes |
|
| from | to | route | turns | classes |
|
||||||
| a | f | ab,df,df,df | depart,roundabout-exit-2,exit roundabout slight right,arrive | [()],[(),(motorway)],[(toll,motorway)],[()] |
|
| a | f | ab,df,df,df | depart,roundabout-exit-2,exit roundabout slight right,arrive | [()],[(),(motorway)],[(toll,motorway)],[()] |
|
||||||
|
|
||||||
|
|||||||
@@ -884,7 +884,7 @@ Feature: Car - Turn restrictions
|
|||||||
| a | c | albic,dobe,dobe,albic,albic | depart,turn left,continue uturn,turn left,arrive |
|
| a | c | albic,dobe,dobe,albic,albic | depart,turn left,continue uturn,turn left,arrive |
|
||||||
| a | e | albic,dobe,dobe | depart,turn left,arrive |
|
| a | e | albic,dobe,dobe | depart,turn left,arrive |
|
||||||
|
|
||||||
@no_turning @conditionals
|
@no_turning @conditionals @restriction-way
|
||||||
Scenario: Car - Conditional restriction with multiple time windows
|
Scenario: Car - Conditional restriction with multiple time windows
|
||||||
Given the extract extra arguments "--parse-conditional-restrictions"
|
Given the extract extra arguments "--parse-conditional-restrictions"
|
||||||
# 5pm Wed 02 May, 2017 GMT
|
# 5pm Wed 02 May, 2017 GMT
|
||||||
@@ -1054,4 +1054,3 @@ Feature: Car - Turn restrictions
|
|||||||
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
|
||||||
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||||
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
@routing @car
|
||||||
|
Feature: Car - Handle physical limitation
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given the profile "car"
|
||||||
|
|
||||||
|
Scenario: Car - Use a narrow way
|
||||||
|
Then routability should be
|
||||||
|
| highway | width | narrow | bothw |
|
||||||
|
| primary | | | x |
|
||||||
|
| primary | narrow | | x |
|
||||||
|
| primary | | yes | x |
|
||||||
|
| primary | 1.8 | | |
|
||||||
|
| primary | 1.9 | | |
|
||||||
|
| primary | 2.0 | | x |
|
||||||
|
| primary | 2.1 | | x |
|
||||||
|
| primary | 1m | | |
|
||||||
|
| primary | 1 m | | |
|
||||||
|
| primary | 3 m | | x |
|
||||||
|
| primary | 6' | | |
|
||||||
|
| primary | 6'0" | | |
|
||||||
|
| primary | 6'2" | | |
|
||||||
|
| primary | 6'3" | | x |
|
||||||
|
| primary | 7' | | x |
|
||||||
|
| primary | 7'0" | | x |
|
||||||
|
|
||||||
|
Scenario: Car - Limited by width
|
||||||
|
Then routability should be
|
||||||
|
| highway | maxwidth:physical | maxwidth | width | est_width | bothw |
|
||||||
|
| primary | 1 | | | | |
|
||||||
|
| primary | 3 | | | | x |
|
||||||
|
| primary | | 1 | | | |
|
||||||
|
| primary | | 3 | | | x |
|
||||||
|
| primary | | | 1 | | |
|
||||||
|
| primary | | | 3 | | x |
|
||||||
|
| primary | | | | 1 | |
|
||||||
|
| primary | | | | 3 | x |
|
||||||
|
|
||||||
|
Scenario: Car - Limited by height
|
||||||
|
Then routability should be
|
||||||
|
| highway | maxheight:physical | maxheight | bothw |
|
||||||
|
| primary | 1 | | |
|
||||||
|
| primary | 3 | | x |
|
||||||
|
| primary | | 1 | |
|
||||||
|
| primary | | 3 | x |
|
||||||
@@ -141,6 +141,33 @@ Feature: Car - Turn restrictions
|
|||||||
| c | a | cj,aj,aj |
|
| c | a | cj,aj,aj |
|
||||||
| c | b | cj,bj,bj |
|
| c | b | cj,bj,bj |
|
||||||
|
|
||||||
|
@no_turning
|
||||||
|
Scenario: Car - Ignore no_*_on_red relations
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a
|
||||||
|
d j b
|
||||||
|
c
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| cj | yes |
|
||||||
|
| aj | -1 |
|
||||||
|
| dj | -1 |
|
||||||
|
| bj | -1 |
|
||||||
|
|
||||||
|
And the relations
|
||||||
|
| type | way:from | way:to | node:via | restriction |
|
||||||
|
| restriction | cj | dj | j | no_turn_on_red |
|
||||||
|
| restriction | cj | bj | j | no_right_turn_on_red |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route |
|
||||||
|
| c | d | cj,dj,dj |
|
||||||
|
| c | a | cj,aj,aj |
|
||||||
|
| c | b | cj,bj,bj |
|
||||||
|
|
||||||
@only_turning
|
@only_turning
|
||||||
Scenario: Car - Only left turn
|
Scenario: Car - Only left turn
|
||||||
Given the node map
|
Given the node map
|
||||||
@@ -575,7 +602,7 @@ Feature: Car - Turn restrictions
|
|||||||
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||||
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||||
|
|
||||||
@restriction @overlap
|
@restriction-way @overlap
|
||||||
Scenario: Car - prohibit turn
|
Scenario: Car - prohibit turn
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -710,7 +737,7 @@ Feature: Car - Turn restrictions
|
|||||||
| a | j | left,first,right,right |
|
| a | j | left,first,right,right |
|
||||||
| f | e | right,third,left,left |
|
| f | e | right,third,left,left |
|
||||||
|
|
||||||
@restriction
|
@restriction-way
|
||||||
Scenario: Car - allow only turn
|
Scenario: Car - allow only turn
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -742,7 +769,7 @@ Feature: Car - Turn restrictions
|
|||||||
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
| c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d |
|
||||||
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||||
|
|
||||||
@restriction
|
@restriction-way
|
||||||
Scenario: Car - allow only turn
|
Scenario: Car - allow only turn
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -771,7 +798,7 @@ Feature: Car - Turn restrictions
|
|||||||
| from | to | route |
|
| from | to | route |
|
||||||
| a | d | ab,be,de,de |
|
| a | d | ab,be,de,de |
|
||||||
|
|
||||||
@restriction
|
@restriction-way
|
||||||
Scenario: Multi Way restriction
|
Scenario: Multi Way restriction
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -808,7 +835,7 @@ Feature: Car - Turn restrictions
|
|||||||
| from | to | route |
|
| from | to | route |
|
||||||
| a | h | horiz,vert,horiz,horiz |
|
| a | h | horiz,vert,horiz,horiz |
|
||||||
|
|
||||||
@restriction
|
@restriction-way
|
||||||
Scenario: Multi-Way overlapping single-way
|
Scenario: Multi-Way overlapping single-way
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -847,7 +874,7 @@ Feature: Car - Turn restrictions
|
|||||||
| h | d | hfb,abcd,abcd | depart,end of road right,arrive | h,b,d |
|
| h | d | hfb,abcd,abcd | depart,end of road right,arrive | h,b,d |
|
||||||
|
|
||||||
|
|
||||||
@restriction
|
@restriction-way
|
||||||
Scenario: Car - prohibit turn, traffic lights
|
Scenario: Car - prohibit turn, traffic lights
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -890,7 +917,7 @@ Feature: Car - Turn restrictions
|
|||||||
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
|
||||||
|
|
||||||
|
|
||||||
@restriction @overlap @geometry
|
@restriction-way @overlap @geometry
|
||||||
Scenario: Geometry
|
Scenario: Geometry
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -925,7 +952,7 @@ Feature: Car - Turn restrictions
|
|||||||
| c | d | bc,bge,de,de |
|
| c | d | bc,bge,de,de |
|
||||||
| c | f | bc,bge,de,de,ef,ef |
|
| c | f | bc,bge,de,de,ef,ef |
|
||||||
|
|
||||||
@restriction @overlap @geometry @traffic-signals
|
@restriction-way @overlap @geometry @traffic-signals
|
||||||
Scenario: Geometry
|
Scenario: Geometry
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -967,7 +994,7 @@ Feature: Car - Turn restrictions
|
|||||||
| c | f | bc,bge,de,de,ef,ef |
|
| c | f | bc,bge,de,de,ef,ef |
|
||||||
|
|
||||||
# don't crash hard on invalid restrictions
|
# don't crash hard on invalid restrictions
|
||||||
@restriction @invalid
|
@restriction-way @invalid
|
||||||
Scenario: Geometry
|
Scenario: Geometry
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -999,7 +1026,7 @@ Feature: Car - Turn restrictions
|
|||||||
| a | f | ab,be,ef,ef |
|
| a | f | ab,be,ef,ef |
|
||||||
|
|
||||||
|
|
||||||
@restriction @overlap @geometry
|
@restriction @restriction-way @overlap @geometry
|
||||||
Scenario: Duplicated restriction
|
Scenario: Duplicated restriction
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -116,3 +116,28 @@ Feature: Testbot - side bias
|
|||||||
| from | to | route | driving_side | time |
|
| from | to | route | driving_side | time |
|
||||||
| d | a | bd,ab,ab | right,right,right | 27s +-1 |
|
| d | a | bd,ab,ab | right,right,right | 27s +-1 |
|
||||||
| d | c | bd,bc,bc | right,right,right | 24s +-1 |
|
| d | c | bd,bc,bc | right,right,right | 24s +-1 |
|
||||||
|
|
||||||
|
Scenario: changing sides
|
||||||
|
Given the profile "car"
|
||||||
|
|
||||||
|
# Note - the boundary in null-island.geojson is at lon = 2.0,
|
||||||
|
# and we use the "last node of the way" as the heuristic to detect
|
||||||
|
# whether the way is in our out of the driving_side polygon
|
||||||
|
And the node locations
|
||||||
|
| node | lat | lon |
|
||||||
|
| a | 0 | 0.5 |
|
||||||
|
| b | 0 | 1.5 |
|
||||||
|
| c | 0 | 2.5 |
|
||||||
|
| d | 0 | 3.5 |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ab |
|
||||||
|
| bc |
|
||||||
|
| cd |
|
||||||
|
|
||||||
|
And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson"
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | driving_side |
|
||||||
|
| d | a | cd,bc,ab,ab | right,right,left,left |
|
||||||
|
| a | d | ab,bc,cd,cd | left,right,right,right |
|
||||||
|
|||||||
@@ -98,11 +98,11 @@ Feature: Car - Guidance - Bridges and Tunnels
|
|||||||
| dce | primary | | Nebenstraße |
|
| dce | primary | | Nebenstraße |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route | turns |
|
| from | to | route | turns |
|
||||||
| a | d | Hauptstraße,Nebenstraße,Nebenstraße | depart,turn left,arrive |
|
| a | d | Hauptstraße,Nebenstraße,Nebenstraße | depart,end of road left,arrive |
|
||||||
| a | e | Hauptstraße,Nebenstraße,Nebenstraße | depart,turn right,arrive |
|
| a | e | Hauptstraße,Nebenstraße,Nebenstraße | depart,end of road right,arrive |
|
||||||
| e | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn left,arrive |
|
| e | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn left,arrive |
|
||||||
| d | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn right,arrive |
|
| d | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn right,arrive |
|
||||||
|
|
||||||
Scenario: Tunnel with Immediate Turn Front and Back
|
Scenario: Tunnel with Immediate Turn Front and Back
|
||||||
Given the node map
|
Given the node map
|
||||||
@@ -129,4 +129,3 @@ Feature: Car - Guidance - Bridges and Tunnels
|
|||||||
| e | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn left,turn left,arrive |
|
| e | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn left,turn left,arrive |
|
||||||
| d | f | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn right,arrive |
|
| d | f | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn right,arrive |
|
||||||
| d | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn left,arrive |
|
| d | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn left,arrive |
|
||||||
|
|
||||||
|
|||||||
@@ -992,7 +992,6 @@ Feature: Slipways and Dedicated Turn Lanes
|
|||||||
| dbef | primary | dbef | |
|
| dbef | primary | dbef | |
|
||||||
| ae | primary_link | ae | yes |
|
| ae | primary_link | ae | yes |
|
||||||
|
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns | locations |
|
| waypoints | route | turns | locations |
|
||||||
| s,f | sabc,dbef,dbef | depart,turn right,arrive | s,a,f |
|
| s,f | sabc,dbef,dbef | depart,turn right,arrive | s,a,f |
|
||||||
@@ -1019,7 +1018,6 @@ Feature: Slipways and Dedicated Turn Lanes
|
|||||||
| dbcf | primary | dbcf | |
|
| dbcf | primary | dbcf | |
|
||||||
| ac | primary_link | ae | yes |
|
| ac | primary_link | ae | yes |
|
||||||
|
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns | locations |
|
| waypoints | route | turns | locations |
|
||||||
| s,f | sab,dbcf,dbcf | depart,turn right,arrive | s,a,f |
|
| s,f | sab,dbcf,dbcf | depart,turn right,arrive | s,a,f |
|
||||||
@@ -1047,7 +1045,55 @@ Feature: Slipways and Dedicated Turn Lanes
|
|||||||
| ae | primary_link | sab | yes |
|
| ae | primary_link | sab | yes |
|
||||||
| cg | primary | cg | |
|
| cg | primary | cg | |
|
||||||
|
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns | locations |
|
| waypoints | route | turns | locations |
|
||||||
| s,f | sab,dbcef,dbcef | depart,turn right,arrive | s,a,f |
|
| s,f | sab,dbcef,dbcef | depart,turn right,arrive | s,a,f |
|
||||||
|
|
||||||
|
|
||||||
|
@sliproads
|
||||||
|
Scenario: Sliproad converted from a fork
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
d
|
||||||
|
.
|
||||||
|
b
|
||||||
|
s . a '.
|
||||||
|
`c
|
||||||
|
.
|
||||||
|
f
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | name | ref | oneway |
|
||||||
|
| sa | tertiary | | D 60A | yes |
|
||||||
|
| ab | tertiary | ab | D 60A | yes |
|
||||||
|
| ac | tertiary | | D 60A | yes |
|
||||||
|
| dbcf | tertiary | dbcf | D 543 | yes |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns | locations |
|
||||||
|
| s,f | ,dbcf,dbcf | depart,turn right,arrive | s,a,f |
|
||||||
|
|
||||||
|
|
||||||
|
@sliproads
|
||||||
|
Scenario: Sliproad to a road with a reference only
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
s . a . b . d
|
||||||
|
` .
|
||||||
|
' .
|
||||||
|
..
|
||||||
|
c
|
||||||
|
.
|
||||||
|
f
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | name | ref | oneway |
|
||||||
|
| sabd | primary | road | | |
|
||||||
|
| bcf | primary | | K108 | |
|
||||||
|
| ac | primary_link | | | yes |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns | locations |
|
||||||
|
| s,f | road,, | depart,turn right,arrive | s,a,f |
|
||||||
|
|||||||
@@ -393,31 +393,44 @@ Feature: Merge Segregated Roads
|
|||||||
"""
|
"""
|
||||||
a
|
a
|
||||||
|
|
|
|
||||||
b
|
b-----z
|
||||||
|
/ \
|
||||||
c h
|
c h
|
||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
d g
|
d g
|
||||||
|
\ /
|
||||||
e
|
e
|
||||||
|
|
|
|
||||||
f
|
f
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
| nodes | name | oneway |
|
| nodes | name | oneway |
|
||||||
| ab | road | no |
|
| ab | road | no |
|
||||||
| ef | road | no |
|
| ef | road | no |
|
||||||
| bcde | road | yes |
|
| bcde | road | yes |
|
||||||
| eghb | road | yes |
|
| eghb | road | yes |
|
||||||
|
| bz | cross | no |
|
||||||
|
|
||||||
|
And the relations
|
||||||
|
| type | way:from | way:to | node:via | restriction |
|
||||||
|
| restriction | bz | bcde | b | no_left_turn |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | turns | route |
|
| waypoints | turns | route |
|
||||||
| a,f | depart,arrive | road,road |
|
| a,f | depart,arrive | road,road |
|
||||||
| c,f | depart,arrive | road,road |
|
| c,f | depart,arrive | road,road |
|
||||||
| f,a | depart,arrive | road,road |
|
| f,a | depart,arrive | road,road |
|
||||||
| g,a | depart,arrive | road,road |
|
| g,a | depart,arrive | road,road |
|
||||||
|
| z,a | depart,turn right,arrive | cross,road,road |
|
||||||
|
|
||||||
Scenario: Traffic Island
|
Scenario: Traffic Island
|
||||||
Given the node map
|
Given the node map
|
||||||
@@ -588,10 +601,10 @@ Feature: Merge Segregated Roads
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns |
|
| waypoints | route | turns |
|
||||||
| a,c | germ,ober | depart,arrive |
|
| a,c | germ,ober | depart,arrive |
|
||||||
| a,g | germ,germ,germ | depart,continue right,arrive |
|
| a,g | germ,germ,germ | depart,continue right,arrive |
|
||||||
| a,1 | germ,germ,germ | depart,continue left,arrive |
|
| a,1 | germ,germ,germ | depart,continue left,arrive |
|
||||||
| d,g | ober,germ,germ | depart,turn left,arrive |
|
| d,g | ober,germ,germ | depart,turn left,arrive |
|
||||||
|
|
||||||
# https://www.openstreetmap.org/#map=19/51.32888/6.57059
|
# https://www.openstreetmap.org/#map=19/51.32888/6.57059
|
||||||
Scenario: Places in presence of oneways
|
Scenario: Places in presence of oneways
|
||||||
@@ -623,16 +636,16 @@ Feature: Merge Segregated Roads
|
|||||||
| cf | albrecht | yes |
|
| cf | albrecht | yes |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns |
|
| waypoints | route | turns |
|
||||||
| a,l | schwert,albrecht,marianne,marianne | depart,new name straight,turn left,arrive |
|
| a,l | schwert,albrecht,marianne,marianne | depart,new name straight,turn left,arrive |
|
||||||
| a,j | schwert,luise,luise | depart,turn right,arrive |
|
| a,j | schwert,luise,luise | depart,turn right,arrive |
|
||||||
| a,1 | schwert,albrecht,albrecht,albrecht | depart,new name straight,continue uturn,arrive |
|
| a,1 | schwert,albrecht,albrecht,albrecht | depart,new name straight,continue uturn,arrive |
|
||||||
| k,l | marianne,marianne | depart,arrive |
|
| k,l | marianne,marianne | depart,arrive |
|
||||||
| k,j | marianne,albrecht,luise,luise | depart,turn left,turn left,arrive |
|
| k,j | marianne,albrecht,luise,luise | depart,turn left,turn left,arrive |
|
||||||
| k,d | marianne,schwert,schwert | depart,turn right,arrive |
|
| k,d | marianne,schwert,schwert | depart,turn right,arrive |
|
||||||
| i,j | luise,luise | depart,arrive |
|
| i,j | luise,luise | depart,arrive |
|
||||||
| i,d | luise,albrecht,schwert,schwert | depart,turn left,turn straight,arrive |
|
| i,d | luise,albrecht,schwert,schwert | depart,turn left,turn straight,arrive |
|
||||||
| i,l | luise,albrecht,marianne,marianne | depart,turn left,turn left,arrive |
|
| i,l | luise,albrecht,marianne,marianne | depart,turn left,turn left,arrive |
|
||||||
|
|
||||||
# https://www.openstreetmap.org/#map=19/52.46339/13.40272
|
# https://www.openstreetmap.org/#map=19/52.46339/13.40272
|
||||||
Scenario: Do not merge links between segregated roads
|
Scenario: Do not merge links between segregated roads
|
||||||
|
|||||||
@@ -745,12 +745,15 @@ Feature: Basic Roundabout
|
|||||||
|
|
||||||
|
|
||||||
Scenario: Drive through roundabout
|
Scenario: Drive through roundabout
|
||||||
|
Given a grid size of 5 meters
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a
|
. a .
|
||||||
b e d f
|
. .
|
||||||
c
|
b e --- d ---- f
|
||||||
g h
|
. .
|
||||||
|
.c.
|
||||||
|
g h
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
@@ -760,12 +763,12 @@ Feature: Basic Roundabout
|
|||||||
| gch | | yes |
|
| gch | | yes |
|
||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | bearings | route | turns |
|
| waypoints | bearings | route | turns |
|
||||||
| e,f | 90 90 | edf,edf | depart,arrive |
|
| e,f | 90 90 | edf,edf | depart,arrive |
|
||||||
| e,h | 90 135 | edf,gch,gch,gch | depart,roundabout-exit-2,exit roundabout straight,arrive |
|
| e,h | 90 130 | edf,gch,gch,gch | depart,roundabout-exit-2,exit roundabout straight,arrive |
|
||||||
| g,f | 45 90 | gch,edf,edf,edf | depart,roundabout-exit-2,exit roundabout right,arrive |
|
| g,f | 50 90 | gch,edf,edf,edf | depart,roundabout-exit-2,exit roundabout slight right,arrive |
|
||||||
| g,h | 45 135 | gch,gch,gch | depart,exit roundabout right,arrive |
|
| g,h | 50 130 | gch,gch,gch | depart,exit roundabout right,arrive |
|
||||||
| e,e | 90 270 | edf,edf,edf | depart,continue uturn,arrive |
|
| e,e | 90 270 | edf,edf,edf,edf | depart,roundabout-exit-3,exit roundabout sharp left,arrive |
|
||||||
|
|
||||||
Scenario: CCW and CW roundabouts with overlaps
|
Scenario: CCW and CW roundabouts with overlaps
|
||||||
Given the node map
|
Given the node map
|
||||||
|
|||||||
@@ -961,12 +961,12 @@ Feature: Simple Turns
|
|||||||
g
|
g
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
f
|
h f
|
||||||
h .
|
.
|
||||||
. .
|
. .
|
||||||
. j
|
. j
|
||||||
. .
|
. .
|
||||||
c
|
c
|
||||||
. . .
|
. . .
|
||||||
|
|||||||
@@ -1372,3 +1372,64 @@ Feature: Simple Turns
|
|||||||
| waypoints | route | turns |
|
| waypoints | route | turns |
|
||||||
| a,d | ab,bcd,bcd | depart,fork slight right,arrive |
|
| a,d | ab,bcd,bcd | depart,fork slight right,arrive |
|
||||||
| a,g | ab,befg,befg | depart,fork slight left,arrive |
|
| a,g | ab,befg,befg | depart,fork slight left,arrive |
|
||||||
|
|
||||||
|
# https://www.openstreetmap.org/#map=18/52.25130/10.42545
|
||||||
|
Scenario: Turn for roads with no name, ref changes
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
d
|
||||||
|
.
|
||||||
|
.
|
||||||
|
e c . . f
|
||||||
|
.
|
||||||
|
.
|
||||||
|
b
|
||||||
|
.
|
||||||
|
.
|
||||||
|
a
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | ref | name |
|
||||||
|
| abc | tertiary | K 57 | |
|
||||||
|
| cd | tertiary | K 56 | |
|
||||||
|
| cf | tertiary | K 56 | |
|
||||||
|
| ce | residential | | Heinrichshöhe |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,f | ,, | depart,turn right,arrive |
|
||||||
|
|
||||||
|
# https://www.openstreetmap.org/#map=18/52.24071/10.29066
|
||||||
|
Scenario: Turn for roads with no name, ref changes
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
x
|
||||||
|
.
|
||||||
|
.
|
||||||
|
d
|
||||||
|
. .
|
||||||
|
. .
|
||||||
|
. .
|
||||||
|
e. . t . c . p. .f
|
||||||
|
. .
|
||||||
|
. .
|
||||||
|
. .
|
||||||
|
b
|
||||||
|
.
|
||||||
|
.
|
||||||
|
a
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | ref | name | oneway |
|
||||||
|
| abp | tertiary | K 23 | | yes |
|
||||||
|
| pdx | tertiary | K 23 | | yes |
|
||||||
|
| xdt | tertiary | K 23 | | yes |
|
||||||
|
| tba | tertiary | K 23 | | yes |
|
||||||
|
| etcpf | primary | B 1 | | no |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| e,x | ,,, | depart,turn sharp left,turn right,arrive |
|
||||||
|
| f,a | ,, | depart,turn left,arrive |
|
||||||
|
|||||||
@@ -150,7 +150,8 @@ module.exports = function () {
|
|||||||
}
|
}
|
||||||
var ok = true;
|
var ok = true;
|
||||||
var encodedResult = '',
|
var encodedResult = '',
|
||||||
extendedTarget = '';
|
extendedTarget = '',
|
||||||
|
resultWaypoints = [];
|
||||||
|
|
||||||
var testSubMatching = (sub, si) => {
|
var testSubMatching = (sub, si) => {
|
||||||
var testSubNode = (ni) => {
|
var testSubNode = (ni) => {
|
||||||
@@ -186,6 +187,29 @@ module.exports = function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (headers.has('waypoints')) {
|
||||||
|
var got_loc = [];
|
||||||
|
for (let i = 0; i < json.tracepoints.length; i++) {
|
||||||
|
if (!json.tracepoints[i]) continue;
|
||||||
|
if (json.tracepoints[i].waypoint_index != null)
|
||||||
|
got_loc.push(json.tracepoints[i].location);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.waypoints.length != got_loc.length)
|
||||||
|
return cb(new Error(`Expected ${row.waypoints.length} waypoints, got ${got_loc.length}`));
|
||||||
|
|
||||||
|
for (i = 0; i < row.waypoints.length; i++)
|
||||||
|
{
|
||||||
|
var want_node = this.findNodeByName(row.waypoints[i]);
|
||||||
|
if (!this.FuzzyMatch.matchLocation(got_loc[i], want_node)) {
|
||||||
|
resultWaypoints.push(util.format('? [%s,%s]', got_loc[i][0], got_loc[i][1]));
|
||||||
|
ok = false;
|
||||||
|
} else {
|
||||||
|
resultWaypoints.push(row.waypoints[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
if (headers.has('matchings')) {
|
if (headers.has('matchings')) {
|
||||||
got.matchings = row.matchings;
|
got.matchings = row.matchings;
|
||||||
@@ -194,7 +218,12 @@ module.exports = function () {
|
|||||||
if (headers.has('timestamps')) {
|
if (headers.has('timestamps')) {
|
||||||
got.timestamps = row.timestamps;
|
got.timestamps = row.timestamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (headers.has('waypoints')) {
|
||||||
|
got.waypoints = row.waypoints;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
got.waypoints = resultWaypoints.join(';');
|
||||||
got.matchings = encodedResult;
|
got.matchings = encodedResult;
|
||||||
row.matchings = extendedTarget;
|
row.matchings = extendedTarget;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ module.exports = {
|
|||||||
|
|
||||||
FuzzyMatch: class {
|
FuzzyMatch: class {
|
||||||
match (got, want) {
|
match (got, want) {
|
||||||
|
// don't fail if bearings input and extected string is empty and actual result is undefined
|
||||||
|
if (want === '' && (got === '' || got === undefined))
|
||||||
|
return true;
|
||||||
|
|
||||||
var matchPercent = want.match(/(.*)\s+~(.+)%$/),
|
var matchPercent = want.match(/(.*)\s+~(.+)%$/),
|
||||||
matchAbs = want.match(/(.*)\s+\+\-(.+)$/),
|
matchAbs = want.match(/(.*)\s+\+\-(.+)$/),
|
||||||
matchRe = want.match(/^\/(.*)\/$/),
|
matchRe = want.match(/^\/(.*)\/$/),
|
||||||
|
|||||||
@@ -59,3 +59,27 @@ Feature: Annotations
|
|||||||
| from | to | route | a:datasources | a:speed |
|
| from | to | route | a:datasources | a:speed |
|
||||||
| a | i | abcdefghi,abcdefghi | 1:0:1:0:1:0:0:0 | 50:10:50:10:50:10:10:10 |
|
| a | i | abcdefghi,abcdefghi | 1:0:1:0:1:0:0:0 | 50:10:50:10:50:10:10:10 |
|
||||||
| i | a | abcdefghi,abcdefghi | 0:1:0:0:0:0:0:1 | 10:50:10:10:10:10:10:50 |
|
| i | a | abcdefghi,abcdefghi | 0:1:0:0:0:0:0:1 | 10:50:10:10:10:10:10:50 |
|
||||||
|
|
||||||
|
Scenario: Speed annotations should handle zero segments
|
||||||
|
Given the profile "testbot"
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a -- b --- c
|
||||||
|
|
|
||||||
|
d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abc |
|
||||||
|
| cd |
|
||||||
|
|
||||||
|
# This test relies on the snapping to the EBN cd to introduce a zero segment after the turn
|
||||||
|
And the query options
|
||||||
|
| annotations | speed,distance,duration,nodes |
|
||||||
|
| bearings | 90,5;180,5 |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | a:speed | a:distance | a:duration | a:nodes |
|
||||||
|
| a | c | abc,abc | 10:10:10 | 249.998641:299.931643:0 | 25:30:0 | 1:2:3 |
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
@routing @testbot @exclude
|
||||||
|
Feature: Testbot - Exclude flags regression tests
|
||||||
|
Background:
|
||||||
|
Given the profile "testbot"
|
||||||
|
|
||||||
|
Scenario: Testbot - Exclude toll regression 1
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a g
|
||||||
|
. .
|
||||||
|
b....d-$-$-e....f
|
||||||
|
. .
|
||||||
|
c h
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | primary | | always drivable |
|
||||||
|
| cb | primary | | always drivable |
|
||||||
|
| bd | primary | | always drivable |
|
||||||
|
| de | motorway | yes | not drivable for exclude=toll |
|
||||||
|
| ef | primary | | always drivable |
|
||||||
|
| fg | primary | | always drivable |
|
||||||
|
| fh | primary | | always drivable |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| exclude | toll |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route |
|
||||||
|
| a | h | |
|
||||||
|
| a | g | |
|
||||||
|
| g | a | |
|
||||||
|
| d | e | |
|
||||||
|
|
||||||
|
Scenario: Testbot - Exclude toll regression 2
|
||||||
|
Given the profile "testbot"
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a g
|
||||||
|
. .
|
||||||
|
b....d-$-$-e....f
|
||||||
|
. .
|
||||||
|
c h..i
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | primary | | always drivable |
|
||||||
|
| cb | primary | | always drivable |
|
||||||
|
| bd | primary | | always drivable |
|
||||||
|
| de | motorway | yes | not drivable for exclude=toll |
|
||||||
|
| ef | primary | | always drivable |
|
||||||
|
| fg | primary | | always drivable |
|
||||||
|
| fh | primary | | always drivable |
|
||||||
|
| hi | primary | | always drivable |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| exclude | toll |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route |
|
||||||
|
| a | h | |
|
||||||
|
| a | g | |
|
||||||
|
| g | a | |
|
||||||
|
| d | e | |
|
||||||
|
| d | i | |
|
||||||
@@ -480,3 +480,207 @@ Feature: Basic Map Matching
|
|||||||
| trace | a:nodes |
|
| trace | a:nodes |
|
||||||
| 12 | 1:2:3:4:5:6 |
|
| 12 | 1:2:3:4:5:6 |
|
||||||
| 21 | 6:5:4:3:2:1 |
|
| 21 | 6:5:4:3:2:1 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Matching with waypoints param for start/end
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a-----b---c
|
||||||
|
|
|
||||||
|
|
|
||||||
|
d
|
||||||
|
|
|
||||||
|
|
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abc | no |
|
||||||
|
| bde | no |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;3 |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | code | matchings | waypoints |
|
||||||
|
| abde | Ok | abde | ae |
|
||||||
|
|
||||||
|
Scenario: Matching with waypoints param that were tidied away
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a - b - c - e
|
||||||
|
|
|
||||||
|
f
|
||||||
|
|
|
||||||
|
g
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abce | no |
|
||||||
|
| cfg | no |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| tidy | true |
|
||||||
|
| waypoints | 0;2;5 |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | code | matchings | waypoints |
|
||||||
|
| abccfg | Ok | abcfg | acg |
|
||||||
|
|
||||||
|
Scenario: Testbot - Map matching refuses to use waypoints with trace splitting
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;3 |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abcd | no |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | timestamps | code |
|
||||||
|
| abcd | 0 1 62 63 | NoMatch |
|
||||||
|
|
||||||
|
Scenario: Testbot - Map matching invalid waypoints
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;4 |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abcd | no |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | code |
|
||||||
|
| abcd | InvalidOptions |
|
||||||
|
|
||||||
|
Scenario: Matching fail with waypoints param missing start/end
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a-----b---c
|
||||||
|
|
|
||||||
|
|
|
||||||
|
d
|
||||||
|
|
|
||||||
|
|
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abc | no |
|
||||||
|
| bde | no |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 1;3 |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | code |
|
||||||
|
| abde | InvalidValue |
|
||||||
|
|
||||||
|
Scenario: Testbot - Map matching with outlier that has no candidate and waypoint parameter
|
||||||
|
Given a grid size of 100 meters
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
|
||||||
|
1
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abcd | no |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;2;3 |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | timestamps | code |
|
||||||
|
| ab1d | 0 1 2 3 | NoMatch |
|
||||||
|
|
||||||
|
Scenario: Regression test - avoid collapsing legs of a tidied split trace
|
||||||
|
Given a grid size of 20 meters
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a--b--f
|
||||||
|
|
|
||||||
|
|
|
||||||
|
e--c---d--g
|
||||||
|
"""
|
||||||
|
Given the query options
|
||||||
|
| tidy | true |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| abf | no |
|
||||||
|
| be | no |
|
||||||
|
| ecdg | no |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | timestamps | matchings | code |
|
||||||
|
| abbecd | 10 11 27 1516914902 1516914913 1516914952 | ab,ecd | Ok |
|
||||||
|
|
||||||
|
Scenario: Regression test - waypoints trimming too much geometry
|
||||||
|
# fixes bug in map matching collapsing that was dropping path geometries
|
||||||
|
# after segments that had 0 distance in internal route results
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
ad
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|e g
|
||||||
|
b--------------c
|
||||||
|
f h
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ab |
|
||||||
|
| bc |
|
||||||
|
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;4 |
|
||||||
|
| overview | full |
|
||||||
|
|
||||||
|
When I match I should get
|
||||||
|
| trace | geometry | code |
|
||||||
|
| defgh | 1,1,1,0.999461,1.000674,0.999461 | Ok |
|
||||||
|
|
||||||
|
@match @testbot
|
||||||
|
Scenario: Regression test - waypoints trimming too much geometry
|
||||||
|
Given the profile "testbot"
|
||||||
|
Given a grid size of 10 meters
|
||||||
|
Given the query options
|
||||||
|
| geometries | geojson |
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
bh
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
c
|
||||||
|
g\
|
||||||
|
\k
|
||||||
|
\
|
||||||
|
\
|
||||||
|
\
|
||||||
|
j f
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| hc |
|
||||||
|
| cf |
|
||||||
|
Given the query options
|
||||||
|
| waypoints | 0;3 |
|
||||||
|
| overview | full |
|
||||||
|
When I match I should get
|
||||||
|
| trace | geometry | code |
|
||||||
|
| bgkj | 1.000135,1,1.000135,0.99964,1.000387,0.999137 | Ok |
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ Feature: Via points
|
|||||||
| waypoints | route |
|
| waypoints | route |
|
||||||
| a,b,e | |
|
| a,b,e | |
|
||||||
|
|
||||||
@todo @3359
|
@3359
|
||||||
Scenario: U-Turn In Bearings
|
Scenario: U-Turn In Bearings
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_,
|
|||||||
});
|
});
|
||||||
non_core_edges.resize(new_end - non_core_edges.begin());
|
non_core_edges.resize(new_end - non_core_edges.begin());
|
||||||
edge_container.Insert(std::move(non_core_edges));
|
edge_container.Insert(std::move(non_core_edges));
|
||||||
|
|
||||||
|
for (const auto filter_index : util::irange<std::size_t>(0, filters.size()))
|
||||||
|
{
|
||||||
|
edge_container.Filter(filters[filter_index], filter_index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract core graph for further contraction
|
// Extract core graph for further contraction
|
||||||
|
|||||||
@@ -60,6 +60,25 @@ struct ContractedEdgeContainer
|
|||||||
flags.resize(edges.size(), ALL_FLAGS);
|
flags.resize(edges.size(), ALL_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Filter(const std::vector<bool> &filter, std::size_t index)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
|
||||||
|
const MergedFlags flag = 1 << index;
|
||||||
|
|
||||||
|
for (auto edge_index : util::irange<std::size_t>(0, edges.size()))
|
||||||
|
{
|
||||||
|
auto allowed = filter[edges[edge_index].source] && filter[edges[edge_index].target];
|
||||||
|
if (allowed)
|
||||||
|
{
|
||||||
|
flags[edge_index] |= flag;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags[edge_index] &= ~flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Merge(std::vector<QueryEdge> new_edges)
|
void Merge(std::vector<QueryEdge> new_edges)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
|
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
|
||||||
@@ -108,7 +127,7 @@ struct ContractedEdgeContainer
|
|||||||
edges.insert(edges.end(), new_edges.begin(), new_end);
|
edges.insert(edges.end(), new_edges.begin(), new_end);
|
||||||
auto edges_size = edges.size();
|
auto edges_size = edges.size();
|
||||||
auto new_edges_size = std::distance(new_edges.begin(), new_end);
|
auto new_edges_size = std::distance(new_edges.begin(), new_end);
|
||||||
BOOST_ASSERT(edges_size >= new_edges_size);
|
BOOST_ASSERT(static_cast<int>(edges_size) >= new_edges_size);
|
||||||
flags.resize(edges_size);
|
flags.resize(edges_size);
|
||||||
std::fill(flags.begin() + edges_size - new_edges_size, flags.end(), flag);
|
std::fill(flags.begin() + edges_size - new_edges_size, flags.end(), flag);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "util/query_heap.hpp"
|
#include "util/query_heap.hpp"
|
||||||
|
|
||||||
#include <tbb/enumerable_thread_specific.h>
|
#include <tbb/enumerable_thread_specific.h>
|
||||||
|
#include <tbb/parallel_for.h>
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ class MatchAPI final : public RouteAPI
|
|||||||
for (auto point_index : util::irange(
|
for (auto point_index : util::irange(
|
||||||
0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
|
0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
|
||||||
{
|
{
|
||||||
|
// tidied_to_original: index of the input coordinate that a tidied coordinate
|
||||||
|
// corresponds to.
|
||||||
|
// sub_matching indices: index of the coordinate passed to map matching plugin that
|
||||||
|
// a matched node corresponds to.
|
||||||
trace_idx_to_matching_idx[tidy_result
|
trace_idx_to_matching_idx[tidy_result
|
||||||
.tidied_to_original[sub_matchings[sub_matching_index]
|
.tidied_to_original[sub_matchings[sub_matching_index]
|
||||||
.indices[point_index]]] =
|
.indices[point_index]]] =
|
||||||
@@ -93,6 +97,9 @@ class MatchAPI final : public RouteAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1);
|
||||||
|
|
||||||
|
std::size_t was_waypoint_idx = 0;
|
||||||
for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||||
{
|
{
|
||||||
if (tidy_result.can_be_removed[trace_index])
|
if (tidy_result.can_be_removed[trace_index])
|
||||||
@@ -114,6 +121,20 @@ class MatchAPI final : public RouteAPI
|
|||||||
waypoint.values["alternatives_count"] =
|
waypoint.values["alternatives_count"] =
|
||||||
sub_matchings[matching_index.sub_matching_index]
|
sub_matchings[matching_index.sub_matching_index]
|
||||||
.alternatives_count[matching_index.point_index];
|
.alternatives_count[matching_index.point_index];
|
||||||
|
// waypoint indices need to be adjusted if route legs were collapsed
|
||||||
|
// waypoint parameter assumes there is only one match object
|
||||||
|
if (!parameters.waypoints.empty())
|
||||||
|
{
|
||||||
|
if (tidy_result.was_waypoint[trace_index])
|
||||||
|
{
|
||||||
|
waypoint.values["waypoint_index"] = was_waypoint_idx;
|
||||||
|
was_waypoint_idx++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
waypoint.values["waypoint_index"] = util::json::Null();
|
||||||
|
}
|
||||||
|
}
|
||||||
waypoints.values.push_back(std::move(waypoint));
|
waypoints.values.push_back(std::move(waypoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,25 +63,40 @@ struct MatchParameters : public RouteParameters
|
|||||||
RouteParameters::GeometriesType::Polyline,
|
RouteParameters::GeometriesType::Polyline,
|
||||||
RouteParameters::OverviewType::Simplified,
|
RouteParameters::OverviewType::Simplified,
|
||||||
{}),
|
{}),
|
||||||
gaps(GapsType::Split), tidy(false)
|
gaps(GapsType::Split), tidy(false), waypoints()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
MatchParameters(std::vector<unsigned> timestamps_, GapsType gaps_, bool tidy_, Args... args_)
|
MatchParameters(std::vector<unsigned> timestamps_, GapsType gaps_, bool tidy_, Args... args_)
|
||||||
|
: MatchParameters(std::move(timestamps_), gaps_, tidy_, {}, std::forward<Args>(args_)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
MatchParameters(std::vector<unsigned> timestamps_,
|
||||||
|
GapsType gaps_,
|
||||||
|
bool tidy_,
|
||||||
|
std::vector<std::size_t> waypoints_,
|
||||||
|
Args... args_)
|
||||||
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)},
|
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)},
|
||||||
gaps(gaps_), tidy(tidy_)
|
gaps(gaps_), tidy(tidy_), waypoints{std::move(waypoints_)}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned> timestamps;
|
std::vector<unsigned> timestamps;
|
||||||
GapsType gaps;
|
GapsType gaps;
|
||||||
bool tidy;
|
bool tidy;
|
||||||
|
std::vector<std::size_t> waypoints;
|
||||||
|
|
||||||
bool IsValid() const
|
bool IsValid() const
|
||||||
{
|
{
|
||||||
|
const auto valid_waypoints =
|
||||||
|
std::all_of(waypoints.begin(), waypoints.end(), [this](const auto &w) {
|
||||||
|
return w < coordinates.size();
|
||||||
|
});
|
||||||
return RouteParameters::IsValid() &&
|
return RouteParameters::IsValid() &&
|
||||||
(timestamps.empty() || timestamps.size() == coordinates.size());
|
(timestamps.empty() || timestamps.size() == coordinates.size()) && valid_waypoints;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ struct Result
|
|||||||
Mask can_be_removed;
|
Mask can_be_removed;
|
||||||
// Maps the MatchParameter's original items to items which should not be removed.
|
// Maps the MatchParameter's original items to items which should not be removed.
|
||||||
Mapping tidied_to_original;
|
Mapping tidied_to_original;
|
||||||
|
// Masking the MatchParameter coordinates for items whose indices were present in the
|
||||||
|
// `waypoints` parameter.
|
||||||
|
Mask was_waypoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Result keep_all(const MatchParameters ¶ms)
|
inline Result keep_all(const MatchParameters ¶ms)
|
||||||
@@ -44,6 +47,17 @@ inline Result keep_all(const MatchParameters ¶ms)
|
|||||||
Result result;
|
Result result;
|
||||||
|
|
||||||
result.can_be_removed.resize(params.coordinates.size(), false);
|
result.can_be_removed.resize(params.coordinates.size(), false);
|
||||||
|
result.was_waypoint.resize(params.coordinates.size(), true);
|
||||||
|
// by default all input coordinates are treated as waypoints
|
||||||
|
if (!params.waypoints.empty())
|
||||||
|
{
|
||||||
|
for (const auto p : params.waypoints)
|
||||||
|
{
|
||||||
|
result.was_waypoint.set(p, false);
|
||||||
|
}
|
||||||
|
// logic is a little funny, uses inversion to set the bitfield
|
||||||
|
result.was_waypoint.flip();
|
||||||
|
}
|
||||||
result.tidied_to_original.reserve(params.coordinates.size());
|
result.tidied_to_original.reserve(params.coordinates.size());
|
||||||
for (std::size_t current = 0; current < params.coordinates.size(); ++current)
|
for (std::size_t current = 0; current < params.coordinates.size(); ++current)
|
||||||
{
|
{
|
||||||
@@ -61,6 +75,8 @@ inline Result keep_all(const MatchParameters ¶ms)
|
|||||||
{
|
{
|
||||||
result.parameters.coordinates.push_back(params.coordinates[i]);
|
result.parameters.coordinates.push_back(params.coordinates[i]);
|
||||||
|
|
||||||
|
if (result.was_waypoint[i])
|
||||||
|
result.parameters.waypoints.push_back(result.parameters.coordinates.size() - 1);
|
||||||
if (!params.hints.empty())
|
if (!params.hints.empty())
|
||||||
result.parameters.hints.push_back(params.hints[i]);
|
result.parameters.hints.push_back(params.hints[i]);
|
||||||
|
|
||||||
@@ -74,6 +90,8 @@ inline Result keep_all(const MatchParameters ¶ms)
|
|||||||
result.parameters.timestamps.push_back(params.timestamps[i]);
|
result.parameters.timestamps.push_back(params.timestamps[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (params.waypoints.empty())
|
||||||
|
result.parameters.waypoints.clear();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -85,6 +103,15 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5})
|
|||||||
Result result;
|
Result result;
|
||||||
|
|
||||||
result.can_be_removed.resize(params.coordinates.size(), false);
|
result.can_be_removed.resize(params.coordinates.size(), false);
|
||||||
|
result.was_waypoint.resize(params.coordinates.size(), true);
|
||||||
|
if (!params.waypoints.empty())
|
||||||
|
{
|
||||||
|
for (const auto p : params.waypoints)
|
||||||
|
{
|
||||||
|
result.was_waypoint.set(p, false);
|
||||||
|
}
|
||||||
|
result.was_waypoint.flip();
|
||||||
|
}
|
||||||
|
|
||||||
result.tidied_to_original.push_back(0);
|
result.tidied_to_original.push_back(0);
|
||||||
|
|
||||||
@@ -138,13 +165,14 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5})
|
|||||||
|
|
||||||
// We have to filter parallel arrays that may be empty or the exact same size.
|
// We have to filter parallel arrays that may be empty or the exact same size.
|
||||||
// result.parameters contains an empty MatchParameters at this point: conditionally fill.
|
// result.parameters contains an empty MatchParameters at this point: conditionally fill.
|
||||||
|
|
||||||
for (std::size_t i = 0; i < result.can_be_removed.size(); ++i)
|
for (std::size_t i = 0; i < result.can_be_removed.size(); ++i)
|
||||||
{
|
{
|
||||||
if (!result.can_be_removed[i])
|
if (!result.can_be_removed[i])
|
||||||
{
|
{
|
||||||
result.parameters.coordinates.push_back(params.coordinates[i]);
|
result.parameters.coordinates.push_back(params.coordinates[i]);
|
||||||
|
|
||||||
|
if (result.was_waypoint[i])
|
||||||
|
result.parameters.waypoints.push_back(result.parameters.coordinates.size() - 1);
|
||||||
if (!params.hints.empty())
|
if (!params.hints.empty())
|
||||||
result.parameters.hints.push_back(params.hints[i]);
|
result.parameters.hints.push_back(params.hints[i]);
|
||||||
|
|
||||||
@@ -157,8 +185,17 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5})
|
|||||||
if (!params.timestamps.empty())
|
if (!params.timestamps.empty())
|
||||||
result.parameters.timestamps.push_back(params.timestamps[i]);
|
result.parameters.timestamps.push_back(params.timestamps[i]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// one of the coordinates meant to be used as a waypoint was marked for removal
|
||||||
|
// update the original waypoint index to the new representative coordinate
|
||||||
|
const auto last_idx = result.parameters.coordinates.size() - 1;
|
||||||
|
if (result.was_waypoint[i] && (result.parameters.waypoints.back() != last_idx))
|
||||||
|
{
|
||||||
|
result.parameters.waypoints.push_back(last_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(result.tidied_to_original.size() == result.parameters.coordinates.size());
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,11 +88,12 @@ class RouteAPI : public BaseAPI
|
|||||||
{
|
{
|
||||||
util::json::Array annotations_store;
|
util::json::Array annotations_store;
|
||||||
annotations_store.values.reserve(leg.annotations.size());
|
annotations_store.values.reserve(leg.annotations.size());
|
||||||
std::for_each(leg.annotations.begin(),
|
|
||||||
leg.annotations.end(),
|
for (const auto &step : leg.annotations)
|
||||||
[Get, &annotations_store](const auto &step) {
|
{
|
||||||
annotations_store.values.push_back(Get(step));
|
annotations_store.values.push_back(Get(step));
|
||||||
});
|
}
|
||||||
|
|
||||||
return annotations_store;
|
return annotations_store;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,10 +256,19 @@ class RouteAPI : public BaseAPI
|
|||||||
// AnnotationsType uses bit flags, & operator checks if a property is set
|
// AnnotationsType uses bit flags, & operator checks if a property is set
|
||||||
if (parameters.annotations_type & RouteParameters::AnnotationsType::Speed)
|
if (parameters.annotations_type & RouteParameters::AnnotationsType::Speed)
|
||||||
{
|
{
|
||||||
|
double prev_speed = 0;
|
||||||
annotation.values["speed"] = GetAnnotations(
|
annotation.values["speed"] = GetAnnotations(
|
||||||
leg_geometry, [](const guidance::LegGeometry::Annotation &anno) {
|
leg_geometry, [&prev_speed](const guidance::LegGeometry::Annotation &anno) {
|
||||||
auto val = std::round(anno.distance / anno.duration * 10.) / 10.;
|
if (anno.duration < std::numeric_limits<double>::min())
|
||||||
return util::json::clamp_float(val);
|
{
|
||||||
|
return prev_speed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto speed = std::round(anno.distance / anno.duration * 10.) / 10.;
|
||||||
|
prev_speed = speed;
|
||||||
|
return util::json::clamp_float(speed);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,11 +303,10 @@ class RouteAPI : public BaseAPI
|
|||||||
{
|
{
|
||||||
util::json::Array nodes;
|
util::json::Array nodes;
|
||||||
nodes.values.reserve(leg_geometry.osm_node_ids.size());
|
nodes.values.reserve(leg_geometry.osm_node_ids.size());
|
||||||
std::for_each(leg_geometry.osm_node_ids.begin(),
|
for (const auto node_id : leg_geometry.osm_node_ids)
|
||||||
leg_geometry.osm_node_ids.end(),
|
{
|
||||||
[this, &nodes](const OSMNodeID &node_id) {
|
nodes.values.push_back(static_cast<std::uint64_t>(node_id));
|
||||||
nodes.values.push_back(static_cast<std::uint64_t>(node_id));
|
}
|
||||||
});
|
|
||||||
annotation.values["nodes"] = std::move(nodes);
|
annotation.values["nodes"] = std::move(nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,12 +53,12 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Engine(const EngineConfig &config)
|
explicit Engine(const EngineConfig &config)
|
||||||
: route_plugin(config.max_locations_viaroute, config.max_alternatives), //
|
: route_plugin(config.max_locations_viaroute, config.max_alternatives), //
|
||||||
table_plugin(config.max_locations_distance_table), //
|
table_plugin(config.max_locations_distance_table), //
|
||||||
nearest_plugin(config.max_results_nearest), //
|
nearest_plugin(config.max_results_nearest), //
|
||||||
trip_plugin(config.max_locations_trip), //
|
trip_plugin(config.max_locations_trip), //
|
||||||
match_plugin(config.max_locations_map_matching), //
|
match_plugin(config.max_locations_map_matching, config.max_radius_map_matching), //
|
||||||
tile_plugin() //
|
tile_plugin() //
|
||||||
|
|
||||||
{
|
{
|
||||||
if (config.use_shared_memory)
|
if (config.use_shared_memory)
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ struct EngineConfig final
|
|||||||
int max_locations_viaroute = -1;
|
int max_locations_viaroute = -1;
|
||||||
int max_locations_distance_table = -1;
|
int max_locations_distance_table = -1;
|
||||||
int max_locations_map_matching = -1;
|
int max_locations_map_matching = -1;
|
||||||
|
double max_radius_map_matching = -1.0;
|
||||||
int max_results_nearest = -1;
|
int max_results_nearest = -1;
|
||||||
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
||||||
bool use_shared_memory = true;
|
bool use_shared_memory = true;
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
|||||||
leg_geometry.locations.size() - 1,
|
leg_geometry.locations.size() - 1,
|
||||||
leg_geometry.locations.size(),
|
leg_geometry.locations.size(),
|
||||||
{intersection},
|
{intersection},
|
||||||
facade.IsLeftHandDriving(source_node_id)});
|
facade.IsLeftHandDriving(target_node_id)});
|
||||||
|
|
||||||
BOOST_ASSERT(steps.front().intersections.size() == 1);
|
BOOST_ASSERT(steps.front().intersections.size() == 1);
|
||||||
BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1);
|
BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1);
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
#include "engine/phantom_node.hpp"
|
#include "engine/phantom_node.hpp"
|
||||||
|
|
||||||
#include "osrm/coordinate.hpp"
|
#include "util/coordinate.hpp"
|
||||||
|
|
||||||
#include "util/guidance/entry_class.hpp"
|
#include "util/guidance/entry_class.hpp"
|
||||||
#include "util/guidance/turn_bearing.hpp"
|
#include "util/guidance/turn_bearing.hpp"
|
||||||
#include "util/guidance/turn_lanes.hpp"
|
#include "util/guidance/turn_lanes.hpp"
|
||||||
|
#include "util/integer_range.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -102,6 +102,53 @@ struct InternalManyRoutesResult
|
|||||||
|
|
||||||
std::vector<InternalRouteResult> routes;
|
std::vector<InternalRouteResult> routes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult &leggy_result,
|
||||||
|
const std::vector<bool> &is_waypoint)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(leggy_result.is_valid());
|
||||||
|
BOOST_ASSERT(is_waypoint[0]); // first and last coords
|
||||||
|
BOOST_ASSERT(is_waypoint.back()); // should always be waypoints
|
||||||
|
// Nothing to collapse! return result as is
|
||||||
|
if (leggy_result.unpacked_path_segments.size() == 1)
|
||||||
|
return leggy_result;
|
||||||
|
|
||||||
|
BOOST_ASSERT(leggy_result.segment_end_coordinates.size() > 1);
|
||||||
|
|
||||||
|
InternalRouteResult collapsed;
|
||||||
|
collapsed.shortest_path_weight = leggy_result.shortest_path_weight;
|
||||||
|
for (auto i : util::irange<std::size_t>(0, leggy_result.unpacked_path_segments.size()))
|
||||||
|
{
|
||||||
|
if (is_waypoint[i])
|
||||||
|
{
|
||||||
|
// start another leg vector
|
||||||
|
collapsed.unpacked_path_segments.push_back(leggy_result.unpacked_path_segments[i]);
|
||||||
|
// save new phantom node pair
|
||||||
|
collapsed.segment_end_coordinates.push_back(leggy_result.segment_end_coordinates[i]);
|
||||||
|
// save data about phantom nodes
|
||||||
|
collapsed.source_traversed_in_reverse.push_back(
|
||||||
|
leggy_result.source_traversed_in_reverse[i]);
|
||||||
|
collapsed.target_traversed_in_reverse.push_back(
|
||||||
|
leggy_result.target_traversed_in_reverse[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// no new leg, collapse the next segment into the last leg
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!collapsed.unpacked_path_segments.empty());
|
||||||
|
auto &last_segment = collapsed.unpacked_path_segments.back();
|
||||||
|
BOOST_ASSERT(!collapsed.segment_end_coordinates.empty());
|
||||||
|
collapsed.segment_end_coordinates.back().target_phantom =
|
||||||
|
leggy_result.segment_end_coordinates[i].target_phantom;
|
||||||
|
collapsed.target_traversed_in_reverse.back() =
|
||||||
|
leggy_result.target_traversed_in_reverse[i];
|
||||||
|
// copy path segments into current leg
|
||||||
|
last_segment.insert(last_segment.end(),
|
||||||
|
leggy_result.unpacked_path_segments[i].begin(),
|
||||||
|
leggy_result.unpacked_path_segments[i].end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collapsed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ class MatchPlugin : public BasePlugin
|
|||||||
using CandidateLists = routing_algorithms::CandidateLists;
|
using CandidateLists = routing_algorithms::CandidateLists;
|
||||||
static const constexpr double RADIUS_MULTIPLIER = 3;
|
static const constexpr double RADIUS_MULTIPLIER = 3;
|
||||||
|
|
||||||
MatchPlugin(const int max_locations_map_matching)
|
MatchPlugin(const int max_locations_map_matching, const double max_radius_map_matching)
|
||||||
: max_locations_map_matching(max_locations_map_matching)
|
: max_locations_map_matching(max_locations_map_matching),
|
||||||
|
max_radius_map_matching(max_radius_map_matching)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ class MatchPlugin : public BasePlugin
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const int max_locations_map_matching;
|
const int max_locations_map_matching;
|
||||||
|
const double max_radius_map_matching;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ struct ExtractionTurn
|
|||||||
const bool is_left_hand_driving;
|
const bool is_left_hand_driving;
|
||||||
double weight;
|
double weight;
|
||||||
double duration;
|
double duration;
|
||||||
TravelMode source_mode;
|
const TravelMode source_mode;
|
||||||
TravelMode target_mode;
|
const TravelMode target_mode;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ namespace extractor
|
|||||||
|
|
||||||
class ScriptingEnvironment;
|
class ScriptingEnvironment;
|
||||||
struct ProfileProperties;
|
struct ProfileProperties;
|
||||||
class NodeBasedGraphFactory;
|
|
||||||
|
|
||||||
class Extractor
|
class Extractor
|
||||||
{
|
{
|
||||||
@@ -102,13 +101,6 @@ class Extractor
|
|||||||
void WriteConditionalRestrictions(
|
void WriteConditionalRestrictions(
|
||||||
const std::string &path,
|
const std::string &path,
|
||||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||||
|
|
||||||
// Find all "segregated" edges, e.g. edges that can be skipped in turn instructions.
|
|
||||||
// The main cases are:
|
|
||||||
// - middle edges between two osm ways in one logic road (U-turn)
|
|
||||||
// - staggered intersections (X-cross)
|
|
||||||
// - square/circle intersections
|
|
||||||
std::unordered_set<EdgeID> FindSegregatedNodes(NodeBasedGraphFactory &factory);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ operator()(const NodeID intersection_node,
|
|||||||
const boost::optional<util::json::Object> &way_style) const
|
const boost::optional<util::json::Object> &way_style) const
|
||||||
{
|
{
|
||||||
// request the number of lanes. This process needs to be in sync with what happens over at
|
// request the number of lanes. This process needs to be in sync with what happens over at
|
||||||
// intersection_generator
|
// intersection analysis
|
||||||
const auto intersection_lanes =
|
const auto intersection_lanes =
|
||||||
intersection.FindMaximum(guidance::makeExtractLanesForRoad(node_based_graph));
|
intersection.FindMaximum(guidance::makeExtractLanesForRoad(node_based_graph));
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,13 @@ namespace guidance
|
|||||||
class DrivewayHandler final : public IntersectionHandler
|
class DrivewayHandler final : public IntersectionHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DrivewayHandler(const IntersectionGenerator &intersection_generator,
|
DrivewayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||||
|
|
||||||
|
#include "extractor/guidance/constants.hpp"
|
||||||
|
#include "extractor/suffix_table.hpp"
|
||||||
|
#include "util/name_table.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if two name ids can be seen as identical (in presence of refs/others)
|
||||||
|
// in our case this translates into no name announcement in either direction (lhs->rhs and
|
||||||
|
// rhs->lhs)
|
||||||
|
bool HaveIdenticalNames(const NameID lhs,
|
||||||
|
const NameID rhs,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif /*OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_*/
|
||||||
@@ -44,14 +44,6 @@ inline auto makeCompareShapeDataByBearing(const double base_bearing)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto makeCompareShapeDataAngleToBearing(const double base_bearing)
|
|
||||||
{
|
|
||||||
return [base_bearing](const auto &lhs, const auto &rhs) {
|
|
||||||
return util::bearing::angleBetween(lhs.bearing, base_bearing) <
|
|
||||||
util::bearing::angleBetween(rhs.bearing, base_bearing);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto makeCompareAngularDeviation(const double angle)
|
inline auto makeCompareAngularDeviation(const double angle)
|
||||||
{
|
{
|
||||||
return [angle](const auto &lhs, const auto &rhs) {
|
return [angle](const auto &lhs, const auto &rhs) {
|
||||||
@@ -301,10 +293,11 @@ struct IntersectionView final : std::vector<IntersectionViewData>, //
|
|||||||
};
|
};
|
||||||
|
|
||||||
// `Intersection` is a relative view of an intersection by an incoming edge.
|
// `Intersection` is a relative view of an intersection by an incoming edge.
|
||||||
// `Intersection` are streets at an intersection ordered from from sharp right counter-clockwise to
|
// `Intersection` are streets at an intersection stored as an ordered list of connected roads
|
||||||
|
// ordered from sharp right counter-clockwise to
|
||||||
// sharp left where `intersection[0]` is _always_ a u-turn
|
// sharp left where `intersection[0]` is _always_ a u-turn
|
||||||
|
|
||||||
// An intersection is an ordered list of connected roads ordered from from sharp right
|
// An intersection is an ordered list of connected roads ordered from sharp right
|
||||||
// counter-clockwise to sharp left where `intersection[0]` is always a u-turn
|
// counter-clockwise to sharp left where `intersection[0]` is always a u-turn
|
||||||
//
|
//
|
||||||
// |
|
// |
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_
|
|
||||||
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_
|
|
||||||
|
|
||||||
#include "extractor/compressed_edge_container.hpp"
|
|
||||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
|
||||||
#include "extractor/guidance/intersection_normalization_operation.hpp"
|
|
||||||
#include "extractor/query_node.hpp"
|
|
||||||
#include "extractor/restriction_index.hpp"
|
|
||||||
#include "util/attributes.hpp"
|
|
||||||
#include "util/node_based_graph.hpp"
|
|
||||||
#include "util/typedefs.hpp"
|
|
||||||
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace extractor
|
|
||||||
{
|
|
||||||
namespace guidance
|
|
||||||
{
|
|
||||||
|
|
||||||
struct IntersectionGenerationParameters
|
|
||||||
{
|
|
||||||
NodeID nid;
|
|
||||||
EdgeID via_eid;
|
|
||||||
};
|
|
||||||
|
|
||||||
// The Intersection Generator is given a turn location and generates an intersection representation
|
|
||||||
// from it. For this all turn possibilities are analysed.
|
|
||||||
// We consider turn restrictions to indicate possible turns. U-turns are generated based on profile
|
|
||||||
// decisions.
|
|
||||||
class IntersectionGenerator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IntersectionGenerator(const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
|
||||||
const RestrictionMap &restriction_map,
|
|
||||||
const std::unordered_set<NodeID> &barrier_nodes,
|
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
|
||||||
const CompressedEdgeContainer &compressed_edge_container);
|
|
||||||
|
|
||||||
// For a source node `a` and a via edge `ab` creates an intersection at target `b`.
|
|
||||||
//
|
|
||||||
// a . . . b . .
|
|
||||||
// .
|
|
||||||
// .
|
|
||||||
//
|
|
||||||
IntersectionView operator()(const NodeID nid, const EdgeID via_eid) const;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute the shape of an intersection, returning a set of connected roads, without any further
|
|
||||||
* concern for which of the entries are actually allowed.
|
|
||||||
* The shape also only comes with turn bearings, not with turn angles. All turn angles will be
|
|
||||||
* set to zero
|
|
||||||
*/
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
IntersectionShape
|
|
||||||
ComputeIntersectionShape(const NodeID center_node,
|
|
||||||
const boost::optional<NodeID> sorting_base = boost::none,
|
|
||||||
bool use_low_precision_angles = false) const;
|
|
||||||
|
|
||||||
// Graph Compression cannot compress every setting. For example any barrier/traffic light cannot
|
|
||||||
// be compressed. As a result, a simple road of the form `a ----- b` might end up as having an
|
|
||||||
// intermediate intersection, if there is a traffic light in between. If we want to look farther
|
|
||||||
// down a road, finding the next actual decision requires the look at multiple intersections.
|
|
||||||
// Here we follow the road until we either reach a dead end or find the next intersection with
|
|
||||||
// more than a single next road. This function skips over degree two nodes to find coorect input
|
|
||||||
// for GetConnectedRoads.
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
IntersectionGenerationParameters SkipDegreeTwoNodes(const NodeID starting_node,
|
|
||||||
const EdgeID via_edge) const;
|
|
||||||
|
|
||||||
// Allow access to the coordinate extractor for all owners
|
|
||||||
const CoordinateExtractor &GetCoordinateExtractor() const;
|
|
||||||
|
|
||||||
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
|
|
||||||
// the node reached from `from_node` via `via_eid`. The resulting candidates have to be analysed
|
|
||||||
// for their actual instructions later on.
|
|
||||||
// The switch for `use_low_precision_angles` enables a faster mode that will procude less
|
|
||||||
// accurate coordinates. It should be good enough to check order of turns, find straightmost
|
|
||||||
// turns. Even good enough to do some simple angle verifications. It is mostly available to
|
|
||||||
// allow for faster graph traversal in the extraction phase.
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
IntersectionView GetConnectedRoads(const NodeID from_node,
|
|
||||||
const EdgeID via_eid,
|
|
||||||
const bool use_low_precision_angles = false) const;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To be used in the road network, we need to check for valid/restricted turns. These two
|
|
||||||
* functions transform a basic intersection / a normalised intersection into the
|
|
||||||
* correct view when entering via a given edge.
|
|
||||||
*/
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
IntersectionView
|
|
||||||
TransformIntersectionShapeIntoView(const NodeID previous_node,
|
|
||||||
const EdgeID entering_via_edge,
|
|
||||||
const IntersectionShape &intersection) const;
|
|
||||||
// version for normalised intersection
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
IntersectionView TransformIntersectionShapeIntoView(
|
|
||||||
const NodeID previous_node,
|
|
||||||
const EdgeID entering_via_edge,
|
|
||||||
const IntersectionShape &normalised_intersection,
|
|
||||||
const IntersectionShape &intersection,
|
|
||||||
const std::vector<IntersectionNormalizationOperation> &merging_map) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container;
|
|
||||||
const RestrictionMap &restriction_map;
|
|
||||||
const std::unordered_set<NodeID> &barrier_nodes;
|
|
||||||
const std::vector<util::Coordinate> &coordinates;
|
|
||||||
|
|
||||||
// own state, used to find the correct coordinates along a road
|
|
||||||
const CoordinateExtractor coordinate_extractor;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace guidance
|
|
||||||
} // namespace extractor
|
|
||||||
} // namespace osrm
|
|
||||||
|
|
||||||
#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_ */
|
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_
|
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_
|
||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/node_based_graph_walker.hpp"
|
#include "extractor/guidance/node_based_graph_walker.hpp"
|
||||||
|
#include "extractor/intersection/intersection_analysis.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
#include "extractor/suffix_table.hpp"
|
#include "extractor/suffix_table.hpp"
|
||||||
|
|
||||||
@@ -34,10 +34,13 @@ class IntersectionHandler
|
|||||||
public:
|
public:
|
||||||
IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table,
|
const SuffixTable &street_name_suffix_table);
|
||||||
const IntersectionGenerator &intersection_generator);
|
|
||||||
|
|
||||||
virtual ~IntersectionHandler() = default;
|
virtual ~IntersectionHandler() = default;
|
||||||
|
|
||||||
@@ -52,15 +55,20 @@ class IntersectionHandler
|
|||||||
protected:
|
protected:
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
const EdgeBasedNodeDataContainer &node_data_container;
|
const EdgeBasedNodeDataContainer &node_data_container;
|
||||||
const std::vector<util::Coordinate> &coordinates;
|
const std::vector<util::Coordinate> &node_coordinates;
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||||
|
const RestrictionMap &node_restriction_map;
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes;
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data;
|
||||||
const util::NameTable &name_table;
|
const util::NameTable &name_table;
|
||||||
const SuffixTable &street_name_suffix_table;
|
const SuffixTable &street_name_suffix_table;
|
||||||
const IntersectionGenerator &intersection_generator;
|
|
||||||
const NodeBasedGraphWalker graph_walker; // for skipping traffic signal, distances etc.
|
const NodeBasedGraphWalker graph_walker; // for skipping traffic signal, distances etc.
|
||||||
|
|
||||||
// Decide on a basic turn types
|
// Decide on a basic turn types
|
||||||
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
|
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
|
||||||
|
|
||||||
|
TurnType::Enum areSameClasses(const EdgeID via_edge, const ConnectedRoad &road) const;
|
||||||
|
|
||||||
// Find the most obvious turn to follow. The function returns an index into the intersection
|
// Find the most obvious turn to follow. The function returns an index into the intersection
|
||||||
// determining whether there is a road that can be seen as obvious turn in the presence of many
|
// determining whether there is a road that can be seen as obvious turn in the presence of many
|
||||||
// other possible turns. The function will consider road categories and other inputs like the
|
// other possible turns. The function will consider road categories and other inputs like the
|
||||||
@@ -90,9 +98,6 @@ class IntersectionHandler
|
|||||||
const std::size_t begin,
|
const std::size_t begin,
|
||||||
const std::size_t end) const;
|
const std::size_t end) const;
|
||||||
|
|
||||||
// Checks the intersection for a through street connected to `intersection[index]`
|
|
||||||
bool isThroughStreet(const std::size_t index, const Intersection &intersection) const;
|
|
||||||
|
|
||||||
// See `getNextIntersection`
|
// See `getNextIntersection`
|
||||||
struct IntersectionViewAndNode final
|
struct IntersectionViewAndNode final
|
||||||
{
|
{
|
||||||
@@ -567,11 +572,19 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
|||||||
// try to find whether there is a turn going to the opposite direction of our obvious
|
// try to find whether there is a turn going to the opposite direction of our obvious
|
||||||
// turn, this should be alright.
|
// turn, this should be alright.
|
||||||
const auto previous_intersection = [&]() -> IntersectionView {
|
const auto previous_intersection = [&]() -> IntersectionView {
|
||||||
const auto parameters = intersection_generator.SkipDegreeTwoNodes(
|
const auto parameters = intersection::skipDegreeTwoNodes(
|
||||||
node_at_intersection, intersection[0].eid);
|
node_based_graph, {node_at_intersection, intersection[0].eid});
|
||||||
if (node_based_graph.GetTarget(parameters.via_eid) == node_at_intersection)
|
if (node_based_graph.GetTarget(parameters.edge) == node_at_intersection)
|
||||||
return {};
|
return {};
|
||||||
return intersection_generator.GetConnectedRoads(parameters.nid, parameters.via_eid);
|
|
||||||
|
return intersection::getConnectedRoads<false>(node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
|
parameters);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (!previous_intersection.empty())
|
if (!previous_intersection.empty())
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZATION_OPERATION_HPP_
|
|
||||||
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZATION_OPERATION_HPP_
|
|
||||||
|
|
||||||
#include "util/typedefs.hpp"
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace extractor
|
|
||||||
{
|
|
||||||
namespace guidance
|
|
||||||
{
|
|
||||||
|
|
||||||
struct IntersectionNormalizationOperation
|
|
||||||
{
|
|
||||||
// the source of the merge, not part of the intersection after the merge is performed.
|
|
||||||
EdgeID merged_eid;
|
|
||||||
// the edge that is covering the `merged_eid`
|
|
||||||
EdgeID into_eid;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace guidance
|
|
||||||
} // namespace extractor
|
|
||||||
} // namespace osrm
|
|
||||||
|
|
||||||
#endif /*OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZATION_OPERATION_HPP_*/
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
|
|
||||||
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
|
|
||||||
|
|
||||||
#include "util/attributes.hpp"
|
|
||||||
#include "util/name_table.hpp"
|
|
||||||
#include "util/typedefs.hpp"
|
|
||||||
|
|
||||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/intersection_normalization_operation.hpp"
|
|
||||||
#include "extractor/guidance/mergable_road_detector.hpp"
|
|
||||||
#include "extractor/query_node.hpp"
|
|
||||||
#include "extractor/suffix_table.hpp"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace extractor
|
|
||||||
{
|
|
||||||
namespace guidance
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
|
||||||
* An intersection is a central part in computing guidance decisions. However the model in OSM and
|
|
||||||
* the view we want to use in guidance are not necessarily the same thing. We have to account for
|
|
||||||
* some models that are chosen explicitly in OSM and that don't actually describe how a human would
|
|
||||||
* experience an intersection.
|
|
||||||
*
|
|
||||||
* For example, if a small pedestrian island is located at a traffic light right in the middle of a
|
|
||||||
* road, OSM tends to model the road as two separate ways. A human would consider these two ways a
|
|
||||||
* single road, though. In this normalizer, we try to account for these subtle differences between
|
|
||||||
* OSM data and human perception to improve our decision base for guidance later on.
|
|
||||||
*/
|
|
||||||
class IntersectionNormalizer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct NormalizationResult
|
|
||||||
{
|
|
||||||
IntersectionShape normalized_shape;
|
|
||||||
std::vector<IntersectionNormalizationOperation> performed_merges;
|
|
||||||
};
|
|
||||||
IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
|
||||||
const std::vector<util::Coordinate> &node_coordinates,
|
|
||||||
const util::NameTable &name_table,
|
|
||||||
const SuffixTable &street_name_suffix_table,
|
|
||||||
const IntersectionGenerator &intersection_generator);
|
|
||||||
|
|
||||||
// The function takes an intersection an converts it to a `perceived` intersection which closer
|
|
||||||
// represents how a human might experience the intersection
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
NormalizationResult operator()(const NodeID node_at_intersection,
|
|
||||||
IntersectionShape intersection) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
|
||||||
const IntersectionGenerator &intersection_generator;
|
|
||||||
const MergableRoadDetector mergable_road_detector;
|
|
||||||
|
|
||||||
/* check if two indices in an intersection can be seen as a single road in the perceived
|
|
||||||
* intersection representation. See below for an example. Utility function for
|
|
||||||
* MergeSegregatedRoads. It also checks for neighboring merges.
|
|
||||||
* This is due possible segments where multiple roads could end up being merged into one.
|
|
||||||
* We only support merging two roads, not three or more, though.
|
|
||||||
* c c
|
|
||||||
* / /
|
|
||||||
* a - b -> a - b - (c,d) but not a - b d -> a,b,(cde)
|
|
||||||
* \ \
|
|
||||||
* d e
|
|
||||||
*/
|
|
||||||
bool CanMerge(const NodeID intersection_node,
|
|
||||||
const IntersectionShape &intersection,
|
|
||||||
std::size_t first_index,
|
|
||||||
std::size_t second_index) const;
|
|
||||||
|
|
||||||
// Perform an Actual Merge
|
|
||||||
IntersectionNormalizationOperation
|
|
||||||
DetermineMergeDirection(const IntersectionShapeData &lhs,
|
|
||||||
const IntersectionShapeData &rhs) const;
|
|
||||||
IntersectionShapeData MergeRoads(const IntersectionShapeData &destination,
|
|
||||||
const IntersectionShapeData &source) const;
|
|
||||||
IntersectionShapeData MergeRoads(const IntersectionNormalizationOperation direction,
|
|
||||||
const IntersectionShapeData &lhs,
|
|
||||||
const IntersectionShapeData &rhs,
|
|
||||||
const double opposite_bearing) const;
|
|
||||||
|
|
||||||
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
|
|
||||||
// one.
|
|
||||||
// This function combines roads the following way:
|
|
||||||
//
|
|
||||||
// * *
|
|
||||||
// * is converted to *
|
|
||||||
// v ^ +
|
|
||||||
// v ^ +
|
|
||||||
//
|
|
||||||
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
|
|
||||||
// 160
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
NormalizationResult MergeSegregatedRoads(const NodeID intersection_node,
|
|
||||||
IntersectionShape intersection) const;
|
|
||||||
|
|
||||||
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
|
|
||||||
// intersection itself, it can also happen that intersections are connected to joining roads.
|
|
||||||
//
|
|
||||||
// * *
|
|
||||||
// * is converted to *
|
|
||||||
// v a --- a ---
|
|
||||||
// v ^ +
|
|
||||||
// v ^ +
|
|
||||||
// b
|
|
||||||
//
|
|
||||||
// for the local view of b at a.
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
IntersectionShape AdjustBearingsForMergeAtDestination(const NodeID node_at_intersection,
|
|
||||||
IntersectionShape intersection) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace guidance
|
|
||||||
} // namespace extractor
|
|
||||||
} // namespace osrm
|
|
||||||
|
|
||||||
#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_ */
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_
|
||||||
|
|
||||||
|
#include "extractor/guidance/constants.hpp"
|
||||||
|
#include "extractor/suffix_table.hpp"
|
||||||
|
#include "util/guidance/name_announcements.hpp"
|
||||||
|
|
||||||
|
using osrm::util::angularDeviation;
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename IntersectionType>
|
||||||
|
inline bool isThroughStreet(const std::size_t index,
|
||||||
|
const IntersectionType &intersection,
|
||||||
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table)
|
||||||
|
{
|
||||||
|
|
||||||
|
const auto &data_at_index = node_data_container.GetAnnotation(
|
||||||
|
node_based_graph.GetEdgeData(intersection[index].eid).annotation_data);
|
||||||
|
|
||||||
|
if (data_at_index.name_id == EMPTY_NAMEID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// a through street cannot start at our own position -> index 1
|
||||||
|
for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index)
|
||||||
|
{
|
||||||
|
if (road_index == index)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto &road = intersection[road_index];
|
||||||
|
const auto &road_data = node_data_container.GetAnnotation(
|
||||||
|
node_based_graph.GetEdgeData(road.eid).annotation_data);
|
||||||
|
|
||||||
|
// roads have a near straight angle (180 degree)
|
||||||
|
const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
|
||||||
|
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
|
||||||
|
|
||||||
|
const bool have_same_name = HaveIdenticalNames(
|
||||||
|
data_at_index.name_id, road_data.name_id, name_table, street_name_suffix_table);
|
||||||
|
|
||||||
|
const bool have_same_category =
|
||||||
|
node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification ==
|
||||||
|
node_based_graph.GetEdgeData(road.eid).flags.road_classification;
|
||||||
|
|
||||||
|
if (is_nearly_straight && have_same_name && have_same_category)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif /*OSRM_EXTRACTOR_GUIDANCE_IS_THROUGH_STREET_HPP_*/
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_MERGEABLE_ROADS
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_MERGEABLE_ROADS
|
||||||
#define OSRM_EXTRACTOR_GUIDANCE_MERGEABLE_ROADS
|
#define OSRM_EXTRACTOR_GUIDANCE_MERGEABLE_ROADS
|
||||||
|
|
||||||
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
|
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||||
|
#include "extractor/guidance/have_identical_names.hpp"
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
|
#include "extractor/guidance/turn_lane_types.hpp"
|
||||||
|
#include "extractor/restriction_index.hpp"
|
||||||
#include "util/coordinate.hpp"
|
#include "util/coordinate.hpp"
|
||||||
#include "util/node_based_graph.hpp"
|
#include "util/node_based_graph.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
@@ -9,6 +14,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@@ -39,8 +45,10 @@ class MergableRoadDetector
|
|||||||
MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph,
|
MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &node_coordinates,
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
const IntersectionGenerator &intersection_generator,
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
const CoordinateExtractor &coordinate_extractor,
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
@@ -71,11 +79,6 @@ class MergableRoadDetector
|
|||||||
bool IsDistinctFrom(const MergableRoadData &lhs, const MergableRoadData &rhs) const;
|
bool IsDistinctFrom(const MergableRoadData &lhs, const MergableRoadData &rhs) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// check if two name ids can be seen as identical (in presence of refs/others)
|
|
||||||
// in our case this translates into no name announcement in either direction (lhs->rhs and
|
|
||||||
// rhs->lhs)
|
|
||||||
bool HaveIdenticalNames(const NameID lhs, const NameID rhs) const;
|
|
||||||
|
|
||||||
// When it comes to merging roads, we need to find out if two ways actually represent the
|
// When it comes to merging roads, we need to find out if two ways actually represent the
|
||||||
// same road. This check tries to identify roads which are the same road in opposite directions
|
// same road. This check tries to identify roads which are the same road in opposite directions
|
||||||
bool EdgeDataSupportsMerge(const NodeBasedEdgeClassification &lhs_flags,
|
bool EdgeDataSupportsMerge(const NodeBasedEdgeClassification &lhs_flags,
|
||||||
@@ -159,15 +162,19 @@ class MergableRoadDetector
|
|||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
const EdgeBasedNodeDataContainer &node_data_container;
|
const EdgeBasedNodeDataContainer &node_data_container;
|
||||||
const std::vector<util::Coordinate> &node_coordinates;
|
const std::vector<util::Coordinate> &node_coordinates;
|
||||||
const IntersectionGenerator &intersection_generator;
|
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||||
const CoordinateExtractor &coordinate_extractor;
|
const RestrictionMap &node_restriction_map;
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes;
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data;
|
||||||
|
|
||||||
// name detection
|
// name detection
|
||||||
const util::NameTable &name_table;
|
const util::NameTable &name_table;
|
||||||
const SuffixTable &street_name_suffix_table;
|
const SuffixTable &street_name_suffix_table;
|
||||||
|
|
||||||
|
const CoordinateExtractor coordinate_extractor;
|
||||||
|
|
||||||
// limit for detecting circles / parallel roads
|
// limit for detecting circles / parallel roads
|
||||||
const static double constexpr distance_to_extract = 150;
|
const static double constexpr distance_to_extract = 120;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
#define OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_
|
#define OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_
|
||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/is_through_street.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
#include "util/attributes.hpp"
|
#include "util/attributes.hpp"
|
||||||
@@ -26,9 +26,12 @@ class MotorwayHandler : public IntersectionHandler
|
|||||||
MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table,
|
const SuffixTable &street_name_suffix_table);
|
||||||
const IntersectionGenerator &intersection_generator);
|
|
||||||
|
|
||||||
~MotorwayHandler() override final = default;
|
~MotorwayHandler() override final = default;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
#define OSRM_EXTRACTOR_GUIDANCE_NODE_BASED_GRAPH_WALKER
|
#define OSRM_EXTRACTOR_GUIDANCE_NODE_BASED_GRAPH_WALKER
|
||||||
|
|
||||||
#include "extractor/guidance/constants.hpp"
|
#include "extractor/guidance/constants.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||||
|
#include "extractor/guidance/turn_lane_data.hpp"
|
||||||
|
#include "extractor/intersection/intersection_analysis.hpp"
|
||||||
#include "util/coordinate.hpp"
|
#include "util/coordinate.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
#include "util/node_based_graph.hpp"
|
#include "util/node_based_graph.hpp"
|
||||||
@@ -29,7 +31,11 @@ class NodeBasedGraphWalker
|
|||||||
public:
|
public:
|
||||||
NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
|
NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const IntersectionGenerator &intersection_generator);
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the returned node-id, edge-id are either the last ones used, just prior accumulator
|
* the returned node-id, edge-id are either the last ones used, just prior accumulator
|
||||||
@@ -48,7 +54,11 @@ class NodeBasedGraphWalker
|
|||||||
private:
|
private:
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
const EdgeBasedNodeDataContainer &node_data_container;
|
const EdgeBasedNodeDataContainer &node_data_container;
|
||||||
const IntersectionGenerator &intersection_generator;
|
const std::vector<util::Coordinate> &node_coordinates;
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||||
|
const RestrictionMap &node_restriction_map;
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes;
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -149,7 +159,13 @@ struct SelectStraightmostRoadByNameAndOnlyChoice
|
|||||||
struct IntersectionFinderAccumulator
|
struct IntersectionFinderAccumulator
|
||||||
{
|
{
|
||||||
IntersectionFinderAccumulator(const std::uint8_t hop_limit,
|
IntersectionFinderAccumulator(const std::uint8_t hop_limit,
|
||||||
const IntersectionGenerator &intersection_generator);
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data);
|
||||||
// true if the path has traversed enough distance
|
// true if the path has traversed enough distance
|
||||||
bool terminate();
|
bool terminate();
|
||||||
|
|
||||||
@@ -159,13 +175,19 @@ struct IntersectionFinderAccumulator
|
|||||||
std::uint8_t hops;
|
std::uint8_t hops;
|
||||||
const std::uint8_t hop_limit;
|
const std::uint8_t hop_limit;
|
||||||
|
|
||||||
// we need to be able to look-up the intersection
|
|
||||||
const IntersectionGenerator &intersection_generator;
|
|
||||||
|
|
||||||
// the result we are looking for
|
// the result we are looking for
|
||||||
NodeID nid;
|
NodeID nid;
|
||||||
EdgeID via_edge_id;
|
EdgeID via_edge_id;
|
||||||
IntersectionView intersection;
|
IntersectionView intersection;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container;
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates;
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||||
|
const RestrictionMap &node_restriction_map;
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes;
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class accumulator_type, class selector_type>
|
template <class accumulator_type, class selector_type>
|
||||||
@@ -199,9 +221,15 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
|
|||||||
return {};
|
return {};
|
||||||
|
|
||||||
// look at the next intersection
|
// look at the next intersection
|
||||||
const constexpr auto LOW_PRECISION = true;
|
const auto next_intersection =
|
||||||
const auto next_intersection = intersection_generator.GetConnectedRoads(
|
intersection::getConnectedRoads<true>(node_based_graph,
|
||||||
current_node_id, current_edge_id, LOW_PRECISION);
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
|
{current_node_id, current_edge_id});
|
||||||
|
|
||||||
// don't follow u-turns or go past our initial intersection
|
// don't follow u-turns or go past our initial intersection
|
||||||
if (next_intersection.size() <= 1)
|
if (next_intersection.size() <= 1)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#include "extractor/compressed_edge_container.hpp"
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/is_through_street.hpp"
|
||||||
#include "extractor/guidance/roundabout_type.hpp"
|
#include "extractor/guidance/roundabout_type.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
@@ -42,10 +42,12 @@ class RoundaboutHandler : public IntersectionHandler
|
|||||||
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
const CompressedEdgeContainer &compressed_edge_container,
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table,
|
const SuffixTable &street_name_suffix_table);
|
||||||
const IntersectionGenerator &intersection_generator);
|
|
||||||
|
|
||||||
~RoundaboutHandler() override final = default;
|
~RoundaboutHandler() override final = default;
|
||||||
|
|
||||||
@@ -64,10 +66,6 @@ class RoundaboutHandler : public IntersectionHandler
|
|||||||
const EdgeID via_eid,
|
const EdgeID via_eid,
|
||||||
const Intersection &intersection) const;
|
const Intersection &intersection) const;
|
||||||
|
|
||||||
void invalidateExitAgainstDirection(const NodeID from_nid,
|
|
||||||
const EdgeID via_eid,
|
|
||||||
Intersection &intersection) const;
|
|
||||||
|
|
||||||
// decide whether we lookk at a roundabout or a rotary
|
// decide whether we lookk at a roundabout or a rotary
|
||||||
RoundaboutType getRoundaboutType(const NodeID nid) const;
|
RoundaboutType getRoundaboutType(const NodeID nid) const;
|
||||||
|
|
||||||
@@ -84,7 +82,6 @@ class RoundaboutHandler : public IntersectionHandler
|
|||||||
bool
|
bool
|
||||||
qualifiesAsRoundaboutIntersection(const std::unordered_set<NodeID> &roundabout_nodes) const;
|
qualifiesAsRoundaboutIntersection(const std::unordered_set<NodeID> &roundabout_nodes) const;
|
||||||
|
|
||||||
const CompressedEdgeContainer &compressed_edge_container;
|
|
||||||
const CoordinateExtractor coordinate_extractor;
|
const CoordinateExtractor coordinate_extractor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
class NameTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
class NodeBasedGraphFactory;
|
||||||
|
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
// Find all "segregated" edges, e.g. edges that can be skipped in turn instructions.
|
||||||
|
// The main cases are:
|
||||||
|
// - middle edges between two osm ways in one logic road (U-turn)
|
||||||
|
// - staggered intersections (X-cross)
|
||||||
|
// - square/circle intersections
|
||||||
|
std::unordered_set<EdgeID> findSegregatedNodes(const NodeBasedGraphFactory &factory,
|
||||||
|
const util::NameTable &names);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
#define OSRM_EXTRACTOR_GUIDANCE_SLIPROAD_HANDLER_HPP_
|
#define OSRM_EXTRACTOR_GUIDANCE_SLIPROAD_HANDLER_HPP_
|
||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/is_through_street.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
#include "util/name_table.hpp"
|
#include "util/name_table.hpp"
|
||||||
@@ -24,10 +24,13 @@ namespace guidance
|
|||||||
class SliproadHandler final : public IntersectionHandler
|
class SliproadHandler final : public IntersectionHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SliproadHandler(const IntersectionGenerator &intersection_generator,
|
SliproadHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
@@ -51,9 +54,6 @@ class SliproadHandler final : public IntersectionHandler
|
|||||||
// Next intersection from `start` onto `onto` is too far away for a Siproad scenario
|
// Next intersection from `start` onto `onto` is too far away for a Siproad scenario
|
||||||
bool nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const;
|
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
|
// Does the road from `current` to `next` continue
|
||||||
bool roadContinues(const EdgeID current, const EdgeID next) const;
|
bool roadContinues(const EdgeID current, const EdgeID next) const;
|
||||||
|
|
||||||
@@ -78,6 +78,8 @@ class SliproadHandler final : public IntersectionHandler
|
|||||||
// The return value is guaranteed to not be larger than `threshold`.
|
// The return value is guaranteed to not be larger than `threshold`.
|
||||||
static double scaledThresholdByRoadClass(const double max_threshold,
|
static double scaledThresholdByRoadClass(const double max_threshold,
|
||||||
const RoadClassification &classification);
|
const RoadClassification &classification);
|
||||||
|
|
||||||
|
const CoordinateExtractor coordinate_extractor;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@@ -27,18 +27,24 @@ namespace guidance
|
|||||||
class StatisticsHandler final : public IntersectionHandler
|
class StatisticsHandler final : public IntersectionHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StatisticsHandler(const IntersectionGenerator &intersection_generator,
|
StatisticsHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table)
|
const SuffixTable &street_name_suffix_table)
|
||||||
: IntersectionHandler(node_based_graph,
|
: IntersectionHandler(node_based_graph,
|
||||||
node_data_container,
|
node_data_container,
|
||||||
coordinates,
|
coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
name_table,
|
name_table,
|
||||||
street_name_suffix_table,
|
street_name_suffix_table)
|
||||||
intersection_generator)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +61,7 @@ class StatisticsHandler final : public IntersectionHandler
|
|||||||
|
|
||||||
for (const auto &kv : type_hist)
|
for (const auto &kv : type_hist)
|
||||||
if (kv.second > 0)
|
if (kv.second > 0)
|
||||||
util::Log() << std::fixed << std::setprecision(2)
|
util::Log() << " " << std::fixed << std::setprecision(2)
|
||||||
<< internalInstructionTypeToString(kv.first) << ": " << kv.second
|
<< internalInstructionTypeToString(kv.first) << ": " << kv.second
|
||||||
<< " (" << (kv.second / static_cast<float>(num_types) * 100.) << "%)";
|
<< " (" << (kv.second / static_cast<float>(num_types) * 100.) << "%)";
|
||||||
|
|
||||||
@@ -63,7 +69,7 @@ class StatisticsHandler final : public IntersectionHandler
|
|||||||
|
|
||||||
for (const auto &kv : modifier_hist)
|
for (const auto &kv : modifier_hist)
|
||||||
if (kv.second > 0)
|
if (kv.second > 0)
|
||||||
util::Log() << std::fixed << std::setprecision(2)
|
util::Log() << " " << std::fixed << std::setprecision(2)
|
||||||
<< instructionModifierToString(kv.first) << ": " << kv.second << " ("
|
<< instructionModifierToString(kv.first) << ": " << kv.second << " ("
|
||||||
<< (kv.second / static_cast<float>(num_modifiers) * 100.) << "%)";
|
<< (kv.second / static_cast<float>(num_modifiers) * 100.) << "%)";
|
||||||
}
|
}
|
||||||
@@ -84,12 +90,14 @@ class StatisticsHandler final : public IntersectionHandler
|
|||||||
// numbers closer to the handlers and see how often handlers ran.
|
// numbers closer to the handlers and see how often handlers ran.
|
||||||
for (const auto &road : intersection)
|
for (const auto &road : intersection)
|
||||||
{
|
{
|
||||||
|
if (road.entry_allowed)
|
||||||
|
{
|
||||||
|
const auto type = road.instruction.type;
|
||||||
|
const auto modifier = road.instruction.direction_modifier;
|
||||||
|
|
||||||
const auto type = road.instruction.type;
|
type_hist[type] += 1;
|
||||||
const auto modifier = road.instruction.direction_modifier;
|
modifier_hist[modifier] += 1;
|
||||||
|
}
|
||||||
type_hist[type] += 1;
|
|
||||||
modifier_hist[modifier] += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return intersection;
|
return intersection;
|
||||||
@@ -97,8 +105,8 @@ class StatisticsHandler final : public IntersectionHandler
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
mutable std::mutex lock;
|
mutable std::mutex lock;
|
||||||
mutable std::unordered_map<TurnType::Enum, std::uint64_t> type_hist;
|
mutable std::map<TurnType::Enum, std::uint64_t> type_hist;
|
||||||
mutable std::unordered_map<DirectionModifier::Enum, std::uint64_t> modifier_hist;
|
mutable std::map<DirectionModifier::Enum, std::uint64_t> modifier_hist;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "extractor/guidance/constants.hpp"
|
#include "extractor/guidance/constants.hpp"
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
#include "extractor/travel_mode.hpp"
|
#include "extractor/travel_mode.hpp"
|
||||||
#include "util/node_based_graph.hpp"
|
#include "util/node_based_graph.hpp"
|
||||||
@@ -21,10 +20,13 @@ namespace guidance
|
|||||||
class SuppressModeHandler final : public IntersectionHandler
|
class SuppressModeHandler final : public IntersectionHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SuppressModeHandler(const IntersectionGenerator &intersection_generator,
|
SuppressModeHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
#include "extractor/compressed_edge_container.hpp"
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
#include "extractor/guidance/driveway_handler.hpp"
|
#include "extractor/guidance/driveway_handler.hpp"
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/intersection_normalization_operation.hpp"
|
|
||||||
#include "extractor/guidance/intersection_normalizer.hpp"
|
|
||||||
#include "extractor/guidance/motorway_handler.hpp"
|
#include "extractor/guidance/motorway_handler.hpp"
|
||||||
#include "extractor/guidance/roundabout_handler.hpp"
|
#include "extractor/guidance/roundabout_handler.hpp"
|
||||||
#include "extractor/guidance/sliproad_handler.hpp"
|
#include "extractor/guidance/sliproad_handler.hpp"
|
||||||
@@ -43,10 +40,11 @@ class TurnAnalysis
|
|||||||
public:
|
public:
|
||||||
TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const CompressedEdgeContainer &compressed_edge_container,
|
||||||
const RestrictionMap &restriction_map,
|
const RestrictionMap &restriction_map,
|
||||||
const std::unordered_set<NodeID> &barrier_nodes,
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
const CompressedEdgeContainer &compressed_edge_container,
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
@@ -56,34 +54,14 @@ class TurnAnalysis
|
|||||||
Intersection operator()(const NodeID node_prior_to_intersection,
|
Intersection operator()(const NodeID node_prior_to_intersection,
|
||||||
const EdgeID entering_via_edge) const;
|
const EdgeID entering_via_edge) const;
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a normalized intersection without any assigned turn types.
|
|
||||||
* This intersection can be used as input for intersection classification, turn lane assignment
|
|
||||||
* and similar.
|
|
||||||
*/
|
|
||||||
struct ShapeResult
|
|
||||||
{
|
|
||||||
// the basic shape, containing all turns
|
|
||||||
IntersectionShape intersection_shape;
|
|
||||||
// normalized shape, merged some roads into others, adjusted bearings
|
|
||||||
// see intersection_normalizer for further explanations
|
|
||||||
IntersectionNormalizer::NormalizationResult annotated_normalized_shape;
|
|
||||||
};
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
ShapeResult ComputeIntersectionShapes(const NodeID node_at_center_of_intersection) const;
|
|
||||||
|
|
||||||
// Select turn types based on the intersection shape
|
// Select turn types based on the intersection shape
|
||||||
OSRM_ATTR_WARN_UNUSED
|
OSRM_ATTR_WARN_UNUSED
|
||||||
Intersection AssignTurnTypes(const NodeID from_node,
|
Intersection AssignTurnTypes(const NodeID from_node,
|
||||||
const EdgeID via_eid,
|
const EdgeID via_eid,
|
||||||
const IntersectionView &intersection) const;
|
const IntersectionView &intersection) const;
|
||||||
|
|
||||||
const IntersectionGenerator &GetIntersectionGenerator() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
const IntersectionGenerator intersection_generator;
|
|
||||||
const IntersectionNormalizer intersection_normalizer;
|
|
||||||
const RoundaboutHandler roundabout_handler;
|
const RoundaboutHandler roundabout_handler;
|
||||||
const MotorwayHandler motorway_handler;
|
const MotorwayHandler motorway_handler;
|
||||||
const TurnHandler turn_handler;
|
const TurnHandler turn_handler;
|
||||||
|
|||||||
@@ -2,15 +2,27 @@
|
|||||||
#define OSRM_EXTRACTOR_GUIDANCE_TURN_DISCOVERY_HPP_
|
#define OSRM_EXTRACTOR_GUIDANCE_TURN_DISCOVERY_HPP_
|
||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
#include "extractor/guidance/turn_lane_data.hpp"
|
||||||
|
#include "extractor/restriction_index.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
struct Coordinate;
|
||||||
|
}
|
||||||
|
|
||||||
namespace extractor
|
namespace extractor
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class CompressedEdgeContainer;
|
||||||
|
|
||||||
namespace guidance
|
namespace guidance
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace lanes
|
namespace lanes
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -21,8 +33,13 @@ bool findPreviousIntersection(
|
|||||||
const NodeID node,
|
const NodeID node,
|
||||||
const EdgeID via_edge,
|
const EdgeID via_edge,
|
||||||
const Intersection &intersection,
|
const Intersection &intersection,
|
||||||
const IntersectionGenerator &intersection_generator,
|
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph, // query edge data
|
const util::NodeBasedDynamicGraph &node_based_graph, // query edge data
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
// output parameters, will be in an arbitrary state on failure
|
// output parameters, will be in an arbitrary state on failure
|
||||||
NodeID &result_node,
|
NodeID &result_node,
|
||||||
EdgeID &result_via_edge,
|
EdgeID &result_via_edge,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
#define OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_
|
#define OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_
|
||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/is_through_street.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
#include "util/attributes.hpp"
|
#include "util/attributes.hpp"
|
||||||
@@ -30,9 +30,12 @@ class TurnHandler : public IntersectionHandler
|
|||||||
TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table,
|
const SuffixTable &street_name_suffix_table);
|
||||||
const IntersectionGenerator &intersection_generator);
|
|
||||||
|
|
||||||
~TurnHandler() override final = default;
|
~TurnHandler() override final = default;
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,11 @@ struct TurnInstruction
|
|||||||
|
|
||||||
TurnType::Enum type : 5;
|
TurnType::Enum type : 5;
|
||||||
DirectionModifier::Enum direction_modifier : 3;
|
DirectionModifier::Enum direction_modifier : 3;
|
||||||
// the lane tupel that is used for the turn
|
|
||||||
|
bool IsUTurn() const
|
||||||
|
{
|
||||||
|
return type != TurnType::NoTurn && direction_modifier == DirectionModifier::UTurn;
|
||||||
|
}
|
||||||
|
|
||||||
static TurnInstruction INVALID() { return {TurnType::Invalid, DirectionModifier::UTurn}; }
|
static TurnInstruction INVALID() { return {TurnType::Invalid, DirectionModifier::UTurn}; }
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ class TurnLaneHandler
|
|||||||
|
|
||||||
TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
LaneDescriptionMap &lane_description_map,
|
LaneDescriptionMap &lane_description_map,
|
||||||
const TurnAnalysis &turn_analysis,
|
const TurnAnalysis &turn_analysis,
|
||||||
util::guidance::LaneDataIdMap &id_map);
|
util::guidance::LaneDataIdMap &id_map);
|
||||||
@@ -90,6 +95,12 @@ class TurnLaneHandler
|
|||||||
// lanes for a turn
|
// lanes for a turn
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
const EdgeBasedNodeDataContainer &node_data_container;
|
const EdgeBasedNodeDataContainer &node_data_container;
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates;
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||||
|
const RestrictionMap &node_restriction_map;
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes;
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data;
|
||||||
|
|
||||||
std::vector<std::uint32_t> turn_lane_offsets;
|
std::vector<std::uint32_t> turn_lane_offsets;
|
||||||
std::vector<TurnLaneType::Mask> turn_lane_masks;
|
std::vector<TurnLaneType::Mask> turn_lane_masks;
|
||||||
LaneDescriptionMap &lane_description_map;
|
LaneDescriptionMap &lane_description_map;
|
||||||
|
|||||||
@@ -100,8 +100,10 @@ typedef util::ConcurrentIDMap<guidance::TurnLaneDescription,
|
|||||||
guidance::TurnLaneDescription_hash>
|
guidance::TurnLaneDescription_hash>
|
||||||
LaneDescriptionMap;
|
LaneDescriptionMap;
|
||||||
|
|
||||||
inline std::tuple<std::vector<std::uint32_t>, std::vector<TurnLaneType::Mask>>
|
using TurnLanesIndexedArray =
|
||||||
transformTurnLaneMapIntoArrays(const LaneDescriptionMap &turn_lane_map)
|
std::tuple<std::vector<std::uint32_t>, std::vector<TurnLaneType::Mask>>;
|
||||||
|
|
||||||
|
inline TurnLanesIndexedArray transformTurnLaneMapIntoArrays(const LaneDescriptionMap &turn_lane_map)
|
||||||
{
|
{
|
||||||
// could use some additional capacity? To avoid a copy during processing, though small data so
|
// could use some additional capacity? To avoid a copy during processing, though small data so
|
||||||
// probably not that important.
|
// probably not that important.
|
||||||
@@ -111,8 +113,7 @@ transformTurnLaneMapIntoArrays(const LaneDescriptionMap &turn_lane_map)
|
|||||||
//
|
//
|
||||||
// turn lane offsets points into the locations of the turn_lane_masks array. We use a standard
|
// turn lane offsets points into the locations of the turn_lane_masks array. We use a standard
|
||||||
// adjacency array like structure to store the turn lane masks.
|
// adjacency array like structure to store the turn lane masks.
|
||||||
std::vector<std::uint32_t> turn_lane_offsets(turn_lane_map.data.size() +
|
std::vector<std::uint32_t> turn_lane_offsets(turn_lane_map.data.size() + 1); // + sentinel
|
||||||
2); // empty ID + sentinel
|
|
||||||
for (auto entry = turn_lane_map.data.begin(); entry != turn_lane_map.data.end(); ++entry)
|
for (auto entry = turn_lane_map.data.begin(); entry != turn_lane_map.data.end(); ++entry)
|
||||||
turn_lane_offsets[entry->second + 1] = entry->first.size();
|
turn_lane_offsets[entry->second + 1] = entry->first.size();
|
||||||
|
|
||||||
@@ -125,6 +126,7 @@ transformTurnLaneMapIntoArrays(const LaneDescriptionMap &turn_lane_map)
|
|||||||
std::copy(entry->first.begin(),
|
std::copy(entry->first.begin(),
|
||||||
entry->first.end(),
|
entry->first.end(),
|
||||||
turn_lane_masks.begin() + turn_lane_offsets[entry->second]);
|
turn_lane_masks.begin() + turn_lane_offsets[entry->second]);
|
||||||
|
|
||||||
return std::make_tuple(std::move(turn_lane_offsets), std::move(turn_lane_masks));
|
return std::make_tuple(std::move(turn_lane_offsets), std::move(turn_lane_masks));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_ANALYSIS_HPP
|
||||||
|
#define OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_ANALYSIS_HPP
|
||||||
|
|
||||||
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
|
#include "extractor/guidance/mergable_road_detector.hpp"
|
||||||
|
#include "extractor/guidance/turn_lane_types.hpp"
|
||||||
|
#include "extractor/intersection/intersection_edge.hpp"
|
||||||
|
#include "extractor/restriction_index.hpp"
|
||||||
|
|
||||||
|
#include "util/coordinate.hpp"
|
||||||
|
#include "util/node_based_graph.hpp"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace intersection
|
||||||
|
{
|
||||||
|
|
||||||
|
IntersectionEdges getIncomingEdges(const util::NodeBasedDynamicGraph &graph,
|
||||||
|
const NodeID intersection);
|
||||||
|
|
||||||
|
IntersectionEdges getOutgoingEdges(const util::NodeBasedDynamicGraph &graph,
|
||||||
|
const NodeID intersection);
|
||||||
|
|
||||||
|
bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph,
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const RestrictionMap &restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const IntersectionEdgeGeometries &geometries,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
|
const IntersectionEdge &from,
|
||||||
|
const IntersectionEdge &to);
|
||||||
|
|
||||||
|
double findEdgeBearing(const IntersectionEdgeGeometries &geometries, const EdgeID &edge);
|
||||||
|
|
||||||
|
double findEdgeLength(const IntersectionEdgeGeometries &geometries, const EdgeID &edge);
|
||||||
|
|
||||||
|
std::pair<IntersectionEdgeGeometries, std::unordered_set<EdgeID>>
|
||||||
|
getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const guidance::MergableRoadDetector &detector,
|
||||||
|
const NodeID intersection);
|
||||||
|
|
||||||
|
guidance::IntersectionView
|
||||||
|
convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const RestrictionMap &restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const IntersectionEdgeGeometries &edge_geometries,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
|
const IntersectionEdge &incoming_edge,
|
||||||
|
const IntersectionEdges &outgoing_edges,
|
||||||
|
const std::unordered_set<EdgeID> &merged_edges);
|
||||||
|
|
||||||
|
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
|
||||||
|
// the node reached from `incoming_edge`. The resulting candidates have to be analyzed
|
||||||
|
// for their actual instructions later on.
|
||||||
|
template <bool USE_CLOSE_COORDINATE>
|
||||||
|
guidance::IntersectionView
|
||||||
|
getConnectedRoads(const util::NodeBasedDynamicGraph &graph,
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
|
const IntersectionEdge &incoming_edge);
|
||||||
|
|
||||||
|
// Graph Compression cannot compress every setting. For example any barrier/traffic light cannot
|
||||||
|
// be compressed. As a result, a simple road of the form `a ----- b` might end up as having an
|
||||||
|
// intermediate intersection, if there is a traffic light in between. If we want to look farther
|
||||||
|
// down a road, finding the next actual decision requires the look at multiple intersections.
|
||||||
|
// Here we follow the road until we either reach a dead end or find the next intersection with
|
||||||
|
// more than a single next road. This function skips over degree two nodes to find correct input
|
||||||
|
// for getConnectedRoads.
|
||||||
|
IntersectionEdge skipDegreeTwoNodes(const util::NodeBasedDynamicGraph &graph,
|
||||||
|
IntersectionEdge road);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_EDGE_HPP
|
||||||
|
#define OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_EDGE_HPP
|
||||||
|
|
||||||
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace intersection
|
||||||
|
{
|
||||||
|
|
||||||
|
// IntersectionEdge is an alias for incoming and outgoing node-based graph edges of an intersection
|
||||||
|
struct IntersectionEdge
|
||||||
|
{
|
||||||
|
NodeID node;
|
||||||
|
EdgeID edge;
|
||||||
|
|
||||||
|
bool operator<(const IntersectionEdge &other) const
|
||||||
|
{
|
||||||
|
return std::tie(node, edge) < std::tie(other.node, other.edge);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using IntersectionEdges = std::vector<IntersectionEdge>;
|
||||||
|
|
||||||
|
struct IntersectionEdgeGeometry
|
||||||
|
{
|
||||||
|
EdgeID edge;
|
||||||
|
double initial_bearing;
|
||||||
|
double perceived_bearing;
|
||||||
|
double length;
|
||||||
|
|
||||||
|
bool operator<(const IntersectionEdgeGeometry &other) const { return edge < other.edge; }
|
||||||
|
};
|
||||||
|
|
||||||
|
using IntersectionEdgeGeometries = std::vector<IntersectionEdgeGeometry>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -41,9 +41,13 @@ class NodeBasedGraphFactory
|
|||||||
std::vector<TurnRestriction> &turn_restrictions,
|
std::vector<TurnRestriction> &turn_restrictions,
|
||||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||||
|
|
||||||
auto const &GetGraph() { return compressed_output_graph; }
|
auto const &GetGraph() const { return compressed_output_graph; }
|
||||||
auto const &GetBarriers() const { return barriers; }
|
auto const &GetBarriers() const { return barriers; }
|
||||||
auto const &GetTrafficSignals() const { return traffic_signals; }
|
auto const &GetTrafficSignals() const { return traffic_signals; }
|
||||||
|
auto const &GetCompressedEdges() const { return compressed_edge_container; }
|
||||||
|
auto const &GetCoordinates() const { return coordinates; }
|
||||||
|
auto const &GetAnnotationData() const { return annotation_data; }
|
||||||
|
auto const &GetOsmNodes() const { return osm_node_ids; }
|
||||||
auto &GetCompressedEdges() { return compressed_edge_container; }
|
auto &GetCompressedEdges() { return compressed_edge_container; }
|
||||||
auto &GetCoordinates() { return coordinates; }
|
auto &GetCoordinates() { return coordinates; }
|
||||||
auto &GetAnnotationData() { return annotation_data; }
|
auto &GetAnnotationData() { return annotation_data; }
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#include <boost/optional/optional.hpp>
|
#include <boost/optional/optional.hpp>
|
||||||
|
|
||||||
#include <tbb/concurrent_vector.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@@ -186,6 +186,8 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
|||||||
params->Get(Nan::New("max_locations_map_matching").ToLocalChecked());
|
params->Get(Nan::New("max_locations_map_matching").ToLocalChecked());
|
||||||
auto max_results_nearest = params->Get(Nan::New("max_results_nearest").ToLocalChecked());
|
auto max_results_nearest = params->Get(Nan::New("max_results_nearest").ToLocalChecked());
|
||||||
auto max_alternatives = params->Get(Nan::New("max_alternatives").ToLocalChecked());
|
auto max_alternatives = params->Get(Nan::New("max_alternatives").ToLocalChecked());
|
||||||
|
auto max_radius_map_matching =
|
||||||
|
params->Get(Nan::New("max_radius_map_matching").ToLocalChecked());
|
||||||
|
|
||||||
if (!max_locations_trip->IsUndefined() && !max_locations_trip->IsNumber())
|
if (!max_locations_trip->IsUndefined() && !max_locations_trip->IsNumber())
|
||||||
{
|
{
|
||||||
@@ -233,6 +235,9 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
|||||||
engine_config->max_results_nearest = static_cast<int>(max_results_nearest->NumberValue());
|
engine_config->max_results_nearest = static_cast<int>(max_results_nearest->NumberValue());
|
||||||
if (max_alternatives->IsNumber())
|
if (max_alternatives->IsNumber())
|
||||||
engine_config->max_alternatives = static_cast<int>(max_alternatives->NumberValue());
|
engine_config->max_alternatives = static_cast<int>(max_alternatives->NumberValue());
|
||||||
|
if (max_radius_map_matching->IsNumber())
|
||||||
|
engine_config->max_radius_map_matching =
|
||||||
|
static_cast<double>(max_radius_map_matching->NumberValue());
|
||||||
|
|
||||||
return engine_config;
|
return engine_config;
|
||||||
}
|
}
|
||||||
@@ -1166,7 +1171,7 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
|||||||
Nan::ThrowError("Timestamps array items must be numbers");
|
Nan::ThrowError("Timestamps array items must be numbers");
|
||||||
return match_parameters_ptr();
|
return match_parameters_ptr();
|
||||||
}
|
}
|
||||||
params->timestamps.emplace_back(static_cast<unsigned>(timestamp->NumberValue()));
|
params->timestamps.emplace_back(static_cast<std::size_t>(timestamp->NumberValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1215,6 +1220,60 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
|||||||
params->tidy = tidy->BooleanValue();
|
params->tidy = tidy->BooleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj->Has(Nan::New("waypoints").ToLocalChecked()))
|
||||||
|
{
|
||||||
|
v8::Local<v8::Value> waypoints = obj->Get(Nan::New("waypoints").ToLocalChecked());
|
||||||
|
if (waypoints.IsEmpty())
|
||||||
|
return match_parameters_ptr();
|
||||||
|
|
||||||
|
// must be array
|
||||||
|
if (!waypoints->IsArray())
|
||||||
|
{
|
||||||
|
Nan::ThrowError(
|
||||||
|
"Waypoints must be an array of integers corresponding to the input coordinates.");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto waypoints_array = v8::Local<v8::Array>::Cast(waypoints);
|
||||||
|
// must have at least two elements
|
||||||
|
if (waypoints_array->Length() < 2)
|
||||||
|
{
|
||||||
|
Nan::ThrowError("At least two waypoints must be provided");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
auto coords_size = params->coordinates.size();
|
||||||
|
auto waypoints_array_size = waypoints_array->Length();
|
||||||
|
|
||||||
|
const auto first_index = Nan::To<std::uint32_t>(waypoints_array->Get(0)).FromJust();
|
||||||
|
const auto last_index =
|
||||||
|
Nan::To<std::uint32_t>(waypoints_array->Get(waypoints_array_size - 1)).FromJust();
|
||||||
|
if (first_index != 0 || last_index != coords_size - 1)
|
||||||
|
{
|
||||||
|
Nan::ThrowError("First and last waypoints values must correspond to first and last "
|
||||||
|
"coordinate indices");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < waypoints_array_size; ++i)
|
||||||
|
{
|
||||||
|
v8::Local<v8::Value> waypoint_value = waypoints_array->Get(i);
|
||||||
|
// all elements must be numbers
|
||||||
|
if (!waypoint_value->IsNumber())
|
||||||
|
{
|
||||||
|
Nan::ThrowError("Waypoint values must be an array of integers");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
// check that the waypoint index corresponds with an inpute coordinate
|
||||||
|
const auto index = Nan::To<std::uint32_t>(waypoint_value).FromJust();
|
||||||
|
if (index >= coords_size)
|
||||||
|
{
|
||||||
|
Nan::ThrowError("Waypoints must correspond with the index of an input coordinate");
|
||||||
|
return match_parameters_ptr();
|
||||||
|
}
|
||||||
|
params->waypoints.emplace_back(static_cast<unsigned>(waypoint_value->NumberValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool parsedSuccessfully = parseCommonParameters(obj, params);
|
bool parsedSuccessfully = parseCommonParameters(obj, params);
|
||||||
if (!parsedSuccessfully)
|
if (!parsedSuccessfully)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <boost/iterator/iterator_facade.hpp>
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
#include <boost/range/iterator_range.hpp>
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
|
||||||
#include <tbb/parallel_sort.h>
|
#include <tbb/parallel_sort.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
#include "util/dynamic_graph.hpp"
|
#include "util/dynamic_graph.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <tbb/blocked_range.h>
|
||||||
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/parallel_reduce.h>
|
#include <tbb/parallel_reduce.h>
|
||||||
#include <tbb/parallel_sort.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|||||||
@@ -28,17 +28,31 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
|
|||||||
|
|
||||||
MatchParametersGrammar() : BaseGrammar(root_rule)
|
MatchParametersGrammar() : BaseGrammar(root_rule)
|
||||||
{
|
{
|
||||||
|
#ifdef BOOST_HAS_LONG_LONG
|
||||||
|
if (std::is_same<std::size_t, unsigned long long>::value)
|
||||||
|
size_t_ = qi::ulong_long;
|
||||||
|
else
|
||||||
|
size_t_ = qi::ulong_;
|
||||||
|
#else
|
||||||
|
size_t_ = qi::ulong_;
|
||||||
|
#endif
|
||||||
|
|
||||||
timestamps_rule =
|
timestamps_rule =
|
||||||
qi::lit("timestamps=") >
|
qi::lit("timestamps=") >
|
||||||
(qi::uint_ %
|
(qi::uint_ %
|
||||||
';')[ph::bind(&engine::api::MatchParameters::timestamps, qi::_r1) = qi::_1];
|
';')[ph::bind(&engine::api::MatchParameters::timestamps, qi::_r1) = qi::_1];
|
||||||
|
|
||||||
|
waypoints_rule =
|
||||||
|
qi::lit("waypoints=") >
|
||||||
|
(size_t_ % ';')[ph::bind(&engine::api::MatchParameters::waypoints, qi::_r1) = qi::_1];
|
||||||
|
|
||||||
gaps_type.add("split", engine::api::MatchParameters::GapsType::Split)(
|
gaps_type.add("split", engine::api::MatchParameters::GapsType::Split)(
|
||||||
"ignore", engine::api::MatchParameters::GapsType::Ignore);
|
"ignore", engine::api::MatchParameters::GapsType::Ignore);
|
||||||
|
|
||||||
root_rule =
|
root_rule =
|
||||||
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
||||||
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) |
|
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) |
|
||||||
|
waypoints_rule(qi::_r1) |
|
||||||
(qi::lit("gaps=") >
|
(qi::lit("gaps=") >
|
||||||
gaps_type[ph::bind(&engine::api::MatchParameters::gaps, qi::_r1) = qi::_1]) |
|
gaps_type[ph::bind(&engine::api::MatchParameters::gaps, qi::_r1) = qi::_1]) |
|
||||||
(qi::lit("tidy=") >
|
(qi::lit("tidy=") >
|
||||||
@@ -49,6 +63,8 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
|
|||||||
private:
|
private:
|
||||||
qi::rule<Iterator, Signature> root_rule;
|
qi::rule<Iterator, Signature> root_rule;
|
||||||
qi::rule<Iterator, Signature> timestamps_rule;
|
qi::rule<Iterator, Signature> timestamps_rule;
|
||||||
|
qi::rule<Iterator, Signature> waypoints_rule;
|
||||||
|
qi::rule<Iterator, std::size_t()> size_t_;
|
||||||
|
|
||||||
qi::symbols<char, engine::api::MatchParameters::GapsType> gaps_type;
|
qi::symbols<char, engine::api::MatchParameters::GapsType> gaps_type;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,14 +48,6 @@ const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA",
|
|||||||
"HSGR_CHECKSUM",
|
"HSGR_CHECKSUM",
|
||||||
"TIMESTAMP",
|
"TIMESTAMP",
|
||||||
"FILE_INDEX_PATH",
|
"FILE_INDEX_PATH",
|
||||||
"CH_CORE_MARKER_0",
|
|
||||||
"CH_CORE_MARKER_1",
|
|
||||||
"CH_CORE_MARKER_2",
|
|
||||||
"CH_CORE_MARKER_3",
|
|
||||||
"CH_CORE_MARKER_4",
|
|
||||||
"CH_CORE_MARKER_5",
|
|
||||||
"CH_CORE_MARKER_6",
|
|
||||||
"CH_CORE_MARKER_7",
|
|
||||||
"DATASOURCES_NAMES",
|
"DATASOURCES_NAMES",
|
||||||
"PROPERTIES",
|
"PROPERTIES",
|
||||||
"BEARING_CLASSID",
|
"BEARING_CLASSID",
|
||||||
@@ -132,14 +124,6 @@ struct DataLayout
|
|||||||
HSGR_CHECKSUM,
|
HSGR_CHECKSUM,
|
||||||
TIMESTAMP,
|
TIMESTAMP,
|
||||||
FILE_INDEX_PATH,
|
FILE_INDEX_PATH,
|
||||||
CH_CORE_MARKER_0,
|
|
||||||
CH_CORE_MARKER_1,
|
|
||||||
CH_CORE_MARKER_2,
|
|
||||||
CH_CORE_MARKER_3,
|
|
||||||
CH_CORE_MARKER_4,
|
|
||||||
CH_CORE_MARKER_5,
|
|
||||||
CH_CORE_MARKER_6,
|
|
||||||
CH_CORE_MARKER_7,
|
|
||||||
DATASOURCES_NAMES,
|
DATASOURCES_NAMES,
|
||||||
PROPERTIES,
|
PROPERTIES,
|
||||||
BEARING_CLASSID,
|
BEARING_CLASSID,
|
||||||
@@ -200,15 +184,7 @@ struct DataLayout
|
|||||||
|
|
||||||
inline uint64_t GetBlockEntries(BlockID bid) const { return num_entries[bid]; }
|
inline uint64_t GetBlockEntries(BlockID bid) const { return num_entries[bid]; }
|
||||||
|
|
||||||
inline uint64_t GetBlockSize(BlockID bid) const
|
inline uint64_t GetBlockSize(BlockID bid) const { return num_entries[bid] * entry_size[bid]; }
|
||||||
{
|
|
||||||
// special bit encoding
|
|
||||||
if (bid >= CH_CORE_MARKER_0 && bid <= CH_CORE_MARKER_7)
|
|
||||||
{
|
|
||||||
return (num_entries[bid] / 32 + 1) * entry_size[bid];
|
|
||||||
}
|
|
||||||
return num_entries[bid] * entry_size[bid];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64_t GetSizeOfLayout() const
|
inline uint64_t GetSizeOfLayout() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ struct StorageConfig final : IOConfig
|
|||||||
{".osrm.hsgr",
|
{".osrm.hsgr",
|
||||||
".osrm.nbg_nodes",
|
".osrm.nbg_nodes",
|
||||||
".osrm.ebg_nodes",
|
".osrm.ebg_nodes",
|
||||||
".osrm.core",
|
|
||||||
".osrm.cells",
|
".osrm.cells",
|
||||||
".osrm.cell_metrics",
|
".osrm.cell_metrics",
|
||||||
".osrm.mldgr",
|
".osrm.mldgr",
|
||||||
|
|||||||
@@ -144,18 +144,6 @@ inline double restrictAngleToValidRange(const double angle)
|
|||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// finds the angle between two angles, based on the minum difference between the two
|
|
||||||
inline double angleBetween(const double lhs, const double rhs)
|
|
||||||
{
|
|
||||||
const auto difference = std::abs(lhs - rhs);
|
|
||||||
const auto is_clockwise_difference = difference <= 180;
|
|
||||||
const auto angle_between_candidate = .5 * (lhs + rhs);
|
|
||||||
if (is_clockwise_difference)
|
|
||||||
return angle_between_candidate;
|
|
||||||
else
|
|
||||||
return restrictAngleToValidRange(angle_between_candidate + 180);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ template <typename EdgeDataT> class DynamicGraph
|
|||||||
|
|
||||||
number_of_nodes = nodes;
|
number_of_nodes = nodes;
|
||||||
number_of_edges = static_cast<EdgeIterator>(graph.size());
|
number_of_edges = static_cast<EdgeIterator>(graph.size());
|
||||||
node_array.resize(number_of_nodes + 1);
|
node_array.resize(number_of_nodes);
|
||||||
EdgeIterator edge = 0;
|
EdgeIterator edge = 0;
|
||||||
EdgeIterator position = 0;
|
EdgeIterator position = 0;
|
||||||
for (const auto node : irange(0u, number_of_nodes))
|
for (const auto node : irange(0u, number_of_nodes))
|
||||||
@@ -129,7 +129,6 @@ template <typename EdgeDataT> class DynamicGraph
|
|||||||
node_array[node].edges = edge - last_edge;
|
node_array[node].edges = edge - last_edge;
|
||||||
position += node_array[node].edges;
|
position += node_array[node].edges;
|
||||||
}
|
}
|
||||||
node_array.back().first_edge = position;
|
|
||||||
edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
|
edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
|
||||||
edge_list.resize(position);
|
edge_list.resize(position);
|
||||||
edge = 0;
|
edge = 0;
|
||||||
@@ -144,6 +143,8 @@ template <typename EdgeDataT> class DynamicGraph
|
|||||||
++edge;
|
++edge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(node_array.size() == number_of_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy&move for the same data
|
// Copy&move for the same data
|
||||||
@@ -191,6 +192,8 @@ template <typename EdgeDataT> class DynamicGraph
|
|||||||
// Removes all edges to and from nodes for which filter(node_id) returns false
|
// Removes all edges to and from nodes for which filter(node_id) returns false
|
||||||
template <typename Pred> auto Filter(Pred filter) const &
|
template <typename Pred> auto Filter(Pred filter) const &
|
||||||
{
|
{
|
||||||
|
BOOST_ASSERT(node_array.size() == number_of_nodes);
|
||||||
|
|
||||||
DynamicGraph other;
|
DynamicGraph other;
|
||||||
|
|
||||||
other.number_of_nodes = number_of_nodes;
|
other.number_of_nodes = number_of_nodes;
|
||||||
@@ -202,6 +205,8 @@ template <typename EdgeDataT> class DynamicGraph
|
|||||||
std::transform(
|
std::transform(
|
||||||
node_array.begin(), node_array.end(), other.node_array.begin(), [&](const Node &node) {
|
node_array.begin(), node_array.end(), other.node_array.begin(), [&](const Node &node) {
|
||||||
const EdgeIterator first_edge = other.edge_list.size();
|
const EdgeIterator first_edge = other.edge_list.size();
|
||||||
|
|
||||||
|
BOOST_ASSERT(node_id < number_of_nodes);
|
||||||
if (filter(node_id++))
|
if (filter(node_id++))
|
||||||
{
|
{
|
||||||
std::copy_if(edge_list.begin() + node.first_edge,
|
std::copy_if(edge_list.begin() + node.first_edge,
|
||||||
@@ -416,7 +421,7 @@ template <typename EdgeDataT> class DynamicGraph
|
|||||||
void Renumber(const std::vector<NodeID> &old_to_new_node)
|
void Renumber(const std::vector<NodeID> &old_to_new_node)
|
||||||
{
|
{
|
||||||
// permutate everything but the sentinel
|
// permutate everything but the sentinel
|
||||||
util::inplacePermutation(node_array.begin(), std::prev(node_array.end()), old_to_new_node);
|
util::inplacePermutation(node_array.begin(), node_array.end(), old_to_new_node);
|
||||||
|
|
||||||
// Build up edge permutation
|
// Build up edge permutation
|
||||||
auto new_edge_index = 0;
|
auto new_edge_index = 0;
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ namespace guidance
|
|||||||
// Name Change Logic
|
// Name Change Logic
|
||||||
// Used both during Extraction as well as during Post-Processing
|
// Used both during Extraction as well as during Post-Processing
|
||||||
|
|
||||||
inline std::string longest_common_substring(const std::string &lhs, const std::string &rhs)
|
inline util::StringView longest_common_substring(const util::StringView &lhs,
|
||||||
|
const util::StringView &rhs)
|
||||||
{
|
{
|
||||||
if (lhs.empty() || rhs.empty())
|
if (lhs.empty() || rhs.empty())
|
||||||
return "";
|
return "";
|
||||||
@@ -60,15 +61,15 @@ inline std::string longest_common_substring(const std::string &lhs, const std::s
|
|||||||
|
|
||||||
// TODO US-ASCII support only, no UTF-8 support
|
// TODO US-ASCII support only, no UTF-8 support
|
||||||
// While UTF-8 might work in some cases, we do not guarantee full functionality
|
// While UTF-8 might work in some cases, we do not guarantee full functionality
|
||||||
inline auto decompose(const std::string &lhs, const std::string &rhs)
|
template <typename StringView> inline auto decompose(const StringView &lhs, const StringView &rhs)
|
||||||
{
|
{
|
||||||
auto const lcs = longest_common_substring(lhs, rhs);
|
auto const lcs = longest_common_substring(lhs, rhs);
|
||||||
|
|
||||||
// trim spaces, transform to lower
|
// trim spaces, transform to lower
|
||||||
const auto trim = [](auto str) {
|
const auto trim = [](StringView view) {
|
||||||
// we compare suffixes based on this value, it might break UTF chars, but as long as we are
|
// we compare suffixes based on this value, it might break UTF chars, but as long as we are
|
||||||
// consistent in handling, we do not create bad results
|
// consistent in handling, we do not create bad results
|
||||||
boost::to_lower(str);
|
std::string str = boost::to_lower_copy(view.to_string());
|
||||||
auto front = str.find_first_not_of(" ");
|
auto front = str.find_first_not_of(" ");
|
||||||
|
|
||||||
if (front == std::string::npos)
|
if (front == std::string::npos)
|
||||||
@@ -80,8 +81,7 @@ inline auto decompose(const std::string &lhs, const std::string &rhs)
|
|||||||
|
|
||||||
if (lcs.empty())
|
if (lcs.empty())
|
||||||
{
|
{
|
||||||
std::string empty = "";
|
return std::make_tuple(trim(lhs), trim(rhs), std::string(), std::string());
|
||||||
return std::make_tuple(trim(lhs), trim(rhs), empty, empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the common substring in both
|
// find the common substring in both
|
||||||
@@ -92,32 +92,27 @@ inline auto decompose(const std::string &lhs, const std::string &rhs)
|
|||||||
BOOST_ASSERT(rhs_pos + lcs.size() <= rhs.size());
|
BOOST_ASSERT(rhs_pos + lcs.size() <= rhs.size());
|
||||||
|
|
||||||
// prefixes
|
// prefixes
|
||||||
std::string lhs_prefix = (lhs_pos > 0) ? lhs.substr(0, lhs_pos) : "";
|
auto lhs_prefix = (lhs_pos > 0) ? lhs.substr(0, lhs_pos) : StringView();
|
||||||
std::string rhs_prefix = (rhs_pos > 0) ? rhs.substr(0, rhs_pos) : "";
|
auto rhs_prefix = (rhs_pos > 0) ? rhs.substr(0, rhs_pos) : StringView();
|
||||||
|
|
||||||
// suffices
|
// suffices
|
||||||
std::string lhs_suffix = lhs.substr(lhs_pos + lcs.size());
|
auto lhs_suffix = lhs.substr(lhs_pos + lcs.size());
|
||||||
std::string rhs_suffix = rhs.substr(rhs_pos + lcs.size());
|
auto rhs_suffix = rhs.substr(rhs_pos + lcs.size());
|
||||||
|
|
||||||
lhs_prefix = trim(std::move(lhs_prefix));
|
return std::make_tuple(trim(lhs_prefix), trim(lhs_suffix), trim(rhs_prefix), trim(rhs_suffix));
|
||||||
lhs_suffix = trim(std::move(lhs_suffix));
|
|
||||||
rhs_prefix = trim(std::move(rhs_prefix));
|
|
||||||
rhs_suffix = trim(std::move(rhs_suffix));
|
|
||||||
|
|
||||||
return std::make_tuple(lhs_prefix, lhs_suffix, rhs_prefix, rhs_suffix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: there is an overload without suffix checking below.
|
// Note: there is an overload without suffix checking below.
|
||||||
// (that's the reason we template the suffix table here)
|
// (that's the reason we template the suffix table here)
|
||||||
template <typename SuffixTable>
|
template <typename StringView, typename SuffixTable>
|
||||||
inline bool requiresNameAnnounced(const std::string &from_name,
|
inline bool requiresNameAnnounced(const StringView &from_name,
|
||||||
const std::string &from_ref,
|
const StringView &from_ref,
|
||||||
const std::string &from_pronunciation,
|
const StringView &from_pronunciation,
|
||||||
const std::string &from_exits,
|
const StringView &from_exits,
|
||||||
const std::string &to_name,
|
const StringView &to_name,
|
||||||
const std::string &to_ref,
|
const StringView &to_ref,
|
||||||
const std::string &to_pronunciation,
|
const StringView &to_pronunciation,
|
||||||
const std::string &to_exits,
|
const StringView &to_exits,
|
||||||
const SuffixTable &suffix_table)
|
const SuffixTable &suffix_table)
|
||||||
{
|
{
|
||||||
// first is empty and the second is not
|
// first is empty and the second is not
|
||||||
@@ -134,7 +129,7 @@ inline bool requiresNameAnnounced(const std::string &from_name,
|
|||||||
boost::starts_with(from_name, to_name) || boost::starts_with(to_name, from_name);
|
boost::starts_with(from_name, to_name) || boost::starts_with(to_name, from_name);
|
||||||
|
|
||||||
const auto checkForPrefixOrSuffixChange =
|
const auto checkForPrefixOrSuffixChange =
|
||||||
[](const std::string &first, const std::string &second, const SuffixTable &suffix_table) {
|
[](const StringView &first, const StringView &second, const SuffixTable &suffix_table) {
|
||||||
std::string first_prefix, first_suffix, second_prefix, second_suffix;
|
std::string first_prefix, first_suffix, second_prefix, second_suffix;
|
||||||
std::tie(first_prefix, first_suffix, second_prefix, second_suffix) =
|
std::tie(first_prefix, first_suffix, second_prefix, second_suffix) =
|
||||||
decompose(first, second);
|
decompose(first, second);
|
||||||
@@ -203,17 +198,17 @@ inline bool requiresNameAnnounced(const std::string &from_name,
|
|||||||
struct NopSuffixTable final
|
struct NopSuffixTable final
|
||||||
{
|
{
|
||||||
NopSuffixTable() {}
|
NopSuffixTable() {}
|
||||||
bool isSuffix(const std::string &) const { return false; }
|
bool isSuffix(const StringView &) const { return false; }
|
||||||
} static const table;
|
} static const table;
|
||||||
|
|
||||||
return requiresNameAnnounced(from_name,
|
return requiresNameAnnounced(util::StringView(from_name),
|
||||||
from_ref,
|
util::StringView(from_ref),
|
||||||
from_pronunciation,
|
util::StringView(from_pronunciation),
|
||||||
from_exits,
|
util::StringView(from_exits),
|
||||||
to_name,
|
util::StringView(to_name),
|
||||||
to_ref,
|
util::StringView(to_ref),
|
||||||
to_pronunciation,
|
util::StringView(to_pronunciation),
|
||||||
to_exits,
|
util::StringView(to_exits),
|
||||||
table);
|
table);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,37 +220,17 @@ inline bool requiresNameAnnounced(const NameID from_name_id,
|
|||||||
if (from_name_id == to_name_id)
|
if (from_name_id == to_name_id)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return requiresNameAnnounced(name_table.GetNameForID(from_name_id).to_string(),
|
return requiresNameAnnounced(name_table.GetNameForID(from_name_id),
|
||||||
name_table.GetRefForID(from_name_id).to_string(),
|
name_table.GetRefForID(from_name_id),
|
||||||
name_table.GetPronunciationForID(from_name_id).to_string(),
|
name_table.GetPronunciationForID(from_name_id),
|
||||||
name_table.GetExitsForID(from_name_id).to_string(),
|
name_table.GetExitsForID(from_name_id),
|
||||||
//
|
//
|
||||||
name_table.GetNameForID(to_name_id).to_string(),
|
name_table.GetNameForID(to_name_id),
|
||||||
name_table.GetRefForID(to_name_id).to_string(),
|
name_table.GetRefForID(to_name_id),
|
||||||
name_table.GetPronunciationForID(to_name_id).to_string(),
|
name_table.GetPronunciationForID(to_name_id),
|
||||||
name_table.GetExitsForID(to_name_id).to_string(),
|
name_table.GetExitsForID(to_name_id),
|
||||||
//
|
//
|
||||||
suffix_table);
|
suffix_table);
|
||||||
// FIXME: converts StringViews to strings since the name change heuristics mutates in place
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool requiresNameAnnounced(const NameID from_name_id,
|
|
||||||
const NameID to_name_id,
|
|
||||||
const util::NameTable &name_table)
|
|
||||||
{
|
|
||||||
if (from_name_id == to_name_id)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return requiresNameAnnounced(name_table.GetNameForID(from_name_id).to_string(),
|
|
||||||
name_table.GetRefForID(from_name_id).to_string(),
|
|
||||||
name_table.GetPronunciationForID(from_name_id).to_string(),
|
|
||||||
name_table.GetExitsForID(from_name_id).to_string(),
|
|
||||||
//
|
|
||||||
name_table.GetNameForID(to_name_id).to_string(),
|
|
||||||
name_table.GetRefForID(to_name_id).to_string(),
|
|
||||||
name_table.GetExitsForID(to_name_id).to_string(),
|
|
||||||
name_table.GetPronunciationForID(to_name_id).to_string());
|
|
||||||
// FIXME: converts StringViews to strings since the name change heuristics mutates in place
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <boost/iterator/iterator_facade.hpp>
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
#include <boost/iterator/reverse_iterator.hpp>
|
#include <boost/iterator/reverse_iterator.hpp>
|
||||||
|
|
||||||
#include <tbb/atomic.h>
|
#include <tbb/atomic.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <boost/iostreams/device/mapped_file.hpp>
|
#include <boost/iostreams/device/mapped_file.hpp>
|
||||||
|
|
||||||
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/parallel_sort.h>
|
#include <tbb/parallel_sort.h>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "osrm",
|
"name": "osrm",
|
||||||
"version": "5.14.0-latest.1",
|
"version": "5.15.3",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+10
-2
@@ -37,6 +37,10 @@ function setup()
|
|||||||
turn_bias = 1.075,
|
turn_bias = 1.075,
|
||||||
cardinal_directions = false,
|
cardinal_directions = false,
|
||||||
|
|
||||||
|
-- Size of the vehicle, to be limited by physical restriction of the way
|
||||||
|
vehicle_height = 2.5, -- in metters, 2.5m is the height of van
|
||||||
|
vehicle_width = 1.9, -- in metters, ways with narrow tag are considered narrower than 2.2m
|
||||||
|
|
||||||
-- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other
|
-- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other
|
||||||
suffix_list = {
|
suffix_list = {
|
||||||
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea'
|
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea'
|
||||||
@@ -100,7 +104,7 @@ function setup()
|
|||||||
},
|
},
|
||||||
|
|
||||||
classes = Sequence {
|
classes = Sequence {
|
||||||
'toll', 'motorway', 'ferry', 'restricted'
|
'toll', 'motorway', 'ferry', 'restricted', 'tunnel'
|
||||||
},
|
},
|
||||||
|
|
||||||
-- classes to support for exclude flags
|
-- classes to support for exclude flags
|
||||||
@@ -253,6 +257,8 @@ function setup()
|
|||||||
["at:rural"] = 100,
|
["at:rural"] = 100,
|
||||||
["at:trunk"] = 100,
|
["at:trunk"] = 100,
|
||||||
["be:motorway"] = 120,
|
["be:motorway"] = 120,
|
||||||
|
["by:urban"] = 60,
|
||||||
|
["by:motorway"] = 110,
|
||||||
["ch:rural"] = 80,
|
["ch:rural"] = 80,
|
||||||
["ch:trunk"] = 100,
|
["ch:trunk"] = 100,
|
||||||
["ch:motorway"] = 120,
|
["ch:motorway"] = 120,
|
||||||
@@ -276,7 +282,6 @@ function setup()
|
|||||||
["ru:living_street"] = 20,
|
["ru:living_street"] = 20,
|
||||||
["ru:urban"] = 60,
|
["ru:urban"] = 60,
|
||||||
["ru:motorway"] = 110,
|
["ru:motorway"] = 110,
|
||||||
["ua:urban"] = 60,
|
|
||||||
["uk:nsl_single"] = (60*1609)/1000,
|
["uk:nsl_single"] = (60*1609)/1000,
|
||||||
["uk:nsl_dual"] = (70*1609)/1000,
|
["uk:nsl_dual"] = (70*1609)/1000,
|
||||||
["uk:motorway"] = (70*1609)/1000,
|
["uk:motorway"] = (70*1609)/1000,
|
||||||
@@ -356,6 +361,9 @@ function process_way(profile, way, result, relations)
|
|||||||
-- routable. this includes things like status=impassable,
|
-- routable. this includes things like status=impassable,
|
||||||
-- toll=yes and oneway=reversible
|
-- toll=yes and oneway=reversible
|
||||||
WayHandlers.blocked_ways,
|
WayHandlers.blocked_ways,
|
||||||
|
WayHandlers.avoid_ways,
|
||||||
|
WayHandlers.handle_height,
|
||||||
|
WayHandlers.handle_width,
|
||||||
|
|
||||||
-- determine access status by checking our hierarchy of
|
-- determine access status by checking our hierarchy of
|
||||||
-- access tags, e.g: motorcar, motor_vehicle, vehicle
|
-- access tags, e.g: motorcar, motor_vehicle, vehicle
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
local Sequence = require('lib/sequence')
|
||||||
|
|
||||||
|
Measure = {}
|
||||||
|
|
||||||
|
-- measurements conversion constants
|
||||||
|
local inch_to_meters = 0.0254
|
||||||
|
local feet_to_inches = 12
|
||||||
|
|
||||||
|
--- Parse string as a height in meters.
|
||||||
|
--- according to http://wiki.openstreetmap.org/wiki/Key:maxheight
|
||||||
|
function Measure.parse_value_meters(value)
|
||||||
|
local n = tonumber(value:gsub(",", "."):match("%d+%.?%d*"))
|
||||||
|
if n then
|
||||||
|
inches = value:match("'.*")
|
||||||
|
if inches then -- Imperial unit to metric
|
||||||
|
-- try to parse feets/inch
|
||||||
|
n = n * feet_to_inches
|
||||||
|
local m = tonumber(inches:match("%d+"))
|
||||||
|
if m then
|
||||||
|
n = n + m
|
||||||
|
end
|
||||||
|
n = n * inch_to_meters
|
||||||
|
end
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- according to http://wiki.openstreetmap.org/wiki/Map_Features/Units#Explicit_specifications
|
||||||
|
local tonns_parse_patterns = Sequence {
|
||||||
|
"%d+",
|
||||||
|
"%d+.%d+",
|
||||||
|
"%d+.%d+ ?t"
|
||||||
|
}
|
||||||
|
|
||||||
|
local kg_parse_patterns = Sequence {
|
||||||
|
"%d+ ?kg"
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Parse weight value in kilograms
|
||||||
|
function Measure.parse_value_kilograms(value)
|
||||||
|
-- try to parse kilograms
|
||||||
|
for i, templ in ipairs(kg_parse_patterns) do
|
||||||
|
m = string.match(value, templ)
|
||||||
|
if m then
|
||||||
|
return tonumber(m)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- try to parse tonns
|
||||||
|
for i, templ in ipairs(tonns_parse_patterns) do
|
||||||
|
m = string.match(value, templ)
|
||||||
|
if m then
|
||||||
|
return tonumber(m) * 1000
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get maxheight of specified way in meters. If there are no
|
||||||
|
--- max height, then return nil
|
||||||
|
function Measure.get_max_height(raw_value)
|
||||||
|
if raw_value then
|
||||||
|
return Measure.parse_value_meters(raw_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get maxwidth of specified way in meters.
|
||||||
|
function Measure.get_max_width(raw_value)
|
||||||
|
if raw_value then
|
||||||
|
return Measure.parse_value_meters(raw_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get maxweight of specified way in kilogramms
|
||||||
|
function Measure.get_max_weight(raw_value)
|
||||||
|
if raw_value then
|
||||||
|
return Measure.parse_value_kilograms(raw_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return Measure;
|
||||||
@@ -8,6 +8,7 @@ local get_turn_lanes = require("lib/guidance").get_turn_lanes
|
|||||||
local set_classification = require("lib/guidance").set_classification
|
local set_classification = require("lib/guidance").set_classification
|
||||||
local get_destination = require("lib/destination").get_destination
|
local get_destination = require("lib/destination").get_destination
|
||||||
local Tags = require('lib/tags')
|
local Tags = require('lib/tags')
|
||||||
|
local Measure = require("lib/measure")
|
||||||
|
|
||||||
WayHandlers = {}
|
WayHandlers = {}
|
||||||
|
|
||||||
@@ -282,6 +283,12 @@ end
|
|||||||
function WayHandlers.classes(profile,way,result,data)
|
function WayHandlers.classes(profile,way,result,data)
|
||||||
local forward_toll, backward_toll = Tags.get_forward_backward_by_key(way, data, "toll")
|
local forward_toll, backward_toll = Tags.get_forward_backward_by_key(way, data, "toll")
|
||||||
local forward_route, backward_route = Tags.get_forward_backward_by_key(way, data, "route")
|
local forward_route, backward_route = Tags.get_forward_backward_by_key(way, data, "route")
|
||||||
|
local tunnel = way:get_value_by_key("tunnel")
|
||||||
|
|
||||||
|
if tunnel and tunnel ~= "no" then
|
||||||
|
result.forward_classes["tunnel"] = true
|
||||||
|
result.backward_classes["tunnel"] = true
|
||||||
|
end
|
||||||
|
|
||||||
if forward_toll == "yes" then
|
if forward_toll == "yes" then
|
||||||
result.forward_classes["toll"] = true
|
result.forward_classes["toll"] = true
|
||||||
@@ -429,6 +436,47 @@ function WayHandlers.parse_maxspeed(source,profile)
|
|||||||
return n
|
return n
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- handle maxheight tags
|
||||||
|
function WayHandlers.handle_height(profile,way,result,data)
|
||||||
|
local keys = Sequence { 'maxheight:physical', 'maxheight' }
|
||||||
|
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
|
||||||
|
forward = Measure.get_max_height(forward)
|
||||||
|
backward = Measure.get_max_height(backward)
|
||||||
|
|
||||||
|
if forward and forward < profile.vehicle_height then
|
||||||
|
result.forward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
|
||||||
|
if backward and backward < profile.vehicle_height then
|
||||||
|
result.backward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle maxwidth tags
|
||||||
|
function WayHandlers.handle_width(profile,way,result,data)
|
||||||
|
local keys = Sequence { 'maxwidth:physical', 'maxwidth', 'width', 'est_width' }
|
||||||
|
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
|
||||||
|
local narrow = way:get_value_by_key('narrow')
|
||||||
|
|
||||||
|
if ((forward and forward == 'narrow') or (narrow and narrow == 'yes')) and profile.vehicle_width > 2.2 then
|
||||||
|
result.forward_mode = mode.inaccessible
|
||||||
|
elseif forward then
|
||||||
|
forward = Measure.get_max_width(forward)
|
||||||
|
if forward and forward <= profile.vehicle_width then
|
||||||
|
result.forward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((backward and backward == 'narrow') or (narrow and narrow == 'yes')) and profile.vehicle_width > 2.2 then
|
||||||
|
result.backward_mode = mode.inaccessible
|
||||||
|
elseif backward then
|
||||||
|
backward = Measure.get_max_width(backward)
|
||||||
|
if backward and backward <= profile.vehicle_width then
|
||||||
|
result.backward_mode = mode.inaccessible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- handle oneways tags
|
-- handle oneways tags
|
||||||
function WayHandlers.oneway(profile,way,result,data)
|
function WayHandlers.oneway(profile,way,result,data)
|
||||||
if not profile.oneway_handling then
|
if not profile.oneway_handling then
|
||||||
@@ -490,6 +538,15 @@ function WayHandlers.weights(profile,way,result,data)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- handle general avoid rules
|
||||||
|
|
||||||
|
function WayHandlers.avoid_ways(profile,way,result,data)
|
||||||
|
if profile.avoid[data.highway] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- handle various that can block access
|
-- handle various that can block access
|
||||||
function WayHandlers.blocked_ways(profile,way,result,data)
|
function WayHandlers.blocked_ways(profile,way,result,data)
|
||||||
|
|
||||||
|
|||||||
@@ -71,10 +71,10 @@ def build_pretty_printer():
|
|||||||
pp.add_printer('TurnLaneData', '::TurnLaneData$', TurnLaneDataPrinter)
|
pp.add_printer('TurnLaneData', '::TurnLaneData$', TurnLaneDataPrinter)
|
||||||
return pp
|
return pp
|
||||||
|
|
||||||
gdb.pretty_printers = [x for x in gdb.pretty_printers if x.name != 'OSRM'] # unregister OSRM pretty printer before (re)loading
|
## unregister OSRM pretty printer before (re)loading
|
||||||
|
gdb.pretty_printers = [x for x in gdb.pretty_printers if not isinstance(x, gdb.printing.RegexpCollectionPrettyPrinter) or x.name != 'OSRM']
|
||||||
gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())
|
gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())
|
||||||
|
|
||||||
|
|
||||||
import geojson
|
import geojson
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/enumerable_thread_specific.h>
|
#include <tbb/enumerable_thread_specific.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/parallel_invoke.h>
|
#include <tbb/parallel_invoke.h>
|
||||||
@@ -384,7 +385,7 @@ void RenumberData(std::vector<RemainingNodeData> &remaining_nodes,
|
|||||||
// we need to make a copy here because we are going to modify it
|
// we need to make a copy here because we are going to modify it
|
||||||
auto to_orig = new_to_old_node_id;
|
auto to_orig = new_to_old_node_id;
|
||||||
|
|
||||||
auto new_node_id = 0;
|
auto new_node_id = 0u;
|
||||||
|
|
||||||
// All remaining nodes get the low IDs
|
// All remaining nodes get the low IDs
|
||||||
for (auto &remaining : remaining_nodes)
|
for (auto &remaining : remaining_nodes)
|
||||||
|
|||||||
@@ -11,12 +11,13 @@ bool EngineConfig::IsValid() const
|
|||||||
// leads to an empty path
|
// leads to an empty path
|
||||||
const bool all_path_are_empty = storage_config.GetPath("").empty();
|
const bool all_path_are_empty = storage_config.GetPath("").empty();
|
||||||
|
|
||||||
const auto unlimited_or_more_than = [](const int v, const int limit) {
|
const auto unlimited_or_more_than = [](const auto v, const auto limit) {
|
||||||
return v == -1 || v > limit;
|
return v == -1 || v > limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool limits_valid = unlimited_or_more_than(max_locations_distance_table, 2) &&
|
const bool limits_valid = unlimited_or_more_than(max_locations_distance_table, 2) &&
|
||||||
unlimited_or_more_than(max_locations_map_matching, 2) &&
|
unlimited_or_more_than(max_locations_map_matching, 2) &&
|
||||||
|
unlimited_or_more_than(max_radius_map_matching, 0) &&
|
||||||
unlimited_or_more_than(max_locations_trip, 2) &&
|
unlimited_or_more_than(max_locations_trip, 2) &&
|
||||||
unlimited_or_more_than(max_locations_viaroute, 2) &&
|
unlimited_or_more_than(max_locations_viaroute, 2) &&
|
||||||
unlimited_or_more_than(max_results_nearest, 0) &&
|
unlimited_or_more_than(max_results_nearest, 0) &&
|
||||||
|
|||||||
@@ -41,15 +41,14 @@ bool noIntermediaryIntersections(const RouteStep &step)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Link roads, as far as we are concerned, are short unnamed segments between to named segments.
|
// Link roads, as far as we are concerned, are short unnamed segments between to named segments.
|
||||||
bool isLinkroad(const RouteStep &pre_link_step,
|
bool isLinkRoad(const RouteStep &pre_link_step,
|
||||||
const RouteStep &link_step,
|
const RouteStep &link_step,
|
||||||
const RouteStep &post_link_step)
|
const RouteStep &post_link_step)
|
||||||
{
|
{
|
||||||
const constexpr double MAX_LINK_ROAD_LENGTH = 2 * MAX_COLLAPSE_DISTANCE;
|
const constexpr double MAX_LINK_ROAD_LENGTH = 2 * MAX_COLLAPSE_DISTANCE;
|
||||||
const auto is_short = link_step.distance <= MAX_LINK_ROAD_LENGTH;
|
const auto is_short = link_step.distance <= MAX_LINK_ROAD_LENGTH;
|
||||||
const auto unnamed = link_step.name_id == EMPTY_NAMEID;
|
const auto unnamed = link_step.name.empty();
|
||||||
const auto between_named =
|
const auto between_named = !pre_link_step.name.empty() && !post_link_step.name.empty();
|
||||||
(pre_link_step.name_id != EMPTY_NAMEID) && (post_link_step.name_id != EMPTY_NAMEID);
|
|
||||||
|
|
||||||
return is_short && unnamed && between_named && noIntermediaryIntersections(link_step);
|
return is_short && unnamed && between_named && noIntermediaryIntersections(link_step);
|
||||||
}
|
}
|
||||||
@@ -196,7 +195,7 @@ bool isUTurn(const RouteStepIterator step_prior_to_intersection,
|
|||||||
const auto only_allowed_turn = (numberOfAllowedTurns(*step_leaving_intersection) == 1) &&
|
const auto only_allowed_turn = (numberOfAllowedTurns(*step_leaving_intersection) == 1) &&
|
||||||
noIntermediaryIntersections(*step_entering_intersection);
|
noIntermediaryIntersections(*step_entering_intersection);
|
||||||
|
|
||||||
return collapsable || isLinkroad(*step_prior_to_intersection,
|
return collapsable || isLinkRoad(*step_prior_to_intersection,
|
||||||
*step_entering_intersection,
|
*step_entering_intersection,
|
||||||
*step_leaving_intersection) ||
|
*step_leaving_intersection) ||
|
||||||
only_allowed_turn;
|
only_allowed_turn;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -139,6 +140,17 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
return Error("InvalidValue", "Invalid coordinate value.", json_result);
|
return Error("InvalidValue", "Invalid coordinate value.", json_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_radius_map_matching > 0 && std::any_of(parameters.radiuses.begin(),
|
||||||
|
parameters.radiuses.end(),
|
||||||
|
[&](const auto &radius) {
|
||||||
|
if (!radius)
|
||||||
|
return false;
|
||||||
|
return *radius > max_radius_map_matching;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
return Error("TooBig", "Radius search size is too large for map matching.", json_result);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for same or increasing timestamps. Impl. note: Incontrast to `sort(first,
|
// Check for same or increasing timestamps. Impl. note: Incontrast to `sort(first,
|
||||||
// last, less_equal)` checking `greater` in reverse meets irreflexive requirements.
|
// last, less_equal)` checking `greater` in reverse meets irreflexive requirements.
|
||||||
const auto time_increases_monotonically = std::is_sorted(
|
const auto time_increases_monotonically = std::is_sorted(
|
||||||
@@ -163,6 +175,16 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
tidied = api::tidy::keep_all(parameters);
|
tidied = api::tidy::keep_all(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error: first and last points should be waypoints
|
||||||
|
if (!parameters.waypoints.empty() &&
|
||||||
|
(tidied.parameters.waypoints[0] != 0 ||
|
||||||
|
tidied.parameters.waypoints.back() != (tidied.parameters.coordinates.size() - 1)))
|
||||||
|
{
|
||||||
|
return Error("InvalidValue",
|
||||||
|
"First and last coordinates must be specified as waypoints.",
|
||||||
|
json_result);
|
||||||
|
}
|
||||||
|
|
||||||
// assuming radius is the standard deviation of a normal distribution
|
// assuming radius is the standard deviation of a normal distribution
|
||||||
// that models GPS noise (in this model), x3 should give us the correct
|
// that models GPS noise (in this model), x3 should give us the correct
|
||||||
// search radius with > 99% confidence
|
// search radius with > 99% confidence
|
||||||
@@ -218,6 +240,34 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
return Error("NoMatch", "Could not match the trace.", json_result);
|
return Error("NoMatch", "Could not match the trace.", json_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trace was split, we don't support the waypoints parameter across multiple match objects
|
||||||
|
if (sub_matchings.size() > 1 && !parameters.waypoints.empty())
|
||||||
|
{
|
||||||
|
return Error("NoMatch", "Could not match the trace with the given waypoints.", json_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error: Check if user-supplied waypoints can be found in the resulting matches
|
||||||
|
if (!parameters.waypoints.empty())
|
||||||
|
{
|
||||||
|
std::set<std::size_t> tidied_waypoints(tidied.parameters.waypoints.begin(),
|
||||||
|
tidied.parameters.waypoints.end());
|
||||||
|
for (const auto &sm : sub_matchings)
|
||||||
|
{
|
||||||
|
std::for_each(sm.indices.begin(),
|
||||||
|
sm.indices.end(),
|
||||||
|
[&tidied_waypoints](const auto index) { tidied_waypoints.erase(index); });
|
||||||
|
}
|
||||||
|
if (!tidied_waypoints.empty())
|
||||||
|
{
|
||||||
|
return Error(
|
||||||
|
"NoMatch", "Requested waypoint parameter could not be matched.", json_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we haven't errored yet, only allow leg collapsing if it was originally requested
|
||||||
|
BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1);
|
||||||
|
const auto collapse_legs = !parameters.waypoints.empty();
|
||||||
|
|
||||||
|
// each sub_route will correspond to a MatchObject
|
||||||
std::vector<InternalRouteResult> sub_routes(sub_matchings.size());
|
std::vector<InternalRouteResult> sub_routes(sub_matchings.size());
|
||||||
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
|
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
|
||||||
{
|
{
|
||||||
@@ -234,12 +284,31 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
|
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
|
||||||
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||||
}
|
}
|
||||||
// force uturns to be on, since we split the phantom nodes anyway and only have
|
// force uturns to be on
|
||||||
// bi-directional
|
// we split the phantom nodes anyway and only have bi-directional phantom nodes for
|
||||||
// phantom nodes for possible uturns
|
// possible uturns
|
||||||
sub_routes[index] =
|
sub_routes[index] =
|
||||||
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
|
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
|
||||||
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
|
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
|
||||||
|
if (collapse_legs)
|
||||||
|
{
|
||||||
|
std::vector<bool> waypoint_legs;
|
||||||
|
waypoint_legs.reserve(sub_matchings[index].indices.size());
|
||||||
|
for (unsigned i = 0, j = 0; i < sub_matchings[index].indices.size(); ++i)
|
||||||
|
{
|
||||||
|
auto current_wp = tidied.parameters.waypoints[j];
|
||||||
|
if (current_wp == sub_matchings[index].indices[i])
|
||||||
|
{
|
||||||
|
waypoint_legs.push_back(true);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
waypoint_legs.push_back(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sub_routes[index] = CollapseInternalRouteResult(sub_routes[index], waypoint_legs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api::MatchAPI match_api{facade, parameters, tidied};
|
api::MatchAPI match_api{facade, parameters, tidied};
|
||||||
|
|||||||
@@ -784,9 +784,8 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
|||||||
begin(weighted_packed_paths) + 1,
|
begin(weighted_packed_paths) + 1,
|
||||||
alternative_paths_last);
|
alternative_paths_last);
|
||||||
|
|
||||||
alternative_paths_last = filterPackedPathsByCellSharing(begin(weighted_packed_paths), //
|
alternative_paths_last = filterPackedPathsByCellSharing(
|
||||||
end(weighted_packed_paths), //
|
begin(weighted_packed_paths), alternative_paths_last, partition);
|
||||||
partition); //
|
|
||||||
|
|
||||||
BOOST_ASSERT(weighted_packed_paths.size() >= 1);
|
BOOST_ASSERT(weighted_packed_paths.size() >= 1);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include "extractor/scripting_environment.hpp"
|
#include "extractor/scripting_environment.hpp"
|
||||||
#include "extractor/suffix_table.hpp"
|
#include "extractor/suffix_table.hpp"
|
||||||
|
|
||||||
|
#include "extractor/intersection/intersection_analysis.hpp"
|
||||||
|
|
||||||
#include "extractor/serialization.hpp"
|
#include "extractor/serialization.hpp"
|
||||||
#include "storage/io.hpp"
|
#include "storage/io.hpp"
|
||||||
|
|
||||||
@@ -375,7 +377,9 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
|
|||||||
m_edge_based_node_container.nodes[edge_based_node_id].segregated =
|
m_edge_based_node_container.nodes[edge_based_node_id].segregated =
|
||||||
segregated_edges.count(eid) > 0;
|
segregated_edges.count(eid) > 0;
|
||||||
|
|
||||||
m_edge_based_node_weights.push_back(m_edge_based_node_weights[eid]);
|
const auto ebn_weight = m_edge_based_node_weights[nbe_to_ebn_mapping[eid]];
|
||||||
|
BOOST_ASSERT(ebn_weight == INVALID_EDGE_WEIGHT || ebn_weight == edge_data.weight);
|
||||||
|
m_edge_based_node_weights.push_back(ebn_weight);
|
||||||
|
|
||||||
edge_based_node_id++;
|
edge_based_node_id++;
|
||||||
progress.PrintStatus(progress_counter++);
|
progress.PrintStatus(progress_counter++);
|
||||||
@@ -419,22 +423,39 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
|
|
||||||
TurnDataExternalContainer turn_data_container;
|
TurnDataExternalContainer turn_data_container;
|
||||||
|
|
||||||
|
SuffixTable street_name_suffix_table(scripting_environment);
|
||||||
|
const auto &turn_lanes_data = transformTurnLaneMapIntoArrays(lane_description_map);
|
||||||
|
guidance::MergableRoadDetector mergable_road_detector(m_node_based_graph,
|
||||||
|
m_edge_based_node_container,
|
||||||
|
m_coordinates,
|
||||||
|
m_compressed_edge_container,
|
||||||
|
node_restriction_map,
|
||||||
|
m_barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table);
|
||||||
|
|
||||||
// Loop over all turns and generate new set of edges.
|
// Loop over all turns and generate new set of edges.
|
||||||
// Three nested loop look super-linear, but we are dealing with a (kind of)
|
// Three nested loop look super-linear, but we are dealing with a (kind of)
|
||||||
// linear number of turns only.
|
// linear number of turns only.
|
||||||
SuffixTable street_name_suffix_table(scripting_environment);
|
|
||||||
guidance::TurnAnalysis turn_analysis(m_node_based_graph,
|
guidance::TurnAnalysis turn_analysis(m_node_based_graph,
|
||||||
m_edge_based_node_container,
|
m_edge_based_node_container,
|
||||||
m_coordinates,
|
m_coordinates,
|
||||||
|
m_compressed_edge_container,
|
||||||
node_restriction_map,
|
node_restriction_map,
|
||||||
m_barrier_nodes,
|
m_barrier_nodes,
|
||||||
m_compressed_edge_container,
|
turn_lanes_data,
|
||||||
name_table,
|
name_table,
|
||||||
street_name_suffix_table);
|
street_name_suffix_table);
|
||||||
|
|
||||||
util::guidance::LaneDataIdMap lane_data_map;
|
util::guidance::LaneDataIdMap lane_data_map;
|
||||||
guidance::lanes::TurnLaneHandler turn_lane_handler(m_node_based_graph,
|
guidance::lanes::TurnLaneHandler turn_lane_handler(m_node_based_graph,
|
||||||
m_edge_based_node_container,
|
m_edge_based_node_container,
|
||||||
|
m_coordinates,
|
||||||
|
m_compressed_edge_container,
|
||||||
|
node_restriction_map,
|
||||||
|
m_barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
lane_description_map,
|
lane_description_map,
|
||||||
turn_analysis,
|
turn_analysis,
|
||||||
lane_data_map);
|
lane_data_map);
|
||||||
@@ -537,14 +558,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
// the situation of the turn
|
// the situation of the turn
|
||||||
const auto node_along_road_entering,
|
const auto node_along_road_entering,
|
||||||
const auto node_based_edge_from,
|
const auto node_based_edge_from,
|
||||||
const auto node_at_center_of_intersection,
|
const auto intersection_node,
|
||||||
const auto node_based_edge_to,
|
const auto node_based_edge_to,
|
||||||
const auto &intersection,
|
const auto incoming_bearing,
|
||||||
const auto &turn,
|
const auto &turn,
|
||||||
const auto entry_class_id) {
|
const auto entry_class_id) {
|
||||||
|
|
||||||
const auto node_restricted = isRestricted(node_along_road_entering,
|
const auto node_restricted = isRestricted(node_along_road_entering,
|
||||||
node_at_center_of_intersection,
|
intersection_node,
|
||||||
m_node_based_graph.GetTarget(turn.eid),
|
m_node_based_graph.GetTarget(turn.eid),
|
||||||
conditional_restriction_map);
|
conditional_restriction_map);
|
||||||
|
|
||||||
@@ -556,7 +577,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
conditional = {{edge_based_node_from,
|
conditional = {{edge_based_node_from,
|
||||||
edge_based_node_to,
|
edge_based_node_to,
|
||||||
{static_cast<std::uint64_t>(-1),
|
{static_cast<std::uint64_t>(-1),
|
||||||
m_coordinates[node_at_center_of_intersection],
|
m_coordinates[intersection_node],
|
||||||
conditions}}};
|
conditions}}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,15 +593,15 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
TurnData turn_data = {turn.instruction,
|
TurnData turn_data = {turn.instruction,
|
||||||
turn.lane_data_id,
|
turn.lane_data_id,
|
||||||
entry_class_id,
|
entry_class_id,
|
||||||
util::guidance::TurnBearing(intersection[0].bearing),
|
util::guidance::TurnBearing(incoming_bearing),
|
||||||
util::guidance::TurnBearing(turn.bearing)};
|
util::guidance::TurnBearing(turn.bearing)};
|
||||||
|
|
||||||
// compute weight and duration penalties
|
// compute weight and duration penalties
|
||||||
auto is_traffic_light = m_traffic_lights.count(node_at_center_of_intersection);
|
auto is_traffic_light = m_traffic_lights.count(intersection_node);
|
||||||
ExtractionTurn extracted_turn(
|
ExtractionTurn extracted_turn(
|
||||||
turn.angle,
|
turn.angle,
|
||||||
m_node_based_graph.GetOutDegree(node_at_center_of_intersection),
|
m_node_based_graph.GetOutDegree(intersection_node),
|
||||||
turn.instruction.direction_modifier == guidance::DirectionModifier::UTurn,
|
turn.instruction.IsUTurn(),
|
||||||
is_traffic_light,
|
is_traffic_light,
|
||||||
edge_data1.flags.restricted,
|
edge_data1.flags.restricted,
|
||||||
edge_data2.flags.restricted,
|
edge_data2.flags.restricted,
|
||||||
@@ -630,8 +651,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
|
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
|
||||||
const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
|
const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
|
||||||
|
|
||||||
lookup::TurnIndexBlock turn_index_block = {
|
lookup::TurnIndexBlock turn_index_block = {from_node, intersection_node, to_node};
|
||||||
from_node, node_at_center_of_intersection, to_node};
|
|
||||||
|
|
||||||
// insert data into the designated buffer
|
// insert data into the designated buffer
|
||||||
return std::make_pair(
|
return std::make_pair(
|
||||||
@@ -653,17 +673,26 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
if (buffer->nodes_processed == 0)
|
if (buffer->nodes_processed == 0)
|
||||||
return buffer;
|
return buffer;
|
||||||
|
|
||||||
for (auto node_at_center_of_intersection = intersection_node_range.begin(),
|
for (auto intersection_node = intersection_node_range.begin(),
|
||||||
end = intersection_node_range.end();
|
end = intersection_node_range.end();
|
||||||
node_at_center_of_intersection < end;
|
intersection_node < end;
|
||||||
++node_at_center_of_intersection)
|
++intersection_node)
|
||||||
{
|
{
|
||||||
|
|
||||||
// We capture the thread-local work in these objects, then flush
|
// We capture the thread-local work in these objects, then flush
|
||||||
// them in a controlled manner at the end of the parallel range
|
// them in a controlled manner at the end of the parallel range
|
||||||
|
const auto &incoming_edges =
|
||||||
|
intersection::getIncomingEdges(m_node_based_graph, intersection_node);
|
||||||
|
const auto &outgoing_edges =
|
||||||
|
intersection::getOutgoingEdges(m_node_based_graph, intersection_node);
|
||||||
|
|
||||||
const auto shape_result =
|
intersection::IntersectionEdgeGeometries edge_geometries;
|
||||||
turn_analysis.ComputeIntersectionShapes(node_at_center_of_intersection);
|
std::unordered_set<EdgeID> merged_edge_ids;
|
||||||
|
std::tie(edge_geometries, merged_edge_ids) =
|
||||||
|
intersection::getIntersectionGeometries(m_node_based_graph,
|
||||||
|
m_compressed_edge_container,
|
||||||
|
m_coordinates,
|
||||||
|
mergable_road_detector,
|
||||||
|
intersection_node);
|
||||||
|
|
||||||
// all nodes in the graph are connected in both directions. We check all
|
// 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,
|
// outgoing nodes to find the incoming edge. This is a larger search overhead,
|
||||||
@@ -683,45 +712,33 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
// From the flags alone, we cannot determine which nodes are connected to
|
// 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
|
// `b` by an outgoing edge. Therefore, we have to search all connected edges for
|
||||||
// edges entering `b`
|
// edges entering `b`
|
||||||
for (const EdgeID outgoing_edge :
|
|
||||||
m_node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection))
|
for (const auto &incoming_edge : incoming_edges)
|
||||||
{
|
{
|
||||||
const NodeID node_along_road_entering =
|
|
||||||
m_node_based_graph.GetTarget(outgoing_edge);
|
|
||||||
|
|
||||||
const auto incoming_edge = m_node_based_graph.FindEdge(
|
|
||||||
node_along_road_entering, node_at_center_of_intersection);
|
|
||||||
|
|
||||||
if (m_node_based_graph.GetEdgeData(incoming_edge).reversed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
++node_based_edge_counter;
|
++node_based_edge_counter;
|
||||||
|
|
||||||
auto intersection_with_flags_and_angles =
|
const auto intersection_view =
|
||||||
turn_analysis.GetIntersectionGenerator()
|
convertToIntersectionView(m_node_based_graph,
|
||||||
.TransformIntersectionShapeIntoView(
|
m_edge_based_node_container,
|
||||||
node_along_road_entering,
|
node_restriction_map,
|
||||||
incoming_edge,
|
m_barrier_nodes,
|
||||||
shape_result.annotated_normalized_shape.normalized_shape,
|
edge_geometries,
|
||||||
shape_result.intersection_shape,
|
turn_lanes_data,
|
||||||
shape_result.annotated_normalized_shape.performed_merges);
|
incoming_edge,
|
||||||
|
outgoing_edges,
|
||||||
|
merged_edge_ids);
|
||||||
|
|
||||||
auto intersection =
|
auto intersection = turn_analysis.AssignTurnTypes(
|
||||||
turn_analysis.AssignTurnTypes(node_along_road_entering,
|
incoming_edge.node, incoming_edge.edge, intersection_view);
|
||||||
incoming_edge,
|
|
||||||
intersection_with_flags_and_angles);
|
|
||||||
|
|
||||||
OSRM_ASSERT(intersection.valid(),
|
|
||||||
m_coordinates[node_at_center_of_intersection]);
|
|
||||||
|
|
||||||
|
OSRM_ASSERT(intersection.valid(), m_coordinates[intersection_node]);
|
||||||
intersection = turn_lane_handler.assignTurnLanes(
|
intersection = turn_lane_handler.assignTurnLanes(
|
||||||
node_along_road_entering, incoming_edge, std::move(intersection));
|
incoming_edge.node, incoming_edge.edge, std::move(intersection));
|
||||||
|
|
||||||
// the entry class depends on the turn, so we have to classify the
|
// the entry class depends on the turn, so we have to classify the
|
||||||
// interesction for
|
// interesction for every edge
|
||||||
// every edge
|
const auto turn_classification =
|
||||||
const auto turn_classification = classifyIntersection(
|
classifyIntersection(intersection, m_coordinates[intersection_node]);
|
||||||
intersection, m_coordinates[node_at_center_of_intersection]);
|
|
||||||
|
|
||||||
const auto entry_class_id =
|
const auto entry_class_id =
|
||||||
entry_class_hash.ConcurrentFindOrAdd(turn_classification.first);
|
entry_class_hash.ConcurrentFindOrAdd(turn_classification.first);
|
||||||
@@ -732,19 +749,37 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
// Note - this is strictly speaking not thread safe, but we know we
|
// Note - this is strictly speaking not thread safe, but we know we
|
||||||
// should never be touching the same element twice, so we should
|
// should never be touching the same element twice, so we should
|
||||||
// be fine.
|
// be fine.
|
||||||
bearing_class_by_node_based_node[node_at_center_of_intersection] =
|
bearing_class_by_node_based_node[intersection_node] = bearing_class_id;
|
||||||
bearing_class_id;
|
|
||||||
|
|
||||||
// check if we are turning off a via way
|
// check if we are turning off a via way
|
||||||
const auto turning_off_via_way = way_restriction_map.IsViaWay(
|
const auto turning_off_via_way =
|
||||||
node_along_road_entering, node_at_center_of_intersection);
|
way_restriction_map.IsViaWay(incoming_edge.node, intersection_node);
|
||||||
|
|
||||||
for (const auto &turn : intersection)
|
// Save reversed incoming bearing to compute turn angles
|
||||||
|
const auto reversed_incoming_bearing = util::bearing::reverse(
|
||||||
|
findEdgeBearing(edge_geometries, incoming_edge.edge));
|
||||||
|
|
||||||
|
for (const auto &outgoing_edge : outgoing_edges)
|
||||||
{
|
{
|
||||||
// only keep valid turns
|
if (!intersection::isTurnAllowed(m_node_based_graph,
|
||||||
if (!turn.entry_allowed)
|
m_edge_based_node_container,
|
||||||
|
node_restriction_map,
|
||||||
|
m_barrier_nodes,
|
||||||
|
edge_geometries,
|
||||||
|
turn_lanes_data,
|
||||||
|
incoming_edge,
|
||||||
|
outgoing_edge))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const auto turn =
|
||||||
|
std::find_if(intersection.begin(),
|
||||||
|
intersection.end(),
|
||||||
|
[edge = outgoing_edge.edge](const auto &road) {
|
||||||
|
return road.eid == edge;
|
||||||
|
});
|
||||||
|
OSRM_ASSERT(turn != intersection.end(),
|
||||||
|
m_coordinates[intersection_node]);
|
||||||
|
|
||||||
// In case a way restriction starts at a given location, add a turn onto
|
// In case a way restriction starts at a given location, add a turn onto
|
||||||
// every artificial node eminating here.
|
// every artificial node eminating here.
|
||||||
//
|
//
|
||||||
@@ -766,22 +801,22 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
// duplicated node associated with the turn. (e.g. ab via bc switches bc
|
// duplicated node associated with the turn. (e.g. ab via bc switches bc
|
||||||
// to bc_dup)
|
// to bc_dup)
|
||||||
auto const target_id = way_restriction_map.RemapIfRestricted(
|
auto const target_id = way_restriction_map.RemapIfRestricted(
|
||||||
nbe_to_ebn_mapping[turn.eid],
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||||
node_along_road_entering,
|
incoming_edge.node,
|
||||||
node_at_center_of_intersection,
|
outgoing_edge.node,
|
||||||
m_node_based_graph.GetTarget(turn.eid),
|
m_node_based_graph.GetTarget(outgoing_edge.edge),
|
||||||
m_number_of_edge_based_nodes);
|
m_number_of_edge_based_nodes);
|
||||||
|
|
||||||
{ // scope to forget edge_with_data after
|
{ // scope to forget edge_with_data after
|
||||||
const auto edge_with_data_and_condition =
|
const auto edge_with_data_and_condition =
|
||||||
generate_edge(nbe_to_ebn_mapping[incoming_edge],
|
generate_edge(nbe_to_ebn_mapping[incoming_edge.edge],
|
||||||
target_id,
|
target_id,
|
||||||
node_along_road_entering,
|
incoming_edge.node,
|
||||||
incoming_edge,
|
incoming_edge.edge,
|
||||||
node_at_center_of_intersection,
|
outgoing_edge.node,
|
||||||
turn.eid,
|
outgoing_edge.edge,
|
||||||
intersection,
|
reversed_incoming_bearing,
|
||||||
turn,
|
*turn,
|
||||||
entry_class_id);
|
entry_class_id);
|
||||||
|
|
||||||
buffer->continuous_data.edges_list.push_back(
|
buffer->continuous_data.edges_list.push_back(
|
||||||
@@ -808,7 +843,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
if (turning_off_via_way)
|
if (turning_off_via_way)
|
||||||
{
|
{
|
||||||
const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs(
|
const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs(
|
||||||
node_along_road_entering, node_at_center_of_intersection);
|
incoming_edge.node, intersection_node);
|
||||||
|
|
||||||
// next to the normal restrictions tracked in `entry_allowed`, via
|
// next to the normal restrictions tracked in `entry_allowed`, via
|
||||||
// ways might introduce additional restrictions. These are handled
|
// ways might introduce additional restrictions. These are handled
|
||||||
@@ -816,12 +851,12 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
for (auto duplicated_node_id : duplicated_nodes)
|
for (auto duplicated_node_id : duplicated_nodes)
|
||||||
{
|
{
|
||||||
const auto from_id =
|
const auto from_id =
|
||||||
m_number_of_edge_based_nodes -
|
NodeID(m_number_of_edge_based_nodes -
|
||||||
way_restriction_map.NumberOfDuplicatedNodes() +
|
way_restriction_map.NumberOfDuplicatedNodes() +
|
||||||
duplicated_node_id;
|
duplicated_node_id);
|
||||||
|
|
||||||
auto const node_at_end_of_turn =
|
auto const node_at_end_of_turn =
|
||||||
m_node_based_graph.GetTarget(turn.eid);
|
m_node_based_graph.GetTarget(outgoing_edge.edge);
|
||||||
|
|
||||||
const auto is_way_restricted = way_restriction_map.IsRestricted(
|
const auto is_way_restricted = way_restriction_map.IsRestricted(
|
||||||
duplicated_node_id, node_at_end_of_turn);
|
duplicated_node_id, node_at_end_of_turn);
|
||||||
@@ -836,14 +871,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
|
|
||||||
// add into delayed data
|
// add into delayed data
|
||||||
auto edge_with_data_and_condition =
|
auto edge_with_data_and_condition =
|
||||||
generate_edge(NodeID(from_id),
|
generate_edge(from_id,
|
||||||
nbe_to_ebn_mapping[turn.eid],
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||||
node_along_road_entering,
|
incoming_edge.node,
|
||||||
incoming_edge,
|
incoming_edge.edge,
|
||||||
node_at_center_of_intersection,
|
outgoing_edge.node,
|
||||||
turn.eid,
|
outgoing_edge.edge,
|
||||||
intersection,
|
reversed_incoming_bearing,
|
||||||
turn,
|
*turn,
|
||||||
entry_class_id);
|
entry_class_id);
|
||||||
|
|
||||||
buffer->delayed_data.push_back(
|
buffer->delayed_data.push_back(
|
||||||
@@ -860,24 +895,24 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
{
|
{
|
||||||
// add a new conditional for the edge we just created
|
// add a new conditional for the edge we just created
|
||||||
buffer->conditionals.push_back(
|
buffer->conditionals.push_back(
|
||||||
{NodeID(from_id),
|
{from_id,
|
||||||
nbe_to_ebn_mapping[turn.eid],
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||||
{static_cast<std::uint64_t>(-1),
|
{static_cast<std::uint64_t>(-1),
|
||||||
m_coordinates[node_at_center_of_intersection],
|
m_coordinates[intersection_node],
|
||||||
restriction.condition}});
|
restriction.condition}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto edge_with_data_and_condition =
|
auto edge_with_data_and_condition =
|
||||||
generate_edge(NodeID(from_id),
|
generate_edge(from_id,
|
||||||
nbe_to_ebn_mapping[turn.eid],
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||||
node_along_road_entering,
|
incoming_edge.node,
|
||||||
incoming_edge,
|
incoming_edge.edge,
|
||||||
node_at_center_of_intersection,
|
outgoing_edge.node,
|
||||||
turn.eid,
|
outgoing_edge.edge,
|
||||||
intersection,
|
reversed_incoming_bearing,
|
||||||
turn,
|
*turn,
|
||||||
entry_class_id);
|
entry_class_id);
|
||||||
|
|
||||||
buffer->delayed_data.push_back(
|
buffer->delayed_data.push_back(
|
||||||
|
|||||||
+7
-230
@@ -13,6 +13,8 @@
|
|||||||
#include "extractor/restriction_parser.hpp"
|
#include "extractor/restriction_parser.hpp"
|
||||||
#include "extractor/scripting_environment.hpp"
|
#include "extractor/scripting_environment.hpp"
|
||||||
|
|
||||||
|
#include "extractor/guidance/segregated_intersection_classification.hpp"
|
||||||
|
|
||||||
#include "storage/io.hpp"
|
#include "storage/io.hpp"
|
||||||
|
|
||||||
#include "util/exception.hpp"
|
#include "util/exception.hpp"
|
||||||
@@ -220,7 +222,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
|||||||
util::Log() << "Find segregated edges in node-based graph ..." << std::flush;
|
util::Log() << "Find segregated edges in node-based graph ..." << std::flush;
|
||||||
TIMER_START(segregated);
|
TIMER_START(segregated);
|
||||||
|
|
||||||
auto segregated_edges = FindSegregatedNodes(node_based_graph_factory);
|
util::NameTable names(config.GetPath(".osrm.names").string());
|
||||||
|
auto segregated_edges = guidance::findSegregatedNodes(node_based_graph_factory, names);
|
||||||
|
|
||||||
TIMER_STOP(segregated);
|
TIMER_STOP(segregated);
|
||||||
util::Log() << "ok, after " << TIMER_SEC(segregated) << "s";
|
util::Log() << "ok, after " << TIMER_SEC(segregated) << "s";
|
||||||
@@ -362,7 +365,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
TIMER_START(parsing);
|
TIMER_START(parsing);
|
||||||
|
|
||||||
{ // Parse OSM header
|
{ // Parse OSM header
|
||||||
osmium::io::Reader reader(input_file, osmium::osm_entity_bits::nothing);
|
osmium::io::Reader reader(input_file, pool, osmium::osm_entity_bits::nothing);
|
||||||
osmium::io::Header header = reader.header();
|
osmium::io::Header header = reader.header();
|
||||||
|
|
||||||
std::string generator = header.get("generator");
|
std::string generator = header.get("generator");
|
||||||
@@ -542,7 +545,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
|
|
||||||
{ // Relations reading pipeline
|
{ // Relations reading pipeline
|
||||||
util::Log() << "Parse relations ...";
|
util::Log() << "Parse relations ...";
|
||||||
osmium::io::Reader reader(input_file, osmium::osm_entity_bits::relation, read_meta);
|
osmium::io::Reader reader(input_file, pool, osmium::osm_entity_bits::relation, read_meta);
|
||||||
tbb::parallel_pipeline(
|
tbb::parallel_pipeline(
|
||||||
num_threads, buffer_reader(reader) & buffer_relation_cache & buffer_storage_relation);
|
num_threads, buffer_reader(reader) & buffer_relation_cache & buffer_storage_relation);
|
||||||
}
|
}
|
||||||
@@ -550,6 +553,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
{ // Nodes and ways reading pipeline
|
{ // Nodes and ways reading pipeline
|
||||||
util::Log() << "Parse ways and nodes ...";
|
util::Log() << "Parse ways and nodes ...";
|
||||||
osmium::io::Reader reader(input_file,
|
osmium::io::Reader reader(input_file,
|
||||||
|
pool,
|
||||||
osmium::osm_entity_bits::node | osmium::osm_entity_bits::way |
|
osmium::osm_entity_bits::node | osmium::osm_entity_bits::way |
|
||||||
osmium::osm_entity_bits::relation,
|
osmium::osm_entity_bits::relation,
|
||||||
read_meta);
|
read_meta);
|
||||||
@@ -838,232 +842,5 @@ void Extractor::WriteCompressedNodeBasedGraph(const std::string &path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EdgeInfo
|
|
||||||
{
|
|
||||||
NodeID node;
|
|
||||||
|
|
||||||
util::StringView name;
|
|
||||||
|
|
||||||
// 0 - outgoing (forward), 1 - incoming (reverse), 2 - both outgoing and incoming
|
|
||||||
int direction;
|
|
||||||
|
|
||||||
ClassData road_class;
|
|
||||||
|
|
||||||
guidance::RoadPriorityClass::Enum road_priority_class;
|
|
||||||
|
|
||||||
struct LessName
|
|
||||||
{
|
|
||||||
bool operator()(EdgeInfo const &e1, EdgeInfo const &e2) const { return e1.name < e2.name; }
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
bool IsSegregated(std::vector<EdgeInfo> v1,
|
|
||||||
std::vector<EdgeInfo> v2,
|
|
||||||
EdgeInfo const ¤t,
|
|
||||||
double edgeLength)
|
|
||||||
{
|
|
||||||
if (v1.size() < 2 || v2.size() < 2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto const sort_by_name_fn = [](std::vector<EdgeInfo> &v) {
|
|
||||||
std::sort(v.begin(), v.end(), EdgeInfo::LessName());
|
|
||||||
};
|
|
||||||
|
|
||||||
sort_by_name_fn(v1);
|
|
||||||
sort_by_name_fn(v2);
|
|
||||||
|
|
||||||
// Internal edge with the name should be connected with any other neibour edge with the same
|
|
||||||
// name, e.g. isolated edge with unique name is not segregated.
|
|
||||||
// b - 'b' road continues here
|
|
||||||
// |
|
|
||||||
// - - a - |
|
|
||||||
// b - segregated edge
|
|
||||||
// - - a - |
|
|
||||||
if (!current.name.empty())
|
|
||||||
{
|
|
||||||
auto const findNameFn = [¤t](std::vector<EdgeInfo> const &v) {
|
|
||||||
return std::binary_search(v.begin(), v.end(), current, EdgeInfo::LessName());
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!findNameFn(v1) && !findNameFn(v2))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_intersection like routine to get equal result pairs
|
|
||||||
std::vector<std::pair<EdgeInfo const *, EdgeInfo const *>> commons;
|
|
||||||
|
|
||||||
auto i1 = v1.begin();
|
|
||||||
auto i2 = v2.begin();
|
|
||||||
|
|
||||||
while (i1 != v1.end() && i2 != v2.end())
|
|
||||||
{
|
|
||||||
if (i1->name == i2->name)
|
|
||||||
{
|
|
||||||
if (!i1->name.empty())
|
|
||||||
commons.push_back(std::make_pair(&(*i1), &(*i2)));
|
|
||||||
|
|
||||||
++i1;
|
|
||||||
++i2;
|
|
||||||
}
|
|
||||||
else if (i1->name < i2->name)
|
|
||||||
++i1;
|
|
||||||
else
|
|
||||||
++i2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commons.size() < 2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto const check_equal_class = [](std::pair<EdgeInfo const *, EdgeInfo const *> const &e) {
|
|
||||||
// Or (e.first->road_class & e.second->road_class != 0)
|
|
||||||
return e.first->road_class == e.second->road_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t equal_class_count = 0;
|
|
||||||
for (auto const &e : commons)
|
|
||||||
if (check_equal_class(e))
|
|
||||||
++equal_class_count;
|
|
||||||
|
|
||||||
if (equal_class_count < 2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto const get_length_threshold = [](EdgeInfo const *e) {
|
|
||||||
switch (e->road_priority_class)
|
|
||||||
{
|
|
||||||
case guidance::RoadPriorityClass::MOTORWAY:
|
|
||||||
case guidance::RoadPriorityClass::TRUNK:
|
|
||||||
return 30.0;
|
|
||||||
case guidance::RoadPriorityClass::PRIMARY:
|
|
||||||
return 20.0;
|
|
||||||
case guidance::RoadPriorityClass::SECONDARY:
|
|
||||||
case guidance::RoadPriorityClass::TERTIARY:
|
|
||||||
return 10.0;
|
|
||||||
default:
|
|
||||||
return 5.0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
double threshold = std::numeric_limits<double>::max();
|
|
||||||
for (auto const &e : commons)
|
|
||||||
threshold =
|
|
||||||
std::min(threshold, get_length_threshold(e.first) + get_length_threshold(e.second));
|
|
||||||
|
|
||||||
return edgeLength <= threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_set<EdgeID> Extractor::FindSegregatedNodes(NodeBasedGraphFactory &factory)
|
|
||||||
{
|
|
||||||
util::NameTable names(config.GetPath(".osrm.names").string());
|
|
||||||
|
|
||||||
auto const &graph = factory.GetGraph();
|
|
||||||
auto const &annotation = factory.GetAnnotationData();
|
|
||||||
|
|
||||||
guidance::CoordinateExtractor coordExtractor(
|
|
||||||
graph, factory.GetCompressedEdges(), factory.GetCoordinates());
|
|
||||||
|
|
||||||
auto const get_edge_length = [&](NodeID from_node, EdgeID edgeID, NodeID to_node) {
|
|
||||||
auto const geom = coordExtractor.GetCoordinatesAlongRoad(from_node, edgeID, false, to_node);
|
|
||||||
double length = 0.0;
|
|
||||||
for (size_t i = 1; i < geom.size(); ++i)
|
|
||||||
{
|
|
||||||
length += osrm::util::coordinate_calculation::haversineDistance(geom[i - 1], geom[i]);
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto const get_edge_info = [&](NodeID node, auto const &edgeData) -> EdgeInfo {
|
|
||||||
/// @todo Make string normalization/lowercase/trim for comparison ...
|
|
||||||
|
|
||||||
auto const id = annotation[edgeData.annotation_data].name_id;
|
|
||||||
BOOST_ASSERT(id != INVALID_NAMEID);
|
|
||||||
auto const name = names.GetNameForID(id);
|
|
||||||
|
|
||||||
return {node,
|
|
||||||
name,
|
|
||||||
edgeData.reversed ? 1 : 0,
|
|
||||||
annotation[edgeData.annotation_data].classes,
|
|
||||||
edgeData.flags.road_classification.GetClass()};
|
|
||||||
};
|
|
||||||
|
|
||||||
auto const collect_edge_info_fn = [&](auto const &edges1, NodeID node2) {
|
|
||||||
std::vector<EdgeInfo> info;
|
|
||||||
|
|
||||||
for (auto const &e : edges1)
|
|
||||||
{
|
|
||||||
NodeID const target = graph.GetTarget(e);
|
|
||||||
if (target == node2)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
info.push_back(get_edge_info(target, graph.GetEdgeData(e)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.empty())
|
|
||||||
return info;
|
|
||||||
|
|
||||||
std::sort(info.begin(), info.end(), [](EdgeInfo const &e1, EdgeInfo const &e2) {
|
|
||||||
return e1.node < e2.node;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Merge equal infos with correct direction.
|
|
||||||
auto curr = info.begin();
|
|
||||||
auto next = curr;
|
|
||||||
while (++next != info.end())
|
|
||||||
{
|
|
||||||
if (curr->node == next->node)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(curr->name == next->name);
|
|
||||||
BOOST_ASSERT(curr->road_class == next->road_class);
|
|
||||||
BOOST_ASSERT(curr->direction != next->direction);
|
|
||||||
curr->direction = 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
curr = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.erase(
|
|
||||||
std::unique(info.begin(),
|
|
||||||
info.end(),
|
|
||||||
[](EdgeInfo const &e1, EdgeInfo const &e2) { return e1.node == e2.node; }),
|
|
||||||
info.end());
|
|
||||||
|
|
||||||
return info;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto const isSegregatedFn = [&](auto const &edgeData,
|
|
||||||
auto const &edges1,
|
|
||||||
NodeID node1,
|
|
||||||
auto const &edges2,
|
|
||||||
NodeID node2,
|
|
||||||
double edgeLength) {
|
|
||||||
return IsSegregated(collect_edge_info_fn(edges1, node2),
|
|
||||||
collect_edge_info_fn(edges2, node1),
|
|
||||||
get_edge_info(node1, edgeData),
|
|
||||||
edgeLength);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_set<EdgeID> segregated_edges;
|
|
||||||
|
|
||||||
for (NodeID sourceID = 0; sourceID < graph.GetNumberOfNodes(); ++sourceID)
|
|
||||||
{
|
|
||||||
auto const sourceEdges = graph.GetAdjacentEdgeRange(sourceID);
|
|
||||||
for (EdgeID edgeID : sourceEdges)
|
|
||||||
{
|
|
||||||
auto const &edgeData = graph.GetEdgeData(edgeID);
|
|
||||||
|
|
||||||
if (edgeData.reversed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
NodeID const targetID = graph.GetTarget(edgeID);
|
|
||||||
auto const targetEdges = graph.GetAdjacentEdgeRange(targetID);
|
|
||||||
|
|
||||||
double const length = get_edge_length(sourceID, edgeID, targetID);
|
|
||||||
if (isSegregatedFn(edgeData, sourceEdges, sourceID, targetEdges, targetID, length))
|
|
||||||
segregated_edges.insert(edgeID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return segregated_edges;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace extractor
|
} // namespace extractor
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|||||||
@@ -12,18 +12,24 @@ namespace extractor
|
|||||||
namespace guidance
|
namespace guidance
|
||||||
{
|
{
|
||||||
|
|
||||||
DrivewayHandler::DrivewayHandler(const IntersectionGenerator &intersection_generator,
|
DrivewayHandler::DrivewayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table)
|
const SuffixTable &street_name_suffix_table)
|
||||||
: IntersectionHandler(node_based_graph,
|
: IntersectionHandler(node_based_graph,
|
||||||
node_data_container,
|
node_data_container,
|
||||||
coordinates,
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
name_table,
|
name_table,
|
||||||
street_name_suffix_table,
|
street_name_suffix_table)
|
||||||
intersection_generator)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,12 +70,12 @@ operator()(const NodeID nid, const EdgeID source_edge_id, Intersection intersect
|
|||||||
});
|
});
|
||||||
|
|
||||||
(void)nid;
|
(void)nid;
|
||||||
OSRM_ASSERT(road != intersection.end(), coordinates[nid]);
|
OSRM_ASSERT(road != intersection.end(), node_coordinates[nid]);
|
||||||
|
|
||||||
if (road->instruction == TurnInstruction::INVALID())
|
if (road->instruction == TurnInstruction::INVALID())
|
||||||
return intersection;
|
return intersection;
|
||||||
|
|
||||||
OSRM_ASSERT(road->instruction.type == TurnType::Turn, coordinates[nid]);
|
OSRM_ASSERT(road->instruction.type == TurnType::Turn, node_coordinates[nid]);
|
||||||
|
|
||||||
road->instruction.type =
|
road->instruction.type =
|
||||||
isSameName(source_edge_id, road->eid) ? TurnType::NoTurn : TurnType::NewName;
|
isSameName(source_edge_id, road->eid) ? TurnType::NoTurn : TurnType::NewName;
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||||
|
|
||||||
|
#include "util/guidance/name_announcements.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if two name ids can be seen as identical (in presence of refs/others)
|
||||||
|
// in our case this translates into no name announcement in either direction (lhs->rhs and
|
||||||
|
// rhs->lhs)
|
||||||
|
bool HaveIdenticalNames(const NameID lhs,
|
||||||
|
const NameID rhs,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table)
|
||||||
|
{
|
||||||
|
const auto non_empty = (lhs != EMPTY_NAMEID) && (rhs != EMPTY_NAMEID);
|
||||||
|
|
||||||
|
// symmetrical check for announcements
|
||||||
|
return non_empty &&
|
||||||
|
!util::guidance::requiresNameAnnounced(lhs, rhs, name_table, street_name_suffix_table) &&
|
||||||
|
!util::guidance::requiresNameAnnounced(rhs, lhs, name_table, street_name_suffix_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif /*OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_*/
|
||||||
@@ -1,488 +0,0 @@
|
|||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
|
|
||||||
#include "extractor/geojson_debug_policies.hpp"
|
|
||||||
|
|
||||||
#include "util/geojson_debug_logger.hpp"
|
|
||||||
|
|
||||||
#include "util/assert.hpp"
|
|
||||||
#include "util/bearing.hpp"
|
|
||||||
#include "util/coordinate_calculation.hpp"
|
|
||||||
#include "util/log.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
#include <functional> // mem_fn
|
|
||||||
#include <limits>
|
|
||||||
#include <numeric>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <boost/range/algorithm/count_if.hpp>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace extractor
|
|
||||||
{
|
|
||||||
namespace guidance
|
|
||||||
{
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
const constexpr bool USE_LOW_PRECISION_MODE = true;
|
|
||||||
// the inverse of use low precision mode
|
|
||||||
const constexpr bool USE_HIGH_PRECISION_MODE = !USE_LOW_PRECISION_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionGenerator::IntersectionGenerator(
|
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
|
||||||
const RestrictionMap &restriction_map,
|
|
||||||
const std::unordered_set<NodeID> &barrier_nodes,
|
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
|
||||||
const CompressedEdgeContainer &compressed_edge_container)
|
|
||||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
|
||||||
restriction_map(restriction_map), barrier_nodes(barrier_nodes), coordinates(coordinates),
|
|
||||||
coordinate_extractor(node_based_graph, compressed_edge_container, coordinates)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionView IntersectionGenerator::operator()(const NodeID from_node,
|
|
||||||
const EdgeID via_eid) const
|
|
||||||
{
|
|
||||||
return GetConnectedRoads(from_node, via_eid, USE_HIGH_PRECISION_MODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionShape
|
|
||||||
IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_intersection,
|
|
||||||
const boost::optional<NodeID> sorting_base,
|
|
||||||
const bool use_low_precision_angles) const
|
|
||||||
{
|
|
||||||
const auto intersection_degree = node_based_graph.GetOutDegree(node_at_center_of_intersection);
|
|
||||||
const util::Coordinate turn_coordinate = coordinates[node_at_center_of_intersection];
|
|
||||||
|
|
||||||
// compute bearings in a relatively small circle to prevent wrong roads order with true bearings
|
|
||||||
struct RoadWithInitialBearing
|
|
||||||
{
|
|
||||||
double bearing;
|
|
||||||
IntersectionShapeData road;
|
|
||||||
};
|
|
||||||
std::vector<RoadWithInitialBearing> initial_roads_ordering;
|
|
||||||
// reserve enough items (+ the possibly missing u-turn edge)
|
|
||||||
initial_roads_ordering.reserve(intersection_degree);
|
|
||||||
|
|
||||||
// number of lanes at the intersection changes how far we look down the road
|
|
||||||
const auto edge_range = node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection);
|
|
||||||
const auto max_lanes_intersection =
|
|
||||||
std::accumulate(edge_range.begin(),
|
|
||||||
edge_range.end(),
|
|
||||||
std::uint8_t{0},
|
|
||||||
[this](const auto current_max, const auto current_eid) {
|
|
||||||
return std::max(current_max,
|
|
||||||
node_based_graph.GetEdgeData(current_eid)
|
|
||||||
.flags.road_classification.GetNumberOfLanes());
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const EdgeID edge_connected_to_intersection :
|
|
||||||
node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection))
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(edge_connected_to_intersection != SPECIAL_EDGEID);
|
|
||||||
const NodeID to_node = node_based_graph.GetTarget(edge_connected_to_intersection);
|
|
||||||
double bearing = 0.;
|
|
||||||
|
|
||||||
auto coordinates = coordinate_extractor.GetCoordinatesAlongRoad(
|
|
||||||
node_at_center_of_intersection, edge_connected_to_intersection, !INVERT, to_node);
|
|
||||||
|
|
||||||
const auto close_coordinate =
|
|
||||||
coordinate_extractor.ExtractCoordinateAtLength(2. /*m*/, coordinates);
|
|
||||||
const auto initial_bearing =
|
|
||||||
util::coordinate_calculation::bearing(turn_coordinate, close_coordinate);
|
|
||||||
|
|
||||||
const auto segment_length = util::coordinate_calculation::getLength(
|
|
||||||
coordinates.begin(),
|
|
||||||
coordinates.end(),
|
|
||||||
util::coordinate_calculation::haversineDistance);
|
|
||||||
|
|
||||||
const auto extract_coordinate = [&](const NodeID from_node,
|
|
||||||
const EdgeID via_eid,
|
|
||||||
const bool traversed_in_reverse,
|
|
||||||
const NodeID to_node) {
|
|
||||||
return (use_low_precision_angles || intersection_degree <= 2)
|
|
||||||
? coordinate_extractor.GetCoordinateCloseToTurn(
|
|
||||||
from_node, via_eid, traversed_in_reverse, to_node)
|
|
||||||
: coordinate_extractor.ExtractRepresentativeCoordinate(
|
|
||||||
from_node,
|
|
||||||
via_eid,
|
|
||||||
traversed_in_reverse,
|
|
||||||
to_node,
|
|
||||||
max_lanes_intersection,
|
|
||||||
std::move(coordinates));
|
|
||||||
};
|
|
||||||
|
|
||||||
// we have to look down the road a bit to get the correct turn
|
|
||||||
const auto coordinate_along_edge_leaving = extract_coordinate(
|
|
||||||
node_at_center_of_intersection, edge_connected_to_intersection, !INVERT, to_node);
|
|
||||||
|
|
||||||
bearing =
|
|
||||||
util::coordinate_calculation::bearing(turn_coordinate, coordinate_along_edge_leaving);
|
|
||||||
|
|
||||||
// OSM data sometimes contains duplicated nodes with identical coordinates, or
|
|
||||||
// because of coordinate precision rounding, end up at the same coordinate.
|
|
||||||
// It's impossible to calculate a bearing between these, so we log a warning
|
|
||||||
// that the data should be checked.
|
|
||||||
// The bearing calculation should return 0 in these cases, which may not be correct,
|
|
||||||
// but is at least not random.
|
|
||||||
if (turn_coordinate == coordinate_along_edge_leaving)
|
|
||||||
{
|
|
||||||
util::Log(logDEBUG) << "Zero length segment at " << coordinate_along_edge_leaving
|
|
||||||
<< " could cause invalid intersection exit bearing.";
|
|
||||||
BOOST_ASSERT(std::abs(bearing) <= 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
initial_roads_ordering.push_back(
|
|
||||||
{initial_bearing, {edge_connected_to_intersection, bearing, segment_length}});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!initial_roads_ordering.empty())
|
|
||||||
{
|
|
||||||
const auto base_initial_bearing = [&]() {
|
|
||||||
if (sorting_base)
|
|
||||||
{
|
|
||||||
const auto itr = std::find_if(initial_roads_ordering.begin(),
|
|
||||||
initial_roads_ordering.end(),
|
|
||||||
[&](const auto &data) {
|
|
||||||
return node_based_graph.GetTarget(
|
|
||||||
data.road.eid) == *sorting_base;
|
|
||||||
});
|
|
||||||
if (itr != initial_roads_ordering.end())
|
|
||||||
return util::bearing::reverse(itr->bearing);
|
|
||||||
}
|
|
||||||
return util::bearing::reverse(initial_roads_ordering.begin()->bearing);
|
|
||||||
}();
|
|
||||||
|
|
||||||
// sort roads with respect to the initial bearings, a tie-breaker for equal initial bearings
|
|
||||||
// is to order roads via final bearings to have roads in clockwise order
|
|
||||||
//
|
|
||||||
// rhs <---. lhs <----.
|
|
||||||
// / /
|
|
||||||
// lhs / rhs /
|
|
||||||
//
|
|
||||||
// lhs road is before rhs one rhs road is before lhs one
|
|
||||||
// bearing::angleBetween < 180 bearing::angleBetween > 180
|
|
||||||
const auto initial_bearing_order = makeCompareShapeDataAngleToBearing(base_initial_bearing);
|
|
||||||
std::sort(initial_roads_ordering.begin(),
|
|
||||||
initial_roads_ordering.end(),
|
|
||||||
[&initial_bearing_order](const auto &lhs, const auto &rhs) {
|
|
||||||
return initial_bearing_order(lhs, rhs) ||
|
|
||||||
(lhs.bearing == rhs.bearing &&
|
|
||||||
util::bearing::angleBetween(lhs.road.bearing, rhs.road.bearing) <
|
|
||||||
180);
|
|
||||||
});
|
|
||||||
|
|
||||||
// copy intersection data in the initial order
|
|
||||||
IntersectionShape intersection;
|
|
||||||
intersection.reserve(initial_roads_ordering.size());
|
|
||||||
std::transform(initial_roads_ordering.begin(),
|
|
||||||
initial_roads_ordering.end(),
|
|
||||||
std::back_inserter(intersection),
|
|
||||||
[](const auto &entry) { return entry.road; });
|
|
||||||
|
|
||||||
if (intersection.size() > 2)
|
|
||||||
{ // Check bearings ordering with respect to true bearings
|
|
||||||
const auto base_bearing = intersection.front().bearing;
|
|
||||||
const auto bearings_order =
|
|
||||||
makeCompareShapeDataAngleToBearing(util::bearing::reverse(base_bearing));
|
|
||||||
for (auto curr = intersection.begin(), next = std::next(curr);
|
|
||||||
next != intersection.end();
|
|
||||||
++curr, ++next)
|
|
||||||
{
|
|
||||||
if (bearings_order(*next, *curr))
|
|
||||||
{ // If the true bearing is out of the initial order (next before current) then
|
|
||||||
// adjust the next bearing to keep the order. The adjustment angle is at most
|
|
||||||
// 0.5° or a half-angle between the current bearing and the base bearing.
|
|
||||||
// to prevent overlapping over base bearing + 360°.
|
|
||||||
const auto angle_adjustment = std::min(
|
|
||||||
.5, util::restrictAngleToValidRange(base_bearing - curr->bearing) / 2.);
|
|
||||||
next->bearing =
|
|
||||||
util::restrictAngleToValidRange(curr->bearing + angle_adjustment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return intersection;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IntersectionShape{};
|
|
||||||
}
|
|
||||||
|
|
||||||
// a
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// v
|
|
||||||
// For an intersection from_node --via_eid--> turn_node ----> c
|
|
||||||
// ^
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// b
|
|
||||||
// This functions returns _all_ turns as if the graph was undirected.
|
|
||||||
// That means we not only get (from_node, turn_node, c) in the above example
|
|
||||||
// but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are
|
|
||||||
// marked as invalid and only needed for intersection classification.
|
|
||||||
IntersectionView IntersectionGenerator::GetConnectedRoads(const NodeID from_node,
|
|
||||||
const EdgeID via_eid,
|
|
||||||
const bool use_low_precision_angles) const
|
|
||||||
{
|
|
||||||
// make sure the via-eid is valid
|
|
||||||
BOOST_ASSERT([this](const NodeID from_node, const EdgeID via_eid) {
|
|
||||||
const auto range = node_based_graph.GetAdjacentEdgeRange(from_node);
|
|
||||||
return range.front() <= via_eid && via_eid <= range.back();
|
|
||||||
}(from_node, via_eid));
|
|
||||||
|
|
||||||
auto intersection = ComputeIntersectionShape(
|
|
||||||
node_based_graph.GetTarget(via_eid), boost::none, use_low_precision_angles);
|
|
||||||
return TransformIntersectionShapeIntoView(from_node, via_eid, std::move(intersection));
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionGenerationParameters
|
|
||||||
IntersectionGenerator::SkipDegreeTwoNodes(const NodeID starting_node, const EdgeID via_edge) const
|
|
||||||
{
|
|
||||||
NodeID query_node = starting_node;
|
|
||||||
EdgeID query_edge = via_edge;
|
|
||||||
|
|
||||||
const auto get_next_edge = [this](const NodeID from, const EdgeID via) {
|
|
||||||
const NodeID new_node = node_based_graph.GetTarget(via);
|
|
||||||
BOOST_ASSERT(node_based_graph.GetOutDegree(new_node) == 2);
|
|
||||||
const EdgeID begin_edges_new_node = node_based_graph.BeginEdges(new_node);
|
|
||||||
return (node_based_graph.GetTarget(begin_edges_new_node) == from) ? begin_edges_new_node + 1
|
|
||||||
: begin_edges_new_node;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_set<NodeID> visited_nodes;
|
|
||||||
// skip trivial nodes without generating the intersection in between, stop at the very first
|
|
||||||
// intersection of degree > 2
|
|
||||||
while (0 == visited_nodes.count(query_node) &&
|
|
||||||
2 == node_based_graph.GetOutDegree(node_based_graph.GetTarget(query_edge)))
|
|
||||||
{
|
|
||||||
visited_nodes.insert(query_node);
|
|
||||||
const auto next_node = node_based_graph.GetTarget(query_edge);
|
|
||||||
const auto next_edge = get_next_edge(query_node, query_edge);
|
|
||||||
|
|
||||||
query_node = next_node;
|
|
||||||
query_edge = next_edge;
|
|
||||||
|
|
||||||
// check if there is a relevant change in the graph
|
|
||||||
if (!CanBeCompressed(node_based_graph.GetEdgeData(query_edge),
|
|
||||||
node_based_graph.GetEdgeData(next_edge),
|
|
||||||
node_data_container) ||
|
|
||||||
(node_based_graph.GetTarget(next_edge) == starting_node))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {query_node, query_edge};
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
|
|
||||||
const NodeID previous_node,
|
|
||||||
const EdgeID entering_via_edge,
|
|
||||||
const IntersectionShape &intersection_shape) const
|
|
||||||
{
|
|
||||||
// requires a copy of the intersection
|
|
||||||
return TransformIntersectionShapeIntoView(previous_node,
|
|
||||||
entering_via_edge,
|
|
||||||
intersection_shape, // creates a copy
|
|
||||||
intersection_shape, // reference to local
|
|
||||||
{}); // empty vector of performed merges
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
|
|
||||||
const NodeID previous_node,
|
|
||||||
const EdgeID entering_via_edge,
|
|
||||||
const IntersectionShape &normalized_intersection,
|
|
||||||
const IntersectionShape &intersection,
|
|
||||||
const std::vector<IntersectionNormalizationOperation> &performed_merges) const
|
|
||||||
{
|
|
||||||
const auto node_at_intersection = node_based_graph.GetTarget(entering_via_edge);
|
|
||||||
|
|
||||||
// request all turn restrictions
|
|
||||||
auto const restrictions = restriction_map.Restrictions(previous_node, node_at_intersection);
|
|
||||||
|
|
||||||
// check turn restrictions to find a node that is the only allowed target when coming from a
|
|
||||||
// node to an intersection
|
|
||||||
// d
|
|
||||||
// |
|
|
||||||
// a - b - c and `only_straight_on ab | bc would return `c` for `a,b`
|
|
||||||
const auto find_only_valid_turn = [&]() -> boost::optional<NodeID> {
|
|
||||||
const auto itr = std::find_if(restrictions.first, restrictions.second, [](auto pair) {
|
|
||||||
return pair.second->is_only;
|
|
||||||
});
|
|
||||||
if (itr != restrictions.second)
|
|
||||||
return itr->second->AsNodeRestriction().to;
|
|
||||||
else
|
|
||||||
return boost::none;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto only_valid_turn = find_only_valid_turn();
|
|
||||||
|
|
||||||
// barriers change our behaviour regarding u-turns
|
|
||||||
const bool is_barrier_node = barrier_nodes.find(node_at_intersection) != barrier_nodes.end();
|
|
||||||
|
|
||||||
const auto connect_to_previous_node = [this, previous_node](const IntersectionShapeData road) {
|
|
||||||
return node_based_graph.GetTarget(road.eid) == previous_node;
|
|
||||||
};
|
|
||||||
|
|
||||||
// check which of the edges is the u-turn edge
|
|
||||||
const auto uturn_edge_itr =
|
|
||||||
std::find_if(intersection.begin(), intersection.end(), connect_to_previous_node);
|
|
||||||
|
|
||||||
// there needs to be a connection, otherwise stuff went seriously wrong. Note that this is not
|
|
||||||
// necessarily the same id as `entering_via_edge`.
|
|
||||||
// In cases where parallel edges are present, we only remember the minimal edge. Both share
|
|
||||||
// exactly the same coordinates, so the u-turn is still the best choice here.
|
|
||||||
BOOST_ASSERT(uturn_edge_itr != intersection.end());
|
|
||||||
|
|
||||||
const auto is_restricted = [&](const NodeID destination) {
|
|
||||||
// check if we have a dedicated destination
|
|
||||||
if (only_valid_turn)
|
|
||||||
return *only_valid_turn != destination;
|
|
||||||
|
|
||||||
// check if explicitly forbidden
|
|
||||||
return restrictions.second !=
|
|
||||||
std::find_if(restrictions.first, restrictions.second, [&](const auto &restriction) {
|
|
||||||
return restriction.second->AsNodeRestriction().to == destination;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto is_allowed_turn = [&](const IntersectionShapeData &road) {
|
|
||||||
const auto &road_data = node_based_graph.GetEdgeData(road.eid);
|
|
||||||
const NodeID road_destination_node = node_based_graph.GetTarget(road.eid);
|
|
||||||
// reverse edges are never valid turns because the resulting turn would look like this:
|
|
||||||
// from_node --via_edge--> node_at_intersection <--onto_edge-- to_node
|
|
||||||
// however we need this for capture intersection shape for incoming one-ways
|
|
||||||
return !road_data.reversed &&
|
|
||||||
// we are not turning over a barrier
|
|
||||||
(!is_barrier_node || road_destination_node == previous_node) &&
|
|
||||||
// don't allow restricted turns
|
|
||||||
!is_restricted(road_destination_node);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// due to merging of roads, the u-turn might actually not be part of the intersection anymore
|
|
||||||
// uturn is a pair of {edge id, bearing}
|
|
||||||
const auto uturn = [&]() {
|
|
||||||
const auto merge_entry = std::find_if(
|
|
||||||
performed_merges.begin(), performed_merges.end(), [&uturn_edge_itr](const auto entry) {
|
|
||||||
return entry.merged_eid == uturn_edge_itr->eid;
|
|
||||||
});
|
|
||||||
if (merge_entry != performed_merges.end())
|
|
||||||
{
|
|
||||||
const auto merged_into_id = merge_entry->into_eid;
|
|
||||||
const auto merged_u_turn = std::find_if(
|
|
||||||
normalized_intersection.begin(),
|
|
||||||
normalized_intersection.end(),
|
|
||||||
[&](const IntersectionShapeData &road) { return road.eid == merged_into_id; });
|
|
||||||
BOOST_ASSERT(merged_u_turn != normalized_intersection.end());
|
|
||||||
return std::make_pair(merged_u_turn->eid,
|
|
||||||
util::bearing::reverse(merged_u_turn->bearing));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto uturn_edge_at_normalized_intersection_itr =
|
|
||||||
std::find_if(normalized_intersection.begin(),
|
|
||||||
normalized_intersection.end(),
|
|
||||||
connect_to_previous_node);
|
|
||||||
BOOST_ASSERT(uturn_edge_at_normalized_intersection_itr !=
|
|
||||||
normalized_intersection.end());
|
|
||||||
return std::make_pair(
|
|
||||||
uturn_edge_at_normalized_intersection_itr->eid,
|
|
||||||
util::bearing::reverse(uturn_edge_at_normalized_intersection_itr->bearing));
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
IntersectionView intersection_view;
|
|
||||||
intersection_view.reserve(normalized_intersection.size());
|
|
||||||
std::transform(normalized_intersection.begin(),
|
|
||||||
normalized_intersection.end(),
|
|
||||||
std::back_inserter(intersection_view),
|
|
||||||
[&](const IntersectionShapeData &road) {
|
|
||||||
return IntersectionViewData(
|
|
||||||
road,
|
|
||||||
is_allowed_turn(road),
|
|
||||||
util::bearing::angleBetween(uturn.second, road.bearing));
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto uturn_edge_at_intersection_view_itr =
|
|
||||||
std::find_if(intersection_view.begin(), intersection_view.end(), connect_to_previous_node);
|
|
||||||
// number of found valid exit roads
|
|
||||||
const auto valid_count =
|
|
||||||
std::count_if(intersection_view.begin(),
|
|
||||||
intersection_view.end(),
|
|
||||||
[](const IntersectionViewData &road) { return road.entry_allowed; });
|
|
||||||
// in general, we don't wan't to allow u-turns. If we don't look at a barrier, we have to check
|
|
||||||
// for dead end streets. These are the only ones that we allow uturns for, next to barriers
|
|
||||||
// (which are also kind of a dead end, but we don't have to check these again :))
|
|
||||||
if (uturn_edge_at_intersection_view_itr != intersection_view.end() &&
|
|
||||||
((uturn_edge_at_intersection_view_itr->entry_allowed && !is_barrier_node &&
|
|
||||||
valid_count != 1) ||
|
|
||||||
valid_count == 0))
|
|
||||||
{
|
|
||||||
const auto allow_uturn_at_dead_end = [&]() {
|
|
||||||
const auto &uturn_data = node_based_graph.GetEdgeData(uturn_edge_itr->eid);
|
|
||||||
|
|
||||||
// we can't turn back onto oneway streets
|
|
||||||
if (uturn_data.reversed)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// don't allow explicitly restricted turns
|
|
||||||
if (is_restricted(previous_node))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// we define dead ends as roads that can only be entered via the possible u-turn
|
|
||||||
const auto is_bidirectional = [&](const EdgeID entering_via_edge) {
|
|
||||||
const auto to_node = node_based_graph.GetTarget(entering_via_edge);
|
|
||||||
const auto reverse_edge = node_based_graph.FindEdge(to_node, node_at_intersection);
|
|
||||||
BOOST_ASSERT(reverse_edge != SPECIAL_EDGEID);
|
|
||||||
return !node_based_graph.GetEdgeData(reverse_edge).reversed;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto bidirectional_edges = [&]() {
|
|
||||||
std::uint32_t count = 0;
|
|
||||||
for (const auto eid : node_based_graph.GetAdjacentEdgeRange(node_at_intersection))
|
|
||||||
if (is_bidirectional(eid))
|
|
||||||
++count;
|
|
||||||
return count;
|
|
||||||
}();
|
|
||||||
|
|
||||||
// Checking for dead-end streets is kind of difficult. There is obvious dead ends
|
|
||||||
// (single road connected)
|
|
||||||
return bidirectional_edges <= 1;
|
|
||||||
}();
|
|
||||||
uturn_edge_at_intersection_view_itr->entry_allowed = allow_uturn_at_dead_end;
|
|
||||||
}
|
|
||||||
std::sort(std::begin(intersection_view),
|
|
||||||
std::end(intersection_view),
|
|
||||||
std::mem_fn(&IntersectionViewData::CompareByAngle));
|
|
||||||
|
|
||||||
// Move entering_via_edge to intersection front and place all roads prior entering_via_edge
|
|
||||||
// at the end of the intersection view with 360° angle
|
|
||||||
auto entering_via_it = std::find_if(intersection_view.begin(),
|
|
||||||
intersection_view.end(),
|
|
||||||
[&uturn](auto &road) { return road.eid == uturn.first; });
|
|
||||||
|
|
||||||
OSRM_ASSERT(entering_via_it != intersection_view.end() && entering_via_it->angle >= 0. &&
|
|
||||||
entering_via_it->angle < std::numeric_limits<double>::epsilon(),
|
|
||||||
coordinates[node_at_intersection]);
|
|
||||||
|
|
||||||
if (entering_via_it != intersection_view.begin() && entering_via_it != intersection_view.end())
|
|
||||||
{
|
|
||||||
std::for_each(
|
|
||||||
intersection_view.begin(), entering_via_it, [](auto &road) { road.angle = 360.; });
|
|
||||||
std::rotate(intersection_view.begin(), entering_via_it, intersection_view.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersection_view;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CoordinateExtractor &IntersectionGenerator::GetCoordinateExtractor() const
|
|
||||||
{
|
|
||||||
return coordinate_extractor;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace guidance
|
|
||||||
} // namespace extractor
|
|
||||||
} // namespace osrm
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
#include "extractor/guidance/constants.hpp"
|
#include "extractor/guidance/constants.hpp"
|
||||||
|
#include "extractor/intersection/intersection_analysis.hpp"
|
||||||
|
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
#include "util/guidance/name_announcements.hpp"
|
#include "util/guidance/name_announcements.hpp"
|
||||||
@@ -45,17 +46,27 @@ inline bool requiresAnnouncement(const util::NodeBasedDynamicGraph &node_based_g
|
|||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
IntersectionHandler::IntersectionHandler(
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const util::NameTable &name_table,
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
const SuffixTable &street_name_suffix_table,
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
const IntersectionGenerator &intersection_generator)
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table)
|
||||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||||
coordinates(coordinates), name_table(name_table),
|
node_coordinates(node_coordinates), compressed_geometries(compressed_geometries),
|
||||||
street_name_suffix_table(street_name_suffix_table),
|
node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes),
|
||||||
intersection_generator(intersection_generator),
|
turn_lanes_data(turn_lanes_data), name_table(name_table),
|
||||||
graph_walker(node_based_graph, node_data_container, intersection_generator)
|
street_name_suffix_table(street_name_suffix_table), graph_walker(node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,17 +82,19 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge,
|
|||||||
if (!on_ramp && onto_ramp)
|
if (!on_ramp && onto_ramp)
|
||||||
return TurnType::OnRamp;
|
return TurnType::OnRamp;
|
||||||
|
|
||||||
const auto &in_name =
|
const auto &in_name_id =
|
||||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
||||||
.name_id;
|
.name_id;
|
||||||
const auto &out_name =
|
const auto &out_name_id =
|
||||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||||
.name_id;
|
.name_id;
|
||||||
|
const auto &in_name_empty = name_table.GetNameForID(in_name_id).empty();
|
||||||
|
const auto &out_name_empty = name_table.GetNameForID(out_name_id).empty();
|
||||||
|
|
||||||
const auto same_name = !util::guidance::requiresNameAnnounced(
|
const auto same_name = !util::guidance::requiresNameAnnounced(
|
||||||
in_name, out_name, name_table, street_name_suffix_table);
|
in_name_id, out_name_id, name_table, street_name_suffix_table);
|
||||||
|
|
||||||
if (in_name != EMPTY_NAMEID && out_name != EMPTY_NAMEID && same_name)
|
if (!in_name_empty && !out_name_empty && same_name)
|
||||||
{
|
{
|
||||||
return TurnType::Continue;
|
return TurnType::Continue;
|
||||||
}
|
}
|
||||||
@@ -89,6 +102,19 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge,
|
|||||||
return TurnType::Turn;
|
return TurnType::Turn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TurnType::Enum IntersectionHandler::areSameClasses(const EdgeID via_edge,
|
||||||
|
const ConnectedRoad &road) const
|
||||||
|
{
|
||||||
|
const auto &in_classes =
|
||||||
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
||||||
|
.classes;
|
||||||
|
const auto &out_classes =
|
||||||
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||||
|
.classes;
|
||||||
|
|
||||||
|
return in_classes == out_classes;
|
||||||
|
}
|
||||||
|
|
||||||
TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t num_roads,
|
TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t num_roads,
|
||||||
const EdgeID via_edge,
|
const EdgeID via_edge,
|
||||||
const bool through_street,
|
const bool through_street,
|
||||||
@@ -160,8 +186,8 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
|
|||||||
// or actually follow the full road. When 2399 lands, we can exchange here for a
|
// or actually follow the full road. When 2399 lands, we can exchange here for a
|
||||||
// precalculated distance value.
|
// precalculated distance value.
|
||||||
const auto distance = util::coordinate_calculation::haversineDistance(
|
const auto distance = util::coordinate_calculation::haversineDistance(
|
||||||
coordinates[node_based_graph.GetTarget(via_edge)],
|
node_coordinates[node_based_graph.GetTarget(via_edge)],
|
||||||
coordinates[node_based_graph.GetTarget(road.eid)]);
|
node_coordinates[node_based_graph.GetTarget(road.eid)]);
|
||||||
|
|
||||||
return {TurnType::Turn,
|
return {TurnType::Turn,
|
||||||
(angularDeviation(road.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
|
(angularDeviation(road.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
|
||||||
@@ -182,7 +208,8 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
|
|||||||
if (needs_notification)
|
if (needs_notification)
|
||||||
return {TurnType::Notification, getTurnDirection(road.angle)};
|
return {TurnType::Notification, getTurnDirection(road.angle)};
|
||||||
else
|
else
|
||||||
return {num_roads == 2 ? TurnType::NoTurn : TurnType::Suppressed,
|
return {num_roads == 2 && areSameClasses(via_edge, road) ? TurnType::NoTurn
|
||||||
|
: TurnType::Suppressed,
|
||||||
getTurnDirection(road.angle)};
|
getTurnDirection(road.angle)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,7 +218,7 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
|
|||||||
{
|
{
|
||||||
return {TurnType::Notification, getTurnDirection(road.angle)};
|
return {TurnType::Notification, getTurnDirection(road.angle)};
|
||||||
}
|
}
|
||||||
if (num_roads > 2)
|
if (num_roads > 2 || !areSameClasses(via_edge, road))
|
||||||
{
|
{
|
||||||
return {TurnType::Suppressed, getTurnDirection(road.angle)};
|
return {TurnType::Suppressed, getTurnDirection(road.angle)};
|
||||||
}
|
}
|
||||||
@@ -405,44 +432,6 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntersectionHandler::isThroughStreet(const std::size_t index,
|
|
||||||
const Intersection &intersection) const
|
|
||||||
{
|
|
||||||
const auto &data_at_index = node_data_container.GetAnnotation(
|
|
||||||
node_based_graph.GetEdgeData(intersection[index].eid).annotation_data);
|
|
||||||
|
|
||||||
if (data_at_index.name_id == EMPTY_NAMEID)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// a through street cannot start at our own position -> index 1
|
|
||||||
for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index)
|
|
||||||
{
|
|
||||||
if (road_index == index)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto &road = intersection[road_index];
|
|
||||||
const auto &road_data = node_data_container.GetAnnotation(
|
|
||||||
node_based_graph.GetEdgeData(road.eid).annotation_data);
|
|
||||||
|
|
||||||
// roads have a near straight angle (180 degree)
|
|
||||||
const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
|
|
||||||
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
|
|
||||||
|
|
||||||
const bool have_same_name =
|
|
||||||
road_data.name_id != EMPTY_NAMEID &&
|
|
||||||
!util::guidance::requiresNameAnnounced(
|
|
||||||
data_at_index.name_id, road_data.name_id, name_table, street_name_suffix_table);
|
|
||||||
|
|
||||||
const bool have_same_category =
|
|
||||||
node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification ==
|
|
||||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification;
|
|
||||||
|
|
||||||
if (is_nearly_straight && have_same_name && have_same_category)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::optional<IntersectionHandler::IntersectionViewAndNode>
|
boost::optional<IntersectionHandler::IntersectionViewAndNode>
|
||||||
IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) const
|
IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) const
|
||||||
{
|
{
|
||||||
@@ -460,17 +449,24 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons
|
|||||||
// Starting at node `a` via edge `e0` the intersection generator returns the intersection at `c`
|
// Starting at node `a` via edge `e0` the intersection generator returns the intersection at `c`
|
||||||
// writing `tl` (traffic signal) node and the edge `e1` which has the intersection as target.
|
// writing `tl` (traffic signal) node and the edge `e1` which has the intersection as target.
|
||||||
|
|
||||||
const auto intersection_parameters = intersection_generator.SkipDegreeTwoNodes(at, via);
|
const auto intersection_parameters =
|
||||||
|
intersection::skipDegreeTwoNodes(node_based_graph, {at, via});
|
||||||
// This should never happen, guard against nevertheless
|
// This should never happen, guard against nevertheless
|
||||||
if (intersection_parameters.nid == SPECIAL_NODEID ||
|
if (intersection_parameters.node == SPECIAL_NODEID ||
|
||||||
intersection_parameters.via_eid == SPECIAL_EDGEID)
|
intersection_parameters.edge == SPECIAL_EDGEID)
|
||||||
{
|
{
|
||||||
return boost::none;
|
return boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto intersection =
|
auto intersection = intersection::getConnectedRoads<false>(node_based_graph,
|
||||||
intersection_generator(intersection_parameters.nid, intersection_parameters.via_eid);
|
node_data_container,
|
||||||
auto intersection_node = node_based_graph.GetTarget(intersection_parameters.via_eid);
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
|
intersection_parameters);
|
||||||
|
auto intersection_node = node_based_graph.GetTarget(intersection_parameters.edge);
|
||||||
|
|
||||||
if (intersection.size() <= 2 || intersection.isTrafficSignalOrBarrier())
|
if (intersection.size() <= 2 || intersection.isTrafficSignalOrBarrier())
|
||||||
{
|
{
|
||||||
@@ -488,8 +484,8 @@ bool IntersectionHandler::isSameName(const EdgeID source_edge_id, const EdgeID t
|
|||||||
const auto &target_edge_data = node_data_container.GetAnnotation(
|
const auto &target_edge_data = node_data_container.GetAnnotation(
|
||||||
node_based_graph.GetEdgeData(target_edge_id).annotation_data);
|
node_based_graph.GetEdgeData(target_edge_id).annotation_data);
|
||||||
|
|
||||||
return source_edge_data.name_id != EMPTY_NAMEID && //
|
return !name_table.GetNameForID(source_edge_data.name_id).empty() && //
|
||||||
target_edge_data.name_id != EMPTY_NAMEID && //
|
!name_table.GetNameForID(target_edge_data.name_id).empty() && //
|
||||||
!util::guidance::requiresNameAnnounced(source_edge_data.name_id,
|
!util::guidance::requiresNameAnnounced(source_edge_data.name_id,
|
||||||
target_edge_data.name_id,
|
target_edge_data.name_id,
|
||||||
name_table,
|
name_table,
|
||||||
|
|||||||
@@ -1,430 +0,0 @@
|
|||||||
#include "extractor/guidance/intersection_normalizer.hpp"
|
|
||||||
#include "util/bearing.hpp"
|
|
||||||
#include "util/coordinate_calculation.hpp"
|
|
||||||
|
|
||||||
#include <tuple>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
using osrm::util::angularDeviation;
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace extractor
|
|
||||||
{
|
|
||||||
namespace guidance
|
|
||||||
{
|
|
||||||
|
|
||||||
IntersectionNormalizer::IntersectionNormalizer(
|
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
|
||||||
const util::NameTable &name_table,
|
|
||||||
const SuffixTable &street_name_suffix_table,
|
|
||||||
const IntersectionGenerator &intersection_generator)
|
|
||||||
: node_based_graph(node_based_graph), intersection_generator(intersection_generator),
|
|
||||||
mergable_road_detector(node_based_graph,
|
|
||||||
node_data_container,
|
|
||||||
coordinates,
|
|
||||||
intersection_generator,
|
|
||||||
intersection_generator.GetCoordinateExtractor(),
|
|
||||||
name_table,
|
|
||||||
street_name_suffix_table)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionNormalizer::NormalizationResult IntersectionNormalizer::
|
|
||||||
operator()(const NodeID node_at_intersection, IntersectionShape intersection) const
|
|
||||||
{
|
|
||||||
const auto intersection_copy = intersection;
|
|
||||||
auto merged_shape_and_merges =
|
|
||||||
MergeSegregatedRoads(node_at_intersection, std::move(intersection));
|
|
||||||
merged_shape_and_merges.normalized_shape = AdjustBearingsForMergeAtDestination(
|
|
||||||
node_at_intersection, std::move(merged_shape_and_merges.normalized_shape));
|
|
||||||
return merged_shape_and_merges;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IntersectionNormalizer::CanMerge(const NodeID intersection_node,
|
|
||||||
const IntersectionShape &intersection,
|
|
||||||
std::size_t fist_index_in_ccw,
|
|
||||||
std::size_t second_index_in_ccw) const
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(((fist_index_in_ccw + 1) % intersection.size()) == second_index_in_ccw);
|
|
||||||
|
|
||||||
// don't merge on degree two, since it's most likely a bollard/traffic light or a round way
|
|
||||||
if (intersection.size() <= 2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto can_merge = mergable_road_detector.CanMergeRoad(
|
|
||||||
intersection_node, intersection[fist_index_in_ccw], intersection[second_index_in_ccw]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Merging should never depend on order/never merge more than two roads. To ensure that we don't
|
|
||||||
* merge anything that is impacted by neighboring roads (e.g. three roads of the same name as in
|
|
||||||
* parking lots/border checkpoints), we check if the neigboring roads would be merged as well.
|
|
||||||
* In that case, we cannot merge, since we would end up merging multiple items together
|
|
||||||
*/
|
|
||||||
const auto is_distinct = [&]() {
|
|
||||||
const auto next_index_in_ccw = (second_index_in_ccw + 1) % intersection.size();
|
|
||||||
const auto distinct_to_next_in_ccw = mergable_road_detector.IsDistinctFrom(
|
|
||||||
intersection[second_index_in_ccw], intersection[next_index_in_ccw]);
|
|
||||||
const auto prev_index_in_ccw =
|
|
||||||
(fist_index_in_ccw + intersection.size() - 1) % intersection.size();
|
|
||||||
const auto distinct_to_prev_in_ccw = mergable_road_detector.IsDistinctFrom(
|
|
||||||
intersection[prev_index_in_ccw], intersection[fist_index_in_ccw]);
|
|
||||||
return distinct_to_next_in_ccw && distinct_to_prev_in_ccw;
|
|
||||||
};
|
|
||||||
|
|
||||||
// use lazy evaluation to check only if mergable
|
|
||||||
return can_merge && is_distinct();
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionNormalizationOperation
|
|
||||||
IntersectionNormalizer::DetermineMergeDirection(const IntersectionShapeData &lhs,
|
|
||||||
const IntersectionShapeData &rhs) const
|
|
||||||
{
|
|
||||||
if (node_based_graph.GetEdgeData(lhs.eid).reversed)
|
|
||||||
return {lhs.eid, rhs.eid};
|
|
||||||
else
|
|
||||||
return {rhs.eid, lhs.eid};
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionShapeData IntersectionNormalizer::MergeRoads(const IntersectionShapeData &into,
|
|
||||||
const IntersectionShapeData &from) const
|
|
||||||
{
|
|
||||||
// we only merge small angles. If the difference between both is large, we are looking at a
|
|
||||||
// bearing leading north. Such a bearing cannot be handled via the basic average. In this
|
|
||||||
// case we actually need to shift the bearing by half the difference.
|
|
||||||
const auto aroundZero = [](const double first, const double second) {
|
|
||||||
return (std::max(first, second) - std::min(first, second)) >= 180;
|
|
||||||
};
|
|
||||||
|
|
||||||
// find the angle between two other angles
|
|
||||||
const auto combineAngles = [aroundZero](const double first, const double second) {
|
|
||||||
if (!aroundZero(first, second))
|
|
||||||
return .5 * (first + second);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto offset = angularDeviation(first, second);
|
|
||||||
auto new_angle = std::max(first, second) + .5 * offset;
|
|
||||||
if (new_angle >= 360)
|
|
||||||
return new_angle - 360;
|
|
||||||
return new_angle;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto result = into;
|
|
||||||
BOOST_ASSERT(!node_based_graph.GetEdgeData(into.eid).reversed);
|
|
||||||
result.bearing = combineAngles(into.bearing, from.bearing);
|
|
||||||
BOOST_ASSERT(0 <= result.bearing && result.bearing < 360.0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionShapeData
|
|
||||||
IntersectionNormalizer::MergeRoads(const IntersectionNormalizationOperation direction,
|
|
||||||
const IntersectionShapeData &lhs,
|
|
||||||
const IntersectionShapeData &rhs,
|
|
||||||
const double opposite_bearing) const
|
|
||||||
{
|
|
||||||
// In some intersections, turning roads can introduce artificial turns if we merge here.
|
|
||||||
// Consider a scenario like:
|
|
||||||
//
|
|
||||||
// a . g - f
|
|
||||||
// | .
|
|
||||||
// | .
|
|
||||||
// |.
|
|
||||||
// d-b--------e
|
|
||||||
// |
|
|
||||||
// c
|
|
||||||
//
|
|
||||||
// Merging `bgf` and `be` would introduce an angle, even though d-b-e is perfectly straight
|
|
||||||
// We don't change the angle, if such an opposite road exists
|
|
||||||
if (direction.merged_eid == lhs.eid)
|
|
||||||
{
|
|
||||||
// change the angle only if the opposite direction is not nearly straight
|
|
||||||
if (angularDeviation(opposite_bearing, rhs.bearing) >
|
|
||||||
(STRAIGHT_ANGLE - MAXIMAL_ALLOWED_NO_TURN_DEVIATION))
|
|
||||||
return rhs;
|
|
||||||
else
|
|
||||||
return MergeRoads(rhs, lhs);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (angularDeviation(opposite_bearing, lhs.bearing) >
|
|
||||||
(STRAIGHT_ANGLE - MAXIMAL_ALLOWED_NO_TURN_DEVIATION))
|
|
||||||
return lhs;
|
|
||||||
else
|
|
||||||
return MergeRoads(lhs, rhs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Segregated Roads often merge onto a single intersection.
|
|
||||||
* While technically representing different roads, they are
|
|
||||||
* often looked at as a single road.
|
|
||||||
* Due to the merging, turn Angles seem off, wenn we compute them from the
|
|
||||||
* initial positions.
|
|
||||||
*
|
|
||||||
* b<b<b<b(1)<b<b<b
|
|
||||||
* aaaaa-b
|
|
||||||
* b>b>b>b(2)>b>b>b
|
|
||||||
*
|
|
||||||
* Would be seen as a slight turn going fro a to (2). A Sharp turn going from
|
|
||||||
* (1) to (2).
|
|
||||||
*
|
|
||||||
* In cases like these, we megre this segregated roads into a single road to
|
|
||||||
* end up with a case like:
|
|
||||||
*
|
|
||||||
* aaaaa-bbbbbb
|
|
||||||
*
|
|
||||||
* for the turn representation.
|
|
||||||
* Anything containing the first u-turn in a merge affects all other angles
|
|
||||||
* and is handled separately from all others.
|
|
||||||
*/
|
|
||||||
IntersectionNormalizer::NormalizationResult
|
|
||||||
IntersectionNormalizer::MergeSegregatedRoads(const NodeID intersection_node,
|
|
||||||
IntersectionShape intersection) const
|
|
||||||
{
|
|
||||||
const auto getRight = [&](std::size_t index) {
|
|
||||||
return (index + intersection.size() - 1) % intersection.size();
|
|
||||||
};
|
|
||||||
|
|
||||||
// This map stores for all edges that participated in a merging operation in which edge id they
|
|
||||||
// end up in the end. We only store what we have merged into other edges.
|
|
||||||
std::vector<IntersectionNormalizationOperation> merging_map;
|
|
||||||
const auto merge = [this, &merging_map](const IntersectionShapeData &first,
|
|
||||||
const IntersectionShapeData &second,
|
|
||||||
const double opposite_bearing) {
|
|
||||||
|
|
||||||
const auto direction = DetermineMergeDirection(first, second);
|
|
||||||
BOOST_ASSERT(
|
|
||||||
std::find_if(merging_map.begin(), merging_map.end(), [direction](const auto pair) {
|
|
||||||
return pair.merged_eid == direction.merged_eid;
|
|
||||||
}) == merging_map.end());
|
|
||||||
merging_map.push_back(direction);
|
|
||||||
return MergeRoads(direction, first, second, opposite_bearing);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (intersection.size() <= 1)
|
|
||||||
return {intersection, merging_map};
|
|
||||||
|
|
||||||
const auto intersection_copy = intersection;
|
|
||||||
const auto opposite_bearing = [this, intersection_copy](const IntersectionShapeData &lhs,
|
|
||||||
const IntersectionShapeData &rhs) {
|
|
||||||
if (node_based_graph.GetEdgeData(lhs.eid).reversed)
|
|
||||||
{
|
|
||||||
return intersection_copy.FindClosestBearing(util::bearing::reverse(rhs.bearing))
|
|
||||||
->bearing;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(node_based_graph.GetEdgeData(rhs.eid).reversed);
|
|
||||||
return intersection_copy.FindClosestBearing(util::bearing::reverse(lhs.bearing))
|
|
||||||
->bearing;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// check for merges including the basic u-turn
|
|
||||||
// these result in an adjustment of all other angles. This is due to how these angles are
|
|
||||||
// perceived. Considering the following example:
|
|
||||||
//
|
|
||||||
// c b
|
|
||||||
// Y
|
|
||||||
// a
|
|
||||||
//
|
|
||||||
// coming from a to b (given a road that splits at the fork into two one-ways), the turn is not
|
|
||||||
// considered as a turn but rather as going straight.
|
|
||||||
// Now if we look at the situation merging:
|
|
||||||
//
|
|
||||||
// a b
|
|
||||||
// \ /
|
|
||||||
// e - + - d
|
|
||||||
// |
|
|
||||||
// c
|
|
||||||
//
|
|
||||||
// With a,b representing the same road, the intersection itself represents a classif for way
|
|
||||||
// intersection so we handle it like
|
|
||||||
//
|
|
||||||
// (a),b
|
|
||||||
// |
|
|
||||||
// e - + - d
|
|
||||||
// |
|
|
||||||
// c
|
|
||||||
//
|
|
||||||
// To be able to consider this adjusted representation down the line, we merge some roads.
|
|
||||||
// If the merge occurs at the u-turn edge, we need to adjust all angles, though, since they are
|
|
||||||
// with respect to the now changed perceived location of a. If we move (a) to the left, we add
|
|
||||||
// the difference to all angles. Otherwise we subtract it.
|
|
||||||
// these result in an adjustment of all other angles
|
|
||||||
if (CanMerge(intersection_node, intersection, intersection.size() - 1, 0))
|
|
||||||
{
|
|
||||||
// moving `a` to the left
|
|
||||||
const auto opposite = opposite_bearing(intersection.front(), intersection.back());
|
|
||||||
intersection[0] = merge(intersection.front(), intersection.back(), opposite);
|
|
||||||
// FIXME if we have a left-sided country, we need to switch this off and enable it
|
|
||||||
// below
|
|
||||||
intersection.pop_back();
|
|
||||||
}
|
|
||||||
else if (CanMerge(intersection_node, intersection, 0, 1))
|
|
||||||
{
|
|
||||||
const auto opposite = opposite_bearing(intersection.front(), intersection[1]);
|
|
||||||
intersection[0] = merge(intersection.front(), intersection[1], opposite);
|
|
||||||
intersection.erase(intersection.begin() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// a merge including the first u-turn requires an adjustment of the turn angles
|
|
||||||
// therefore these are handled prior to this step
|
|
||||||
for (std::size_t index = 2; index < intersection.size(); ++index)
|
|
||||||
{
|
|
||||||
if (CanMerge(intersection_node, intersection, getRight(index), index))
|
|
||||||
{
|
|
||||||
const auto opposite =
|
|
||||||
opposite_bearing(intersection[getRight(index)], intersection[index]);
|
|
||||||
intersection[getRight(index)] =
|
|
||||||
merge(intersection[getRight(index)], intersection[index], opposite);
|
|
||||||
intersection.erase(intersection.begin() + index);
|
|
||||||
--index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {intersection, merging_map};
|
|
||||||
}
|
|
||||||
|
|
||||||
// OSM can have some very steep angles for joining roads. Considering the following intersection:
|
|
||||||
// x
|
|
||||||
// |
|
|
||||||
// v __________c
|
|
||||||
// /
|
|
||||||
// a ---d
|
|
||||||
// \ __________b
|
|
||||||
//
|
|
||||||
// with c->d as a oneway
|
|
||||||
// and d->b as a oneway, the turn von x->d is actually a turn from x->a. So when looking at the
|
|
||||||
// intersection coming from x, we want to interpret the situation as
|
|
||||||
// x
|
|
||||||
// |
|
|
||||||
// a __ d __ v__________c
|
|
||||||
// |
|
|
||||||
// |_______________b
|
|
||||||
//
|
|
||||||
// Where we see the turn to `d` as a right turn, rather than going straight.
|
|
||||||
// We do this by adjusting the local turn angle at `x` to turn onto `d` to be reflective of this
|
|
||||||
// situation, where `v` would be the node at the intersection.
|
|
||||||
IntersectionShape
|
|
||||||
IntersectionNormalizer::AdjustBearingsForMergeAtDestination(const NodeID node_at_intersection,
|
|
||||||
IntersectionShape intersection) const
|
|
||||||
{
|
|
||||||
// nothing to do for dead ends
|
|
||||||
if (intersection.size() <= 1)
|
|
||||||
return intersection;
|
|
||||||
|
|
||||||
// we don't adjust any road that is longer than 30 meters (between centers of intersections),
|
|
||||||
// since the road is probably too long otherwise to impact perception.
|
|
||||||
const double constexpr PRUNING_DISTANCE = 30;
|
|
||||||
// never adjust u-turns
|
|
||||||
for (std::size_t index = 0; index < intersection.size(); ++index)
|
|
||||||
{
|
|
||||||
auto &road = intersection[index];
|
|
||||||
// only consider roads that are close
|
|
||||||
if (road.segment_length > PRUNING_DISTANCE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// to find out about the above situation, we need to look at the next intersection (at d in
|
|
||||||
// the example). If the initial road can be merged to the left/right, we are about to adjust
|
|
||||||
// the angle.
|
|
||||||
const auto next_intersection_along_road = intersection_generator.ComputeIntersectionShape(
|
|
||||||
node_based_graph.GetTarget(road.eid), node_at_intersection);
|
|
||||||
|
|
||||||
if (next_intersection_along_road.size() <= 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto node_at_next_intersection = node_based_graph.GetTarget(road.eid);
|
|
||||||
|
|
||||||
const auto adjustAngle = [](double angle, double offset) {
|
|
||||||
angle += offset;
|
|
||||||
if (angle > 360)
|
|
||||||
return angle - 360.;
|
|
||||||
else if (angle < 0)
|
|
||||||
return angle + 360.;
|
|
||||||
return angle;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto range = node_based_graph.GetAdjacentEdgeRange(node_at_next_intersection);
|
|
||||||
if (range.size() <= 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// the order does not matter
|
|
||||||
const auto get_offset = [](const IntersectionShapeData &lhs,
|
|
||||||
const IntersectionShapeData &rhs) {
|
|
||||||
return 0.5 * angularDeviation(lhs.bearing, rhs.bearing);
|
|
||||||
};
|
|
||||||
|
|
||||||
// When offsetting angles in our turns, we don't want to get past the next turn. This
|
|
||||||
// function simply limits an offset to be at most half the distance to the next turn in the
|
|
||||||
// offfset direction
|
|
||||||
const auto get_corrected_offset = [](
|
|
||||||
const double offset,
|
|
||||||
const IntersectionShapeData &road,
|
|
||||||
const IntersectionShapeData &next_road_in_offset_direction) {
|
|
||||||
const auto offset_limit =
|
|
||||||
angularDeviation(road.bearing, next_road_in_offset_direction.bearing);
|
|
||||||
// limit the offset with an additional buffer
|
|
||||||
return (offset + MAXIMAL_ALLOWED_NO_TURN_DEVIATION > offset_limit) ? 0.5 * offset_limit
|
|
||||||
: offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
// only if straighmost angles get smaller, we consider it an improvement
|
|
||||||
auto const improves_straightmost = [&](auto const index, auto const offset) {
|
|
||||||
const auto itr = next_intersection_along_road.FindClosestBearing(
|
|
||||||
util::bearing::reverse(next_intersection_along_road[index].bearing));
|
|
||||||
const auto angle = util::bearing::angleBetween(
|
|
||||||
util::bearing::reverse(itr->bearing), next_intersection_along_road[index].bearing);
|
|
||||||
|
|
||||||
return util::angularDeviation(angle, STRAIGHT_ANGLE) >
|
|
||||||
util::angularDeviation(angle + offset, STRAIGHT_ANGLE);
|
|
||||||
};
|
|
||||||
|
|
||||||
// check if the u-turn edge at the next intersection could be merged to the left/right. If
|
|
||||||
// this is the case and the road is not far away (see previous distance check), if
|
|
||||||
// influences the perceived angle.
|
|
||||||
if (CanMerge(node_at_next_intersection, next_intersection_along_road, 0, 1))
|
|
||||||
{
|
|
||||||
const auto offset =
|
|
||||||
get_offset(next_intersection_along_road[0], next_intersection_along_road[1]);
|
|
||||||
|
|
||||||
if (improves_straightmost(0, -offset) && improves_straightmost(1, offset))
|
|
||||||
{
|
|
||||||
const auto corrected_offset = get_corrected_offset(
|
|
||||||
offset,
|
|
||||||
road,
|
|
||||||
intersection[(intersection.size() + index - 1) % intersection.size()]);
|
|
||||||
// at the target intersection, we merge to the right, so we need to shift the
|
|
||||||
// current
|
|
||||||
// angle to the left
|
|
||||||
road.bearing = adjustAngle(road.bearing, corrected_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (CanMerge(node_at_next_intersection,
|
|
||||||
next_intersection_along_road,
|
|
||||||
next_intersection_along_road.size() - 1,
|
|
||||||
0))
|
|
||||||
{
|
|
||||||
const auto offset =
|
|
||||||
get_offset(next_intersection_along_road[0],
|
|
||||||
next_intersection_along_road[next_intersection_along_road.size() - 1]);
|
|
||||||
|
|
||||||
if (improves_straightmost(0, offset) &&
|
|
||||||
improves_straightmost(next_intersection_along_road.size() - 1, -offset))
|
|
||||||
{
|
|
||||||
const auto corrected_offset = get_corrected_offset(
|
|
||||||
offset, road, intersection[(index + 1) % intersection.size()]);
|
|
||||||
// at the target intersection, we merge to the left, so we need to shift the current
|
|
||||||
// angle to the right
|
|
||||||
road.bearing = adjustAngle(road.bearing, -corrected_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersection;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace guidance
|
|
||||||
} // namespace extractor
|
|
||||||
} // namespace osrm
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
#include "extractor/guidance/mergable_road_detector.hpp"
|
#include "extractor/guidance/mergable_road_detector.hpp"
|
||||||
#include "extractor/guidance/constants.hpp"
|
#include "extractor/guidance/constants.hpp"
|
||||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
|
||||||
#include "extractor/guidance/node_based_graph_walker.hpp"
|
#include "extractor/guidance/node_based_graph_walker.hpp"
|
||||||
|
#include "extractor/intersection/intersection_analysis.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
#include "extractor/suffix_table.hpp"
|
#include "extractor/suffix_table.hpp"
|
||||||
|
|
||||||
@@ -23,6 +22,8 @@ namespace guidance
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// check a connected road for equality of a name
|
// check a connected road for equality of a name
|
||||||
|
// returns 'true' if no equality because this is used as a filter elsewhere, i.e. filter if fn
|
||||||
|
// returns 'true'
|
||||||
inline auto makeCheckRoadForName(const NameID name_id,
|
inline auto makeCheckRoadForName(const NameID name_id,
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
@@ -32,32 +33,40 @@ inline auto makeCheckRoadForName(const NameID name_id,
|
|||||||
return [name_id, &node_based_graph, &node_data_container, &name_table, &suffix_table](
|
return [name_id, &node_based_graph, &node_data_container, &name_table, &suffix_table](
|
||||||
const MergableRoadDetector::MergableRoadData &road) {
|
const MergableRoadDetector::MergableRoadData &road) {
|
||||||
// since we filter here, we don't want any other name than the one we are looking for
|
// since we filter here, we don't want any other name than the one we are looking for
|
||||||
const auto road_name =
|
const auto road_name_id =
|
||||||
node_data_container
|
node_data_container
|
||||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||||
.name_id;
|
.name_id;
|
||||||
if (name_id == EMPTY_NAMEID || road_name == EMPTY_NAMEID)
|
const auto road_name_empty = name_table.GetNameForID(road_name_id).empty();
|
||||||
|
const auto in_name_empty = name_table.GetNameForID(name_id).empty();
|
||||||
|
if (in_name_empty || road_name_empty)
|
||||||
return true;
|
return true;
|
||||||
const auto requires_announcement =
|
const auto requires_announcement =
|
||||||
util::guidance::requiresNameAnnounced(name_id, road_name, name_table, suffix_table) ||
|
util::guidance::requiresNameAnnounced(
|
||||||
util::guidance::requiresNameAnnounced(road_name, name_id, name_table, suffix_table);
|
name_id, road_name_id, name_table, suffix_table) ||
|
||||||
|
util::guidance::requiresNameAnnounced(road_name_id, name_id, name_table, suffix_table);
|
||||||
|
|
||||||
return requires_announcement;
|
return requires_announcement;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MergableRoadDetector::MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph,
|
MergableRoadDetector::MergableRoadDetector(
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const std::vector<util::Coordinate> &node_coordinates,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const IntersectionGenerator &intersection_generator,
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
const CoordinateExtractor &coordinate_extractor,
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
const util::NameTable &name_table,
|
const RestrictionMap &node_restriction_map,
|
||||||
const SuffixTable &street_name_suffix_table)
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table)
|
||||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||||
node_coordinates(node_coordinates), intersection_generator(intersection_generator),
|
node_coordinates(node_coordinates), compressed_geometries(compressed_geometries),
|
||||||
coordinate_extractor(coordinate_extractor), name_table(name_table),
|
node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes),
|
||||||
street_name_suffix_table(street_name_suffix_table)
|
turn_lanes_data(turn_lanes_data), name_table(name_table),
|
||||||
|
street_name_suffix_table(street_name_suffix_table),
|
||||||
|
coordinate_extractor(node_based_graph, compressed_geometries, node_coordinates)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,16 +122,6 @@ bool MergableRoadDetector::CanMergeRoad(const NodeID intersection_node,
|
|||||||
!IsCircularShape(intersection_node, lhs, rhs);
|
!IsCircularShape(intersection_node, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MergableRoadDetector::HaveIdenticalNames(const NameID lhs, const NameID rhs) const
|
|
||||||
{
|
|
||||||
const auto non_empty = (lhs != EMPTY_NAMEID) && (rhs != EMPTY_NAMEID);
|
|
||||||
|
|
||||||
// symmetrical check for announcements
|
|
||||||
return non_empty &&
|
|
||||||
!util::guidance::requiresNameAnnounced(lhs, rhs, name_table, street_name_suffix_table) &&
|
|
||||||
!util::guidance::requiresNameAnnounced(rhs, lhs, name_table, street_name_suffix_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
|
bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
|
||||||
const MergableRoadData &rhs) const
|
const MergableRoadData &rhs) const
|
||||||
{
|
{
|
||||||
@@ -134,7 +133,9 @@ bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
|
|||||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
||||||
.name_id,
|
.name_id,
|
||||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(rhs.eid).annotation_data)
|
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(rhs.eid).annotation_data)
|
||||||
.name_id);
|
.name_id,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MergableRoadDetector::EdgeDataSupportsMerge(
|
bool MergableRoadDetector::EdgeDataSupportsMerge(
|
||||||
@@ -156,7 +157,8 @@ bool MergableRoadDetector::EdgeDataSupportsMerge(
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we require valid names
|
// we require valid names
|
||||||
if (!HaveIdenticalNames(lhs_annotation.name_id, rhs_annotation.name_id))
|
if (!HaveIdenticalNames(
|
||||||
|
lhs_annotation.name_id, rhs_annotation.name_id, name_table, street_name_suffix_table))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return lhs_flags.road_classification == rhs_flags.road_classification;
|
return lhs_flags.road_classification == rhs_flags.road_classification;
|
||||||
@@ -165,8 +167,9 @@ bool MergableRoadDetector::EdgeDataSupportsMerge(
|
|||||||
bool MergableRoadDetector::IsTrafficLoop(const NodeID intersection_node,
|
bool MergableRoadDetector::IsTrafficLoop(const NodeID intersection_node,
|
||||||
const MergableRoadData &road) const
|
const MergableRoadData &road) const
|
||||||
{
|
{
|
||||||
const auto connection = intersection_generator.SkipDegreeTwoNodes(intersection_node, road.eid);
|
const auto connection =
|
||||||
return intersection_node == node_based_graph.GetTarget(connection.via_eid);
|
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, road.eid});
|
||||||
|
return intersection_node == node_based_graph.GetTarget(connection.edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
||||||
@@ -175,8 +178,22 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
|||||||
{
|
{
|
||||||
// selection data to the right and left
|
// selection data to the right and left
|
||||||
const auto constexpr SMALL_RANDOM_HOPLIMIT = 5;
|
const auto constexpr SMALL_RANDOM_HOPLIMIT = 5;
|
||||||
IntersectionFinderAccumulator left_accumulator(SMALL_RANDOM_HOPLIMIT, intersection_generator),
|
IntersectionFinderAccumulator left_accumulator(SMALL_RANDOM_HOPLIMIT,
|
||||||
right_accumulator(SMALL_RANDOM_HOPLIMIT, intersection_generator);
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data),
|
||||||
|
right_accumulator(SMALL_RANDOM_HOPLIMIT,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data);
|
||||||
|
|
||||||
/* Standard following the straightmost road
|
/* Standard following the straightmost road
|
||||||
* Since both items have the same id, we can `select` based on any setup
|
* Since both items have the same id, we can `select` based on any setup
|
||||||
@@ -188,8 +205,13 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
|||||||
/*requires entry=*/false,
|
/*requires entry=*/false,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
NodeBasedGraphWalker graph_walker(
|
NodeBasedGraphWalker graph_walker(node_based_graph,
|
||||||
node_based_graph, node_data_container, intersection_generator);
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data);
|
||||||
graph_walker.TraverseRoad(intersection_node, lhs.eid, left_accumulator, selector);
|
graph_walker.TraverseRoad(intersection_node, lhs.eid, left_accumulator, selector);
|
||||||
/* if the intersection does not have a right turn, we continue onto the next one once
|
/* if the intersection does not have a right turn, we continue onto the next one once
|
||||||
* (skipping over a single small side street)
|
* (skipping over a single small side street)
|
||||||
@@ -261,7 +283,13 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
|||||||
|
|
||||||
// check if both intersections are connected
|
// check if both intersections are connected
|
||||||
IntersectionFinderAccumulator connect_accumulator(SMALL_RANDOM_HOPLIMIT,
|
IntersectionFinderAccumulator connect_accumulator(SMALL_RANDOM_HOPLIMIT,
|
||||||
intersection_generator);
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data);
|
||||||
graph_walker.TraverseRoad(node_based_graph.GetTarget(left_accumulator.via_edge_id),
|
graph_walker.TraverseRoad(node_based_graph.GetTarget(left_accumulator.via_edge_id),
|
||||||
connector_turn->eid,
|
connector_turn->eid,
|
||||||
connect_accumulator,
|
connect_accumulator,
|
||||||
@@ -276,8 +304,13 @@ bool MergableRoadDetector::IsCircularShape(const NodeID intersection_node,
|
|||||||
const MergableRoadData &lhs,
|
const MergableRoadData &lhs,
|
||||||
const MergableRoadData &rhs) const
|
const MergableRoadData &rhs) const
|
||||||
{
|
{
|
||||||
NodeBasedGraphWalker graph_walker(
|
NodeBasedGraphWalker graph_walker(node_based_graph,
|
||||||
node_based_graph, node_data_container, intersection_generator);
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data);
|
||||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||||
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
||||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||||
@@ -343,8 +376,13 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Find a coordinate following a road that is far away
|
// Find a coordinate following a road that is far away
|
||||||
NodeBasedGraphWalker graph_walker(
|
NodeBasedGraphWalker graph_walker(node_based_graph,
|
||||||
node_based_graph, node_data_container, intersection_generator);
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data);
|
||||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||||
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
||||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||||
@@ -414,10 +452,16 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// compare reference distance:
|
// compare reference distance:
|
||||||
const auto distance_between_roads = util::coordinate_calculation::findClosestDistance(
|
const auto distance_mid_left_to_right = util::coordinate_calculation::findClosestDistance(
|
||||||
coordinates_to_the_left[coordinates_to_the_left.size() / 2],
|
coordinates_to_the_left[coordinates_to_the_left.size() / 2],
|
||||||
coordinates_to_the_right.begin(),
|
coordinates_to_the_right.begin(),
|
||||||
coordinates_to_the_right.end());
|
coordinates_to_the_right.end());
|
||||||
|
const auto distance_mid_right_to_left = util::coordinate_calculation::findClosestDistance(
|
||||||
|
coordinates_to_the_right[coordinates_to_the_right.size() / 2],
|
||||||
|
coordinates_to_the_left.begin(),
|
||||||
|
coordinates_to_the_left.end());
|
||||||
|
const auto distance_between_roads =
|
||||||
|
std::min(distance_mid_left_to_right, distance_mid_right_to_left);
|
||||||
|
|
||||||
const auto lane_count_lhs = std::max<int>(
|
const auto lane_count_lhs = std::max<int>(
|
||||||
1, node_based_graph.GetEdgeData(lhs.eid).flags.road_classification.GetNumberOfLanes());
|
1, node_based_graph.GetEdgeData(lhs.eid).flags.road_classification.GetNumberOfLanes());
|
||||||
@@ -438,12 +482,12 @@ bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node,
|
|||||||
* location with the same name repeatet at least three times
|
* location with the same name repeatet at least three times
|
||||||
*/
|
*/
|
||||||
const auto left_connection =
|
const auto left_connection =
|
||||||
intersection_generator.SkipDegreeTwoNodes(intersection_node, lhs.eid);
|
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, lhs.eid});
|
||||||
const auto right_connection =
|
const auto right_connection =
|
||||||
intersection_generator.SkipDegreeTwoNodes(intersection_node, rhs.eid);
|
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, rhs.eid});
|
||||||
|
|
||||||
const auto left_candidate = node_based_graph.GetTarget(left_connection.via_eid);
|
const auto left_candidate = node_based_graph.GetTarget(left_connection.edge);
|
||||||
const auto right_candidate = node_based_graph.GetTarget(right_connection.via_eid);
|
const auto right_candidate = node_based_graph.GetTarget(right_connection.edge);
|
||||||
|
|
||||||
const auto candidate_is_valid =
|
const auto candidate_is_valid =
|
||||||
left_candidate == right_candidate && left_candidate != intersection_node;
|
left_candidate == right_candidate && left_candidate != intersection_node;
|
||||||
@@ -465,16 +509,18 @@ bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node,
|
|||||||
.name_id;
|
.name_id;
|
||||||
|
|
||||||
const auto has_required_name = [this, required_name_id](const auto edge_id) {
|
const auto has_required_name = [this, required_name_id](const auto edge_id) {
|
||||||
const auto road_name =
|
const auto road_name_id =
|
||||||
node_data_container
|
node_data_container
|
||||||
.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||||
.name_id;
|
.name_id;
|
||||||
if (required_name_id == EMPTY_NAMEID || road_name == EMPTY_NAMEID)
|
const auto &road_name_empty = name_table.GetNameForID(road_name_id).empty();
|
||||||
|
const auto &required_name_empty = name_table.GetNameForID(required_name_id).empty();
|
||||||
|
if (required_name_empty && road_name_empty)
|
||||||
return false;
|
return false;
|
||||||
return !util::guidance::requiresNameAnnounced(
|
return !util::guidance::requiresNameAnnounced(
|
||||||
required_name_id, road_name, name_table, street_name_suffix_table) ||
|
required_name_id, road_name_id, name_table, street_name_suffix_table) ||
|
||||||
!util::guidance::requiresNameAnnounced(
|
!util::guidance::requiresNameAnnounced(
|
||||||
road_name, required_name_id, name_table, street_name_suffix_table);
|
road_name_id, required_name_id, name_table, street_name_suffix_table);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* the beautiful way would be:
|
/* the beautiful way would be:
|
||||||
@@ -509,9 +555,16 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node,
|
|||||||
const MergableRoadData &road) const
|
const MergableRoadData &road) const
|
||||||
{
|
{
|
||||||
const auto next_intersection_parameters =
|
const auto next_intersection_parameters =
|
||||||
intersection_generator.SkipDegreeTwoNodes(intersection_node, road.eid);
|
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, road.eid});
|
||||||
const auto next_intersection_along_road = intersection_generator.GetConnectedRoads(
|
const auto next_intersection_along_road =
|
||||||
next_intersection_parameters.nid, next_intersection_parameters.via_eid);
|
intersection::getConnectedRoads<false>(node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
|
next_intersection_parameters);
|
||||||
const auto extract_name_id = [this](const MergableRoadData &road) {
|
const auto extract_name_id = [this](const MergableRoadData &road) {
|
||||||
return node_data_container
|
return node_data_container
|
||||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||||
@@ -536,7 +589,7 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node,
|
|||||||
|
|
||||||
// we cannot be looking at the same road we came from
|
// we cannot be looking at the same road we came from
|
||||||
if (node_based_graph.GetTarget(opposite_of_next_road_along_path->eid) ==
|
if (node_based_graph.GetTarget(opposite_of_next_road_along_path->eid) ==
|
||||||
next_intersection_parameters.nid)
|
next_intersection_parameters.node)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* check if the opposite of the next road decision was sane. It could have been just as well our
|
/* check if the opposite of the next road decision was sane. It could have been just as well our
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "extractor/guidance/constants.hpp"
|
#include "extractor/guidance/constants.hpp"
|
||||||
#include "extractor/guidance/road_classification.hpp"
|
#include "extractor/guidance/road_classification.hpp"
|
||||||
|
|
||||||
|
#include "util/assert.hpp"
|
||||||
#include "util/bearing.hpp"
|
#include "util/bearing.hpp"
|
||||||
#include "util/guidance/name_announcements.hpp"
|
#include "util/guidance/name_announcements.hpp"
|
||||||
|
|
||||||
@@ -42,15 +43,21 @@ inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_base
|
|||||||
MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
const std::vector<util::Coordinate> &coordinates,
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table,
|
const SuffixTable &street_name_suffix_table)
|
||||||
const IntersectionGenerator &intersection_generator)
|
|
||||||
: IntersectionHandler(node_based_graph,
|
: IntersectionHandler(node_based_graph,
|
||||||
node_data_container,
|
node_data_container,
|
||||||
coordinates,
|
coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
name_table,
|
name_table,
|
||||||
street_name_suffix_table,
|
street_name_suffix_table)
|
||||||
intersection_generator)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +239,12 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
|||||||
intersection[1].instruction =
|
intersection[1].instruction =
|
||||||
getInstructionForObvious(intersection.size(),
|
getInstructionForObvious(intersection.size(),
|
||||||
via_eid,
|
via_eid,
|
||||||
isThroughStreet(1, intersection),
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
intersection[1]);
|
intersection[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -246,8 +258,16 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
|||||||
|
|
||||||
if (road.angle == continue_angle)
|
if (road.angle == continue_angle)
|
||||||
{
|
{
|
||||||
road.instruction = getInstructionForObvious(
|
road.instruction =
|
||||||
intersection.size(), via_eid, isThroughStreet(1, intersection), road);
|
getInstructionForObvious(intersection.size(),
|
||||||
|
via_eid,
|
||||||
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
|
road);
|
||||||
}
|
}
|
||||||
else if (road.angle < continue_angle)
|
else if (road.angle < continue_angle)
|
||||||
{
|
{
|
||||||
@@ -271,17 +291,11 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
|||||||
// handle motorway forks
|
// handle motorway forks
|
||||||
else if (exiting_motorways > 1)
|
else if (exiting_motorways > 1)
|
||||||
{
|
{
|
||||||
if (exiting_motorways == 2 && intersection.size() == 2)
|
if (exiting_motorways == 2)
|
||||||
{
|
|
||||||
intersection[1].instruction =
|
|
||||||
getInstructionForObvious(intersection.size(),
|
|
||||||
via_eid,
|
|
||||||
isThroughStreet(1, intersection),
|
|
||||||
intersection[1]);
|
|
||||||
intersection[0].entry_allowed = false; // UTURN on the freeway
|
|
||||||
}
|
|
||||||
else if (exiting_motorways == 2)
|
|
||||||
{
|
{
|
||||||
|
OSRM_ASSERT(intersection.size() != 2,
|
||||||
|
node_coordinates[node_based_graph.GetTarget(via_eid)]);
|
||||||
|
|
||||||
// standard fork
|
// standard fork
|
||||||
std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
|
std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
|
||||||
second_valid = std::numeric_limits<std::size_t>::max();
|
second_valid = std::numeric_limits<std::size_t>::max();
|
||||||
@@ -352,8 +366,16 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
|||||||
BOOST_ASSERT(!intersection[0].entry_allowed);
|
BOOST_ASSERT(!intersection[0].entry_allowed);
|
||||||
BOOST_ASSERT(isMotorwayClass(intersection[1].eid, node_based_graph));
|
BOOST_ASSERT(isMotorwayClass(intersection[1].eid, node_based_graph));
|
||||||
|
|
||||||
intersection[1].instruction = getInstructionForObvious(
|
intersection[1].instruction =
|
||||||
intersection.size(), via_eid, isThroughStreet(1, intersection), intersection[1]);
|
getInstructionForObvious(intersection.size(),
|
||||||
|
via_eid,
|
||||||
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
|
intersection[1]);
|
||||||
}
|
}
|
||||||
else if (intersection.size() == 3)
|
else if (intersection.size() == 3)
|
||||||
{
|
{
|
||||||
@@ -379,11 +401,15 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
|||||||
//
|
//
|
||||||
// 7 1
|
// 7 1
|
||||||
// 0
|
// 0
|
||||||
|
const auto &first_intersection_name_empty =
|
||||||
|
name_table.GetNameForID(first_intersection_data.name_id).empty();
|
||||||
|
const auto &second_intersection_name_empty =
|
||||||
|
name_table.GetNameForID(second_intersection_data.name_id).empty();
|
||||||
if (intersection[1].entry_allowed)
|
if (intersection[1].entry_allowed)
|
||||||
{
|
{
|
||||||
if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
|
if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
|
||||||
second_intersection_data.name_id != EMPTY_NAMEID &&
|
!second_intersection_name_empty && !first_intersection_name_empty &&
|
||||||
first_intersection_data.name_id != EMPTY_NAMEID && first_second_same_name)
|
first_second_same_name)
|
||||||
{
|
{
|
||||||
// circular order indicates a merge to the left (0-3 onto 4
|
// circular order indicates a merge to the left (0-3 onto 4
|
||||||
if (angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) <
|
if (angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) <
|
||||||
@@ -399,7 +425,12 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
|||||||
intersection[1].instruction =
|
intersection[1].instruction =
|
||||||
getInstructionForObvious(intersection.size(),
|
getInstructionForObvious(intersection.size(),
|
||||||
via_eid,
|
via_eid,
|
||||||
isThroughStreet(1, intersection),
|
isThroughStreet(1,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
intersection[1]);
|
intersection[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,8 +438,8 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
|||||||
{
|
{
|
||||||
BOOST_ASSERT(intersection[2].entry_allowed);
|
BOOST_ASSERT(intersection[2].entry_allowed);
|
||||||
if (isMotorwayClass(intersection[2].eid, node_based_graph) &&
|
if (isMotorwayClass(intersection[2].eid, node_based_graph) &&
|
||||||
second_intersection_data.name_id != EMPTY_NAMEID &&
|
!second_intersection_name_empty && !first_intersection_name_empty &&
|
||||||
first_intersection_data.name_id != EMPTY_NAMEID && first_second_same_name)
|
first_second_same_name)
|
||||||
{
|
{
|
||||||
// circular order (5-0) onto 4
|
// circular order (5-0) onto 4
|
||||||
if (angularDeviation(intersection[2].angle, STRAIGHT_ANGLE) <
|
if (angularDeviation(intersection[2].angle, STRAIGHT_ANGLE) <
|
||||||
@@ -424,7 +455,12 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
|||||||
intersection[2].instruction =
|
intersection[2].instruction =
|
||||||
getInstructionForObvious(intersection.size(),
|
getInstructionForObvious(intersection.size(),
|
||||||
via_eid,
|
via_eid,
|
||||||
isThroughStreet(2, intersection),
|
isThroughStreet(2,
|
||||||
|
intersection,
|
||||||
|
node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table),
|
||||||
intersection[2]);
|
intersection[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "extractor/guidance/node_based_graph_walker.hpp"
|
#include "extractor/guidance/node_based_graph_walker.hpp"
|
||||||
|
#include "extractor/intersection/intersection_analysis.hpp"
|
||||||
#include "util/bearing.hpp"
|
#include "util/bearing.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
|
||||||
@@ -14,11 +15,18 @@ namespace guidance
|
|||||||
{
|
{
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
NodeBasedGraphWalker::NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
|
NodeBasedGraphWalker::NodeBasedGraphWalker(
|
||||||
const EdgeBasedNodeDataContainer &node_data_container,
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const IntersectionGenerator &intersection_generator)
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data)
|
||||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||||
intersection_generator(intersection_generator)
|
node_coordinates(node_coordinates), compressed_geometries(compressed_geometries),
|
||||||
|
node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes),
|
||||||
|
turn_lanes_data(turn_lanes_data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,8 +243,18 @@ operator()(const NodeID /*nid*/,
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
IntersectionFinderAccumulator::IntersectionFinderAccumulator(
|
IntersectionFinderAccumulator::IntersectionFinderAccumulator(
|
||||||
const std::uint8_t hop_limit, const IntersectionGenerator &intersection_generator)
|
const std::uint8_t hop_limit,
|
||||||
: hops(0), hop_limit(hop_limit), intersection_generator(intersection_generator)
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
|
const EdgeBasedNodeDataContainer &node_data_container,
|
||||||
|
const std::vector<util::Coordinate> &node_coordinates,
|
||||||
|
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||||
|
const RestrictionMap &node_restriction_map,
|
||||||
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
|
const guidance::TurnLanesIndexedArray &turn_lanes_data)
|
||||||
|
: hops(0), hop_limit(hop_limit), node_based_graph(node_based_graph),
|
||||||
|
node_data_container(node_data_container), node_coordinates(node_coordinates),
|
||||||
|
compressed_geometries(compressed_geometries), node_restriction_map(node_restriction_map),
|
||||||
|
barrier_nodes(barrier_nodes), turn_lanes_data(turn_lanes_data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +279,14 @@ void IntersectionFinderAccumulator::update(const NodeID from_node,
|
|||||||
nid = from_node;
|
nid = from_node;
|
||||||
via_edge_id = via_edge;
|
via_edge_id = via_edge;
|
||||||
|
|
||||||
intersection = intersection_generator.GetConnectedRoads(from_node, via_edge, true);
|
intersection = intersection::getConnectedRoads<true>(node_based_graph,
|
||||||
|
node_data_container,
|
||||||
|
node_coordinates,
|
||||||
|
compressed_geometries,
|
||||||
|
node_restriction_map,
|
||||||
|
barrier_nodes,
|
||||||
|
turn_lanes_data,
|
||||||
|
{from_node, via_edge});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user