Compare commits

..

48 Commits

Author SHA1 Message Date
Daniel Patterson 36db965c39 Update npm version for RC.1 2017-08-14 17:16:45 -07:00
Daniel Patterson 4e81764ce2 Update CHANGELOG for changes since 5.10 2017-08-14 17:16:05 -07:00
Michael Krasnyk 1e9f983289 Add mocked offline datafacade to engine tests 2017-08-14 16:18:36 +02:00
Michael Krasnyk 2e404c60f4 Remove references to external sources 2017-08-14 16:18:36 +02:00
vng 40857aae61 Inject offline compressed data facade with OSRM_EXTERNAL_MEMORY option. 2017-08-14 16:18:36 +02:00
vng a64145b712 Fixed mld algorithm to use template data facade. 2017-08-14 16:18:36 +02:00
vng 945f6da85e Removed useless include. 2017-08-14 16:18:36 +02:00
vng 76d5d054cb Compilation fix. 2017-08-14 16:18:36 +02:00
Michael Krasnyk 20cfa159ec Fix boost::optional construction error 2017-08-11 17:32:35 +02:00
Daniel J. Hofmann 3ff1a4263d Adds releasing docs about bumping to latest, see #4386 2017-08-11 15:53:14 +02:00
Patrick Niklaus 3141eb5dce [skip ci] Update CONTRIBUTING.md to include correct pre-commit hook 2017-08-11 10:06:07 +00:00
Daniel J. Hofmann 75d6f59026 Publicly expose binaries to Node.js bindings, resolves #4377 2017-08-11 12:04:53 +02:00
Daniel J. Hofmann ae42ce7017 [skip ci] Updates lockfile for latest master version 2017-08-11 12:04:53 +02:00
Moritz Kobitzsch e9c9c87bbc adjust geojson logger to changes in extractor 2017-08-11 12:03:40 +02:00
Michael Krasnyk 8a6dba46b1 Change windows time zones in West Africa to WAT zone 2017-08-11 11:53:25 +02:00
Moritz Kobitzsch 93299d6651 handle conditional via-way restrictions
- refactor conditional restriction handling to not use external data (first OSM nodes on ways)
 - BREAKING: changes internal file format of osrm.restrictions
 - add support for general conditional penalties based on edge-based nodes (requires unique edges between nodes)
2017-08-11 11:53:25 +02:00
vng f34320a89b Fixed getting entry bearing for maneuver. 2017-08-11 11:40:58 +02:00
Moritz Kobitzsch a17b07bc4c fix bug in conflict resolution 2017-08-11 11:01:54 +02:00
Moritz Kobitzsch 3a01ba52ef remove a few tests that are simply testing same code paths as others 2017-08-10 12:28:31 +02:00
Mateusz Loskot d796c66990 Prefer implicit expansion of CMake variables
Unify CMAKE_CXX_COMPILER_ID tests without quoting/bracketing
the variable to use implicit expansion.
Replace STREQUAL with MATCHES to avoid policy warning about
attempt to expand "MSVC" variable, where it literal is intended.
2017-08-10 12:26:48 +02:00
Mateusz Loskot 80b705e997 Add workaround for Visual C++ issue with std::array in debug
If Visual C++ _ITERATOR_DEBUG_LEVEL > 0, then
accessing std::array<char[N], M> elements via reference to const
causes compilation error:

...\msvc\14.10.25017\include\array(181): error C2440: 'return': cannot convert from 'const char *' to 'const char (&)[256]'

Alternative workaround is to remove const qualifier from the GetClassName method.
2017-08-10 12:21:42 +02:00
Moritz Kobitzsch 7069af3e20 explicitly use local eslint version for linting 2017-08-09 14:14:44 +02:00
Daniel J. Hofmann 209a926b45 Re-adds .npmignore, resolves #4193 2017-08-08 16:16:35 +02:00
Mateusz Loskot 71e0c7a3cf Add define WIN32_LEAN_AND_MEAN for Visual C++
Helps to avoid compiler C2011 errors due to WinSock types redefinition
from dual #include of winsock.h and winsock2.h
2017-08-08 15:50:47 +02:00
Daniel J. Hofmann b88d96f07d [skip ci] Updates lockfiles 2017-08-08 11:37:20 +02:00
Daniel J. Hofmann 46f75c3d92 [skip ci] Bumps version to 5.11 2017-08-08 11:37:20 +02:00
Mateusz Loskot 3b8e5cec88 Ignore build directories starting with _build
Convenient to manage multiple builds with basic
naming convention (eg. _build.gcc7, _build.vs2017).

[ci skip]
2017-08-08 11:14:39 +02:00
FILLAU Jean-Maxime a420169109 Reintroduce location for NodeRef in luabinding 2017-08-08 10:59:25 +02:00
Michael Krasnyk a8db269fd5 Adjust lower bound for crossroad angle in sliproads handler, #4348/2 2017-08-04 14:37:13 +02:00
Michael Krasnyk a5efcfdede Sliproads test case with acute angle at the main intersection 2017-08-04 14:37:13 +02:00
Michael Krasnyk 1ecc913fc2 Fix sliproad scenario with 4 roads in a target intersection, #4348/1 2017-08-04 14:07:35 +02:00
Michael Krasnyk 08eb3b11bc Test case for sliproad handling with 4 roads at target intersection 2017-08-04 14:07:35 +02:00
Moritz Kobitzsch b59d9a2f27 update test-case for changed turn angles 2017-08-04 12:57:55 +02:00
Moritz Kobitzsch e9a5e32330 fix prevention of copy elision 2017-08-04 12:57:55 +02:00
Moritz Kobitzsch be9bdfa47e adjust constants for changed turn angle 2017-08-04 11:20:31 +02:00
Moritz Kobitzsch 153e934ed4 shift circle angle a bit 2017-08-04 11:20:31 +02:00
Michael Krasnyk 4757c96d9a Add a check for non-empty segments in CSV speed files 2017-08-04 11:19:32 +02:00
Michael Krasnyk 1efc527281 Test with a traffic update on an edge with traffic signal 2017-08-04 11:19:32 +02:00
Moritz Kobitzsch 468b59c53d add changelog entry for compression of traffic signals 2017-08-04 11:19:32 +02:00
Moritz Kobitzsch 15426975b6 deduplicate geometry 2017-08-04 11:19:32 +02:00
Moritz Kobitzsch bbcf343e40 compress traffic signals
- handle penalties within edges (not phantom nodes)
 - changes model from providing penalties on turns to using additional segments
2017-08-04 11:19:32 +02:00
Moritz Kobitzsch f0d3cf4e43 removing duplicated test 2017-08-04 11:19:32 +02:00
Moritz Kobitzsch 4c965b9f44 Add regression test for interaction between via-way and via-node 2017-08-03 14:37:05 +02:00
Moritz Kobitzsch e5143247c2 move babel to dev dependencies, update releasing docs to reflect scripts in package.json 2017-08-03 14:31:41 +02:00
Daniel J. Hofmann 3a676183b2 Updates our node osrm docs and re-runs docs generation, resolves #4043 2017-08-03 14:31:41 +02:00
Daniel J. Hofmann 64265926a4 Adds babel transformation needed for node osrm docs 2017-08-03 14:31:41 +02:00
Michael Krasnyk df2d4daad3 Fix gcc5 internal compilation error 2017-08-02 10:25:38 +02:00
Michael Krasnyk fd0d79e17b Update pre-installed TBB version to 2017_U7 2017-08-02 10:25:38 +02:00
92 changed files with 5931 additions and 3285 deletions
+1
View File
@@ -46,6 +46,7 @@ Thumbs.db
# build related files #
#######################
/_build*
/build/
/example/build/
/test/data/monaco*
+15
View File
@@ -0,0 +1,15 @@
*
!README.md
!CHANGELOG.md
!CONTRIBUTING.MD
!LICENCE.TXT
!package.json
!package-lock.json
!yarn.lock
!docs
!example
!taginfo.json
!lib/*.js
!profiles/*
!profiles/lib/*
!profiles/examples/*
+1 -2
View File
@@ -17,7 +17,6 @@ notifications:
branches:
only:
- master
- "5.10"
# enable building tags
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
@@ -302,7 +301,7 @@ before_install:
- mkdir -p ${CMAKE_DIR}
- travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${CMAKE_DIR} || travis_terminate 1
- export PATH=${CMAKE_DIR}/bin:${PATH}
- ${MASON} install tbb 2017_20161128 && export LD_LIBRARY_PATH=$(${MASON} prefix tbb 2017_20161128)/lib/:${LD_LIBRARY_PATH}
- ${MASON} install tbb 2017_U7 && export LD_LIBRARY_PATH=$(${MASON} prefix tbb 2017_U7)/lib/:${LD_LIBRARY_PATH}
- ${MASON} install ccache ${CCACHE_VERSION} && export PATH=$(${MASON} prefix ccache ${CCACHE_VERSION})/bin:${PATH}
- |
if [[ ! -z ${CLANG_VERSION} ]]; then
+23
View File
@@ -1,3 +1,24 @@
# 5.11.0
- Changes from 5.10:
- Features
- BREAKING: Added support for conditional via-way instructions. This features changes the file format of osrm.restrictions and requires re-extraction
- Internals
- BREAKING: Traffic signals will no longer be represented as turns internally. This requires re-processing of data but enables via-way turn restrictions across highway=traffic_signals
- Additional checks for empty segments when loading traffic data files
- Tunes the constants for turns in sharp curves just a tiny bit to circumvent a mix-up in fork directions at a specific intersection (https://github.com/Project-OSRM/osrm-backend/issues/4331)
- Infrastructure
- Refactor datafacade to make implementing additional DataFacades simpler
- Bugfixes
- API docs are now buildable again
- Suppress unnecessary extra turn instruction when exiting a motorway via a motorway_link onto a primary road (https://github.com/Project-OSRM/osrm-backend/issues/4348 scenario 4)
- Suppress unnecessary extra turn instruction when taking a tertiary_link road from a teritary onto a residential road (https://github.com/Project-OSRM/osrm-backend/issues/4348 scenario 2)
- Various MSVC++ build environment fixes
- Avoid a bug that crashes GCC6
- Re-include .npmignore to slim down published modules
- Fix a pre-processing bug where incorrect directions could be issued when two turns would have similar instructions and we tried to give them distinct values (https://github.com/Project-OSRM/osrm-backend/pull/4375)
- The entry bearing for correct the cardinality of a direction value (https://github.com/Project-OSRM/osrm-backend/pull/4353
- Change timezones in West Africa to the WAT zone so they're recognized on the Windows platform
# 5.10.0
- Changes from 5.9:
- Profiles:
@@ -21,6 +42,8 @@
- Algorithm)
- BREAKING: the file format requires re-processing due to the changes on via-ways
- Added support for via-way restrictions
- Node.js Bindings:
- Include binaries in the `node_modules/.bin` directory so they're in the PATH when running inside Node
# 5.9.2
- API:
+18 -17
View File
@@ -60,7 +60,7 @@ if (POLICY CMP0048)
endif()
project(OSRM C CXX)
set(OSRM_VERSION_MAJOR 5)
set(OSRM_VERSION_MINOR 10)
set(OSRM_VERSION_MINOR 11)
set(OSRM_VERSION_PATCH 0)
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
@@ -102,11 +102,11 @@ if(WIN32 AND MSVC_VERSION LESS 1900)
endif()
# Strictly require GCC>=4.9 and Clang>=3.4 - GCC 4.8 is already too old for C++14.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
message(FATAL_ERROR "GCC>=4.9 required. In case you are on Ubuntu upgrade via ppa:ubuntu-toolchain-r/test")
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
message(FATAL_ERROR "Clang>=3.4 required. In case you are on Ubuntu upgrade via http://apt.llvm.org")
endif()
@@ -182,7 +182,7 @@ endif()
# Disable LTO when mason+gcc is detected before testing for / setting any flags.
# Mason builds libraries with Clang, mixing does not work in the context of lto.
if(ENABLE_MASON AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND ENABLE_LTO)
if(ENABLE_MASON AND CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND ENABLE_LTO)
set(ENABLE_LTO OFF)
message(WARNING "Mason and GCC's LTO not work together. Disabling LTO.")
endif()
@@ -211,9 +211,9 @@ endif()
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
message(STATUS "Configuring debug mode flags")
set(ENABLE_ASSERTIONS ON)
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline -fno-omit-frame-pointer")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og -ggdb")
else()
@@ -232,7 +232,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
if(ENABLE_LTO AND LTO_AVAILABLE)
set(OLD_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# GCC in addition allows parallelizing LTO
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
include(ProcessorCount)
ProcessorCount(NPROC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=${NPROC}")
@@ -255,7 +255,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
endif()
# Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0" AND NOT MINGW)
find_program(GCC_AR gcc-ar)
find_program(GCC_RANLIB gcc-ranlib)
@@ -271,7 +271,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
endif()
# Same for clang LTO requires their own toolchain
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
find_program(LLVM_AR llvm-ar)
find_program(LLVM_RANLIB llvm-ranlib)
if ("${LLVM_AR}" STREQUAL "LLVM_AR-NOTFOUND" OR "${LLVM_RANLIB}" STREQUAL "LLVM_RANLIB-NOTFOUND")
@@ -285,7 +285,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
endif()
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
message(STATUS "Disabling LTO on GCC < 4.9.0 since it is broken, see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57038")
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
set(ENABLE_LTO Off)
@@ -315,9 +315,9 @@ if (ENABLE_SANITIZER)
endif()
# Configuring compilers
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC -fcolor-diagnostics -ftemplate-depth=1024 -Wno-unused-command-line-argument")
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(COLOR_FLAG "-fdiagnostics-color=auto")
check_cxx_compiler_flag("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
if(NOT HAS_COLOR_FLAG)
@@ -337,13 +337,14 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
endif()
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
# using Intel C++
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC")
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
# using Visual Studio C++
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} zlib)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") # avoid compiler error C1128 from scripting_environment_lua.cpp
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /DWIN32_LEAN_AND_MEAN") # avoid compiler error C2011 from dual #include of winsock.h and winsock2.h
add_dependency_defines(-DBOOST_LIB_DIAGNOSTIC)
add_dependency_defines(-D_CRT_SECURE_NO_WARNINGS)
add_dependency_defines(-DNOMINMAX) # avoid min and max macros that can break compilation
@@ -359,7 +360,7 @@ execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-Wl,--version" ERROR_QUIET OUTPUT
# For ld.gold and ld.bfs (the GNU linkers) we optimize hard
if("${LINKER_VERSION}" MATCHES "GNU gold" OR "${LINKER_VERSION}" MATCHES "GNU ld")
message(STATUS "Setting linker optimizations")
if(NOT (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC" OR "${LD_AVOID_GC_SECTIONS}"))
if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "MSVC" OR "${LD_AVOID_GC_SECTIONS}"))
# Tell compiler to put every function in separate section, linker can then match sections and functions
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
# Tell linker to do dead code and data eminination during link time discarding sections
@@ -377,7 +378,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
# Activate C++1y
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++1y")
endif()
@@ -568,7 +569,7 @@ else()
endif()
# prefix compilation with ccache by default if available and on clang or gcc
if(ENABLE_CCACHE AND (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU"))
if(ENABLE_CCACHE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU"))
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
message(STATUS "Using ccache to speed up incremental builds")
+1 -1
View File
@@ -18,7 +18,7 @@ if [ x"$remote" = xorigin ] ; then
echo "Rejected push to $remote/master" ; exit 1
fi
./scripts/format.sh
./scripts/format.sh && ./scripts/error_on_dirty.sh
if [ $? -ne 0 ] ; then
echo "Unstaged format changes" ; exit 1
fi
+1 -1
View File
@@ -53,4 +53,4 @@ We may introduce forward-compatible changes: query parameters and response prope
10. Wait until the travis build has been completed and check if the node binaries were published by doing:
`rm -rf node_modules && npm install` locally.
11. For final releases run `npm publish` or `npm publish --tag next` for release candidates.
12. Bump version in `package.json` to `{MAJOR}.{MINOR+1}.0-latest.1` on the `master` branch after the release.
-7
View File
@@ -21,13 +21,6 @@ Feature: Bicycle - Handle cycling
When I route I should get
| from | to | route | modes |
| a | g | abc,cde,efg,efg | cycling,cycling,cycling,cycling |
| b | f | abc,cde,efg,efg | cycling,cycling,cycling,cycling |
| e | c | cde,cde | cycling,cycling |
| e | b | cde,abc,abc | cycling,cycling,cycling |
| e | a | cde,abc,abc | cycling,cycling,cycling |
| c | e | cde,cde | cycling,cycling |
| c | f | cde,efg,efg | cycling,cycling,cycling |
| c | g | cde,efg,efg | cycling,cycling,cycling |
Scenario: Bicycle - Properly handle durations
Given the node map
+23 -23
View File
@@ -21,15 +21,15 @@ Feature: Bike - Destination only, no passing through
| axye | |
When I route I should get
| from | to | route |
| a | b | ab,ab |
| a | c | ab,bcd,bcd |
| a | d | ab,bcd,bcd |
| a | e | axye,axye |
| e | d | de,de |
| e | c | de,bcd,bcd |
| e | b | de,bcd,bcd |
| e | a | axye,axye |
| from | to | route |
| a | b | ab,ab |
| a | c | ab,bcd |
| a | d | ab,bcd |
| a | e | axye,axye |
| e | d | de,de |
| e | c | de,bcd |
| e | b | de,bcd |
| e | a | axye,axye |
Scenario: Bike - Destination only street
Given the node map
@@ -49,15 +49,15 @@ Feature: Bike - Destination only, no passing through
| axye | |
When I route I should get
| from | to | route |
| a | b | ab,ab |
| a | c | ab,bc,bc |
| a | d | ab,bc,cd,cd |
| a | e | axye,axye |
| e | d | de,de |
| e | c | de,cd,cd |
| e | b | de,cd,bc,bc |
| e | a | axye,axye |
| from | to | route |
| a | b | ab,ab |
| a | c | ab,bc |
| a | d | ab,bc,cd |
| a | e | axye,axye |
| e | d | de,de |
| e | c | de,cd,cd |
| e | b | de,cd,bc |
| e | a | axye,axye |
Scenario: Bike - Routing inside a destination only area
Given the node map
@@ -76,8 +76,8 @@ Feature: Bike - Destination only, no passing through
| axye | |
When I route I should get
| from | to | route |
| a | e | ab,bc,cd,de,de |
| e | a | de,cd,bc,ab,ab |
| b | d | bc,cd,cd |
| d | b | cd,bc,bc |
| from | to | route |
| a | e | ab,bc,cd,de |
| e | a | de,cd,bc,ab |
| b | d | bc,cd |
| d | b | cd,bc |
-5
View File
@@ -21,12 +21,7 @@ Feature: Bike - Handle ferry routes
When I route I should get
| from | to | route |
| a | g | abc,cde,efg,efg |
| b | f | abc,cde,efg,efg |
| e | c | cde,cde |
| e | b | cde,abc,abc |
| e | a | cde,abc,abc |
| c | e | cde,cde |
| c | f | cde,efg,efg |
| c | g | cde,efg,efg |
Scenario: Bike - Ferry duration, single node
+1 -96
View File
@@ -20,11 +20,8 @@ Feature: Bike - Mode flag
When I route I should get
| from | to | route | modes |
| a | d | ab,bc,cd,cd | cycling,ferry,cycling,cycling |
| d | a | cd,bc,ab,ab | cycling,ferry,cycling,cycling |
| c | a | bc,ab,ab | ferry,cycling,cycling |
| d | b | cd,bc,bc | cycling,ferry,ferry |
| a | c | ab,bc,bc | cycling,ferry,ferry |
| b | d | bc,cd,cd | ferry,cycling,cycling |
Scenario: Bike - Mode when using a train
Given the node map
@@ -42,12 +39,10 @@ Feature: Bike - Mode flag
When I route I should get
| from | to | route | modes |
| a | d | ab,bc,cd,cd | cycling,train,cycling,cycling |
| d | a | cd,bc,ab,ab | cycling,train,cycling,cycling |
| c | a | bc,ab,ab | train,cycling,cycling |
| d | b | cd,bc,bc | cycling,train,train |
| a | c | ab,bc,bc | cycling,train,train |
| b | d | bc,cd,cd | train,cycling,cycling |
#representative test for all pushes (and mode changes). Where a bike is pushed is tested over in access.feature
Scenario: Bike - Mode when pushing bike against oneways
Given the node map
"""
@@ -70,96 +65,6 @@ Feature: Bike - Mode flag
| d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
| a | c | ab,bc,bc | cycling,cycling,cycling |
| b | d | bc,cd,cd | cycling,cycling,cycling |
Scenario: Bike - Mode when pushing on pedestrain streets
Given the node map
"""
a b
c d
"""
And the ways
| nodes | highway |
| ab | primary |
| bc | pedestrian |
| cd | primary |
When I route I should get
| from | to | route | modes |
| a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
| d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
| a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
| b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bike - Mode when pushing on pedestrain areas
Given the node map
"""
a b
c d f
"""
And the ways
| nodes | highway | area |
| ab | primary | |
| bcd | pedestrian | yes |
| df | primary | |
When I route I should get
| from | to | route | modes |
| a | f | ab,bcd,df,df | cycling,pushing bike,cycling,cycling |
| f | a | df,bcd,ab,ab | cycling,pushing bike,cycling,cycling |
| d | a | bcd,ab,ab | pushing bike,cycling,cycling |
| f | b | df,bcd,bcd | cycling,pushing bike,pushing bike |
| a | d | ab,bcd,bcd | cycling,pushing bike,pushing bike |
| b | f | bcd,df,df | pushing bike,cycling,cycling |
Scenario: Bike - Mode when pushing on steps
Given the node map
"""
a b
c d f
"""
And the ways
| nodes | highway |
| ab | primary |
| bc | steps |
| cd | primary |
When I route I should get
| from | to | route | modes |
| a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
| d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
| a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
| b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bike - Mode when bicycle=dismount
Given the node map
"""
a b
c d f
"""
And the ways
| nodes | highway | bicycle |
| ab | primary | |
| bc | primary | dismount |
| cd | primary | |
When I route I should get
| from | to | route | modes |
| a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
| d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
| a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
| b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bicycle - Modes when starting on forward oneway
Given the node map
-47
View File
@@ -1,47 +0,0 @@
@routing @bicycle @ref @name
Feature: Bike - Way ref
Background:
Given the profile "bicycle"
Scenario: Bike - Way with both name and ref
Given the node map
"""
a b
"""
And the ways
| nodes | name | ref |
| ab | Utopia Drive | E7 |
When I route I should get
| from | to | route | ref |
| a | b | Utopia Drive,Utopia Drive | E7,E7 |
Scenario: Bike - Way with only ref
Given the node map
"""
a b
"""
And the ways
| nodes | name | ref |
| ab | | E7 |
When I route I should get
| from | to | route | ref |
| a | b | , | E7,E7 |
Scenario: Bike - Way with only name
Given the node map
"""
a b
"""
And the ways
| nodes | name |
| ab | Utopia Drive |
When I route I should get
| from | to | route |
| a | b | Utopia Drive,Utopia Drive |
+3 -182
View File
@@ -7,6 +7,8 @@ Feature: Bike - Turn restrictions
Given the profile "bicycle"
Given a grid size of 200 meters
# check to see if bicycle profiles handle relations. The code path is the same as in cars.
# If relations are passed, all variants tested in car also work for bike
@no_turning
Scenario: Bike - No left turn
Given the node map
@@ -33,188 +35,7 @@ Feature: Bike - Turn restrictions
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@no_turning
Scenario: Bike - No right turn
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway | foot |
| sj | yes | no |
| nj | -1 | no |
| wj | -1 | no |
| ej | -1 | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | ej | j | no_right_turn |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@no_turning
Scenario: Bike - No u-turn
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway | foot |
| sj | yes | no |
| nj | -1 | no |
| wj | -1 | no |
| ej | -1 | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | wj | j | no_u_turn |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@no_turning
Scenario: Bike - Handle any no_* relation
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway | foot |
| sj | yes | no |
| nj | -1 | no |
| wj | -1 | no |
| ej | -1 | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | wj | j | no_weird_zigzags |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@only_turning
Scenario: Bike - Only left turn
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway | foot |
| sj | yes | no |
| nj | -1 | no |
| wj | -1 | no |
| ej | -1 | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | wj | j | only_left_turn |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@only_turning
Scenario: Bike - Only right turn
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway | foot |
| sj | yes | no |
| nj | -1 | no |
| wj | -1 | no |
| ej | -1 | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | ej | j | only_right_turn |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@only_turning
Scenario: Bike - Only straight on
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway | foot |
| sj | yes | no |
| nj | -1 | no |
| wj | -1 | no |
| ej | -1 | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | nj | j | only_straight_on |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@no_turning
Scenario: Bike - Handle any only_* restriction
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway | foot |
| sj | yes | no |
| nj | -1 | no |
| wj | -1 | no |
| ej | -1 | no |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | nj | j | only_weird_zigzags |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
## exceptions are different for bike over car and need to be tested here
@except
Scenario: Bike - Except tag and on no_ restrictions
Given the node map
-9
View File
@@ -22,13 +22,7 @@ Feature: Car - Handle driving
When I route I should get
| from | to | route | modes |
| a | g | abc,cde,efg,efg | driving,driving,driving,driving |
| b | f | abc,cde,efg,efg | driving,driving,driving,driving |
| e | c | cde,cde | driving,driving |
| e | b | cde,abc,abc | driving,driving,driving |
| e | a | cde,abc,abc | driving,driving,driving |
| c | e | cde,cde | driving,driving |
| c | f | cde,efg,efg | driving,driving,driving |
| c | g | cde,efg,efg | driving,driving,driving |
Scenario: Car - Control test without durations, osrm uses movable bridge speed to calculate duration
Given the node map
@@ -47,8 +41,6 @@ Feature: Car - Handle driving
When I route I should get
| from | to | route | modes | speed | time |
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | 13 km/h | 340s +-1 |
| b | f | abc,cde,efg,efg | driving,driving,driving,driving | 9 km/h | 318s +-1 |
| c | e | cde,cde | driving,driving | 5 km/h | 295s +-1 |
| e | c | cde,cde | driving,driving | 5 km/h | 295s +-1 |
Scenario: Car - Properly handle durations
@@ -68,6 +60,5 @@ Feature: Car - Handle driving
When I route I should get
| from | to | route | modes | speed |
| a | g | abc,cde,efg,efg | driving,driving,driving,driving | 7 km/h |
| b | f | abc,cde,efg,efg | driving,driving,driving,driving | 5 km/h |
| c | e | cde,cde | driving,driving | 2 km/h |
| e | c | cde,cde | driving,driving | 2 km/h |
+279 -5
View File
@@ -72,6 +72,75 @@ Feature: Car - Turn restrictions
| n | m | nj,pjm,pjm |
| s | m | js,pjm,pjm |
@no_turning @conditionals
Scenario: Car - Restriction With Compressed Geometry
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map
"""
n
|
i
|
j-k-l-m
|
s
"""
And the ways
| nodes |
| nij |
| js |
| jklm |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | nij | jklm | j | no_left_turn @ (Mo-Fr 07:00-10:30) |
When I route I should get
| from | to | route |
| n | m | nij,js,js,jklm,jklm |
@no_turning @conditionals
Scenario: Car - Restriction With Compressed Geometry and Traffic Signal
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 10am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200"
Given the node map
"""
n
|
i
|
j-k-l-m
|
s
"""
And the ways
| nodes |
| nij |
| js |
| jklm |
And the nodes
| node | highway |
| i | traffic_signal |
| k | traffic_signal |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | nij | jklm | j | no_left_turn @ (Mo-Fr 07:00-10:30) |
When I route I should get
| from | to | route |
| n | m | nij,js,js,jklm,jklm |
@no_turning @conditionals
Scenario: Car - ignores except restriction
Given the extract extra arguments "--parse-conditional-restrictions"
@@ -530,6 +599,81 @@ Feature: Car - Turn restrictions
| n | p | nj,js,js,jp,jp |
| m | p | mj,jp,jp |
@restriction-way
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
c
|
| f
| |
b---e
| |
a d
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
When I route I should get
| from | to | route | turns | locations |
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
| 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 | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
# condition is off
@restriction-way
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# time stamp for 12am on Tues, 02 May 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493726400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493726400"
Given the node map
"""
c
|
| f
| |
b---e
| |
a d
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
When I route I should get
| from | to | route |
| a | d | ab,be,de,de |
| a | f | ab,be,ef,ef |
| c | d | bc,be,de,de |
| c | f | bc,be,ef,ef |
# https://www.openstreetmap.org/#map=18/38.91099/-77.00888
@no_turning @conditionals
Scenario: Car - DC North capitol situation, two on one off
@@ -769,15 +913,145 @@ Feature: Car - Turn restrictions
| dg |
And the relations
| type | way:from | way:to | way:via | restriction:conditional |
| restriction | ab | be | ef | no_uturn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | ef | no_uturn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
And the relations
| type | way:from | way:to | node:via | restriction:conditional |
| restriction | ed | dg | d | no_uturn @ (Mo-Fr 07:00-11:00,16:00-18:30) |
When I route I should get
| from | to | route | # |
| a | f | ab,be,ef,ef | currently we do not handle conditional via-ways, this test will have to change when we do |
| f | 1 | ef,eh,gh,dg,dg | |
| from | to | route |
| a | f | ab,bc,bc,be,ef,ef |
| f | 1 | ef,eh,gh,dg,dg |
@restriction-way @overlap
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
c
|
| f
| |
b---e
| |
a d
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
And the relations
| type | way:from | way:via | way:to | restriction |
| restriction | ab | be | de | no_right_turn |
# condition is off, but the general restriction should take precedence
When I route I should get
| from | to | route | turns | locations |
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
| 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 | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
@restriction-way @overlap
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
c
|
| f
| |
b---e
| |
| d
|
a
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
And the relations
| type | way:from | node:via | way:to | restriction:conditional |
| restriction | be | e | de | no_right_turn @ (Mo-Fr 16:00-18:00) |
# way restriction is off, node-restriction is on
When I route I should get
| from | to | route | turns | locations |
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
| a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f |
| c | d | bc,be,ef,ef,de,de | depart,turn left,turn left,continue uturn,new name straight,arrive | c,b,e,f,e,d |
| c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
@restriction-way @overlap
Scenario: Car - prohibit turn
Given the extract extra arguments "--parse-conditional-restrictions"
# 5pm Wed 02 May, 2017 GMT
Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400"
Given the node map
"""
c
|
| f
| |
b---e
| |
| d
|
a
"""
And the ways
| nodes |
| ab |
| bc |
| be |
| de |
| ef |
And the relations
| type | way:from | way:via | way:to | restriction:conditional |
| restriction | ab | be | de | no_right_turn @ (Mo-Fr 16:00-18:00) |
And the relations
| type | way:from | node:via | way:to | restriction:conditional |
| restriction | be | e | de | no_right_turn @ (Mo-Fr 07:00-11:00) |
# node restrictino is off, way restriction is on
When I route I should get
| from | to | route | turns | locations |
| a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d |
| 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 | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f |
+18
View File
@@ -50,6 +50,7 @@ Feature: Car - Handle ferry routes
| b | f | abc,cde,efg,efg | driving,ferry,driving,driving | 9 km/h | 162.4s |
| c | e | cde,cde | ferry,ferry | 5 km/h | 151.4s |
| e | c | cde,cde | ferry,ferry | 5 km/h | 151.4s |
Scenario: Car - Properly handle simple durations
Given the node map
"""
@@ -91,3 +92,20 @@ Feature: Car - Handle ferry routes
| b | f | abc,cde,efg,efg | driving,ferry,driving,driving | 18 km/h | 78.4s |
| c | e | cde,cde | ferry,ferry | 11 km/h | 67.4s |
| e | c | cde,cde | ferry,ferry | 11 km/h | 67.4s |
@snapping
Scenario: Car - Snapping when using a ferry
Given the node map
"""
a b c d e f
"""
And the ways
| nodes | highway | route | duration |
| ab | primary | | |
| bcde | | ferry | 0:10 |
| ef | primary | | |
When I route I should get
| from | to | route | modes | time |
| c | d | bcde,bcde | ferry,ferry | 600s |
-44
View File
@@ -1,44 +0,0 @@
@routing @car @mode
Feature: Car - Mode flag
Background:
Given the profile "car"
Scenario: Car - Mode when using a ferry
Given the node map
"""
a b
c d
"""
And the ways
| nodes | highway | route | duration |
| ab | primary | | |
| bc | | ferry | 0:01 |
| cd | primary | | |
When I route I should get
| from | to | route | modes |
| a | d | ab,bc,cd,cd | driving,ferry,driving,driving |
| d | a | cd,bc,ab,ab | driving,ferry,driving,driving |
| c | a | bc,ab,ab | ferry,driving,driving |
| d | b | cd,bc,bc | driving,ferry,ferry |
| a | c | ab,bc,bc | driving,ferry,ferry |
| b | d | bc,cd,cd | ferry,driving,driving |
Scenario: Car - Snapping when using a ferry
Given the node map
"""
a b c d e f
"""
And the ways
| nodes | highway | route | duration |
| ab | primary | | |
| bcde | | ferry | 0:10 |
| ef | primary | | |
When I route I should get
| from | to | route | modes | time |
| c | d | bcde,bcde | ferry,ferry | 600s |
-16
View File
@@ -5,22 +5,6 @@ Feature: Car - Street names in instructions
Given the profile "car"
Given a grid size of 5 meters
Scenario: Car - A named street
Given the node map
"""
a b
c
"""
And the ways
| nodes | name | ref |
| ab | My Way | |
| bc | Your Way | A1 |
When I route I should get
| from | to | route | ref |
| a | c | My Way,Your Way | ,A1|
Scenario: Car - A named street with pronunciation
Given the node map
"""
+5 -5
View File
@@ -954,11 +954,11 @@ Feature: Car - Turn restrictions
# this case is currently not handling the via-way restrictions and we need support for looking across traffic signals.
# It is mainly included to show limitations and to prove that we don't crash hard here
When I route I should get
| from | to | route |
| a | d | ab,bge,de,de |
| a | f | ab,bge,ef,ef |
| c | d | bc,bge,de,de |
| c | f | bc,bge,ef,ef |
| from | to | route |
| a | d | ab,bge,ef,ef,de,de |
| a | f | ab,bge,ef,ef |
| c | d | bc,bge,de,de |
| c | f | bc,bge,de,de,ef,ef |
# don't crash hard on invalid restrictions
@restriction @invalid
@@ -37,3 +37,57 @@ Feature: Car - Handle traffic lights
| 3 | 4 | 13.1s | no turn with traffic light |
| g | j | 18.7s | turn with no traffic light |
| k | n | 20.7s | turn with traffic light |
Scenario: Tarrif Signal Geometry
Given the query options
| overview | full |
| geometries | polyline |
Given the node map
"""
a - b - c
"""
And the ways
| nodes | highway |
| abc | primary |
And the nodes
| node | highway |
| b | traffic_signals |
When I route I should get
| from | to | route | geometry |
| a | c | abc,abc | _ibE_ibE?gJ?gJ |
@traffic
Scenario: Traffic update on the edge with a traffic signal
Given the node map
"""
a - b - c
"""
And the ways
| nodes | highway |
| abc | primary |
And the nodes
| node | highway |
| b | traffic_signals |
And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
1,2,65
2,1,65
"""
And the query options
| annotations | datasources,nodes,speed,duration,weight |
When I route I should get
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
| a | c | abc,abc | 59 km/h | 24.2,0 | 24.2s | 399.9m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
| c | a | abc,abc | 59 km/h | 24.2,0 | 24.2s | 399.9m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
-6
View File
@@ -21,13 +21,7 @@ Feature: Foot - Handle ferry routes
When I route I should get
| from | to | route | modes |
| a | g | abc,cde,efg,efg | walking,ferry,walking,walking |
| b | f | abc,cde,efg,efg | walking,ferry,walking,walking |
| e | c | cde,cde | ferry,ferry |
| e | b | cde,abc,abc | ferry,walking,walking |
| e | a | cde,abc,abc | ferry,walking,walking |
| c | e | cde,cde | ferry,ferry |
| c | f | cde,efg,efg | ferry,walking,walking |
| c | g | cde,efg,efg | ferry,walking,walking |
Scenario: Foot - Ferry duration, single node
Given the node map
+4 -20
View File
@@ -14,25 +14,9 @@ Feature: Foot - Street names in instructions
And the ways
| nodes | name | ref |
| ab | My Way | A6 |
| bc | Your Way | B7 |
| ab | My Way | |
| bc | | A7 |
When I route I should get
| from | to | route |
| a | c | My Way,Your Way,Your Way |
@unnamed
Scenario: Foot - No longer use way type to describe unnamed ways, see #3231
Given the node map
"""
a b c d
"""
And the ways
| nodes | highway | name |
| ab | footway | |
| bcd | track | |
When I route I should get
| from | to | route |
| a | d | , |
| from | to | route | ref |
| a | c | My Way,, | ,A7,A7 |
-47
View File
@@ -1,47 +0,0 @@
@routing @foot @ref @name
Feature: Foot - Way ref
Background:
Given the profile "foot"
Scenario: Foot - Way with both name and ref
Given the node map
"""
a b
"""
And the ways
| nodes | name | ref |
| ab | Utopia Drive | E7 |
When I route I should get
| from | to | route | ref |
| a | b | Utopia Drive,Utopia Drive | E7,E7 |
Scenario: Foot - Way with only ref
Given the node map
"""
a b
"""
And the ways
| nodes | name | ref |
| ab | | E7 |
When I route I should get
| from | to | route | ref |
| a | b | , | E7,E7 |
Scenario: Foot - Way with only name
Given the node map
"""
a b
"""
And the ways
| nodes | name |
| ab | Utopia Drive |
When I route I should get
| from | to | route |
| a | b | Utopia Drive,Utopia Drive |
-180
View File
@@ -32,84 +32,6 @@ Feature: Foot - Turn restrictions
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@no_turning
Scenario: Foot - No right turn
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway |
| sj | yes |
| nj | -1 |
| wj | -1 |
| ej | -1 |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | ej | j | no_right_turn |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@no_turning
Scenario: Foot - No u-turn
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway |
| sj | yes |
| nj | -1 |
| wj | -1 |
| ej | -1 |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | wj | j | no_u_turn |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@no_turning
Scenario: Foot - Handle any no_* relation
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway |
| sj | yes |
| nj | -1 |
| wj | -1 |
| ej | -1 |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | wj | j | no_weird_zigzags |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@only_turning
Scenario: Foot - Only left turn
Given the node map
@@ -136,84 +58,6 @@ Feature: Foot - Turn restrictions
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@only_turning
Scenario: Foot - Only right turn
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway |
| sj | yes |
| nj | -1 |
| wj | -1 |
| ej | -1 |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | ej | j | only_right_turn |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@only_turning
Scenario: Foot - Only straight on
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway |
| sj | yes |
| nj | -1 |
| wj | -1 |
| ej | -1 |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | nj | j | only_straight_on |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@no_turning
Scenario: Foot - Handle any only_* restriction
Given the node map
"""
n
w j e
s
"""
And the ways
| nodes | oneway |
| sj | yes |
| nj | -1 |
| wj | -1 |
| ej | -1 |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | sj | nj | j | only_weird_zigzags |
When I route I should get
| from | to | route |
| s | w | sj,wj,wj |
| s | n | sj,nj,nj |
| s | e | sj,ej,ej |
@except
Scenario: Foot - Except tag and on no_ restrictions
Given the node map
@@ -246,30 +90,6 @@ Feature: Foot - Turn restrictions
| s | c | sj,cj,cj |
| s | d | sj,dj,dj |
@except
Scenario: Foot - Except tag and on only_ restrictions
Given the node map
"""
a b
j
s
"""
And the ways
| nodes | oneway |
| sj | yes |
| aj | no |
| bj | no |
And the relations
| type | way:from | way:to | node:via | restriction | except |
| restriction | sj | aj | j | only_straight_on | foot |
When I route I should get
| from | to | route |
| s | a | sj,aj,aj |
| s | b | sj,bj,bj |
@except
Scenario: Foot - Multiple except tag values
Given the node map
+2 -3
View File
@@ -1,10 +1,9 @@
@routing @foot @roundabout @instruction
@routing @foot @roundabout @instruction @todo
Feature: Roundabout Instructions
Background:
Given the profile "foot"
@todo
Scenario: Foot - Roundabout instructions
# You can walk in both directions on a roundabout, bu the normal roundabout instructions don't
# make sense when you're going the opposite way around the roundabout.
@@ -27,7 +26,7 @@ Feature: Roundabout Instructions
| abcda | roundabout |
When I route I should get
| from | to | route | turns |
| from | to | route | turns |
| s | t | sa,tb | depart,roundabout-exit-1,arrive |
| s | u | sa,uc | depart,roundabout-exit-2,arrive |
| s | v | sa,vd | depart,roundabout-exit-3,arrive |
+54 -2
View File
@@ -863,8 +863,8 @@ Feature: Slipways and Dedicated Turn Lanes
| af | primary | sliproad | yes |
When I route I should get
| waypoints | route | turns | locations |
| s,g | main,sliproad,another,another | depart,turn right,turn left,arrive | s,a,f,g |
| waypoints | route | turns | locations |
| s,g | main,sliproad,another,another | depart,turn right,turn slight left,arrive | s,a,f,g |
@sliproads:
Scenario: Throughabout-Sliproad
@@ -944,3 +944,55 @@ Feature: Slipways and Dedicated Turn Lanes
When I route I should get
| waypoints | route | turns | locations |
| a,k | road,,, | depart,turn right,roundabout turn right exit-1,arrive | a,b,h,k |
@sliproads
Scenario: Sliproad with 4 roads at target
Given the node map
"""
d
.
s . a . b . c . t
` . '
` . '
'.'
e
.
f
"""
And the ways
| nodes | highway | name | oneway |
| sabct | primary | sabct | |
| dbef | primary | dbef | |
| ae | primary_link | ae | yes |
| ec | primary_link | ec | yes |
When I route I should get
| waypoints | route | turns | locations |
| s,f | sabct,dbef,dbef | depart,turn right,arrive | s,a,f |
| f,t | dbef,sabct,sabct | depart,turn right,arrive | f,e,t |
@sliproads
Scenario: Sliproad and acute angle (50°) at the main intersection
Given the node map
"""
d
/
s . a . . b . c
` /
' /
e
/
f
"""
And the ways
| nodes | highway | name | oneway |
| sabc | primary | sabc | |
| dbef | primary | dbef | |
| ae | primary_link | ae | yes |
When I route I should get
| waypoints | route | turns | locations |
| s,f | sabc,dbef,dbef | depart,turn right,arrive | s,a,f |
+11 -11
View File
@@ -809,14 +809,14 @@ Feature: Simple Turns
When I route I should get
| waypoints | route | turns | intersections |
| a,g | Perle,Heide,Heide | depart,turn right,arrive | true:90;true:90 true:180 false:270 true:345;true:18 |
| a,k | Perle,Friede,Friede | depart,turn left,arrive | true:90;true:90 true:180 false:270 true:345;true:153 |
| a,e | Perle,Perle | depart,arrive | true:90,true:90 true:180 false:270 true:345;true:270 |
| e,k | Perle,Friede,Friede | depart,turn right,arrive | true:270;false:90 true:180 true:270 true:345;true:153 |
| e,g | Perle,Heide,Heide | depart,turn left,arrive | true:270;false:90 true:180 true:270 true:345;true:18 |
| h,k | Heide,Friede | depart,arrive | true:16,true:90 true:180 true:270 true:345;true:153 |
| h,e | Heide,Perle,Perle | depart,turn right,arrive | true:16;true:90 true:180 true:270 true:345;true:270 |
| h,a | Heide,Perle,Perle | depart,turn left,arrive | true:16;true:90 true:180 true:270 true:345;true:90 |
| a,g | Perle,Heide,Heide | depart,turn right,arrive | true:90;true:90 true:195 false:270 true:345;true:18 |
| a,k | Perle,Friede,Friede | depart,turn left,arrive | true:90;true:90 true:195 false:270 true:345;true:153 |
| a,e | Perle,Perle | depart,arrive | true:90,true:90 true:195 false:270 true:345;true:270 |
| e,k | Perle,Friede,Friede | depart,turn right,arrive | true:270;false:90 true:195 true:270 true:345;true:153 |
| e,g | Perle,Heide,Heide | depart,turn left,arrive | true:270;false:90 true:195 true:270 true:345;true:18 |
| h,k | Heide,Friede | depart,arrive | true:16,true:90 true:195 true:270 true:345;true:153 |
| h,e | Heide,Perle,Perle | depart,turn right,arrive | true:16;true:90 true:195 true:270 true:345;true:270 |
| h,a | Heide,Perle,Perle | depart,turn left,arrive | true:16;true:90 true:195 true:270 true:345;true:90 |
#http://www.openstreetmap.org/#map=19/52.53293/13.32956
Scenario: Curved Exit from Curved Road
@@ -1006,8 +1006,8 @@ Feature: Simple Turns
| waypoints | route | turns |
| a,e | Heide,Heide,Heide | depart,continue uturn,arrive |
| a,g | Heide,Fenn,Fenn | depart,turn right,arrive |
| a,h | Heide,Friede,Friede | depart,turn slight left,arrive |
| i,e | Perle,Heide,Heide | depart,turn right,arrive |
| a,h | Heide,Friede,Friede | depart,turn left,arrive |
| i,e | Perle,Heide,Heide | depart,turn sharp right,arrive |
| i,h | Perle,Friede,Friede | depart,turn left,arrive |
#http://www.openstreetmap.org/#map=19/52.48630/13.36017
@@ -1189,7 +1189,7 @@ Feature: Simple Turns
When I route I should get
| waypoints | route | turns |
| a,c | rose,trift | depart,arrive |
| a,c | rose,trift,trift | depart,turn slight left,arrive |
| a,k | rose,muhle,muhle | depart,turn slight right,arrive |
| d,f | trift,rose | depart,arrive |
| d,k | trift,muhle,muhle | depart,turn sharp left,arrive |
+3 -3
View File
@@ -788,9 +788,9 @@ Feature: Simple Turns
| bg | primary | yes |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,turn sharp right,arrive |
| a,f | abc,bf,bf | depart,turn right,arrive |
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,turn right,arrive |
| a,f | abc,bf,bf | depart,turn slight right,arrive |
Scenario: Right Turn Assignment Three Conflicting Turns with invalid - 3
Given the node map
-35
View File
@@ -1,35 +0,0 @@
@routing @datastore @testbot
Feature: Temporary tests related to osrm-datastore
Background:
Given the profile "testbot"
Scenario: Scenario ab
Given the node map
"""
a b
"""
And the ways
| nodes |
| ab |
When I route I should get
| from | to | route |
| a | b | ab,ab |
| b | a | ab,ab |
Scenario: Scenaria xy
Given the node map
"""
x y
"""
And the ways
| nodes |
| xy |
When I route I should get
| from | to | route |
| x | y | xy,xy |
| y | x | xy,xy |
-20
View File
@@ -226,23 +226,3 @@ Feature: Distance calculation
| x | v | xv,xv | 424m +-1 |
| x | w | xw,xw | 360m +-1 |
| x | y | xy,xy | 316m +-1 |
@maze
Scenario: Distance of a maze of short segments
Given a grid size of 7 meters
Given the node map
"""
a b s t
d c r q
e f o p
h g n m
i j k l
"""
And the ways
| nodes |
| abcdefghijklmnopqrst |
When I route I should get
| from | to | route | distance |
| a | t | abcdefghijklmnopqrst,abcdefghijklmnopqrst | 133m +-1 |
+10 -10
View File
@@ -21,12 +21,12 @@ Feature: Durations
| ef | primary | 01:02:03 |
When I route I should get
| from | to | route | distance | time |
| a | b | ab,ab | 100m +-1 | 60s +-1 |
| b | c | bc,bc | 200m +-1 | 600s +-1 |
| c | d | cd,cd | 300m +-1 | 3600s +-1 |
| d | e | de,de | 141m +-2 | 36000s +-1 |
| e | f | ef,ef | 224m +-2 | 3723s +-1 |
| from | to | route | time |
| a | b | ab,ab | 60s +-1 |
| b | c | bc,bc | 600s +-1 |
| c | d | cd,cd | 3600s +-1 |
| d | e | de,de | 36000s +-1 |
| e | f | ef,ef | 3723s +-1 |
@todo
Scenario: Partial duration of ways
@@ -40,7 +40,7 @@ Feature: Durations
| abc | primary | 0:01 |
When I route I should get
| from | to | route | distance | time |
| a | c | abc,abc | 300m +-1 | 60s +-1 |
| a | b | ab,ab | 100m +-1 | 20s +-1 |
| b | c | bc,bc | 200m +-1 | 40s +-1 |
| from | to | route | time |
| a | c | abc,abc | 60s +-1 |
| a | b | ab,ab | 20s +-1 |
| b | c | bc,bc | 40s +-1 |
-82
View File
@@ -5,51 +5,6 @@ Feature: Testbot - oneways
Given the profile "testbot"
Given a grid size of 250 meters
Scenario: Routing on a oneway roundabout
Given the node map
"""
v
x d c
e b
f a
g h y
z
"""
And the ways
| nodes | oneway |
| ab | yes |
| bc | yes |
| cd | yes |
| de | yes |
| ef | yes |
| fg | yes |
| gh | yes |
| ha | yes |
| vx | yes |
| vy | yes |
| yz | yes |
| xe | yes |
When I route I should get
| from | to | route |
| a | b | ab,ab |
| b | c | bc,bc |
| c | d | cd,cd |
| d | e | de,de |
| e | f | ef,ef |
| f | g | fg,fg |
| g | h | gh,gh |
| h | a | ha,ha |
| b | a | bc,cd,de,ef,fg,gh,ha,ha |
| c | b | cd,de,ef,fg,gh,ha,ab,ab |
| d | c | de,ef,fg,gh,ha,ab,bc,bc |
| e | d | ef,fg,gh,ha,ab,bc,cd,cd |
| f | e | fg,gh,ha,ab,bc,cd,de,de |
| g | f | gh,ha,ab,bc,cd,de,ef,ef |
| h | g | ha,ab,bc,cd,de,ef,fg,fg |
| a | h | ab,bc,cd,de,ef,fg,gh,gh |
Scenario: Testbot - Simple oneway
Then routability should be
| highway | foot | oneway | forw | backw |
@@ -60,27 +15,6 @@ Feature: Testbot - oneways
| highway | foot | oneway | forw | backw |
| primary | no | -1 | | x |
Scenario: Testbot - Around the Block
Given the node map
"""
a b
e d c f
"""
And the ways
| nodes | oneway | foot |
| ab | yes | no |
| bc | | no |
| cd | | no |
| da | | no |
| de | | no |
| cf | | no |
When I route I should get
| from | to | route |
| a | b | ab,ab |
| b | a | bc,cd,da,da |
Scenario: Testbot - Handle various oneway tag values
Then routability should be
| foot | oneway | forw | backw |
@@ -93,19 +27,3 @@ Feature: Testbot - oneways
| no | true | x | |
| no | 1 | x | |
| no | -1 | | x |
Scenario: Testbot - Two consecutive oneways
Given the node map
"""
a b c
"""
And the ways
| nodes | oneway |
| ab | yes |
| bc | yes |
When I route I should get
| from | to | route |
| a | c | ab,bc,bc |
+53 -46
View File
@@ -26,6 +26,33 @@ Feature: Penalties
| a | c | abc,abc | 20s +-1 | 200m +-1 |
| d | f | def,def | 27s +-1 | 200m +-1 |
# Penalties not on the phantom nodes
Scenario: Traffic signals should incur a delay, without changing distance
Given the node map
"""
a b c d e
f g h i j
"""
And the nodes
| node | highway |
| c | traffic_signals |
And the ways
| nodes |
| ab |
| bcd |
| de |
| fg |
| ghi |
| ij |
When I route I should get
| from | to | route | time | distance |
| a | e | ab,bcd,de | 47s +-1 | 400m +-1 |
| f | j | fg,ghi,ij | 40s +-1 | 400m +-1 |
Scenario: Signal penalty should not depend on way type
Given the node map
"""
@@ -72,55 +99,35 @@ Feature: Penalties
| from | to | route | time |
| a | e | abcde,abcde | 61s +-1 |
@todo
Scenario: Signal penalty should not depend on way type
Given the node map
"""
a b c
d e f
g h i
"""
@todo
Scenario: Signal penalty should not depend on way type
Given the node map
"""
a b c
d e f
g h i
"""
And the nodes
| node | highway |
| b | traffic_signals |
| e | traffic_signals |
| h | traffic_signals |
And the nodes
| node | highway |
| b | traffic_signals |
| e | traffic_signals |
| h | traffic_signals |
And the ways
| nodes | highway |
| abc | primary |
| def | secondary |
| ghi | tertiary |
And the ways
| nodes | highway |
| abc | primary |
| def | secondary |
| ghi | tertiary |
When I route I should get
| from | to | route | time |
| a | b | abc,abc | 10s +-1 |
| a | c | abc,abc | 27s +-1 |
| d | e | def,def | 20s +-1 |
| d | f | def,def | 47s +-1 |
| g | h | ghi,ghi | 30s +-1 |
| g | i | ghi,ghi | 67s +-1 |
Scenario: Passing multiple traffic signals should incur a accumulated delay
Given the node map
"""
a b c d e
"""
And the nodes
| node | highway |
| b | traffic_signals |
| c | traffic_signals |
| d | traffic_signals |
And the ways
| nodes |
| abcde |
When I route I should get
| from | to | route | time |
| a | e | abcde,abcde | 61s +-1 |
When I route I should get
| from | to | route | time |
| a | b | abc,abc | 10s +-1 |
| a | c | abc,abc | 27s +-1 |
| d | e | def,def | 20s +-1 |
| d | f | def,def | 47s +-1 |
| g | h | ghi,ghi | 30s +-1 |
| g | i | ghi,ghi | 67s +-1 |
@todo
Scenario: Starting or ending at a traffic signal should not incur a delay
-9
View File
@@ -1,13 +1,6 @@
#ifndef OSRM_ENGINE_DATAFACADE_DATAFACADE_HPP
#define OSRM_ENGINE_DATAFACADE_DATAFACADE_HPP
#ifdef OSRM_EXTERNAL_MEMORY
// Register your own data backend here
#error "No external memory implementation found"
#else
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
namespace osrm
@@ -22,5 +15,3 @@ using DataFacade = datafacade::ContiguousInternalMemoryDataFacade<AlgorithmT>;
}
#endif
#endif
+27 -22
View File
@@ -11,6 +11,7 @@
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include <algorithm>
#include <utility>
#include <vector>
@@ -20,7 +21,6 @@ namespace engine
{
namespace guidance
{
// Extracts the geometry for each segment and calculates the traveled distance
// Combines the geometry form the phantom node with the PathData
// to the full route geometry.
@@ -53,9 +53,9 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
source_node.fwd_segment_position + (reversed_source ? 1 : 0);
const auto source_node_id =
reversed_source ? source_node.reverse_segment_id.id : source_node.forward_segment_id.id;
const auto source_gemetry_id = facade.GetGeometryIndex(source_node_id).id;
const std::vector<NodeID> source_geometry =
facade.GetUncompressedForwardGeometry(source_gemetry_id);
const auto source_geometry_id = facade.GetGeometryIndex(source_node_id).id;
std::vector<NodeID> source_geometry = facade.GetUncompressedForwardGeometry(source_geometry_id);
geometry.osm_node_ids.push_back(
facade.GetOSMNodeIDOfNode(source_geometry[source_segment_start_coordinate]));
@@ -78,21 +78,26 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
}
prev_coordinate = coordinate;
geometry.annotations.emplace_back(LegGeometry::Annotation{
current_distance,
// NOTE: we want annotations to include only the duration/weight
// of the segment itself. For segments immediately before
// a turn, the duration_until_turn/weight_until_turn values
// include the turn cost. To counter this, we subtract
// the duration_of_turn/weight_of_turn value, which is 0 for
// non-preceeding-turn segments, but contains the turn value
// for segments before a turn.
(path_point.duration_until_turn - path_point.duration_of_turn) / 10.,
(path_point.weight_until_turn - path_point.weight_of_turn) /
facade.GetWeightMultiplier(),
path_point.datasource_id});
geometry.locations.push_back(std::move(coordinate));
geometry.osm_node_ids.push_back(facade.GetOSMNodeIDOfNode(path_point.turn_via_node));
const auto osm_node_id = facade.GetOSMNodeIDOfNode(path_point.turn_via_node);
if (osm_node_id != geometry.osm_node_ids.back())
{
geometry.annotations.emplace_back(LegGeometry::Annotation{
current_distance,
// NOTE: we want annotations to include only the duration/weight
// of the segment itself. For segments immediately before
// a turn, the duration_until_turn/weight_until_turn values
// include the turn cost. To counter this, we subtract
// the duration_of_turn/weight_of_turn value, which is 0 for
// non-preceeding-turn segments, but contains the turn value
// for segments before a turn.
(path_point.duration_until_turn - path_point.duration_of_turn) / 10.,
(path_point.weight_until_turn - path_point.weight_of_turn) /
facade.GetWeightMultiplier(),
path_point.datasource_id});
geometry.locations.push_back(std::move(coordinate));
geometry.osm_node_ids.push_back(osm_node_id);
}
}
current_distance =
util::coordinate_calculation::haversineDistance(prev_coordinate, target_node.location);
@@ -102,9 +107,9 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
const auto target_node_id =
reversed_target ? target_node.reverse_segment_id.id : target_node.forward_segment_id.id;
const auto target_gemetry_id = facade.GetGeometryIndex(target_node_id).id;
const auto target_geometry_id = facade.GetGeometryIndex(target_node_id).id;
const std::vector<DatasourceID> forward_datasources =
facade.GetUncompressedForwardDatasources(target_gemetry_id);
facade.GetUncompressedForwardDatasources(target_geometry_id);
// FIXME if source and target phantoms are on the same segment then duration and weight
// will be from one projected point till end of segment
@@ -127,7 +132,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
const auto target_segment_end_coordinate =
target_node.fwd_segment_position + (reversed_target ? 0 : 1);
const std::vector<NodeID> target_geometry =
facade.GetUncompressedForwardGeometry(target_gemetry_id);
facade.GetUncompressedForwardGeometry(target_geometry_id);
geometry.osm_node_ids.push_back(
facade.GetOSMNodeIDOfNode(target_geometry[target_segment_end_coordinate]));
+4
View File
@@ -1,10 +1,14 @@
#ifndef RAW_ROUTE_DATA_H
#define RAW_ROUTE_DATA_H
#include "extractor/class_data.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/travel_mode.hpp"
#include "engine/phantom_node.hpp"
#include "osrm/coordinate.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/guidance/turn_bearing.hpp"
#include "util/guidance/turn_lanes.hpp"
-3
View File
@@ -5,9 +5,6 @@
#include "engine/plugins/plugin_base.hpp"
#include "engine/routing_algorithms.hpp"
#include "engine/map_matching/bayes_classifier.hpp"
#include "engine/routing_algorithms/map_matching.hpp"
#include "engine/routing_algorithms/shortest_path.hpp"
#include "util/json_util.hpp"
#include <vector>
+1 -2
View File
@@ -5,8 +5,7 @@
#include "engine/api/table_parameters.hpp"
#include "engine/routing_algorithms.hpp"
#include "engine/routing_algorithms/many_to_many.hpp"
#include "engine/search_engine_data.hpp"
#include "util/json_container.hpp"
namespace osrm
+2 -3
View File
@@ -3,10 +3,9 @@
#include "engine/plugins/plugin_base.hpp"
#include "engine/api/route_api.hpp"
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/api/route_parameters.hpp"
#include "engine/routing_algorithms.hpp"
#include "engine/search_engine_data.hpp"
#include "util/json_container.hpp"
#include <cstdlib>
@@ -134,23 +134,13 @@ void annotatePath(const FacadeT &facade,
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id == target_node_id ||
phantom_node_pair.target_phantom.reverse_segment_id.id == target_node_id);
auto node_from = unpacked_nodes.begin(), node_last = std::prev(unpacked_nodes.end());
for (auto edge = unpacked_edges.begin(); node_from != node_last; ++node_from, ++edge)
{
const auto &edge_data = facade.GetEdgeData(*edge);
const auto turn_id = edge_data.turn_id; // edge-based graph edge index
const auto node_id = *node_from; // edge-based graph node index
const auto name_index = facade.GetNameIndex(node_id);
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id);
const extractor::TravelMode travel_mode = facade.GetTravelMode(node_id);
const auto classes = facade.GetClassData(node_id);
// datastructures to hold extracted data from geometry
std::vector<NodeID> id_vector;
std::vector<EdgeWeight> weight_vector;
std::vector<EdgeWeight> duration_vector;
std::vector<DatasourceID> datasource_vector;
const auto geometry_index = facade.GetGeometryIndex(node_id);
std::vector<NodeID> id_vector;
std::vector<EdgeWeight> weight_vector;
std::vector<EdgeWeight> duration_vector;
std::vector<DatasourceID> datasource_vector;
const auto get_segment_geometry = [&](const auto geometry_index) {
if (geometry_index.forward)
{
id_vector = facade.GetUncompressedForwardGeometry(geometry_index.id);
@@ -165,6 +155,22 @@ void annotatePath(const FacadeT &facade,
duration_vector = facade.GetUncompressedReverseDurations(geometry_index.id);
datasource_vector = facade.GetUncompressedReverseDatasources(geometry_index.id);
}
};
auto node_from = unpacked_nodes.begin(), node_last = std::prev(unpacked_nodes.end());
for (auto edge = unpacked_edges.begin(); node_from != node_last; ++node_from, ++edge)
{
const auto &edge_data = facade.GetEdgeData(*edge);
const auto turn_id = edge_data.turn_id; // edge-based graph edge index
const auto node_id = *node_from; // edge-based graph node index
const auto name_index = facade.GetNameIndex(node_id);
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id);
const extractor::TravelMode travel_mode = facade.GetTravelMode(node_id);
const auto classes = facade.GetClassData(node_id);
const auto geometry_index = facade.GetGeometryIndex(node_id);
get_segment_geometry(geometry_index);
BOOST_ASSERT(id_vector.size() > 0);
BOOST_ASSERT(datasource_vector.size() > 0);
BOOST_ASSERT(weight_vector.size() == id_vector.size() - 1);
@@ -216,21 +222,14 @@ void annotatePath(const FacadeT &facade,
}
std::size_t start_index = 0, end_index = 0;
std::vector<unsigned> id_vector;
std::vector<EdgeWeight> weight_vector;
std::vector<EdgeWeight> duration_vector;
std::vector<DatasourceID> datasource_vector;
const auto source_geometry_id = facade.GetGeometryIndex(source_node_id).id;
const auto target_geometry_id = facade.GetGeometryIndex(target_node_id).id;
const auto is_local_path = source_geometry_id == target_geometry_id && unpacked_path.empty();
const auto target_geometry = facade.GetGeometryIndex(target_node_id);
const auto is_local_path = source_geometry_id == target_geometry.id && unpacked_path.empty();
get_segment_geometry(target_geometry);
if (target_traversed_in_reverse)
{
id_vector = facade.GetUncompressedReverseGeometry(target_geometry_id);
weight_vector = facade.GetUncompressedReverseWeights(target_geometry_id);
duration_vector = facade.GetUncompressedReverseDurations(target_geometry_id);
datasource_vector = facade.GetUncompressedReverseDatasources(target_geometry_id);
if (is_local_path)
{
start_index =
@@ -246,11 +245,6 @@ void annotatePath(const FacadeT &facade,
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
}
end_index = phantom_node_pair.target_phantom.fwd_segment_position;
id_vector = facade.GetUncompressedForwardGeometry(target_geometry_id);
weight_vector = facade.GetUncompressedForwardWeights(target_geometry_id);
duration_vector = facade.GetUncompressedForwardDurations(target_geometry_id);
datasource_vector = facade.GetUncompressedForwardDatasources(target_geometry_id);
}
// Given the following compressed geometry:
@@ -308,24 +302,6 @@ void annotatePath(const FacadeT &facade,
unpacked_path.front().duration_until_turn =
std::max(unpacked_path.front().duration_until_turn - source_duration, 0);
}
// there is no equivalent to a node-based node in an edge-expanded graph.
// two equivalent routes may start (or end) at different node-based edges
// as they are added with the offset how much "weight" on the edge
// has already been traversed. Depending on offset one needs to remove
// the last node.
if (unpacked_path.size() > 1)
{
const std::size_t last_index = unpacked_path.size() - 1;
const std::size_t second_to_last_index = last_index - 1;
if (unpacked_path[last_index].turn_via_node ==
unpacked_path[second_to_last_index].turn_via_node)
{
unpacked_path.pop_back();
}
BOOST_ASSERT(!unpacked_path.empty());
}
}
template <typename Algorithm>
@@ -30,7 +30,8 @@ namespace
// Unrestricted search (Args is const PhantomNodes &):
// * use partition.GetQueryLevel to find the node query level based on source and target phantoms
// * allow to traverse all cells
inline LevelID getNodeQueryLevel(const partition::MultiLevelPartitionView &partition,
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
NodeID node,
const PhantomNodes &phantom_nodes)
{
@@ -54,8 +55,8 @@ inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return tr
// Restricted search (Args is LevelID, CellID):
// * use the fixed level for queries
// * check if the node cell is the same as the specified parent onr
inline LevelID
getNodeQueryLevel(const partition::MultiLevelPartitionView &, NodeID, LevelID level, CellID)
template <typename MultiLevelPartition>
inline LevelID getNodeQueryLevel(const MultiLevelPartition &, NodeID, LevelID level, CellID)
{
return level;
}
@@ -130,10 +131,10 @@ retrievePackedPathFromHeap(const SearchEngineData<Algorithm>::QueryHeap &forward
return packed_path;
}
template <bool DIRECTION, typename... Args>
template <bool DIRECTION, typename Algorithm, typename... Args>
void routingStep(const DataFacade<Algorithm> &facade,
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
NodeID &middle_node,
EdgeWeight &path_upper_bound,
const bool force_loop_forward,
@@ -260,11 +261,11 @@ using UnpackedNodes = std::vector<NodeID>;
using UnpackedEdges = std::vector<EdgeID>;
using UnpackedPath = std::tuple<EdgeWeight, UnpackedNodes, UnpackedEdges>;
template <typename... Args>
template <typename Algorithm, typename... Args>
UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool force_loop_forward,
const bool force_loop_reverse,
EdgeWeight weight_upper_bound,
@@ -389,10 +390,11 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
}
// Alias to be compatible with the CH-based search
template <typename Algorithm>
inline void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight,
std::vector<NodeID> &unpacked_nodes,
const bool force_loop_forward,
@@ -442,13 +444,14 @@ void unpackPath(const FacadeT &facade,
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
}
inline double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
template <typename Algorithm>
double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
{
forward_heap.Clear();
reverse_heap.Clear();
@@ -1,5 +1,5 @@
#ifndef SHORTEST_PATH_HPP
#define SHORTEST_PATH_HPP
#ifndef OSRM_SHORTEST_PATH_HPP
#define OSRM_SHORTEST_PATH_HPP
#include "engine/algorithm.hpp"
#include "engine/routing_algorithms/routing_base.hpp"
@@ -23,4 +23,4 @@ InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_worki
} // namespace engine
} // namespace osrm
#endif /* SHORTEST_PATH_HPP */
#endif /* OSRM_SHORTEST_PATH_HPP */
@@ -0,0 +1,463 @@
#ifndef OSRM_SHORTEST_PATH_IMPL_HPP
#define OSRM_SHORTEST_PATH_IMPL_HPP
#include "engine/routing_algorithms/shortest_path.hpp"
#include <boost/assert.hpp>
#include <boost/optional.hpp>
namespace osrm
{
namespace engine
{
namespace routing_algorithms
{
namespace
{
const static constexpr bool DO_NOT_FORCE_LOOP = false;
// allows a uturn at the target_phantom
// searches source forward/reverse -> target forward/reverse
template <typename Algorithm>
void searchWithUTurn(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool search_from_forward_node,
const bool search_from_reverse_node,
const bool search_to_forward_node,
const bool search_to_reverse_node,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
const int total_weight_to_forward,
const int total_weight_to_reverse,
int &new_total_weight,
std::vector<NodeID> &leg_packed_path)
{
forward_heap.Clear();
reverse_heap.Clear();
if (search_from_forward_node)
{
forward_heap.Insert(source_phantom.forward_segment_id.id,
-source_phantom.GetForwardWeightPlusOffset(),
source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
forward_heap.Insert(source_phantom.reverse_segment_id.id,
-source_phantom.GetReverseWeightPlusOffset(),
source_phantom.reverse_segment_id.id);
}
if (search_to_forward_node)
{
reverse_heap.Insert(target_phantom.forward_segment_id.id,
target_phantom.GetForwardWeightPlusOffset(),
target_phantom.forward_segment_id.id);
}
if (search_to_reverse_node)
{
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
target_phantom.GetReverseWeightPlusOffset(),
target_phantom.reverse_segment_id.id);
}
// this is only relevent if source and target are on the same compressed edge
auto is_oneway_source = !(search_from_forward_node && search_from_reverse_node);
auto is_oneway_target = !(search_to_forward_node && search_to_reverse_node);
// we only enable loops here if we can't search from forward to backward node
auto needs_loop_forwards = is_oneway_source && needsLoopForward(source_phantom, target_phantom);
auto needs_loop_backwards =
is_oneway_target && needsLoopBackwards(source_phantom, target_phantom);
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
new_total_weight,
leg_packed_path,
needs_loop_forwards,
needs_loop_backwards,
{source_phantom, target_phantom});
// if no route is found between two parts of the via-route, the entire route becomes
// invalid. Adding to invalid edge weight sadly doesn't return an invalid edge weight. Here
// we prevent the possible overflow, faking the addition of infinity + x == infinity
if (new_total_weight != INVALID_EDGE_WEIGHT)
new_total_weight += std::min(total_weight_to_forward, total_weight_to_reverse);
}
// searches shortest path between:
// source forward/reverse -> target forward
// source forward/reverse -> target reverse
template <typename Algorithm>
void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool search_from_forward_node,
const bool search_from_reverse_node,
const bool search_to_forward_node,
const bool search_to_reverse_node,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
const int total_weight_to_forward,
const int total_weight_to_reverse,
int &new_total_weight_to_forward,
int &new_total_weight_to_reverse,
std::vector<NodeID> &leg_packed_path_forward,
std::vector<NodeID> &leg_packed_path_reverse)
{
if (search_to_forward_node)
{
forward_heap.Clear();
reverse_heap.Clear();
reverse_heap.Insert(target_phantom.forward_segment_id.id,
target_phantom.GetForwardWeightPlusOffset(),
target_phantom.forward_segment_id.id);
if (search_from_forward_node)
{
forward_heap.Insert(source_phantom.forward_segment_id.id,
total_weight_to_forward -
source_phantom.GetForwardWeightPlusOffset(),
source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
forward_heap.Insert(source_phantom.reverse_segment_id.id,
total_weight_to_reverse -
source_phantom.GetReverseWeightPlusOffset(),
source_phantom.reverse_segment_id.id);
}
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
new_total_weight_to_forward,
leg_packed_path_forward,
needsLoopForward(source_phantom, target_phantom),
routing_algorithms::DO_NOT_FORCE_LOOP,
{source_phantom, target_phantom});
}
if (search_to_reverse_node)
{
forward_heap.Clear();
reverse_heap.Clear();
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
target_phantom.GetReverseWeightPlusOffset(),
target_phantom.reverse_segment_id.id);
if (search_from_forward_node)
{
forward_heap.Insert(source_phantom.forward_segment_id.id,
total_weight_to_forward -
source_phantom.GetForwardWeightPlusOffset(),
source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
forward_heap.Insert(source_phantom.reverse_segment_id.id,
total_weight_to_reverse -
source_phantom.GetReverseWeightPlusOffset(),
source_phantom.reverse_segment_id.id);
}
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
new_total_weight_to_reverse,
leg_packed_path_reverse,
routing_algorithms::DO_NOT_FORCE_LOOP,
needsLoopBackwards(source_phantom, target_phantom),
{source_phantom, target_phantom});
}
}
template <typename Algorithm>
void unpackLegs(const DataFacade<Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector,
const std::vector<NodeID> &total_packed_path,
const std::vector<std::size_t> &packed_leg_begin,
const EdgeWeight shortest_path_weight,
InternalRouteResult &raw_route_data)
{
raw_route_data.unpacked_path_segments.resize(packed_leg_begin.size() - 1);
raw_route_data.shortest_path_weight = shortest_path_weight;
for (const auto current_leg : util::irange<std::size_t>(0UL, packed_leg_begin.size() - 1))
{
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
const auto &unpack_phantom_node_pair = phantom_nodes_vector[current_leg];
unpackPath(facade,
leg_begin,
leg_end,
unpack_phantom_node_pair,
raw_route_data.unpacked_path_segments[current_leg]);
raw_route_data.source_traversed_in_reverse.push_back(
(*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back(
(*std::prev(leg_end) !=
phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id));
}
}
}
template <typename Algorithm>
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector,
const boost::optional<bool> continue_straight_at_waypoint)
{
InternalRouteResult raw_route_data;
raw_route_data.segment_end_coordinates = phantom_nodes_vector;
const bool allow_uturn_at_waypoint =
!(continue_straight_at_waypoint ? *continue_straight_at_waypoint
: facade.GetContinueStraightDefault());
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1;
int total_weight_to_forward = 0;
int total_weight_to_reverse = 0;
bool search_from_forward_node =
phantom_nodes_vector.front().source_phantom.IsValidForwardSource();
bool search_from_reverse_node =
phantom_nodes_vector.front().source_phantom.IsValidReverseSource();
std::vector<NodeID> prev_packed_leg_to_forward;
std::vector<NodeID> prev_packed_leg_to_reverse;
std::vector<NodeID> total_packed_path_to_forward;
std::vector<std::size_t> packed_leg_to_forward_begin;
std::vector<NodeID> total_packed_path_to_reverse;
std::vector<std::size_t> packed_leg_to_reverse_begin;
std::size_t current_leg = 0;
// this implements a dynamic program that finds the shortest route through
// a list of vias
for (const auto &phantom_node_pair : phantom_nodes_vector)
{
int new_total_weight_to_forward = INVALID_EDGE_WEIGHT;
int new_total_weight_to_reverse = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_leg_to_forward;
std::vector<NodeID> packed_leg_to_reverse;
const auto &source_phantom = phantom_node_pair.source_phantom;
const auto &target_phantom = phantom_node_pair.target_phantom;
bool search_to_forward_node = target_phantom.IsValidForwardTarget();
bool search_to_reverse_node = target_phantom.IsValidReverseTarget();
BOOST_ASSERT(!search_from_forward_node || source_phantom.IsValidForwardSource());
BOOST_ASSERT(!search_from_reverse_node || source_phantom.IsValidReverseSource());
if (search_to_reverse_node || search_to_forward_node)
{
if (allow_uturn_at_waypoint)
{
searchWithUTurn(engine_working_data,
facade,
forward_heap,
reverse_heap,
search_from_forward_node,
search_from_reverse_node,
search_to_forward_node,
search_to_reverse_node,
source_phantom,
target_phantom,
total_weight_to_forward,
total_weight_to_reverse,
new_total_weight_to_forward,
packed_leg_to_forward);
// if only the reverse node is valid (e.g. when using the match plugin) we
// actually need to move
if (!target_phantom.IsValidForwardTarget())
{
BOOST_ASSERT(target_phantom.IsValidReverseTarget());
new_total_weight_to_reverse = new_total_weight_to_forward;
packed_leg_to_reverse = std::move(packed_leg_to_forward);
new_total_weight_to_forward = INVALID_EDGE_WEIGHT;
// (*)
//
// Below we have to check if new_total_weight_to_forward is invalid.
// This prevents use-after-move on packed_leg_to_forward.
}
else if (target_phantom.IsValidReverseTarget())
{
new_total_weight_to_reverse = new_total_weight_to_forward;
packed_leg_to_reverse = packed_leg_to_forward;
}
}
else
{
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
search_from_forward_node,
search_from_reverse_node,
search_to_forward_node,
search_to_reverse_node,
source_phantom,
target_phantom,
total_weight_to_forward,
total_weight_to_reverse,
new_total_weight_to_forward,
new_total_weight_to_reverse,
packed_leg_to_forward,
packed_leg_to_reverse);
}
}
// Note: To make sure we do not access the moved-from packed_leg_to_forward
// we guard its access by a check for invalid edge weight. See (*) above.
// No path found for both target nodes?
if ((INVALID_EDGE_WEIGHT == new_total_weight_to_forward) &&
(INVALID_EDGE_WEIGHT == new_total_weight_to_reverse))
{
return raw_route_data;
}
// we need to figure out how the new legs connect to the previous ones
if (current_leg > 0)
{
bool forward_to_forward =
(new_total_weight_to_forward != INVALID_EDGE_WEIGHT) &&
packed_leg_to_forward.front() == source_phantom.forward_segment_id.id;
bool reverse_to_forward =
(new_total_weight_to_forward != INVALID_EDGE_WEIGHT) &&
packed_leg_to_forward.front() == source_phantom.reverse_segment_id.id;
bool forward_to_reverse =
(new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) &&
packed_leg_to_reverse.front() == source_phantom.forward_segment_id.id;
bool reverse_to_reverse =
(new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) &&
packed_leg_to_reverse.front() == source_phantom.reverse_segment_id.id;
BOOST_ASSERT(!forward_to_forward || !reverse_to_forward);
BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse);
// in this case we always need to copy
if (forward_to_forward && forward_to_reverse)
{
// in this case we copy the path leading to the source forward node
// and change the case
total_packed_path_to_reverse = total_packed_path_to_forward;
packed_leg_to_reverse_begin = packed_leg_to_forward_begin;
forward_to_reverse = false;
reverse_to_reverse = true;
}
else if (reverse_to_forward && reverse_to_reverse)
{
total_packed_path_to_forward = total_packed_path_to_reverse;
packed_leg_to_forward_begin = packed_leg_to_reverse_begin;
reverse_to_forward = false;
forward_to_forward = true;
}
BOOST_ASSERT(!forward_to_forward || !forward_to_reverse);
BOOST_ASSERT(!reverse_to_forward || !reverse_to_reverse);
// in this case we just need to swap to regain the correct mapping
if (reverse_to_forward || forward_to_reverse)
{
total_packed_path_to_forward.swap(total_packed_path_to_reverse);
packed_leg_to_forward_begin.swap(packed_leg_to_reverse_begin);
}
}
if (new_total_weight_to_forward != INVALID_EDGE_WEIGHT)
{
BOOST_ASSERT(target_phantom.IsValidForwardTarget());
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
total_packed_path_to_forward.insert(total_packed_path_to_forward.end(),
packed_leg_to_forward.begin(),
packed_leg_to_forward.end());
search_from_forward_node = true;
}
else
{
total_packed_path_to_forward.clear();
packed_leg_to_forward_begin.clear();
search_from_forward_node = false;
}
if (new_total_weight_to_reverse != INVALID_EDGE_WEIGHT)
{
BOOST_ASSERT(target_phantom.IsValidReverseTarget());
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(),
packed_leg_to_reverse.begin(),
packed_leg_to_reverse.end());
search_from_reverse_node = true;
}
else
{
total_packed_path_to_reverse.clear();
packed_leg_to_reverse_begin.clear();
search_from_reverse_node = false;
}
prev_packed_leg_to_forward = std::move(packed_leg_to_forward);
prev_packed_leg_to_reverse = std::move(packed_leg_to_reverse);
total_weight_to_forward = new_total_weight_to_forward;
total_weight_to_reverse = new_total_weight_to_reverse;
++current_leg;
}
BOOST_ASSERT(total_weight_to_forward != INVALID_EDGE_WEIGHT ||
total_weight_to_reverse != INVALID_EDGE_WEIGHT);
// We make sure the fastest route is always in packed_legs_to_forward
if (total_weight_to_forward < total_weight_to_reverse ||
(total_weight_to_forward == total_weight_to_reverse &&
total_packed_path_to_forward.size() < total_packed_path_to_reverse.size()))
{
// insert sentinel
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
BOOST_ASSERT(packed_leg_to_forward_begin.size() == phantom_nodes_vector.size() + 1);
unpackLegs(facade,
phantom_nodes_vector,
total_packed_path_to_forward,
packed_leg_to_forward_begin,
total_weight_to_forward,
raw_route_data);
}
else
{
// insert sentinel
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
BOOST_ASSERT(packed_leg_to_reverse_begin.size() == phantom_nodes_vector.size() + 1);
unpackLegs(facade,
phantom_nodes_vector,
total_packed_path_to_reverse,
packed_leg_to_reverse_begin,
total_weight_to_reverse,
raw_route_data);
}
return raw_route_data;
}
} // namespace routing_algorithms
} // namespace engine
} // namespace osrm
#endif /* OSRM_SHORTEST_PATH_IMPL_HPP */
@@ -3,7 +3,6 @@
#include "engine/algorithm.hpp"
#include "engine/datafacade.hpp"
#include "engine/datafacade/datafacade_base.hpp"
#include "util/coordinate.hpp"
#include "util/typedefs.hpp"
+3 -4
View File
@@ -1,12 +1,12 @@
#ifndef SEARCH_ENGINE_DATA_HPP
#define SEARCH_ENGINE_DATA_HPP
#include <boost/thread/tss.hpp>
#include "engine/algorithm.hpp"
#include "util/query_heap.hpp"
#include "util/typedefs.hpp"
#include <boost/thread/tss.hpp>
namespace osrm
{
namespace engine
@@ -37,7 +37,6 @@ template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
{
using QueryHeap = util::
QueryHeap<NodeID, NodeID, EdgeWeight, HeapData, util::UnorderedMapStorage<NodeID, int>>;
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
using ManyToManyQueryHeap = util::QueryHeap<NodeID,
NodeID,
@@ -45,6 +44,7 @@ template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
ManyToManyHeapData,
util::UnorderedMapStorage<NodeID, int>>;
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>;
static SearchEngineHeapPtr forward_heap_1;
@@ -106,7 +106,6 @@ template <> struct SearchEngineData<routing_algorithms::mld::Algorithm>
util::UnorderedMapStorage<NodeID, int>>;
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>;
static SearchEngineHeapPtr forward_heap_1;
@@ -10,6 +10,8 @@
#include <string>
#include <vector>
#include <boost/optional.hpp>
namespace osrm
{
namespace extractor
@@ -36,7 +38,11 @@ class CompressedEdgeContainer
const EdgeWeight weight1,
const EdgeWeight weight2,
const EdgeDuration duration1,
const EdgeDuration duration2);
const EdgeDuration duration2,
// node-penalties can be added before/or after the traversal of an edge which
// depends on whether we traverse the link forwards or backwards.
const boost::optional<EdgeWeight> node_weight_penalty = boost::none,
const boost::optional<EdgeDuration> node_duration_penalty = boost::none);
void AddUncompressedEdge(const EdgeID edge_id,
const NodeID target_node,
@@ -0,0 +1,28 @@
#ifndef OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
#define OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
#include "util/coordinate.hpp"
#include "util/opening_hours.hpp"
#include <cstdint>
#include <vector>
#include <type_traits>
namespace osrm
{
namespace extractor
{
struct ConditionalTurnPenalty
{
// offset into the sequential list of turn penalties (see TurnIndexBlock for reference);
std::uint64_t turn_offset;
util::Coordinate location;
std::vector<util::OpeningHours> conditions;
};
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_CONDITIONAL_TURN_PENALTY_HPP_
+18 -6
View File
@@ -4,6 +4,7 @@
#define EDGE_BASED_GRAPH_FACTORY_HPP_
#include "extractor/compressed_edge_container.hpp"
#include "extractor/conditional_turn_penalty.hpp"
#include "extractor/edge_based_edge.hpp"
#include "extractor/edge_based_node_segment.hpp"
#include "extractor/extraction_turn.hpp"
@@ -16,7 +17,7 @@
#include "extractor/packed_osm_ids.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/way_restriction_map.hpp"
#include "util/concurrent_id_map.hpp"
@@ -41,11 +42,6 @@
#include <unordered_set>
#include <vector>
#include <boost/filesystem/fstream.hpp>
#include <tbb/concurrent_unordered_map.h>
#include <tbb/concurrent_vector.h>
namespace osrm
{
namespace extractor
@@ -92,7 +88,9 @@ class EdgeBasedGraphFactory
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &cnbg_ebg_mapping_path,
const std::string &conditional_penalties_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_restriction_map,
const WayRestrictionMap &way_restriction_map);
// The following get access functions destroy the content in the factory
@@ -124,6 +122,18 @@ class EdgeBasedGraphFactory
private:
using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
struct Conditional
{
// the edge based nodes allow for a unique identification of conditionals
NodeID from_node;
NodeID to_node;
ConditionalTurnPenalty penalty;
};
// assign the correct index to the penalty value stored in the conditional
std::vector<ConditionalTurnPenalty>
IndexConditionals(std::vector<Conditional> &&conditionals) const;
//! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
//! graph
std::vector<bool> m_edge_based_node_is_startpoint;
@@ -173,7 +183,9 @@ class EdgeBasedGraphFactory
const std::string &turn_weight_penalties_filename,
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &conditional_turn_penalties_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_restriction_map,
const WayRestrictionMap &way_restriction_map);
NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v);
+1 -3
View File
@@ -27,7 +27,6 @@ class ExtractionContainers
void PrepareEdges(ScriptingEnvironment &scripting_environment);
void WriteNodes(storage::io::FileWriter &file_out) const;
void WriteConditionalRestrictions(const std::string &restrictions_file_name);
void WriteEdges(storage::io::FileWriter &file_out) const;
void WriteCharData(const std::string &file_name);
@@ -40,7 +39,7 @@ class ExtractionContainers
using NameOffsets = std::vector<unsigned>;
std::vector<OSMNodeID> barrier_nodes;
std::vector<OSMNodeID> traffic_lights;
std::vector<OSMNodeID> traffic_signals;
NodeIDVector used_node_id_list;
NodeVector all_nodes_list;
EdgeVector all_edges_list;
@@ -65,7 +64,6 @@ class ExtractionContainers
void PrepareData(ScriptingEnvironment &scripting_environment,
const std::string &osrm_path,
const std::string &restrictions_file_name,
const std::string &names_data_path);
};
}
+8
View File
@@ -22,6 +22,14 @@ struct ExtractionTurn
{
}
ExtractionTurn(const bool has_traffic_light = false)
: angle(0), turn_type(guidance::TurnType::NoTurn),
direction_modifier(guidance::DirectionModifier::Straight),
has_traffic_light(has_traffic_light), weight(0.), duration(0.), source_restricted(false),
target_restricted(false)
{
}
const double angle;
const guidance::TurnType::Enum turn_type;
const guidance::DirectionModifier::Enum direction_modifier;
+8 -1
View File
@@ -56,7 +56,9 @@ class Extractor
private:
ExtractorConfig config;
std::tuple<guidance::LaneDescriptionMap, std::vector<TurnRestriction>>
std::tuple<guidance::LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<ConditionalTurnRestriction>>
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
std::pair<std::size_t, EdgeID>
@@ -70,6 +72,7 @@ class Extractor
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
const std::string &intersection_class_output_file,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
guidance::LaneDescriptionMap &turn_lane_map);
void FindComponents(unsigned max_edge_id,
const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
@@ -89,6 +92,10 @@ class Extractor
static void WriteCompressedNodeBasedGraph(const std::string &path,
const util::NodeBasedDynamicGraph &graph,
const std::vector<util::Coordinate> &coordiantes);
void WriteConditionalRestrictions(
const std::string &path,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
};
}
}
+3
View File
@@ -1,6 +1,7 @@
#ifndef GEOMETRY_COMPRESSOR_HPP
#define GEOMETRY_COMPRESSOR_HPP
#include "extractor/scripting_environment.hpp"
#include "util/typedefs.hpp"
#include "util/node_based_graph.hpp"
@@ -24,7 +25,9 @@ class GraphCompressor
public:
void Compress(const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
util::NodeBasedDynamicGraph &graph,
CompressedEdgeContainer &geometry_compressor);
@@ -6,7 +6,7 @@
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_normalization_operation.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/restriction_index.hpp"
#include "util/attributes.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
@@ -116,14 +116,6 @@ class IntersectionGenerator
// own state, used to find the correct coordinates along a road
const CoordinateExtractor coordinate_extractor;
// 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`
boost::optional<NodeID> GetOnlyAllowedTurnIfExistent(const NodeID coming_from_node,
const NodeID node_at_intersection) const;
};
} // namespace guidance
+1 -1
View File
@@ -14,7 +14,7 @@
#include "extractor/guidance/turn_classification.hpp"
#include "extractor/guidance/turn_handler.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/suffix_table.hpp"
#include "util/attributes.hpp"
+2 -1
View File
@@ -83,7 +83,8 @@ struct ProfileProperties
std::string GetClassName(std::size_t index) const
{
BOOST_ASSERT(index <= MAX_CLASS_INDEX);
return std::string(class_names[index]);
const auto &name_it = std::begin(class_names) + index;
return std::string(*name_it);
}
double GetWeightMultiplier() const { return std::pow(10., weight_precision); }
+3 -1
View File
@@ -1,6 +1,7 @@
#ifndef OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
#define OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
#include "extractor/restriction.hpp"
#include "util/typedefs.hpp"
#include <boost/unordered_map.hpp>
@@ -26,7 +27,8 @@ struct TurnRestriction;
class RestrictionCompressor
{
public:
RestrictionCompressor(std::vector<TurnRestriction> &restrictions);
RestrictionCompressor(std::vector<TurnRestriction> &restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
// account for the compression of `from-via-to` into `from-to`
void Compress(const NodeID from, const NodeID via, const NodeID to);
+3 -2
View File
@@ -14,8 +14,9 @@ namespace extractor
// To avoid handling invalid restrictions / creating unnecessary duplicate nodes for via-ways, we do
// a pre-flight check for restrictions and remove all invalid restrictions from the data. Use as
// `restrictions = removeInvalidRestrictions(std::move(restrictions))`
std::vector<TurnRestriction> removeInvalidRestrictions(std::vector<TurnRestriction>,
const util::NodeBasedDynamicGraph &);
std::vector<ConditionalTurnRestriction>
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction>,
const util::NodeBasedDynamicGraph &);
} // namespace extractor
} // namespace osrm
+101
View File
@@ -0,0 +1,101 @@
#ifndef OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
#define OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
#include "extractor/restriction.hpp"
#include "util/typedefs.hpp"
#include <boost/unordered_map.hpp>
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
// allows easy check for whether a node intersection is present at a given intersection
template <typename restriction_type> class RestrictionIndex
{
public:
using value_type = restriction_type;
template <typename extractor_type>
RestrictionIndex(std::vector<restriction_type> &restrictions, extractor_type extractor);
bool IsIndexed(NodeID first, NodeID second) const;
auto Restrictions(NodeID first, NodeID second) const
{
return restriction_hash.equal_range(std::make_pair(first, second));
};
auto Size() const { return restriction_hash.size(); }
private:
boost::unordered_multimap<std::pair<NodeID, NodeID>, restriction_type *> restriction_hash;
};
template <typename restriction_type>
template <typename extractor_type>
RestrictionIndex<restriction_type>::RestrictionIndex(std::vector<restriction_type> &restrictions,
extractor_type extractor)
{
// build a multi-map
for (auto &restriction : restrictions)
restriction_hash.insert(std::make_pair(extractor(restriction), &restriction));
}
template <typename restriction_type>
bool RestrictionIndex<restriction_type>::IsIndexed(const NodeID first, const NodeID second) const
{
return restriction_hash.count(std::make_pair(first, second));
}
struct IndexNodeByFromAndVia
{
std::pair<NodeID, NodeID> operator()(const TurnRestriction &restriction)
{
const auto &node = restriction.AsNodeRestriction();
return std::make_pair(node.from, node.via);
};
};
// check wheter a turn is restricted within a restriction_index
template <typename restriction_map_type>
std::pair<bool, typename restriction_map_type::value_type *>
isRestricted(const NodeID from,
const NodeID via,
const NodeID to,
const restriction_map_type &restriction_map)
{
const auto range = restriction_map.Restrictions(from, via);
// check if a given node_restriction is targeting node
const auto to_is_restricted = [to](const auto &pair) {
const auto &restriction = *pair.second;
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
{
auto const &as_node = restriction.AsNodeRestriction();
auto const restricted = restriction.is_only ? (to != as_node.to) : (to == as_node.to);
return restricted;
}
return false;
};
auto itr = std::find_if(range.first, range.second, to_is_restricted);
if (itr != range.second)
return {true, itr->second};
else
return {false, NULL};
}
using RestrictionMap = RestrictionIndex<TurnRestriction>;
using ConditionalRestrictionMap = RestrictionIndex<ConditionalTurnRestriction>;
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_RESTRICTION_INDEX_HPP_
-110
View File
@@ -1,110 +0,0 @@
#ifndef RESTRICTION_MAP_HPP
#define RESTRICTION_MAP_HPP
#include "extractor/edge_based_edge.hpp"
#include "extractor/restriction.hpp"
#include "util/std_hash.hpp"
#include "util/typedefs.hpp"
#include <boost/assert.hpp>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace osrm
{
namespace extractor
{
struct RestrictionSource
{
NodeID start_node;
NodeID via_node;
RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via) {}
friend inline bool operator==(const RestrictionSource &lhs, const RestrictionSource &rhs)
{
return (lhs.start_node == rhs.start_node && lhs.via_node == rhs.via_node);
}
};
struct RestrictionTarget
{
NodeID target_node;
bool is_only;
explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only) {}
friend inline bool operator==(const RestrictionTarget &lhs, const RestrictionTarget &rhs)
{
return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
}
};
}
}
namespace std
{
template <> struct hash<osrm::extractor::RestrictionSource>
{
size_t operator()(const osrm::extractor::RestrictionSource &r_source) const
{
return hash_val(r_source.start_node, r_source.via_node);
}
};
template <> struct hash<osrm::extractor::RestrictionTarget>
{
size_t operator()(const osrm::extractor::RestrictionTarget &r_target) const
{
return hash_val(r_target.target_node, r_target.is_only);
}
};
}
namespace osrm
{
namespace extractor
{
/**
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
*/
class RestrictionMap
{
public:
RestrictionMap() : m_count(0) {}
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
bool IsViaNode(const NodeID node) const;
// Check if edge (u, v) is the start of any turn restriction.
// If so returns id of first target node.
NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
// Checks if turn <u,v,w> is actually a turn restriction.
bool
CheckIfTurnIsRestricted(const NodeID node_u, const NodeID node_v, const NodeID node_w) const;
std::size_t size() const { return m_count; }
private:
// check of node is the start of any restriction
bool IsSourceNode(const NodeID node) const;
using EmanatingRestrictionsVector = std::vector<RestrictionTarget>;
std::size_t m_count;
//! index -> list of (target, isOnly)
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
//! maps (start, via) -> bucket index
std::unordered_map<RestrictionSource, unsigned> m_restriction_map;
std::unordered_set<NodeID> m_restriction_start_nodes;
std::unordered_set<NodeID> m_no_turn_via_node_set;
};
}
}
#endif // RESTRICTION_MAP_HPP
+49
View File
@@ -1,6 +1,7 @@
#ifndef OSRM_EXTRACTOR_IO_HPP
#define OSRM_EXTRACTOR_IO_HPP
#include "conditional_turn_penalty.hpp"
#include "extractor/datasources.hpp"
#include "extractor/intersection_bearings_container.hpp"
#include "extractor/nbg_to_ebg.hpp"
@@ -273,6 +274,54 @@ inline void write(storage::io::FileWriter &writer,
};
std::for_each(restrictions.begin(), restrictions.end(), write_restriction);
}
inline void read(storage::io::FileReader &reader, ConditionalTurnPenalty &turn_penalty)
{
reader.ReadInto(turn_penalty.turn_offset);
reader.ReadInto(turn_penalty.location.lat);
reader.ReadInto(turn_penalty.location.lon);
auto const num_conditions = reader.ReadElementCount64();
turn_penalty.conditions.resize(num_conditions);
for (auto &condition : turn_penalty.conditions)
{
reader.ReadInto(condition.modifier);
storage::serialization::read(reader, condition.times);
storage::serialization::read(reader, condition.weekdays);
storage::serialization::read(reader, condition.monthdays);
}
}
inline void write(storage::io::FileWriter &writer, const ConditionalTurnPenalty &turn_penalty)
{
writer.WriteOne(turn_penalty.turn_offset);
writer.WriteOne(static_cast<util::FixedLatitude::value_type>(turn_penalty.location.lat));
writer.WriteOne(static_cast<util::FixedLongitude::value_type>(turn_penalty.location.lon));
writer.WriteElementCount64(turn_penalty.conditions.size());
for (const auto &c : turn_penalty.conditions)
{
writer.WriteOne(c.modifier);
storage::serialization::write(writer, c.times);
storage::serialization::write(writer, c.weekdays);
storage::serialization::write(writer, c.monthdays);
}
}
inline void write(storage::io::FileWriter &writer,
const std::vector<ConditionalTurnPenalty> &conditional_penalties)
{
writer.WriteElementCount64(conditional_penalties.size());
for (const auto &penalty : conditional_penalties)
write(writer, penalty);
}
inline void read(storage::io::FileReader &reader,
std::vector<ConditionalTurnPenalty> &conditional_penalties)
{
auto const num_elements = reader.ReadElementCount64();
conditional_penalties.resize(num_elements);
for (auto &penalty : conditional_penalties)
read(reader, penalty);
}
}
}
}
+10 -7
View File
@@ -8,6 +8,7 @@
#include <boost/unordered_map.hpp>
#include "extractor/restriction.hpp"
#include "extractor/restriction_index.hpp"
#include "util/integer_range.hpp"
#include "util/typedefs.hpp"
@@ -18,6 +19,8 @@ namespace osrm
namespace extractor
{
// The WayRestrictionMap uses ConditionalTurnRestrictions in general. Most restrictions will have
// empty conditions, though.
class WayRestrictionMap
{
public:
@@ -26,7 +29,7 @@ class WayRestrictionMap
NodeID from;
NodeID to;
};
WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions);
WayRestrictionMap(const std::vector<ConditionalTurnRestriction> &conditional_restrictions);
// Check if an edge between two nodes is a restricted turn. The check needs to be performed to
// find duplicated nodes during the creation of edge-based-edges
@@ -43,10 +46,13 @@ class WayRestrictionMap
std::vector<ViaWay> DuplicatedNodeRepresentatives() const;
// Access all duplicated NodeIDs for a set of nodes indicating a via way
util::range<DuplicatedNodeID> DuplicatedNodeIDs(const NodeID from, const NodeID to) const;
std::vector<DuplicatedNodeID> DuplicatedNodeIDs(const NodeID from, const NodeID to) const;
// check whether a turn onto a given node is restricted, when coming from a duplicated node
bool IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const;
// Get the restriction resulting in ^ IsRestricted. Requires IsRestricted to evaluate to true
const ConditionalTurnRestriction &GetRestriction(DuplicatedNodeID duplicated_node,
const NodeID to) const;
// changes edge_based_node to the correct duplicated_node_id in case node_based_from,
// node_based_via, node_based_to can be identified with a restriction group
@@ -76,11 +82,8 @@ class WayRestrictionMap
// EBN: 0 . | 2 | 3 | 4 ...
// duplicated node groups: ... | 5 | 7 | ...
std::vector<DuplicatedNodeID> duplicated_node_groups;
boost::unordered_multimap<std::pair<NodeID, NodeID>, RestrictionID> restriction_starts;
boost::unordered_multimap<std::pair<NodeID, NodeID>, RestrictionID> restriction_ends;
std::vector<TurnRestriction> restriction_data;
std::vector<ConditionalTurnRestriction> restriction_data;
RestrictionIndex<ConditionalTurnRestriction> restriction_starts;
};
} // namespace extractor
+1 -1
View File
@@ -97,7 +97,7 @@ template <typename T> void write(io::FileWriter &writer, const std::vector<T> &d
{
const auto count = data.size();
writer.WriteElementCount64(count);
return writer.WriteFrom(data.data(), count);
writer.WriteFrom(data.data(), count);
}
template <typename T> void read(io::FileReader &reader, util::vector_view<T> &data)
+4 -4
View File
@@ -18,13 +18,13 @@ namespace util
struct NodeIdVectorToLineString
{
NodeIdVectorToLineString(const std::vector<extractor::QueryNode> &node_coordinates);
NodeIdVectorToLineString(const std::vector<util::Coordinate> &node_coordinates);
// converts a vector of node ids into a linestring geojson feature
util::json::Object operator()(const std::vector<NodeID> &node_ids,
const boost::optional<json::Object> &properties = {}) const;
const std::vector<extractor::QueryNode> &node_coordinates;
const std::vector<util::Coordinate> &node_coordinates;
};
struct CoordinateVectorToLineString
@@ -36,13 +36,13 @@ struct CoordinateVectorToLineString
struct NodeIdVectorToMultiPoint
{
NodeIdVectorToMultiPoint(const std::vector<extractor::QueryNode> &node_coordinates);
NodeIdVectorToMultiPoint(const std::vector<util::Coordinate> &node_coordinates);
// converts a vector of node ids into a linestring geojson feature
util::json::Object operator()(const std::vector<NodeID> &node_ids,
const boost::optional<json::Object> &properties = {}) const;
const std::vector<extractor::QueryNode> &node_coordinates;
const std::vector<util::Coordinate> &node_coordinates;
};
struct CoordinateVectorToMultiPoint
@@ -69,12 +69,12 @@ struct CoordinateToJsonArray
struct NodeIdToCoordinate
{
NodeIdToCoordinate(const std::vector<extractor::QueryNode> &node_coordinates)
NodeIdToCoordinate(const std::vector<util::Coordinate> &node_coordinates)
: node_coordinates(node_coordinates)
{
}
const std::vector<extractor::QueryNode> &node_coordinates;
const std::vector<util::Coordinate> &node_coordinates;
util::json::Array operator()(const NodeID nid)
{
+2701 -1026
View File
File diff suppressed because it is too large Load Diff
+11 -2
View File
@@ -1,6 +1,6 @@
{
"name": "osrm",
"version": "5.10.0",
"version": "5.11.0-rc.1",
"private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": {
@@ -15,7 +15,7 @@
]
},
"scripts": {
"lint": "eslint -c ./.eslintrc features/step_definitions/ features/support/",
"lint": "node ./node_modules/eslint/bin/eslint.js -c ./.eslintrc features/step_definitions/ features/support/",
"test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld",
"clean": "rm -rf test/cache",
"docs": "./scripts/build_api_docs.sh",
@@ -65,5 +65,14 @@
"host": "https://mapbox-node-binary.s3.amazonaws.com",
"remote_path": "./{name}/v{version}/{configuration}/",
"package_name": "{node_abi}-{platform}-{arch}.tar.gz"
},
"bin": {
"osrm-extract": "./lib/binding/osrm-extract",
"osrm-contract": "./lib/binding/osrm-contract",
"osrm-partition": "./lib/binding/osrm-partition",
"osrm-customize": "./lib/binding/osrm-customize",
"osrm-routed": "./lib/binding/osrm-routed",
"osrm-components": "./lib/binding/osrm-components",
"osrm-datastore": "./lib/binding/osrm-datastore"
}
}
@@ -17,7 +17,7 @@ namespace
{
// check bearings for u-turns.
// since bearings are wrapped around at 0 (we only support 0,360), we need to do some minor math to
// since bearings are wrapped around at 0 (we only support 0,360), we need to do some minor math to
// check if bearings `a` and `b` go in opposite directions. In general we accept some minor
// deviations for u-turns.
bool bearingsAreReversed(const double bearing_in, const double bearing_out)
@@ -123,7 +123,7 @@ bool isStaggeredIntersection(const RouteStepIterator step_prior_to_intersection,
const auto angle = [](const RouteStep &step) {
const auto &intersection = step.intersections.front();
const auto entry_bearing = intersection.bearings[intersection.in];
const auto entry_bearing = util::bearing::reverse(intersection.bearings[intersection.in]);
const auto exit_bearing = intersection.bearings[intersection.out];
return util::bearing::angleBetween(entry_bearing, exit_bearing);
};
+1 -448
View File
@@ -1,10 +1,6 @@
#include "engine/routing_algorithms/shortest_path.hpp"
#include "engine/routing_algorithms/routing_base_ch.hpp"
#include "engine/routing_algorithms/routing_base_mld.hpp"
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include <memory>
#include "engine/routing_algorithms/shortest_path_impl.hpp"
namespace osrm
{
@@ -13,449 +9,6 @@ namespace engine
namespace routing_algorithms
{
namespace
{
const static constexpr bool DO_NOT_FORCE_LOOP = false;
// allows a uturn at the target_phantom
// searches source forward/reverse -> target forward/reverse
template <typename Algorithm>
void searchWithUTurn(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool search_from_forward_node,
const bool search_from_reverse_node,
const bool search_to_forward_node,
const bool search_to_reverse_node,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
const int total_weight_to_forward,
const int total_weight_to_reverse,
int &new_total_weight,
std::vector<NodeID> &leg_packed_path)
{
forward_heap.Clear();
reverse_heap.Clear();
if (search_from_forward_node)
{
forward_heap.Insert(source_phantom.forward_segment_id.id,
-source_phantom.GetForwardWeightPlusOffset(),
source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
forward_heap.Insert(source_phantom.reverse_segment_id.id,
-source_phantom.GetReverseWeightPlusOffset(),
source_phantom.reverse_segment_id.id);
}
if (search_to_forward_node)
{
reverse_heap.Insert(target_phantom.forward_segment_id.id,
target_phantom.GetForwardWeightPlusOffset(),
target_phantom.forward_segment_id.id);
}
if (search_to_reverse_node)
{
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
target_phantom.GetReverseWeightPlusOffset(),
target_phantom.reverse_segment_id.id);
}
// this is only relevent if source and target are on the same compressed edge
auto is_oneway_source = !(search_from_forward_node && search_from_reverse_node);
auto is_oneway_target = !(search_to_forward_node && search_to_reverse_node);
// we only enable loops here if we can't search from forward to backward node
auto needs_loop_forwards = is_oneway_source && needsLoopForward(source_phantom, target_phantom);
auto needs_loop_backwards =
is_oneway_target && needsLoopBackwards(source_phantom, target_phantom);
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
new_total_weight,
leg_packed_path,
needs_loop_forwards,
needs_loop_backwards,
{source_phantom, target_phantom});
// if no route is found between two parts of the via-route, the entire route becomes
// invalid. Adding to invalid edge weight sadly doesn't return an invalid edge weight. Here
// we prevent the possible overflow, faking the addition of infinity + x == infinity
if (new_total_weight != INVALID_EDGE_WEIGHT)
new_total_weight += std::min(total_weight_to_forward, total_weight_to_reverse);
}
// searches shortest path between:
// source forward/reverse -> target forward
// source forward/reverse -> target reverse
template <typename Algorithm>
void search(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool search_from_forward_node,
const bool search_from_reverse_node,
const bool search_to_forward_node,
const bool search_to_reverse_node,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
const int total_weight_to_forward,
const int total_weight_to_reverse,
int &new_total_weight_to_forward,
int &new_total_weight_to_reverse,
std::vector<NodeID> &leg_packed_path_forward,
std::vector<NodeID> &leg_packed_path_reverse)
{
if (search_to_forward_node)
{
forward_heap.Clear();
reverse_heap.Clear();
reverse_heap.Insert(target_phantom.forward_segment_id.id,
target_phantom.GetForwardWeightPlusOffset(),
target_phantom.forward_segment_id.id);
if (search_from_forward_node)
{
forward_heap.Insert(source_phantom.forward_segment_id.id,
total_weight_to_forward -
source_phantom.GetForwardWeightPlusOffset(),
source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
forward_heap.Insert(source_phantom.reverse_segment_id.id,
total_weight_to_reverse -
source_phantom.GetReverseWeightPlusOffset(),
source_phantom.reverse_segment_id.id);
}
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
new_total_weight_to_forward,
leg_packed_path_forward,
needsLoopForward(source_phantom, target_phantom),
routing_algorithms::DO_NOT_FORCE_LOOP,
{source_phantom, target_phantom});
}
if (search_to_reverse_node)
{
forward_heap.Clear();
reverse_heap.Clear();
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
target_phantom.GetReverseWeightPlusOffset(),
target_phantom.reverse_segment_id.id);
if (search_from_forward_node)
{
forward_heap.Insert(source_phantom.forward_segment_id.id,
total_weight_to_forward -
source_phantom.GetForwardWeightPlusOffset(),
source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
forward_heap.Insert(source_phantom.reverse_segment_id.id,
total_weight_to_reverse -
source_phantom.GetReverseWeightPlusOffset(),
source_phantom.reverse_segment_id.id);
}
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
new_total_weight_to_reverse,
leg_packed_path_reverse,
routing_algorithms::DO_NOT_FORCE_LOOP,
needsLoopBackwards(source_phantom, target_phantom),
{source_phantom, target_phantom});
}
}
template <typename Algorithm>
void unpackLegs(const DataFacade<Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector,
const std::vector<NodeID> &total_packed_path,
const std::vector<std::size_t> &packed_leg_begin,
const EdgeWeight shortest_path_weight,
InternalRouteResult &raw_route_data)
{
raw_route_data.unpacked_path_segments.resize(packed_leg_begin.size() - 1);
raw_route_data.shortest_path_weight = shortest_path_weight;
for (const auto current_leg : util::irange<std::size_t>(0UL, packed_leg_begin.size() - 1))
{
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
const auto &unpack_phantom_node_pair = phantom_nodes_vector[current_leg];
unpackPath(facade,
leg_begin,
leg_end,
unpack_phantom_node_pair,
raw_route_data.unpacked_path_segments[current_leg]);
raw_route_data.source_traversed_in_reverse.push_back(
(*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back(
(*std::prev(leg_end) !=
phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id));
}
}
}
template <typename Algorithm>
InternalRouteResult shortestPathSearch(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
const std::vector<PhantomNodes> &phantom_nodes_vector,
const boost::optional<bool> continue_straight_at_waypoint)
{
InternalRouteResult raw_route_data;
raw_route_data.segment_end_coordinates = phantom_nodes_vector;
const bool allow_uturn_at_waypoint =
!(continue_straight_at_waypoint ? *continue_straight_at_waypoint
: facade.GetContinueStraightDefault());
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1;
int total_weight_to_forward = 0;
int total_weight_to_reverse = 0;
bool search_from_forward_node =
phantom_nodes_vector.front().source_phantom.IsValidForwardSource();
bool search_from_reverse_node =
phantom_nodes_vector.front().source_phantom.IsValidReverseSource();
std::vector<NodeID> prev_packed_leg_to_forward;
std::vector<NodeID> prev_packed_leg_to_reverse;
std::vector<NodeID> total_packed_path_to_forward;
std::vector<std::size_t> packed_leg_to_forward_begin;
std::vector<NodeID> total_packed_path_to_reverse;
std::vector<std::size_t> packed_leg_to_reverse_begin;
std::size_t current_leg = 0;
// this implements a dynamic program that finds the shortest route through
// a list of vias
for (const auto &phantom_node_pair : phantom_nodes_vector)
{
int new_total_weight_to_forward = INVALID_EDGE_WEIGHT;
int new_total_weight_to_reverse = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_leg_to_forward;
std::vector<NodeID> packed_leg_to_reverse;
const auto &source_phantom = phantom_node_pair.source_phantom;
const auto &target_phantom = phantom_node_pair.target_phantom;
bool search_to_forward_node = target_phantom.IsValidForwardTarget();
bool search_to_reverse_node = target_phantom.IsValidReverseTarget();
BOOST_ASSERT(!search_from_forward_node || source_phantom.IsValidForwardSource());
BOOST_ASSERT(!search_from_reverse_node || source_phantom.IsValidReverseSource());
if (search_to_reverse_node || search_to_forward_node)
{
if (allow_uturn_at_waypoint)
{
searchWithUTurn(engine_working_data,
facade,
forward_heap,
reverse_heap,
search_from_forward_node,
search_from_reverse_node,
search_to_forward_node,
search_to_reverse_node,
source_phantom,
target_phantom,
total_weight_to_forward,
total_weight_to_reverse,
new_total_weight_to_forward,
packed_leg_to_forward);
// if only the reverse node is valid (e.g. when using the match plugin) we
// actually need to move
if (!target_phantom.IsValidForwardTarget())
{
BOOST_ASSERT(target_phantom.IsValidReverseTarget());
new_total_weight_to_reverse = new_total_weight_to_forward;
packed_leg_to_reverse = std::move(packed_leg_to_forward);
new_total_weight_to_forward = INVALID_EDGE_WEIGHT;
// (*)
//
// Below we have to check if new_total_weight_to_forward is invalid.
// This prevents use-after-move on packed_leg_to_forward.
}
else if (target_phantom.IsValidReverseTarget())
{
new_total_weight_to_reverse = new_total_weight_to_forward;
packed_leg_to_reverse = packed_leg_to_forward;
}
}
else
{
search(engine_working_data,
facade,
forward_heap,
reverse_heap,
search_from_forward_node,
search_from_reverse_node,
search_to_forward_node,
search_to_reverse_node,
source_phantom,
target_phantom,
total_weight_to_forward,
total_weight_to_reverse,
new_total_weight_to_forward,
new_total_weight_to_reverse,
packed_leg_to_forward,
packed_leg_to_reverse);
}
}
// Note: To make sure we do not access the moved-from packed_leg_to_forward
// we guard its access by a check for invalid edge weight. See (*) above.
// No path found for both target nodes?
if ((INVALID_EDGE_WEIGHT == new_total_weight_to_forward) &&
(INVALID_EDGE_WEIGHT == new_total_weight_to_reverse))
{
return raw_route_data;
}
// we need to figure out how the new legs connect to the previous ones
if (current_leg > 0)
{
bool forward_to_forward =
(new_total_weight_to_forward != INVALID_EDGE_WEIGHT) &&
packed_leg_to_forward.front() == source_phantom.forward_segment_id.id;
bool reverse_to_forward =
(new_total_weight_to_forward != INVALID_EDGE_WEIGHT) &&
packed_leg_to_forward.front() == source_phantom.reverse_segment_id.id;
bool forward_to_reverse =
(new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) &&
packed_leg_to_reverse.front() == source_phantom.forward_segment_id.id;
bool reverse_to_reverse =
(new_total_weight_to_reverse != INVALID_EDGE_WEIGHT) &&
packed_leg_to_reverse.front() == source_phantom.reverse_segment_id.id;
BOOST_ASSERT(!forward_to_forward || !reverse_to_forward);
BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse);
// in this case we always need to copy
if (forward_to_forward && forward_to_reverse)
{
// in this case we copy the path leading to the source forward node
// and change the case
total_packed_path_to_reverse = total_packed_path_to_forward;
packed_leg_to_reverse_begin = packed_leg_to_forward_begin;
forward_to_reverse = false;
reverse_to_reverse = true;
}
else if (reverse_to_forward && reverse_to_reverse)
{
total_packed_path_to_forward = total_packed_path_to_reverse;
packed_leg_to_forward_begin = packed_leg_to_reverse_begin;
reverse_to_forward = false;
forward_to_forward = true;
}
BOOST_ASSERT(!forward_to_forward || !forward_to_reverse);
BOOST_ASSERT(!reverse_to_forward || !reverse_to_reverse);
// in this case we just need to swap to regain the correct mapping
if (reverse_to_forward || forward_to_reverse)
{
total_packed_path_to_forward.swap(total_packed_path_to_reverse);
packed_leg_to_forward_begin.swap(packed_leg_to_reverse_begin);
}
}
if (new_total_weight_to_forward != INVALID_EDGE_WEIGHT)
{
BOOST_ASSERT(target_phantom.IsValidForwardTarget());
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
total_packed_path_to_forward.insert(total_packed_path_to_forward.end(),
packed_leg_to_forward.begin(),
packed_leg_to_forward.end());
search_from_forward_node = true;
}
else
{
total_packed_path_to_forward.clear();
packed_leg_to_forward_begin.clear();
search_from_forward_node = false;
}
if (new_total_weight_to_reverse != INVALID_EDGE_WEIGHT)
{
BOOST_ASSERT(target_phantom.IsValidReverseTarget());
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(),
packed_leg_to_reverse.begin(),
packed_leg_to_reverse.end());
search_from_reverse_node = true;
}
else
{
total_packed_path_to_reverse.clear();
packed_leg_to_reverse_begin.clear();
search_from_reverse_node = false;
}
prev_packed_leg_to_forward = std::move(packed_leg_to_forward);
prev_packed_leg_to_reverse = std::move(packed_leg_to_reverse);
total_weight_to_forward = new_total_weight_to_forward;
total_weight_to_reverse = new_total_weight_to_reverse;
++current_leg;
}
BOOST_ASSERT(total_weight_to_forward != INVALID_EDGE_WEIGHT ||
total_weight_to_reverse != INVALID_EDGE_WEIGHT);
// We make sure the fastest route is always in packed_legs_to_forward
if (total_weight_to_forward < total_weight_to_reverse ||
(total_weight_to_forward == total_weight_to_reverse &&
total_packed_path_to_forward.size() < total_packed_path_to_reverse.size()))
{
// insert sentinel
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
BOOST_ASSERT(packed_leg_to_forward_begin.size() == phantom_nodes_vector.size() + 1);
unpackLegs(facade,
phantom_nodes_vector,
total_packed_path_to_forward,
packed_leg_to_forward_begin,
total_weight_to_forward,
raw_route_data);
}
else
{
// insert sentinel
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
BOOST_ASSERT(packed_leg_to_reverse_begin.size() == phantom_nodes_vector.size() + 1);
unpackLegs(facade,
phantom_nodes_vector,
total_packed_path_to_reverse,
packed_leg_to_reverse_begin,
total_weight_to_reverse,
raw_route_data);
}
return raw_route_data;
}
template InternalRouteResult
shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const DataFacade<ch::Algorithm> &facade,
+22 -9
View File
@@ -103,14 +103,17 @@ SegmentDuration CompressedEdgeContainer::ClipDuration(const SegmentDuration dura
// ----------> via_node_id -----------> target_node_id
// weight_1 weight_2
// duration_1 duration_2
void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
const EdgeID edge_id_2,
const NodeID via_node_id,
const NodeID target_node_id,
const EdgeWeight weight1,
const EdgeWeight weight2,
const EdgeDuration duration1,
const EdgeDuration duration2)
void CompressedEdgeContainer::CompressEdge(
const EdgeID edge_id_1,
const EdgeID edge_id_2,
const NodeID via_node_id,
const NodeID target_node_id,
const EdgeWeight weight1,
const EdgeWeight weight2,
const EdgeDuration duration1,
const EdgeDuration duration2,
const boost::optional<EdgeWeight> node_weight_penalty,
const boost::optional<EdgeDuration> node_duration_penalty)
{
// remove super-trivial geometries
BOOST_ASSERT(SPECIAL_EDGEID != edge_id_1);
@@ -151,9 +154,11 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
std::vector<OnewayCompressedEdge> &edge_bucket_list1 =
m_compressed_oneway_geometries[edge_bucket_id1];
bool was_empty = edge_bucket_list1.empty();
// note we don't save the start coordinate: it is implicitly given by edge 1
// weight1 is the distance to the (currently) last coordinate in the bucket
if (edge_bucket_list1.empty())
if (was_empty)
{
edge_bucket_list1.emplace_back(
OnewayCompressedEdge{via_node_id, ClipWeight(weight1), ClipDuration(duration1)});
@@ -162,6 +167,14 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
BOOST_ASSERT(0 < edge_bucket_list1.size());
BOOST_ASSERT(!edge_bucket_list1.empty());
// if the via-node offers a penalty, we add the weight of the penalty as an artificial
// segment that references SPECIAL_NODEID
if (node_weight_penalty && node_duration_penalty)
{
edge_bucket_list1.emplace_back(OnewayCompressedEdge{
via_node_id, ClipWeight(*node_weight_penalty), ClipDuration(*node_duration_penalty)});
}
if (HasEntryForID(edge_id_2))
{
// second edge is not atomic anymore
+180 -30
View File
@@ -1,4 +1,5 @@
#include "extractor/edge_based_graph_factory.hpp"
#include "extractor/conditional_turn_penalty.hpp"
#include "extractor/edge_based_edge.hpp"
#include "extractor/files.hpp"
#include "extractor/guidance/turn_analysis.hpp"
@@ -6,6 +7,7 @@
#include "extractor/scripting_environment.hpp"
#include "extractor/suffix_table.hpp"
#include "extractor/serialization.hpp"
#include "storage/io.hpp"
#include "util/assert.hpp"
@@ -20,8 +22,10 @@
#include "util/timing_util.hpp"
#include <boost/assert.hpp>
#include <boost/functional/hash.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include "boost/unordered_map.hpp"
#include <algorithm>
#include <cmath>
#include <iomanip>
@@ -35,12 +39,26 @@
#include <tbb/pipeline.h>
#include <tbb/task_scheduler_init.h>
namespace std
{
template <> struct hash<std::pair<NodeID, NodeID>>
{
std::size_t operator()(const std::pair<NodeID, NodeID> &mk) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, mk.first);
boost::hash_combine(seed, mk.second);
return seed;
}
};
}
namespace osrm
{
namespace extractor
{
// Configuration to find representative candidate for turn angle calculations
// Configuration to find representative candidate for turn angle calculations
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
CompressedEdgeContainer &compressed_edge_container,
@@ -168,6 +186,11 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
m_compressed_edge_container.GetBucketReference(edge_id_2)[segment_count - 1 - i]
.node_id);
const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id;
// don't add node-segments for penalties
if (current_edge_target_coordinate_id == current_edge_source_coordinate_id)
continue;
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
// build edges
@@ -194,7 +217,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &cnbg_ebg_mapping_path,
const std::string &conditional_penalties_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_node_restriction_map,
const WayRestrictionMap &way_restriction_map)
{
TIMER_START(renumber);
@@ -215,7 +240,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
turn_weight_penalties_filename,
turn_duration_penalties_filename,
turn_penalties_index_filename,
conditional_penalties_filename,
node_restriction_map,
conditional_node_restriction_map,
way_restriction_map);
TIMER_STOP(generate_edges);
@@ -379,7 +406,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const std::string &turn_weight_penalties_filename,
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &conditional_penalties_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_restriction_map,
const WayRestrictionMap &way_restriction_map)
{
@@ -422,6 +451,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto weight_multiplier =
scripting_environment.GetProfileProperties().GetWeightMultiplier();
// filled in during next stage, kept alive through following scope
std::vector<Conditional> conditionals;
// The following block generates the edge-based-edges using a parallel processing
// pipeline. Sets of intersection IDs are batched in groups of GRAINSIZE (100)
// `generator_stage`,
@@ -477,7 +508,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
};
// same as IntersectionData, but grouped with edge to allow sorting after creating. Edges
// are out of order
// can be out of order
struct EdgeWithData
{
EdgeBasedEdge edge;
@@ -492,10 +523,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
std::size_t nodes_processed = 0;
IntersectionData continuous_data;
std::vector<EdgeWithData> delayed_data;
std::vector<Conditional> conditionals;
};
// Generate edges for either artificial nodes or the main graph
const auto generate_edge = [this, &scripting_environment, weight_multiplier](
const auto generate_edge = [this,
&scripting_environment,
weight_multiplier,
&conditional_restriction_map](
// what nodes will be used? In most cases this will be the id stored in the edge_data.
// In case of duplicated nodes (e.g. due to via-way restrictions), one/both of these
// might refer to a newly added edge based node
@@ -509,6 +544,24 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto &intersection,
const auto &turn,
const auto entry_class_id) {
const auto node_restricted = isRestricted(node_along_road_entering,
node_at_center_of_intersection,
m_node_based_graph->GetTarget(turn.eid),
conditional_restriction_map);
boost::optional<Conditional> conditional = boost::none;
if (node_restricted.first)
{
auto const &conditions = node_restricted.second->condition;
// get conditions of the restriction limiting the node
conditional = {{edge_based_node_from,
edge_based_node_to,
{static_cast<std::uint64_t>(-1),
m_coordinates[node_at_center_of_intersection],
conditions}}};
}
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(node_based_edge_from);
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(node_based_edge_to);
@@ -568,15 +621,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto &from_node =
isTrivial ? node_along_road_entering
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
const auto &via_node =
m_compressed_edge_container.GetLastEdgeTargetID(node_based_edge_from);
const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
lookup::TurnIndexBlock turn_index_block = {from_node, via_node, to_node};
lookup::TurnIndexBlock turn_index_block = {
from_node, node_at_center_of_intersection, to_node};
// insert data into the designated buffer
return EdgeWithData{
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data};
return std::make_pair(
EdgeWithData{
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data},
conditional);
};
// Second part of the pipeline is where the intersection analysis is done for
@@ -715,7 +769,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
m_number_of_edge_based_nodes);
{ // scope to forget edge_with_data after
const auto edge_with_data =
const auto edge_with_data_and_condition =
generate_edge(edge_data1.edge_id,
target_id,
node_along_road_entering,
@@ -726,15 +780,21 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
turn,
entry_class_id);
buffer->continuous_data.edges_list.push_back(edge_with_data.edge);
buffer->continuous_data.edges_list.push_back(
edge_with_data_and_condition.first.edge);
buffer->continuous_data.turn_indexes.push_back(
edge_with_data.turn_index);
edge_with_data_and_condition.first.turn_index);
buffer->continuous_data.turn_weight_penalties.push_back(
edge_with_data.turn_weight_penalty);
edge_with_data_and_condition.first.turn_weight_penalty);
buffer->continuous_data.turn_duration_penalties.push_back(
edge_with_data.turn_duration_penalty);
edge_with_data_and_condition.first.turn_duration_penalty);
buffer->continuous_data.turn_data_container.push_back(
edge_with_data.turn_data);
edge_with_data_and_condition.first.turn_data);
if (edge_with_data_and_condition.second)
{
buffer->conditionals.push_back(
*edge_with_data_and_condition.second);
}
}
// when turning off a a via-way turn restriction, we need to not only
@@ -759,25 +819,73 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
auto const node_at_end_of_turn =
m_node_based_graph->GetTarget(turn.eid);
const auto is_restricted = way_restriction_map.IsRestricted(
const auto is_way_restricted = way_restriction_map.IsRestricted(
duplicated_node_id, node_at_end_of_turn);
if (is_restricted)
continue;
if (is_way_restricted)
{
// add into delayed data
auto edge_with_data = generate_edge(
NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
auto const restriction = way_restriction_map.GetRestriction(
duplicated_node_id, node_at_end_of_turn);
buffer->delayed_data.push_back(std::move(edge_with_data));
if (restriction.condition.empty())
continue;
// add into delayed data
auto edge_with_data_and_condition = generate_edge(
NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
buffer->delayed_data.push_back(
std::move(edge_with_data_and_condition.first));
if (edge_with_data_and_condition.second)
{
buffer->conditionals.push_back(
*edge_with_data_and_condition.second);
}
// also add the conditions for the way
if (is_way_restricted && !restriction.condition.empty())
{
// add a new conditional for the edge we just created
buffer->conditionals.push_back(
{NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
{static_cast<std::uint64_t>(-1),
m_coordinates[node_at_center_of_intersection],
restriction.condition}});
}
}
else
{
auto edge_with_data_and_condition = generate_edge(
NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
node_along_road_entering,
incoming_edge,
node_at_center_of_intersection,
turn.eid,
intersection,
turn,
entry_class_id);
buffer->delayed_data.push_back(
std::move(edge_with_data_and_condition.first));
if (edge_with_data_and_condition.second)
{
buffer->conditionals.push_back(
*edge_with_data_and_condition.second);
}
}
}
}
}
@@ -822,6 +930,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
data.turn_indexes.begin(),
data.turn_indexes.end());
conditionals.insert(
conditionals.end(), buffer->conditionals.begin(), buffer->conditionals.end());
// Buffer writes to reduce syscall count
if (turn_indexes_write_buffer.size() >= TURN_INDEX_WRITE_BUFFER_SIZE)
{
@@ -874,6 +985,20 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
}
});
// re-hash conditionals to ocnnect to their respective edge-based edges. Due to the
// ordering, we
// do not really have a choice but to index the conditional penalties and walk over all
// edge-based-edges to find the ID of the edge
auto const indexed_conditionals = IndexConditionals(std::move(conditionals));
{
util::Log() << "Writing " << indexed_conditionals.size()
<< " conditional turn penalties...";
// write conditional turn penalties into the restrictions file
storage::io::FileWriter writer(conditional_penalties_filename,
storage::io::FileWriter::GenerateFingerprint);
extractor::serialization::write(writer, indexed_conditionals);
}
// write weight penalties per turn
BOOST_ASSERT(turn_weight_penalties.size() == turn_duration_penalties.size());
{
@@ -913,11 +1038,36 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
util::Log() << " skips " << restricted_turns_counter << " turns, "
"defined by "
<< node_restriction_map.size() << " restrictions";
<< node_restriction_map.Size() << " restrictions";
util::Log() << " skips " << skipped_uturns_counter << " U turns";
util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
}
std::vector<ConditionalTurnPenalty>
EdgeBasedGraphFactory::IndexConditionals(std::vector<Conditional> &&conditionals) const
{
boost::unordered_multimap<std::pair<NodeID, NodeID>, ConditionalTurnPenalty *> index;
// build and index of all conditional restrictions
for (auto &conditional : conditionals)
index.insert(std::make_pair(std::make_pair(conditional.from_node, conditional.to_node),
&conditional.penalty));
std::vector<ConditionalTurnPenalty> indexed_restrictions;
for (auto const &edge : m_edge_based_edge_list)
{
auto const range = index.equal_range(std::make_pair(edge.source, edge.target));
for (auto itr = range.first; itr != range.second; ++itr)
{
itr->second->turn_offset = edge.data.turn_id;
indexed_restrictions.push_back(*itr->second);
}
}
return indexed_restrictions;
}
std::vector<util::guidance::BearingClass> EdgeBasedGraphFactory::GetBearingClasses() const
{
std::vector<util::guidance::BearingClass> result(bearing_class_hash.data.size());
+8 -17
View File
@@ -126,7 +126,6 @@ ExtractionContainers::ExtractionContainers()
*/
void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environment,
const std::string &osrm_path,
const std::string &restrictions_file_name,
const std::string &name_file_name)
{
storage::io::FileWriter file_out(osrm_path, storage::io::FileWriter::GenerateFingerprint);
@@ -139,7 +138,6 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
WriteEdges(file_out);
PrepareRestrictions();
WriteConditionalRestrictions(restrictions_file_name);
WriteCharData(name_file_name);
}
@@ -616,33 +614,23 @@ void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
util::UnbufferedLog log;
log << "Writing traffic light nodes ... ";
TIMER_START(write_nodes);
std::vector<NodeID> internal_traffic_lights;
for (const auto osm_id : traffic_lights)
std::vector<NodeID> internal_traffic_signals;
for (const auto osm_id : traffic_signals)
{
const auto node_id = mapExternalToInternalNodeID(
used_node_id_list.begin(), used_node_id_list.end(), osm_id);
if (node_id != SPECIAL_NODEID)
{
internal_traffic_lights.push_back(node_id);
internal_traffic_signals.push_back(node_id);
}
}
storage::serialization::write(file_out, internal_traffic_lights);
storage::serialization::write(file_out, internal_traffic_signals);
log << "ok, after " << TIMER_SEC(write_nodes) << "s";
}
util::Log() << "Processed " << max_internal_node_id << " nodes";
}
void ExtractionContainers::WriteConditionalRestrictions(const std::string &path)
{
std::uint64_t written_restriction_count = conditional_turn_restrictions.size();
storage::io::FileWriter restrictions_out_file(path,
storage::io::FileWriter::GenerateFingerprint);
serialization::write(restrictions_out_file, conditional_turn_restrictions);
util::Log() << "number of conditional restrictions written to disk: "
<< written_restriction_count;
}
void ExtractionContainers::PrepareRestrictions()
{
@@ -837,7 +825,8 @@ void ExtractionContainers::PrepareRestrictions()
const auto transform_into_internal_types =
[&](const InputConditionalTurnRestriction &external_restriction) {
// unconditional restriction
if (external_restriction.condition.empty())
if (external_restriction.condition.empty() &&
external_restriction.Type() == RestrictionType::NODE_RESTRICTION)
{
TurnRestriction restriction;
restriction.is_only = external_restriction.is_only;
@@ -851,7 +840,9 @@ void ExtractionContainers::PrepareRestrictions()
restriction.is_only = external_restriction.is_only;
restriction.condition = std::move(external_restriction.condition);
if (transform(external_restriction, restriction))
{
conditional_turn_restrictions.push_back(std::move(restriction));
}
}
};
+46 -25
View File
@@ -23,7 +23,7 @@
#include "util/timing_util.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/restriction_index.hpp"
#include "extractor/way_restriction_map.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
@@ -110,7 +110,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
guidance::LaneDescriptionMap turn_lane_map;
std::vector<TurnRestriction> turn_restrictions;
std::tie(turn_lane_map, turn_restrictions) =
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
std::tie(turn_lane_map, turn_restrictions, conditional_turn_restrictions) =
ParseOSMData(scripting_environment, number_of_threads);
// Transform the node-based graph that OSM is based on into an edge-based graph
@@ -138,6 +139,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
edge_based_edge_list,
config.GetPath(".osrm.icd").string(),
turn_restrictions,
conditional_turn_restrictions,
turn_lane_map);
auto number_of_node_based_nodes = graph_size.first;
@@ -190,7 +192,9 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
return 0;
}
std::tuple<guidance::LaneDescriptionMap, std::vector<TurnRestriction>>
std::tuple<guidance::LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<ConditionalTurnRestriction>>
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
const unsigned number_of_threads)
{
@@ -333,7 +337,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
extraction_containers.PrepareData(scripting_environment,
config.GetPath(".osrm").string(),
config.GetPath(".osrm.restrictions").string(),
config.GetPath(".osrm.names").string());
auto profile_properties = scripting_environment.GetProfileProperties();
@@ -344,7 +347,8 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
return std::make_tuple(std::move(turn_lane_map),
std::move(extraction_containers.unconditional_turn_restrictions));
std::move(extraction_containers.unconditional_turn_restrictions),
std::move(extraction_containers.conditional_turn_restrictions));
}
void Extractor::FindComponents(unsigned max_edge_id,
@@ -440,41 +444,45 @@ Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barriers,
/**
\brief Building an edge-expanded graph from node-based input and turn restrictions
*/
std::pair<std::size_t, EdgeID>
Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
std::vector<util::Coordinate> &coordinates,
extractor::PackedOSMIDs &osm_node_ids,
EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
const std::string &intersection_class_output_file,
std::vector<TurnRestriction> &turn_restrictions,
guidance::LaneDescriptionMap &turn_lane_map)
std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
ScriptingEnvironment &scripting_environment,
std::vector<util::Coordinate> &coordinates,
extractor::PackedOSMIDs &osm_node_ids,
EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
const std::string &intersection_class_output_file,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
guidance::LaneDescriptionMap &turn_lane_map)
{
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::unordered_set<NodeID> traffic_signals;
auto node_based_graph =
LoadNodeBasedGraph(barrier_nodes, traffic_lights, coordinates, osm_node_ids);
LoadNodeBasedGraph(barrier_nodes, traffic_signals, coordinates, osm_node_ids);
CompressedEdgeContainer compressed_edge_container;
GraphCompressor graph_compressor;
graph_compressor.Compress(barrier_nodes,
traffic_lights,
traffic_signals,
scripting_environment,
turn_restrictions,
conditional_turn_restrictions,
*node_based_graph,
compressed_edge_container);
turn_restrictions = removeInvalidRestrictions(std::move(turn_restrictions), *node_based_graph);
conditional_turn_restrictions =
removeInvalidRestrictions(std::move(conditional_turn_restrictions), *node_based_graph);
util::NameTable name_table(config.GetPath(".osrm.names").string());
EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph,
compressed_edge_container,
barrier_nodes,
traffic_lights,
traffic_signals,
coordinates,
osm_node_ids,
scripting_environment.GetProfileProperties(),
@@ -483,8 +491,20 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
const auto create_edge_based_edges = [&]() {
// scoped to relase intermediate datastructures right after the call
RestrictionMap via_node_restriction_map(turn_restrictions);
WayRestrictionMap via_way_restriction_map(turn_restrictions);
std::vector<TurnRestriction> node_restrictions;
for (auto const &t : turn_restrictions)
if (t.Type() == RestrictionType::NODE_RESTRICTION)
node_restrictions.push_back(t);
std::vector<ConditionalTurnRestriction> conditional_node_restrictions;
for (auto const &t : conditional_turn_restrictions)
if (t.Type() == RestrictionType::NODE_RESTRICTION)
conditional_node_restrictions.push_back(t);
RestrictionMap via_node_restriction_map(node_restrictions, IndexNodeByFromAndVia());
WayRestrictionMap via_way_restriction_map(conditional_turn_restrictions);
ConditionalRestrictionMap conditional_node_restriction_map(conditional_node_restrictions,
IndexNodeByFromAndVia());
turn_restrictions.clear();
turn_restrictions.shrink_to_fit();
@@ -495,13 +515,14 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
config.GetPath(".osrm.turn_duration_penalties").string(),
config.GetPath(".osrm.turn_penalties_index").string(),
config.GetPath(".osrm.cnbg_to_ebg").string(),
config.GetPath(".osrm.restrictions").string(),
via_node_restriction_map,
conditional_node_restriction_map,
via_way_restriction_map);
return edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
};
const auto number_of_edge_based_nodes = create_edge_based_edges();
compressed_edge_container.PrintStatistics();
// The osrm-partition tool requires the compressed node based graph with an embedding.
+1 -1
View File
@@ -69,7 +69,7 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
}
if (result_node.traffic_lights)
{
external_memory.traffic_lights.push_back(id);
external_memory.traffic_signals.push_back(id);
}
}
+51 -11
View File
@@ -1,6 +1,8 @@
#include "extractor/graph_compressor.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/extraction_turn.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/restriction.hpp"
#include "extractor/restriction_compressor.hpp"
@@ -18,16 +20,19 @@ namespace osrm
namespace extractor
{
void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
std::vector<TurnRestriction> &turn_restrictions,
util::NodeBasedDynamicGraph &graph,
CompressedEdgeContainer &geometry_compressor)
void GraphCompressor::Compress(
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_signals,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
util::NodeBasedDynamicGraph &graph,
CompressedEdgeContainer &geometry_compressor)
{
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
RestrictionCompressor restriction_compressor(turn_restrictions);
RestrictionCompressor restriction_compressor(turn_restrictions, conditional_turn_restrictions);
// we do not compress turn restrictions on degree two nodes. These nodes are usually used to
// indicated `directed` barriers
@@ -48,8 +53,13 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
}
};
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes);
std::for_each(conditional_turn_restrictions.begin(),
conditional_turn_restrictions.end(),
remember_via_nodes);
{
const auto weight_multiplier =
scripting_environment.GetProfileProperties().GetWeightMultiplier();
util::UnbufferedLog log;
util::Percent progress(log, original_number_of_nodes);
@@ -184,13 +194,31 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
graph.GetEdgeData(reverse_e2).lane_description_id = selectLaneID(
rev_edge_data2.lane_description_id, rev_edge_data1.lane_description_id);
/*
// Do not compress edge if it crosses a traffic signal.
// This can't be done in CanCombineWith, becase we only store the
// traffic signals in the `traffic_lights` list, which EdgeData
// traffic signals in the `traffic signal` list, which EdgeData
// doesn't have access to.
const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
*/
const bool has_node_penalty = traffic_signals.find(node_v) != traffic_signals.end();
boost::optional<EdgeDuration> node_duration_penalty = boost::none;
boost::optional<EdgeWeight> node_weight_penalty = boost::none;
if (has_node_penalty)
continue;
{
// generate an artifical turn for the turn penalty generation
ExtractionTurn extraction_turn(true);
extraction_turn.source_restricted = fwd_edge_data1.restricted;
extraction_turn.target_restricted = fwd_edge_data2.restricted;
// we cannot handle this as node penalty, if it depends on turn direction
if (extraction_turn.source_restricted != extraction_turn.target_restricted)
continue;
scripting_environment.ProcessTurn(extraction_turn);
node_duration_penalty = extraction_turn.duration * 10;
node_weight_penalty = extraction_turn.weight * weight_multiplier;
}
// Get weights before graph is modified
const auto forward_weight1 = fwd_edge_data1.weight;
@@ -217,6 +245,14 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
graph.GetEdgeData(forward_e1).duration += forward_duration2;
graph.GetEdgeData(reverse_e1).duration += reverse_duration2;
if (node_weight_penalty && node_duration_penalty)
{
graph.GetEdgeData(forward_e1).weight += *node_weight_penalty;
graph.GetEdgeData(reverse_e1).weight += *node_weight_penalty;
graph.GetEdgeData(forward_e1).duration += *node_duration_penalty;
graph.GetEdgeData(reverse_e1).duration += *node_duration_penalty;
}
// extend e1's to targets of e2's
graph.SetTarget(forward_e1, node_w);
graph.SetTarget(reverse_e1, node_u);
@@ -236,7 +272,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
forward_weight1,
forward_weight2,
forward_duration1,
forward_duration2);
forward_duration2,
node_weight_penalty,
node_duration_penalty);
geometry_compressor.CompressEdge(reverse_e1,
reverse_e2,
node_v,
@@ -244,7 +282,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
reverse_weight1,
reverse_weight2,
reverse_duration1,
reverse_duration2);
reverse_duration2,
node_weight_penalty,
node_duration_penalty);
}
}
}
@@ -122,15 +122,6 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
// coordinate set to add a small level of fault tolerance
const constexpr double skipping_inaccuracies_distance = 2;
// fallback, mostly necessary for dead ends
if (intersection_node == to_node)
{
const auto result = ExtractCoordinateAtLength(skipping_inaccuracies_distance, coordinates);
// TODO: possibly re-enable with https://github.com/Project-OSRM/osrm-backend/issues/3470
// BOOST_ASSERT(not_same_as_start(result));
return result;
}
const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge);
// roundabouts, check early to avoid other costly checks
@@ -377,14 +368,14 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
* destination lanes and the ones that performa a larger turn.
*/
coordinates = TrimCoordinatesToLength(
std::move(coordinates), 2 * skipping_inaccuracies_distance, segment_distances);
std::move(coordinates), 3 * skipping_inaccuracies_distance, segment_distances);
BOOST_ASSERT(coordinates.size() >= 2);
segment_distances.resize(coordinates.size());
segment_distances.back() = util::coordinate_calculation::haversineDistance(
*(coordinates.end() - 2), coordinates.back());
const auto vector_head = coordinates.back();
coordinates = TrimCoordinatesToLength(
std::move(coordinates), skipping_inaccuracies_distance, segment_distances);
std::move(coordinates), 2 * skipping_inaccuracies_distance, segment_distances);
BOOST_ASSERT(coordinates.size() >= 2);
const auto result =
GetCorrectedCoordinate(turn_coordinate, coordinates.back(), vector_head);
@@ -236,8 +236,25 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
{
const auto node_at_intersection = node_based_graph.GetTarget(entering_via_edge);
// check if there is a single valid turn entering the current intersection
const auto only_valid_turn = GetOnlyAllowedTurnIfExistent(previous_node, node_at_intersection);
// 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();
@@ -258,12 +275,14 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
const auto is_restricted = [&](const NodeID destination) {
// check if we have a dedicated destination
if (only_valid_turn && *only_valid_turn != destination)
return true;
if (only_valid_turn)
return *only_valid_turn != destination;
// not explicitly forbidden
return restriction_map.CheckIfTurnIsRestricted(
previous_node, node_at_intersection, 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) {
@@ -396,21 +415,6 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
return intersection_view;
}
boost::optional<NodeID>
IntersectionGenerator::GetOnlyAllowedTurnIfExistent(const NodeID coming_from_node,
const NodeID node_at_intersection) const
{
// If only restrictions refer to invalid ways somewhere far away, we rather ignore the
// restriction than to not route over the intersection at all.
const auto only_restriction_to_node =
restriction_map.CheckForEmanatingIsOnlyTurn(coming_from_node, node_at_intersection);
if (only_restriction_to_node != SPECIAL_NODEID)
return only_restriction_to_node;
// Ignore broken only restrictions.
return boost::none;
}
const CoordinateExtractor &IntersectionGenerator::GetCoordinateExtractor() const
{
return coordinate_extractor;
+51 -3
View File
@@ -263,8 +263,9 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
if (!allSameMode(source_edge_id, sliproad.eid, find_valid(target_intersection)->eid))
continue;
// Constrain the Sliproad's target to sliproad, outgoing, incoming from main intersection
if (target_intersection.size() != 3)
// Constrain the sliproad's target intersection to 1 or 2 sliproads, outgoing road
// and incoming one from the main intersection
if (target_intersection.size() < 3 || target_intersection.size() > 4)
{
continue;
}
@@ -279,6 +280,51 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
continue;
}
if (target_intersection.size() == 4)
{
// Handle target intersections at `d` with 4 roads
//
// | `main_road_intersection` is intersection at `c`
// v
// a ... b .... c .... e <- fo
// ` . '
// ` . '
// ` . '
// d < `target_intersection` is intersection at `d`
// |
// Conditions for road `bd` to be a sliproad:
// - target_intersection at `d` has 4 roads
// - main_road_intersection at `c` has at least 3 roads
// - target nodes of `db` and `cd` roads is the same node `d`
// - target nodes of `ce` and `de` roads is the same node `e`
// - angle `bde` is sharp
// Check `c` has at least 3 roads at `c` and roads `bd` and `cd` share the node `d`
if (main_road_intersection->intersection.size() < 3 ||
sliproad_edge_target != node_based_graph.GetTarget(crossing_road.eid))
{
continue;
}
// Find a road at `d` that shares the same node `e` with `ce` and ∠ `bde` is sharp
auto next_to_crossing_idx =
is_left_sliproad_turn ? main_road_intersection->intersection.size() - 2 : 2;
auto next_to_crossing_road = main_road_intersection->intersection[next_to_crossing_idx];
auto next_to_crossing_node = node_based_graph.GetTarget(next_to_crossing_road.eid);
auto found_common_node = std::find_if(
begin(target_intersection), end(target_intersection), [&](const auto &road) {
if (next_to_crossing_node == node_based_graph.GetTarget(road.eid))
{
auto direction = getTurnDirection(road.angle);
return direction == DirectionModifier::SharpRight ||
direction == DirectionModifier::SharpLeft;
}
return false;
});
if (found_common_node == target_intersection.end())
continue;
}
// If the sliproad candidate is a through street, we cannot handle it as a sliproad.
if (isThroughStreet(sliproad_edge, target_intersection))
{
@@ -386,7 +432,9 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
continue;
}
if (deviation_from_straight > perpendicular_angle)
// Check sliproads with skew main intersections
if (deviation_from_straight > perpendicular_angle &&
!node_based_graph.GetEdgeData(sliproad.eid).road_classification.IsLinkClass())
{
continue;
}
+8 -6
View File
@@ -391,6 +391,7 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
{
assignTrivialTurns(via_edge, intersection, 1, intersection.size());
}
return intersection;
}
@@ -744,7 +745,7 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
right.instruction = {right_type, DirectionModifier::Right};
return;
}
// Two Right Turns
// Two Left Turns
if (angularDeviation(left.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
{
// Keep left perfect, shift right
@@ -773,17 +774,18 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
return;
}
if (getTurnDirection(left.angle) == DirectionModifier::Right)
// turn to the right
if (getTurnDirection(left.angle) <= 180)
{
if (angularDeviation(left.angle, 85) >= angularDeviation(right.angle, 85))
{
left.instruction = {left_type, DirectionModifier::Right};
right.instruction = {right_type, DirectionModifier::SharpRight};
left.instruction = {left_type, DirectionModifier::SlightRight};
right.instruction = {right_type, DirectionModifier::Right};
}
else
{
left.instruction = {left_type, DirectionModifier::SlightRight};
right.instruction = {right_type, DirectionModifier::Right};
left.instruction = {left_type, DirectionModifier::Right};
right.instruction = {right_type, DirectionModifier::SharpRight};
}
}
else
+6 -1
View File
@@ -10,7 +10,9 @@ namespace osrm
namespace extractor
{
RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restrictions)
RestrictionCompressor::RestrictionCompressor(
std::vector<TurnRestriction> &restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
{
// add a node restriction ptr to the starts/ends maps, needs to be a reference!
auto index = [&](auto &element) {
@@ -35,6 +37,9 @@ RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restr
// add all restrictions as their respective startend pointers
std::for_each(restrictions.begin(), restrictions.end(), index_starts_and_ends);
std::for_each(conditional_turn_restrictions.begin(),
conditional_turn_restrictions.end(),
index_starts_and_ends);
}
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
+2 -2
View File
@@ -10,8 +10,8 @@ namespace osrm
namespace extractor
{
std::vector<TurnRestriction>
removeInvalidRestrictions(std::vector<TurnRestriction> restrictions,
std::vector<ConditionalTurnRestriction>
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction> restrictions,
const util::NodeBasedDynamicGraph &node_based_graph)
{
// definition of what we presume to be a valid via-node restriction
-138
View File
@@ -1,138 +0,0 @@
#include "extractor/restriction_map.hpp"
#include <boost/assert.hpp>
namespace osrm
{
namespace extractor
{
RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list) : m_count(0)
{
// decompose restriction consisting of a start, via and end node into a
// a pair of starting edge and a list of all end nodes
for (auto &restriction : restriction_list)
{
// only handle node restrictions here
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
continue;
const auto &node_restriction = restriction.AsNodeRestriction();
BOOST_ASSERT(node_restriction.Valid());
// This downcasting is OK because when this is called, the node IDs have been
// renumbered into internal values, which should be well under 2^32
// This will be a problem if we have more than 2^32 actual restrictions
BOOST_ASSERT(node_restriction.from < std::numeric_limits<NodeID>::max());
BOOST_ASSERT(node_restriction.via < std::numeric_limits<NodeID>::max());
m_restriction_start_nodes.insert(node_restriction.from);
m_no_turn_via_node_set.insert(node_restriction.via);
// This explicit downcasting is also OK for the same reason.
RestrictionSource restriction_source = {static_cast<NodeID>(node_restriction.from),
static_cast<NodeID>(node_restriction.via)};
std::size_t index;
auto restriction_iter = m_restriction_map.find(restriction_source);
if (restriction_iter == m_restriction_map.end())
{
index = m_restriction_bucket_list.size();
m_restriction_bucket_list.resize(index + 1);
m_restriction_map.emplace(restriction_source, index);
}
else
{
index = restriction_iter->second;
// Map already contains an is_only_*-restriction
if (m_restriction_bucket_list.at(index).begin()->is_only)
{
continue;
}
else if (restriction.is_only)
{
// We are going to insert an is_only_*-restriction. There can be only one.
m_count -= m_restriction_bucket_list.at(index).size();
m_restriction_bucket_list.at(index).clear();
}
}
++m_count;
m_restriction_bucket_list.at(index).emplace_back(node_restriction.to, restriction.is_only);
}
}
bool RestrictionMap::IsViaNode(const NodeID node) const
{
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
}
// Check if edge (u, v) is the start of any turn restriction.
// If so returns id of first target node.
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
if (!IsSourceNode(node_u))
{
return SPECIAL_NODEID;
}
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
if (restriction_iter != m_restriction_map.end())
{
const unsigned index = restriction_iter->second;
const auto &bucket = m_restriction_bucket_list.at(index);
for (const RestrictionTarget &restriction_target : bucket)
{
if (restriction_target.is_only)
{
return restriction_target.target_node;
}
}
}
return SPECIAL_NODEID;
}
// Checks if turn <u,v,w> is actually a turn restriction.
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
const NodeID node_v,
const NodeID node_w) const
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
BOOST_ASSERT(node_w != SPECIAL_NODEID);
if (!IsSourceNode(node_u))
{
return false;
}
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
if (restriction_iter == m_restriction_map.end())
{
return false;
}
const unsigned index = restriction_iter->second;
const auto &bucket = m_restriction_bucket_list.at(index);
for (const RestrictionTarget &restriction_target : bucket)
{
if (node_w == restriction_target.target_node && // target found
!restriction_target.is_only) // and not an only_-restr.
{
return true;
}
// We could be tempted to check for `only` restrictions here as well. However, that check is
// actually perfomed in intersection generation where we can also verify if the only
// restriction is valid at all.
}
return false;
}
// check of node is the start of any restriction
bool RestrictionMap::IsSourceNode(const NodeID node) const
{
return m_restriction_start_nodes.find(node) != m_restriction_start_nodes.end();
}
}
}
+6 -2
View File
@@ -396,8 +396,12 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
"target_restricted",
&ExtractionTurn::target_restricted);
// Keep in mind .location is undefined since we're not using libosmium's location cache
context.state.new_usertype<osmium::NodeRef>("NodeRef", "id", &osmium::NodeRef::ref);
// Keep in mind .location is available only if .pbf is preprocessed to set the location with the
// ref using osmium command "osmium add-locations-to-ways"
context.state.new_usertype<osmium::NodeRef>(
"NodeRef", "id", &osmium::NodeRef::ref, "location", [](const osmium::NodeRef &nref) {
return nref.location();
});
context.state.new_usertype<InternalExtractorEdge>("EdgeSource",
"source_coordinate",
+102 -34
View File
@@ -1,6 +1,7 @@
#include "extractor/way_restriction_map.hpp"
#include "util/for_each_pair.hpp"
#include <functional>
#include <iterator>
#include <tuple>
#include <utility>
@@ -28,12 +29,46 @@ struct FindViaWay
}
};
} // namespace
WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions)
template <typename restriction_type> auto asDuplicatedNode(const restriction_type &restriction)
{
// get all way restrictions
const auto extract_restrictions = [this](const auto &turn_restriction) {
auto &way = restriction.AsWayRestriction();
// group restrictions by the via-way. On same via-ways group by from
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
};
template <typename restriction_type> struct CompareByDuplicatedNode
{
bool operator()(const ConditionalTurnRestriction &lhs, const ConditionalTurnRestriction &rhs)
{
if (asDuplicatedNode(lhs) < asDuplicatedNode(rhs))
{
return true;
}
else if (asDuplicatedNode(rhs) < asDuplicatedNode(lhs))
{
return false;
}
else
{
const auto lhs_to = lhs.AsWayRestriction().out_restriction.to;
const auto rhs_to = rhs.AsWayRestriction().out_restriction.to;
const bool has_conditions_lhs = !lhs.condition.empty();
const bool has_conditions_rhs = !rhs.condition.empty();
return std::tie(lhs_to, lhs.is_only, has_conditions_lhs) <
std::tie(rhs_to, rhs.is_only, has_conditions_rhs);
}
}
};
template <typename restriction_type>
std::vector<restriction_type>
extractRestrictions(const std::vector<restriction_type> &turn_restrictions)
{
std::vector<restriction_type> result;
for (const auto &turn_restriction : turn_restrictions)
{
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
{
const auto &way = turn_restriction.AsWayRestriction();
@@ -41,32 +76,32 @@ WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_re
// so far we can only handle restrictions that are not interrupted
if (way.in_restriction.via == way.out_restriction.from &&
way.in_restriction.to == way.out_restriction.via)
restriction_data.push_back(turn_restriction);
result.push_back(turn_restriction);
}
};
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), extract_restrictions);
}
std::sort(result.begin(), result.end(), CompareByDuplicatedNode<restriction_type>());
auto new_end = std::unique(result.begin(), result.end());
result.erase(new_end, result.end());
return result;
}
const auto as_duplicated_node = [](auto const &restriction) {
auto &way = restriction.AsWayRestriction();
// group restrictions by the via-way. On same via-ways group by from
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
};
const auto by_duplicated_node = [&](auto const &lhs, auto const &rhs) {
return as_duplicated_node(lhs) < as_duplicated_node(rhs);
};
std::sort(restriction_data.begin(), restriction_data.end(), by_duplicated_node);
// map all way restrictions into access containers
for (RestrictionID index = 0; index < restriction_data.size(); ++index)
template <typename restriction_type> struct ByInFromAndVia
{
std::pair<NodeID, NodeID> operator()(const restriction_type &restriction)
{
const auto &restriction = restriction_data[index];
const auto &way = restriction.AsWayRestriction();
restriction_starts.insert(
std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), index));
};
return std::make_pair(way.in_restriction.from, way.in_restriction.via);
}
};
} // namespace
// get all way restrictions
WayRestrictionMap::WayRestrictionMap(
const std::vector<ConditionalTurnRestriction> &turn_restrictions_)
: restriction_data(extractRestrictions(turn_restrictions_)),
restriction_starts(restriction_data, ByInFromAndVia<ConditionalTurnRestriction>())
{
std::size_t offset = 1;
// the first group starts at 0
if (!restriction_data.empty())
@@ -74,8 +109,10 @@ WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_re
auto const add_offset_on_new_groups = [&](auto const &lhs, auto const &rhs) {
BOOST_ASSERT(rhs == restriction_data[offset]);
BOOST_ASSERT(lhs.Type() == RestrictionType::WAY_RESTRICTION);
BOOST_ASSERT(rhs.Type() == RestrictionType::WAY_RESTRICTION);
// add a new lower bound for rhs
if (as_duplicated_node(lhs) != as_duplicated_node(rhs))
if (asDuplicatedNode(lhs) != asDuplicatedNode(rhs))
duplicated_node_groups.push_back(offset);
++offset;
};
@@ -115,7 +152,7 @@ DuplicatedNodeID WayRestrictionMap::AsDuplicatedNodeID(const RestrictionID restr
return distance_to_upper_bound - 1;
}
util::range<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
std::vector<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
const NodeID to) const
{
const auto duplicated_node_range_itr = std::equal_range(
@@ -125,9 +162,13 @@ util::range<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID
return std::distance(restriction_data.begin(), itr);
};
return util::irange<DuplicatedNodeID>(
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first)),
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second)));
auto first = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first));
auto end = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second));
std::vector<DuplicatedNodeID> result(end - first);
std::iota(result.begin(), result.end(), first);
return result;
}
bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const
@@ -138,6 +179,7 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
restriction_index != duplicated_node_groups[duplicated_node + 1];
++restriction_index)
{
BOOST_ASSERT(restriction_index < restriction_data.size());
const auto &restriction = restriction_data[restriction_index];
const auto &way = restriction.AsWayRestriction();
@@ -149,6 +191,32 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
return false;
}
ConditionalTurnRestriction const &
WayRestrictionMap::GetRestriction(DuplicatedNodeID duplicated_node, const NodeID to) const
{
// loop over all restrictions associated with the node. Mark as restricted based on
// is_only/restricted targets
for (RestrictionID restriction_index = duplicated_node_groups[duplicated_node];
restriction_index != duplicated_node_groups[duplicated_node + 1];
++restriction_index)
{
BOOST_ASSERT(restriction_index < restriction_data.size());
const auto &restriction = restriction_data[restriction_index];
const auto &way = restriction.AsWayRestriction();
if (restriction.is_only && (way.out_restriction.to != to))
{
return restriction;
}
else if (!restriction.is_only && (to == way.out_restriction.to))
{
return restriction;
}
}
throw("Asking for the restriction of an unrestricted turn. Check with `IsRestricted` before "
"calling GetRestriction");
}
std::vector<WayRestrictionMap::ViaWay> WayRestrictionMap::DuplicatedNodeRepresentatives() const
{
std::vector<ViaWay> result;
@@ -169,19 +237,19 @@ NodeID WayRestrictionMap::RemapIfRestricted(const NodeID edge_based_node,
const NodeID node_based_to,
const NodeID number_of_edge_based_nodes) const
{
auto range = restriction_starts.equal_range(std::make_pair(node_based_from, node_based_via));
auto range = restriction_starts.Restrictions(node_based_from, node_based_via);
// returns true if the ID saved in an iterator belongs to a turn restriction that references
// node_based_to as destination of the `in_restriction`
const auto restriction_targets_to = [node_based_to, this](const auto &pair) {
return restriction_data[pair.second].AsWayRestriction().in_restriction.to == node_based_to;
return pair.second->AsWayRestriction().in_restriction.to == node_based_to;
};
const auto itr = std::find_if(range.first, range.second, restriction_targets_to);
// in case we found a matching restriction, we can remap the edge_based_node
if (itr != range.second)
return number_of_edge_based_nodes - NumberOfDuplicatedNodes() +
AsDuplicatedNodeID(itr->second);
AsDuplicatedNodeID(itr->second - &restriction_data[0]);
else
return edge_based_node;
}
+13 -1
View File
@@ -36,7 +36,19 @@ SegmentLookupTable readSegmentValues(const std::vector<std::string> &paths)
CSVFilesParser<Segment, SpeedSource> parser(
1, qi::ulong_long >> ',' >> qi::ulong_long, qi::uint_ >> -(',' >> qi::double_));
return parser(paths);
// Check consistency of keys in the result lookup table
auto result = parser(paths);
const auto found_inconsistency =
std::find_if(std::begin(result.lookup), std::end(result.lookup), [](const auto &entry) {
return entry.first.from == entry.first.to;
});
if (found_inconsistency != std::end(result.lookup))
{
throw util::exception("empty segment in CSV with node " +
std::to_string(found_inconsistency->first.from) + " " + SOURCE_REF);
}
return result;
}
TurnLookupTable readTurnValues(const std::vector<std::string> &paths)
+18 -79
View File
@@ -7,6 +7,7 @@
#include "extractor/node_based_edge.hpp"
#include "extractor/packed_osm_ids.hpp"
#include "extractor/restriction.hpp"
#include "extractor/serialization.hpp"
#include "storage/io.hpp"
@@ -443,20 +444,16 @@ updateTurnPenalties(const UpdaterConfig &config,
return updated_turns;
}
bool IsRestrictionValid(const Timezoner &tz_handler,
const extractor::ConditionalTurnRestriction &turn,
const std::vector<util::Coordinate> &coordinates)
bool IsRestrictionValid(const Timezoner &tz_handler, const extractor::ConditionalTurnPenalty &turn)
{
BOOST_ASSERT(!turn.condition.empty());
BOOST_ASSERT(!turn.conditions.empty());
// we utilize the via node (first on ways) to represent the turn restriction
auto const via = turn.Type() == extractor::RestrictionType::WAY_RESTRICTION
? turn.AsWayRestriction().in_restriction.to
: turn.AsNodeRestriction().via;
auto const via = turn.location;
const auto lon = static_cast<double>(toFloating(coordinates[via].lon));
const auto lat = static_cast<double>(toFloating(coordinates[via].lat));
const auto &condition = turn.condition;
const auto lon = static_cast<double>(toFloating(via.lon));
const auto lat = static_cast<double>(toFloating(via.lat));
const auto &conditions = turn.conditions;
// Get local time of the restriction
const auto &local_time = tz_handler(point_t{lon, lat});
@@ -469,85 +466,27 @@ bool IsRestrictionValid(const Timezoner &tz_handler,
// TODO: parsing will fail for combined conditions, e.g. Sa-Su AND weight>7
// http://wiki.openstreetmap.org/wiki/Conditional_restrictions#Combined_conditions:_AND
if (osrm::util::CheckOpeningHours(condition, *local_time))
return true;
return false;
return osrm::util::CheckOpeningHours(conditions, *local_time);
}
std::vector<std::uint64_t>
updateConditionalTurns(const UpdaterConfig &config,
std::vector<TurnPenalty> &turn_weight_penalties,
const std::vector<extractor::ConditionalTurnRestriction> &conditional_turns,
std::vector<util::Coordinate> &coordinates,
updateConditionalTurns(std::vector<TurnPenalty> &turn_weight_penalties,
const std::vector<extractor::ConditionalTurnPenalty> &conditional_turns,
Timezoner time_zone_handler)
{
// Mapped file pointer for turn indices
boost::iostreams::mapped_file_source turn_index_region;
auto turn_index_blocks = util::mmapFile<extractor::lookup::TurnIndexBlock>(
config.GetPath(".osrm.turn_penalties_index"), turn_index_region);
std::vector<std::uint64_t> updated_turns;
if (conditional_turns.size() == 0)
return updated_turns;
// TODO make this into a function
LookupTable<std::tuple<NodeID, NodeID>, NodeID> is_only_lookup;
std::unordered_set<std::tuple<NodeID, NodeID, NodeID>,
std::hash<std::tuple<NodeID, NodeID, NodeID>>>
is_no_set;
for (const auto &node_or_way : conditional_turns)
for (const auto &penalty : conditional_turns)
{
// TODO handle conditional turn restrictions for via-ways (look-up doesn't work here)
// https://github.com/Project-OSRM/osrm-backend/issues/2681#issuecomment-313376385
if (node_or_way.Type() == extractor::RestrictionType::WAY_RESTRICTION)
continue;
if (!IsRestrictionValid(time_zone_handler, node_or_way, coordinates))
continue;
// TODO get rid of this, when we can handle way restrictions
const auto &c = node_or_way.AsNodeRestriction();
// only add restrictions to the lookups if the restriction is valid now
if (node_or_way.is_only)
if (IsRestrictionValid(time_zone_handler, penalty))
{
is_only_lookup.lookup.push_back({std::make_tuple(c.from, c.via), c.to});
}
else
{
is_no_set.insert({std::make_tuple(c.from, c.via, c.to)});
std::cout << "Disabling: " << penalty.turn_offset << std::endl;
turn_weight_penalties[penalty.turn_offset] = INVALID_TURN_PENALTY;
updated_turns.push_back(penalty.turn_offset);
}
}
for (std::uint64_t edge_index = 0; edge_index < turn_weight_penalties.size(); ++edge_index)
{
const extractor::lookup::TurnIndexBlock internal_turn = turn_index_blocks[edge_index];
const auto is_no_tuple =
std::make_tuple(internal_turn.from_id, internal_turn.via_id, internal_turn.to_id);
const auto is_only_tuple = std::make_tuple(internal_turn.from_id, internal_turn.via_id);
// turn has a no_* restriction
if (is_no_set.find(is_no_tuple) != is_no_set.end())
{
util::Log(logDEBUG) << "Conditional penalty set on edge: " << edge_index;
turn_weight_penalties[edge_index] = INVALID_TURN_PENALTY;
updated_turns.push_back(edge_index);
}
// turn has an only_* restriction
else if (is_only_lookup(is_only_tuple))
{
// with only_* restrictions, the turn on which the restriction is tagged is valid
if (*is_only_lookup(is_only_tuple) == internal_turn.to_id)
continue;
util::Log(logDEBUG) << "Conditional penalty set on edge: " << edge_index;
turn_weight_penalties[edge_index] = INVALID_TURN_PENALTY;
updated_turns.push_back(edge_index);
}
}
return updated_turns;
}
}
@@ -638,7 +577,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
load_profile_properties);
}
std::vector<extractor::ConditionalTurnRestriction> conditional_turns;
std::vector<extractor::ConditionalTurnPenalty> conditional_turns;
if (update_conditional_turns)
{
using storage::io::FileReader;
@@ -696,8 +635,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
}
const Timezoner time_zone_handler = Timezoner(config.tz_file_path, config.valid_now);
auto updated_turn_penalties = updateConditionalTurns(
config, turn_weight_penalties, conditional_turns, coordinates, time_zone_handler);
auto updated_turn_penalties =
updateConditionalTurns(turn_weight_penalties, conditional_turns, time_zone_handler);
const auto offset = updated_segments.size();
updated_segments.resize(offset + updated_turn_penalties.size());
// we need to re-compute all edges that have updated turn penalties.
+2 -2
View File
@@ -11,7 +11,7 @@ namespace util
//----------------------------------------------------------------
NodeIdVectorToLineString::NodeIdVectorToLineString(
const std::vector<extractor::QueryNode> &node_coordinates)
const std::vector<util::Coordinate> &node_coordinates)
: node_coordinates(node_coordinates)
{
}
@@ -32,7 +32,7 @@ operator()(const std::vector<NodeID> &node_ids,
//----------------------------------------------------------------
NodeIdVectorToMultiPoint::NodeIdVectorToMultiPoint(
const std::vector<extractor::QueryNode> &node_coordinates)
const std::vector<util::Coordinate> &node_coordinates)
: node_coordinates(node_coordinates)
{
}
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956],
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
exports.test_tile = {'at': [17059, 11948, 15], 'size': 162422};
exports.test_tile = {'at': [17059, 11948, 15], 'size': 162429};
// Test files generated by the routing engine; check test/data
+429
View File
@@ -0,0 +1,429 @@
#include "engine/routing_algorithms/routing_base_mld.hpp"
#include "engine/routing_algorithms/shortest_path_impl.hpp"
#include "engine/search_engine_data.hpp"
#include "util/integer_range.hpp"
#include <boost/test/unit_test.hpp>
namespace osrm
{
namespace engine
{
namespace routing_algorithms
{
// Declare offline data facade algorithm
namespace offline
{
struct Algorithm final
{
};
}
} // routing_algorithms
// Define engine data for offline data facade
template <> struct SearchEngineData<routing_algorithms::offline::Algorithm>
{
using QueryHeap = SearchEngineData<routing_algorithms::mld::Algorithm>::QueryHeap;
using SearchEngineHeapPtr = std::unique_ptr<QueryHeap>;
SearchEngineHeapPtr forward_heap_1;
SearchEngineHeapPtr reverse_heap_1;
void InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes)
{
if (forward_heap_1.get())
{
forward_heap_1->Clear();
}
else
{
forward_heap_1.reset(new QueryHeap(number_of_nodes));
}
if (reverse_heap_1.get())
{
reverse_heap_1->Clear();
}
else
{
reverse_heap_1.reset(new QueryHeap(number_of_nodes));
}
}
};
// Define offline multilevel partition
namespace datafacade
{
struct ExternalMultiLevelPartition
{
CellID GetCell(LevelID /*l*/, NodeID /*node*/) const { return 0; }
LevelID GetQueryLevel(NodeID /*start*/, NodeID /*target*/, NodeID /*node*/) const { return 0; }
LevelID GetHighestDifferentLevel(NodeID /*first*/, NodeID /*second*/) const { return 0; }
std::uint8_t GetNumberOfLevels() const { return 0; }
std::uint32_t GetNumberOfCells(LevelID /*level*/) const { return 0; }
CellID BeginChildren(LevelID /*level*/, CellID /*cell*/) const { return 0; }
CellID EndChildren(LevelID /*level*/, CellID /*cell*/) const { return 0; }
};
// Define external cell storage
struct ExternalCellStorage
{
struct CellImpl
{
auto GetOutWeight(NodeID /*node*/) const
{
return boost::make_iterator_range((EdgeWeight *)0, (EdgeWeight *)0);
}
auto GetInWeight(NodeID /*node*/) const
{
return boost::make_iterator_range((EdgeWeight *)0, (EdgeWeight *)0);
}
auto GetSourceNodes() const
{
return boost::make_iterator_range((EdgeWeight *)0, (EdgeWeight *)0);
}
auto GetDestinationNodes() const
{
return boost::make_iterator_range((EdgeWeight *)0, (EdgeWeight *)0);
}
};
using Cell = CellImpl;
using ConstCell = const CellImpl;
ConstCell GetCell(LevelID /*level*/, CellID /*id*/) const { return Cell{}; }
Cell GetCell(LevelID /*level*/, CellID /*id*/) { return Cell{}; }
};
// Define external data facade
template <>
class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm> final
: public BaseDataFacade
{
ExternalMultiLevelPartition external_partition;
ExternalCellStorage external_cell_storage;
public:
using EdgeData = extractor::EdgeBasedEdge::EdgeData;
// using RTreeLeaf = extractor::EdgeBasedNode;
ContiguousInternalMemoryDataFacade() {}
~ContiguousInternalMemoryDataFacade() {}
unsigned GetNumberOfNodes() const { return 0; }
NodeID GetTarget(const EdgeID /*edgeID*/) const { return 0; }
const EdgeData &GetEdgeData(const EdgeID /*edgeID*/) const
{
static EdgeData outData;
return outData;
}
const auto &GetMultiLevelPartition() const { return external_partition; }
const auto &GetCellStorage() const { return external_cell_storage; }
auto GetBorderEdgeRange(const LevelID /*level*/, const NodeID /*node*/) const
{
return util::irange<EdgeID>(0, 0);
}
EdgeID FindEdge(const NodeID /*from*/, const NodeID /*to*/) const { return SPECIAL_EDGEID; }
unsigned GetCheckSum() const override { return 0; }
// node and edge information access
util::Coordinate GetCoordinateOfNode(const NodeID /*id*/) const override
{
return {osrm::util::FloatLongitude{7.437069}, osrm::util::FloatLatitude{43.749249}};
}
OSMNodeID GetOSMNodeIDOfNode(const NodeID /*id*/) const override { return OSMNodeID(); }
GeometryID GetGeometryIndex(const NodeID /*id*/) const override { return GeometryID{0, false}; }
std::vector<NodeID> GetUncompressedForwardGeometry(const EdgeID /*id*/) const override
{
return {};
}
std::vector<NodeID> GetUncompressedReverseGeometry(const EdgeID /*id*/) const override
{
return {};
}
TurnPenalty GetWeightPenaltyForEdgeID(const unsigned /*id*/) const override
{
return INVALID_TURN_PENALTY;
}
TurnPenalty GetDurationPenaltyForEdgeID(const unsigned /*id*/) const override
{
return INVALID_TURN_PENALTY;
}
std::vector<EdgeWeight> GetUncompressedForwardWeights(const EdgeID /*id*/) const override
{
return {};
}
std::vector<EdgeWeight> GetUncompressedReverseWeights(const EdgeID /*id*/) const override
{
return {};
}
std::vector<EdgeWeight> GetUncompressedForwardDurations(const EdgeID /*geomID*/) const override
{
return {};
}
std::vector<EdgeWeight> GetUncompressedReverseDurations(const EdgeID /*geomID*/) const override
{
return {};
}
std::vector<DatasourceID> GetUncompressedForwardDatasources(const EdgeID /*id*/) const override
{
return {};
}
std::vector<DatasourceID> GetUncompressedReverseDatasources(const EdgeID /*id*/) const override
{
return {};
}
StringView GetDatasourceName(const DatasourceID /*id*/) const override { return StringView{}; }
extractor::guidance::TurnInstruction
GetTurnInstructionForEdgeID(const EdgeID /*id*/) const override
{
return extractor::guidance::TurnInstruction{};
}
extractor::TravelMode GetTravelMode(const NodeID /*id*/) const override
{
return TRAVEL_MODE_DRIVING;
}
std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate /*south_west*/,
const util::Coordinate /*north_east*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/,
const Approach /*approach*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const Approach /*approach*/) const override
{
return {};
}
std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
const unsigned /*max_results*/,
const double /*max_distance*/,
const Approach /*approach*/) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const Approach /*approach*/) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const Approach /*approach*/) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
{
return {};
}
util::guidance::LaneTupleIdPair GetLaneData(const EdgeID /*id*/) const override
{
return util::guidance::LaneTupleIdPair{};
}
extractor::guidance::TurnLaneDescription
GetTurnDescription(const LaneDescriptionID /*laneDescriptionID*/) const override
{
return {};
}
bool HasLaneData(const EdgeID /*id*/) const override { return false; }
NameID GetNameIndex(const NodeID /*nodeID*/) const { return EMPTY_NAMEID; }
StringView GetNameForID(const NameID /*id*/) const override { return StringView{}; }
StringView GetRefForID(const NameID /*id*/) const override { return StringView{}; }
StringView GetPronunciationForID(const NameID /*id*/) const override { return StringView{}; }
StringView GetDestinationsForID(const NameID /*id*/) const override { return StringView{}; }
StringView GetExitsForID(const NameID /*id*/) const override { return StringView{}; }
std::string GetTimestamp() const override { return std::string(); }
bool GetContinueStraightDefault() const override { return false; }
double GetMapMatchingMaxSpeed() const override { return 0; }
const char *GetWeightName() const override { return ""; }
unsigned GetWeightPrecision() const override { return 0; }
double GetWeightMultiplier() const override { return 1; }
ComponentID GetComponentID(NodeID) const override { return ComponentID{}; }
util::guidance::TurnBearing PreTurnBearing(const EdgeID /*eid*/) const override
{
return util::guidance::TurnBearing(0);
}
util::guidance::TurnBearing PostTurnBearing(const EdgeID /*eid*/) const override
{
return util::guidance::TurnBearing(0);
}
util::guidance::BearingClass
GetBearingClass(const BearingClassID /*bearing_class_id*/) const override
{
return util::guidance::BearingClass{};
}
osrm::extractor::ClassData GetClassData(const NodeID /*id*/) const override { return 0; }
std::vector<std::string> GetClasses(const extractor::ClassData /*class_data*/) const override
{
return {};
}
util::guidance::EntryClass GetEntryClass(const EdgeID /*turn_id*/) const override { return {}; }
bool IsLeftHandDriving() const override { return false; }
};
} // datafacade
// Fallback to MLD algorithm: requires from data facade MLD specific members
namespace routing_algorithms
{
namespace offline
{
inline void search(SearchEngineData<Algorithm> &engine_working_data,
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
EdgeWeight &weight,
std::vector<NodeID> &packed_leg,
const bool force_loop_forward,
const bool force_loop_reverse,
const PhantomNodes &phantom_nodes,
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
{
mld::search(engine_working_data,
facade,
forward_heap,
reverse_heap,
weight,
packed_leg,
force_loop_forward,
force_loop_reverse,
phantom_nodes,
weight_upper_bound);
}
template <typename RandomIter, typename FacadeT>
void unpackPath(const FacadeT &facade,
RandomIter packed_path_begin,
RandomIter packed_path_end,
const PhantomNodes &phantom_nodes,
std::vector<PathData> &unpacked_path)
{
mld::unpackPath(facade, packed_path_begin, packed_path_end, phantom_nodes, unpacked_path);
}
} // offline
} // routing_algorithms
} // engine
} // osrm
BOOST_AUTO_TEST_SUITE(offline_facade)
BOOST_AUTO_TEST_CASE(shortest_path)
{
using Algorithm = osrm::engine::routing_algorithms::offline::Algorithm;
osrm::engine::SearchEngineData<Algorithm> heaps;
osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<Algorithm> facade;
std::vector<osrm::engine::PhantomNodes> phantom_nodes;
phantom_nodes.push_back({osrm::engine::PhantomNode{}, osrm::engine::PhantomNode{}});
auto route =
osrm::engine::routing_algorithms::shortestPathSearch(heaps, facade, phantom_nodes, false);
BOOST_CHECK_EQUAL(route.shortest_path_weight, INVALID_EDGE_WEIGHT);
}
BOOST_AUTO_TEST_SUITE_END()
+47 -5
View File
@@ -4,6 +4,8 @@
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include "../unit_tests/mocks/mock_scripting_environment.hpp"
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
@@ -54,7 +56,9 @@ BOOST_AUTO_TEST_CASE(long_road_test)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
MakeUnitEdge(1, 0),
@@ -70,7 +74,13 @@ BOOST_AUTO_TEST_CASE(long_road_test)
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[6].data));
Graph graph(5, edges);
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
BOOST_CHECK_EQUAL(graph.FindEdge(1, 2), SPECIAL_EDGEID);
@@ -91,7 +101,9 @@ BOOST_AUTO_TEST_CASE(loop_test)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
MakeUnitEdge(0, 5),
@@ -120,7 +132,13 @@ BOOST_AUTO_TEST_CASE(loop_test)
BOOST_ASSERT(edges[10].data.IsCompatibleTo(edges[11].data));
Graph graph(6, edges);
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK_EQUAL(graph.FindEdge(5, 0), SPECIAL_EDGEID);
BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
@@ -143,7 +161,9 @@ BOOST_AUTO_TEST_CASE(t_intersection)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
MakeUnitEdge(1, 0),
@@ -159,7 +179,13 @@ BOOST_AUTO_TEST_CASE(t_intersection)
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[5].data));
Graph graph(4, edges);
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);
@@ -176,7 +202,9 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
std::vector<InputEdge> edges = {
MakeUnitEdge(0, 1), MakeUnitEdge(1, 0), MakeUnitEdge(1, 2), MakeUnitEdge(2, 1)};
@@ -186,7 +214,13 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data));
Graph graph(5, edges);
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);
@@ -202,7 +236,9 @@ BOOST_AUTO_TEST_CASE(direction_changes)
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<ConditionalTurnRestriction> conditional_restrictions;
CompressedEdgeContainer container;
test::MockScriptingEnvironment scripting_environment;
std::vector<InputEdge> edges = {
MakeUnitEdge(0, 1), MakeUnitEdge(1, 0), MakeUnitEdge(1, 2), MakeUnitEdge(2, 1)};
@@ -210,7 +246,13 @@ BOOST_AUTO_TEST_CASE(direction_changes)
edges[1].data.reversed = true;
Graph graph(5, edges);
compressor.Compress(barrier_nodes, traffic_lights, restrictions, graph, container);
compressor.Compress(barrier_nodes,
traffic_lights,
scripting_environment,
restrictions,
conditional_restrictions,
graph,
container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID);
@@ -0,0 +1,47 @@
#ifndef MOCK_SCRIPTING_ENVIRONMENT_HPP_
#define MOCK_SCRIPTING_ENVIRONMENT_HPP_
#include "extractor/extraction_segment.hpp"
#include "extractor/extraction_turn.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/scripting_environment.hpp"
#include <string>
#include <utility>
#include <vector>
namespace osrm
{
namespace test
{
// a mock implementation of the scripting environment doing exactly nothing
class MockScriptingEnvironment : public extractor::ScriptingEnvironment
{
const extractor::ProfileProperties &GetProfileProperties() override final
{
static extractor::ProfileProperties properties;
return properties;
}
std::vector<std::string> GetNameSuffixList() override final { return {}; }
std::vector<std::string> GetRestrictions() override final { return {}; }
void ProcessTurn(extractor::ExtractionTurn &) override final {}
void ProcessSegment(extractor::ExtractionSegment &) override final {}
void ProcessElements(const osmium::memory::Buffer &,
const extractor::RestrictionParser &,
std::vector<std::pair<const osmium::Node &, extractor::ExtractionNode>> &,
std::vector<std::pair<const osmium::Way &, extractor::ExtractionWay>> &,
std::vector<extractor::InputConditionalTurnRestriction> &) override final
{
}
};
} // namespace test
} // namespace osrm
#endif // MOCK_SCRIPTING_ENVIRONMENT_HPP_
+760 -210
View File
File diff suppressed because it is too large Load Diff