Compare commits

...

57 Commits

Author SHA1 Message Date
Daniel Patterson 1a89ea2a9f Update CHANGELOG and npm version for 5.11.0-rc.3 2017-08-16 14:07:54 -07:00
Daniel Patterson c1ad275e71 Empty CSV entries (nodeA,nodeA) can be treated as non-fatal as long as we don't try to update any matching artificial segments. 2017-08-16 12:03:23 -07:00
Daniel J. Hofmann 6bae070091 Fixes changelog wrt. conditional via-way restrictions 2017-08-16 11:15:35 +02:00
Moritz Kobitzsch 3687b6cb4b respect difference between continue/turn on changing end-of-road 2017-08-16 09:19:15 +02:00
Moritz Kobitzsch 196ed9eb46 do not change fork directions when combining turns 2017-08-16 09:17:01 +02:00
Daniel Patterson 37c941dff3 Bump version for 5.11.0-rc.2 2017-08-15 12:14:13 -07:00
Daniel Patterson 40a428d49f Fix changelog - binaries weren't published for 5.10 2017-08-15 12:13:20 -07:00
Daniel Patterson 48eeef2d30 Revert "Publicly expose binaries to Node.js bindings, resolves #4377"
This reverts commit 4686272f87.

Unfortunately, this doesn't work alongside `node-pre-gyp` - in fresh installs, the binary
files are not yet downloaded when npm tries to create symlinks, leading to an error.
2017-08-15 11:55:09 -07:00
Moritz Kobitzsch c34520f3a4 add feature to test naming conventions on divided highways 2017-08-15 09:47:13 +02:00
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
103 changed files with 6193 additions and 3331 deletions
+1
View File
@@ -1,4 +1,5 @@
{
"plugins": ["transform-class-properties"],
"presets": [
"stage-0",
"es2015",
+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 -1
View File
@@ -301,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,26 @@
# 5.11.0
- Changes from 5.10:
- Features
- BREAKING: Added support for conditional via-way restrictions. 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
- Use the correct angle modifier at forks
- Issue a `continue` instead of a `turn` when an end-of-road situation (e.g. T-intersection) puts you on the same-named road
# 5.10.0
- Changes from 5.9:
- Profiles:
+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
+30 -29
View File
@@ -27,11 +27,11 @@ var osrm = new OSRM('network.osrm');
This requires you to run `osrm-datastore` prior to creating an `OSRM` object.
- `options.path` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true.
- `options.max_locations_trip` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in trip query (default: unlimited).
- `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query 9default: unlimited).
- `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query (default: unlimited).
- `options.max_locations_distance_table` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in distance table query (default: unlimited).
- `options.max_locations_map_matching` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in map matching query (default: unlimited).
- `options.max_locations_map_matching` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in map-matching query (default: unlimited).
- `options.max_results_nearest` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. results supported in nearest query (default: unlimited).
- `options.max_alternatives` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. number of alternative routes supported (default: 3).
- `options.max_alternatives` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max.number of alternatives supported in alternative routes query (default: 3).
### route
@@ -45,15 +45,16 @@ Returns the fastest route between two or more coordinates while visiting the way
Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`.
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`.
- `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings.
- `options.alternatives` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Search for alternative routes and return as well.
_Please note that even if an alternative route is requested, a result cannot be guaranteed._ (optional, default `false`)
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Returned route steps for each route leg. (optional, default `false`)
- `options.alternatives` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Search for alternative routes. (optional, default `false`)
- `options.alternatives` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Search for up to this many alternative routes.
_Please note that even if alternative routes are requested, a result cannot be guaranteed._ (optional, default `0`)
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route leg. (optional, default `false`)
- `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
- `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`)
- `options.continue_straight` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile.
`null`/`true`/`false`
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
`null`/`true`/`false`
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -194,14 +195,14 @@ if they can not be matched successfully.
- `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction.
Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`.
- `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings.
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Returned route steps for each route. (optional, default `false`)
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route. (optional, default `false`)
- `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
- `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`)
- `options.timestamps` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>?** Timestamp of the input location (integers, UNIX-like timestamp).
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`.
- `options.gaps` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore`. (optional, default `split`)
- `options.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Allows the input track modification to obtain better matching quality for noisy tracks. (optional, default `false`)
- `options.gaps` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore` (optional, default `split`).
- `options.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`).
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -235,25 +236,7 @@ The trip plugin solves the Traveling Salesman Problem using a greedy heuristic
waypoints. The returned path does not have to be the shortest path, _ as TSP is NP-hard it is
only an approximation.
**Parameters**
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query.
- `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees.
- `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction.
Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`.
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `double >= 0` or `null` (unlimited, default).
- `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings.
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Returned route steps for each route. (optional, default `false`)
- `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
- `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` (optional, default `simplified`)
- `options.roundtrip` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Returned route is a roundtrip (route returns to first location). (optional, default `true`)
- `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route starts at `any` or `first` coordinate. (optional, default `any`)
- `options.destination` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route ends at `any` or `last` coordinate. (optional, default `any`)
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
A requirement for computing trips is that all input coordinates are connected.
Note that all input coordinates have to be connected for the trip service to work.
Currently, not all combinations of `roundtrip`, `source` and `destination` are supported.
Right now, the following combinations are possible:
@@ -268,6 +251,24 @@ Right now, the following combinations are possible:
| false | any | last | no |
| false | any | any | no |
**Parameters**
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query.
- `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees.
- `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction.
Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`.
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `double >= 0` or `null` (unlimited, default).
- `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings.
- `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route. (optional, default `false`)
- `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
- `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` (optional, default `simplified`)
- `options.roundtrip` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route is a roundtrip. (optional, default `true`)
- `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route starts at `any` or `first` coordinate. (optional, default `any`)
- `options.destination` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route ends at `any` or `last` coordinate. (optional, default `any`)
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
```javascript
+2 -2
View File
@@ -47,10 +47,10 @@ We may introduce forward-compatible changes: query parameters and response prope
4. Make sure the `package.json` is up to date.
5. Make sure all tests are passing (e.g. Travis CI gives you a :thumbs_up:)
6. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries.
7. Use `npm run build-api-docs` to generate the API documentation. Copy `build/docs/*` to `https://github.com/Project-OSRM/project-osrm.github.com` in the `docs/vN.N.N/api` directory
7. Use `npm run docs` to generate the API documentation. Copy `build/docs/*` to `https://github.com/Project-OSRM/project-osrm.github.com` in the `docs/vN.N.N/api` directory
8. Push tags and commits: `git push; git push --tags`
9. If not a release-candidate: Write a mailing-list post to osrm-talk@openstreetmap.org to announce the release
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
"""
+42 -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
@@ -991,3 +991,40 @@ Feature: Car - Turn restrictions
When I route I should get
| from | to | route |
| a | f | ab,be,ef,ef |
@restriction @overlap @geometry
Scenario: Duplicated restriction
Given the node map
"""
c
|
| f
| |
b-g-e
| |
| d
|
a
"""
And the ways
| nodes |
| ab |
| bc |
| bge |
| de |
| ef |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bge | ef | e | no_left_turn |
And the relations
| type | way:from | way:via | way:to | restriction |
| restriction | ab | bge | de | no_right_turn |
| restriction | bc | bge | ef | no_left_turn |
When I route I should get
| from | to | route |
| a | d | ab,bc,bc,bge,de,de |
@@ -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 |
+5 -5
View File
@@ -52,9 +52,9 @@ Feature: Turn Lane Guidance
| dy | | | YSt |
When I route I should get
| waypoints | route | turns | lanes |
| a,e | MySt,MySt,MySt,MySt | depart,continue right,turn right,arrive | ,straight:false right:false right:true,left:false right:true, |
| e,a | MySt,MySt,MySt,MySt | depart,continue left,turn left,arrive | ,left:true left:false straight:false,left:true right:false, |
| waypoints | route | turns | lanes |
| a,e | MySt,MySt,MySt,MySt | depart,continue right,continue right,arrive | ,straight:false right:false right:true,left:false right:true, |
| e,a | MySt,MySt,MySt,MySt | depart,continue left,continue left,arrive | ,left:true left:false straight:false,left:true right:false, |
@anticipate
Scenario: Anticipate Lane Change for quick same direction turns, changing between streets
@@ -780,8 +780,8 @@ Feature: Turn Lane Guidance
| dy | | YSt |
When I route I should get
| waypoints | route | turns | lanes |
| a,e | MySt,MySt,MySt,MySt | depart,continue right,turn right,arrive | ,straight:false straight:false right:false right:true,left:false right:true, |
| waypoints | route | turns | lanes |
| a,e | MySt,MySt,MySt,MySt | depart,continue right,continue right,arrive | ,straight:false straight:false right:false right:true,left:false right:true, |
@anticipate
Scenario: Don't Overdo It
+3 -3
View File
@@ -628,9 +628,9 @@ Feature: Collapse
| cf | secondary | bottom |
When I route I should get
| waypoints | turns | route | locations |
| a,d | depart,continue right,turn right,arrive | road,road,road,road | a,b,c,d |
| d,a | depart,continue left,turn left,arrive | road,road,road,road | d,c,b,a |
| waypoints | turns | route | locations |
| a,d | depart,continue right,continue right,arrive | road,road,road,road | a,b,c,d |
| d,a | depart,continue left,continue left,arrive | road,road,road,road | d,c,b,a |
Scenario: Forking before a turn
Given the node map
+21
View File
@@ -136,3 +136,24 @@ Feature: Continue Instructions
| a,d | abcdefb,abcdefb,abcdefb | depart,continue right,arrive |
# continuing right here, since the turn to the left is more expensive
| a,e | abcdefb,abcdefb,abcdefb | depart,continue right,arrive |
Scenario: End-Of-Road Continue
Given the node map
"""
a - b - c
|
d - e
|
f
"""
And the ways
| nodes | highway | name |
| abc | primary | road |
| bdf | primary | road |
| ed | primary | turn |
When I route I should get
| waypoints | route | turns |
| e,a | turn,road,road,road | depart,turn right,continue left,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 |
+102
View File
@@ -0,0 +1,102 @@
@routing @guidance
Feature: Divided road entry
Background:
Given the profile "car"
Given a grid size of 5 meters
Scenario: Join on a divided road named after the main road
Given the node map
"""
a-------b-----c
|
d-------e-----f
|
|
g
"""
And the ways
| nodes | name | highway | oneway |
| abc | main st | residential | -1 |
| def | main st | residential | yes |
| be | main st | residential | |
| eg | side st | residential | |
When I route I should get
| waypoints | route | turns |
| g,a | side st,main st,main st| depart,end of road left,arrive |
# Similar to previous one, but the joining way is tagged with the side-street name
Scenario: Join on a divided road, named after the side street
Given the node map
"""
a-------b-----c
|
d-------e-----f
|
|
g
"""
And the ways
| nodes | name | highway | oneway |
| abc | main st | residential | -1 |
| def | main st | residential | yes |
| beg | side st | residential | |
When I route I should get
| waypoints | route | turns |
| g,a | side st,main st,main st| depart,end of road left,arrive |
# Center join named after crossroad
Scenario: Crossing a divided road, named after side-street
Given the node map
"""
h
|
a-------b-----c
|
d-------e-----f
|
|
g
"""
And the ways
| nodes | name | highway | oneway |
| abc | main st | residential | -1 |
| def | main st | residential | yes |
| hbeg | side st | residential | |
When I route I should get
| waypoints | route | turns |
| g,a | side st,main st,main st| depart,turn left,arrive |
# Join named after divided road
Scenario: Crossing a divided road, named after main street
Given the node map
"""
h
|
a-------b-----c
|
d-------e-----f
|
|
g
"""
And the ways
| nodes | name | highway | oneway |
| abc | main st | residential | -1 |
| def | main st | residential | yes |
| be | main st | residential | |
| hb | side st | residential | |
| eg | side st | residential | |
When I route I should get
| waypoints | route | turns |
| g,a | side st,main st,main st| depart,turn left,arrive |
+4 -2
View File
@@ -97,5 +97,7 @@ Feature: Simple Turns
| ei | left | yes |
When I route I should get
| waypoints | route | turns |
| g,a | in,road,road | depart,fork right,arrive |
| waypoints | route | turns |
| g,a | in,road,road | depart,fork slight right,arrive |
| g,h | in,right,right | depart,fork straight,arrive |
| g,i | in,left,left | depart,fork slight left,arrive |
+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
@@ -835,9 +835,9 @@ Feature: Turn Lane Guidance
| cf | secondary | bottom | |
When I route I should get
| waypoints | turns | route | lanes |
| a,d | depart,continue right,turn right,arrive | road,road,road,road | ,straight:false right:true,, |
| d,a | depart,continue left,turn left,arrive | road,road,road,road | ,left:true straight:false,, |
| waypoints | turns | route | lanes |
| a,d | depart,continue right,continue right,arrive | road,road,road,road | ,straight:false right:true,, |
| d,a | depart,continue left,continue left,arrive | road,road,road,road | ,left:true straight:false,, |
@simple
Scenario: Merge Lanes Onto Freeway
+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
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "osrm",
"version": "5.10.0-rc.2",
"version": "5.11.0-rc.3",
"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",
@@ -37,6 +37,7 @@
},
"devDependencies": {
"aws-sdk": "~2.0.31",
"babel-plugin-transform-class-properties": "^6.24.1",
"chalk": "^1.1.3",
"cucumber": "^1.2.1",
"d3-queue": "^2.0.3",
@@ -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);
};
+25 -1
View File
@@ -158,6 +158,18 @@ void TransferTurnTypeStrategy::operator()(RouteStep &step_at_turn_location,
void AdjustToCombinedTurnAngleStrategy::operator()(RouteStep &step_at_turn_location,
const RouteStep &transfer_from_step) const
{
// Forks point to left/right. By doing a combined angle, we would risk ending up with
// unreasonable fork instrucitons. The direction of a fork only depends on the forking location,
// not further angles coming up
//
// d
// . c
// a - b
//
// could end up as `fork left` for `a-b-c`, instead of fork-right
if (hasTurnType(step_at_turn_location, TurnType::Fork))
return;
// TODO assert transfer_from_step == step_at_turn_location + 1
const auto angle = findTotalTurnAngle(step_at_turn_location, transfer_from_step);
step_at_turn_location.maneuver.instruction.direction_modifier = getTurnDirection(angle);
@@ -173,7 +185,19 @@ void AdjustToCombinedTurnStrategy::operator()(RouteStep &step_at_turn_location,
const RouteStep &transfer_from_step) const
{
const auto angle = findTotalTurnAngle(step_at_turn_location, transfer_from_step);
const auto new_modifier = getTurnDirection(angle);
// Forks point to left/right. By doing a combined angle, we would risk ending up with
// unreasonable fork instrucitons. The direction of a fork only depends on the forking location,
// not further angles coming up
//
// d
// . c
// a - b
//
// could end up as `fork left` for `a-b-c`, instead of fork-right
const auto new_modifier = hasTurnType(step_at_turn_location, TurnType::Fork)
? step_at_turn_location.maneuver.instruction.direction_modifier
: getTurnDirection(angle);
// a turn that is a new name or straight (turn/continue)
const auto is_non_turn = [](const RouteStep &step) {
+15 -1
View File
@@ -629,7 +629,21 @@ std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps)
BOOST_ASSERT(step_index > 0);
const auto &previous_step = steps[last_valid_instruction];
if (previous_step.intersections.size() < MIN_END_OF_ROAD_INTERSECTIONS)
step.maneuver.instruction.type = TurnType::Turn;
{
bool same_name =
!(step.name.empty() && step.ref.empty()) &&
!util::guidance::requiresNameAnnounced(previous_step.name,
previous_step.ref,
previous_step.pronunciation,
previous_step.exits,
step.name,
step.ref,
step.pronunciation,
step.exits);
step.maneuver.instruction.type =
same_name ? TurnType::Continue : TurnType::Turn;
}
}
// Remember the last non silent instruction
+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
+178 -32
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
@@ -749,24 +809,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// next to the normal restrictions tracked in `entry_allowed`, via
// ways might introduce additional restrictions. These are handled
// here when turning off a via-way
const auto add_unrestricted_turns =
[&](const auto duplicated_node_id) {
const auto from_id =
m_number_of_edge_based_nodes -
way_restriction_map.NumberOfDuplicatedNodes() +
duplicated_node_id;
for (auto duplicated_node_id : duplicated_nodes)
{
const auto from_id =
m_number_of_edge_based_nodes -
way_restriction_map.NumberOfDuplicatedNodes() +
duplicated_node_id;
auto const node_at_end_of_turn =
m_node_based_graph->GetTarget(turn.eid);
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_way_restricted)
{
auto const restriction = way_restriction_map.GetRestriction(
duplicated_node_id, node_at_end_of_turn);
if (is_restricted)
return;
if (restriction.condition.empty())
continue;
// add into delayed data
auto edge_with_data = generate_edge(
auto edge_with_data_and_condition = generate_edge(
NodeID(from_id),
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
node_along_road_entering,
@@ -777,12 +843,50 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
turn,
entry_class_id);
buffer->delayed_data.push_back(std::move(edge_with_data));
};
buffer->delayed_data.push_back(
std::move(edge_with_data_and_condition.first));
std::for_each(duplicated_nodes.begin(),
duplicated_nodes.end(),
add_unrestricted_turns);
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);
}
}
}
}
}
}
@@ -826,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)
{
@@ -878,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());
{
@@ -917,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
View File
@@ -72,6 +72,12 @@ NAN_MODULE_INIT(Engine::Init)
* @param {Boolean} [options.shared_memory] Connects to the persistent shared memory datastore.
* This requires you to run `osrm-datastore` prior to creating an `OSRM` object.
* @param {String} [options.path] The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true.
* @param {Number} [options.max_locations_trip] Max. locations supported in trip query (default: unlimited).
* @param {Number} [options.max_locations_viaroute] Max. locations supported in viaroute query (default: unlimited).
* @param {Number} [options.max_locations_distance_table] Max. locations supported in distance table query (default: unlimited).
* @param {Number} [options.max_locations_map_matching] Max. locations supported in map-matching query (default: unlimited).
* @param {Number} [options.max_results_nearest] Max. results supported in nearest query (default: unlimited).
* @param {Number} [options.max_alternatives] Max.number of alternatives supported in alternative routes query (default: 3).
*
* @class OSRM
*
@@ -193,6 +199,7 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
* @param {String} [options.geometries=polyline] Returned route geometry format (influences overview and per step). Can also be `geojson`.
* @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`).
* @param {Boolean} [options.continue_straight] Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile.
* @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
* `null`/`true`/`false`
* @param {Function} callback
*
@@ -228,6 +235,7 @@ NAN_METHOD(Engine::route) //
* @param {Array} [options.hints] Hints for the coordinate snapping. Array of base64 encoded strings.
* @param {Number} [options.number=1] Number of nearest segments that should be returned.
* Must be an integer greater than or equal to `1`.
* @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
* @param {Function} callback
*
* @returns {Object} containing `waypoints`.
@@ -269,6 +277,7 @@ NAN_METHOD(Engine::nearest) //
* location with given index as source. Default is to use all.
* @param {Array} [options.destinations] An array of `index` elements (`0 <= integer <
* #coordinates`) to use location with given index as destination. Default is to use all.
* @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
* @param {Function} callback
*
* @returns {Object} containing `durations`, `sources`, and `destinations`.
@@ -350,6 +359,9 @@ NAN_METHOD(Engine::tile)
* @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`).
* @param {Array<Number>} [options.timestamps] Timestamp of the input location (integers, UNIX-like timestamp).
* @param {Array} [options.radiuses] Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`.
* @param {String} [options.gaps] Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore` (optional, default `split`).
* @param {Boolean} [options.tidy] Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`).
*
* @param {Function} callback
*
* @returns {Object} containing `tracepoints` and `matchings`.
@@ -418,6 +430,7 @@ NAN_METHOD(Engine::match) //
* @param {Boolean} [options.roundtrip=true] Return route is a roundtrip.
* @param {String} [options.source=any] Return route starts at `any` or `first` coordinate.
* @param {String} [options.destination=any] Return route ends at `any` or `last` coordinate.
* @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
*
* @returns {Object} containing `waypoints` and `trips`.
* **`waypoints`**: an array of [`Waypoint`](#waypoint) objects representing all waypoints in input order.
+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))
{
util::Log(logWARNING) << "Empty segment in CSV with node " +
std::to_string(found_inconsistency->first.from);
}
return result;
}
TurnLookupTable readTurnValues(const std::vector<std::string> &paths)
+30 -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"
@@ -220,6 +221,12 @@ updateSegmentData(const UpdaterConfig &config,
{
auto u = osm_node_ids[nodes_range[segment_offset]];
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
// Self-loops are artifical segments (e.g. traffic light nodes), do not
// waste time updating them with traffic data
if (u == v)
continue;
if (auto value = segment_speed_lookup({u, v}))
{
auto segment_length = segment_lengths[segment_offset];
@@ -253,6 +260,12 @@ updateSegmentData(const UpdaterConfig &config,
{
auto u = osm_node_ids[nodes_range[segment_offset]];
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
// Self-loops are artifical segments (e.g. traffic light nodes), do not
// waste time updating them with traffic data
if (u == v)
continue;
if (auto value = segment_speed_lookup({v, u}))
{
auto segment_length = segment_lengths[segment_offset];
@@ -443,20 +456,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 +478,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 +589,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 +647,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()

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