Compare commits
183 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 896445a337 | |||
| 8c21e1267e | |||
| ad3fd46da5 | |||
| 62f0e11bfa | |||
| 03d653c0bb | |||
| cbfb055f81 | |||
| 2288704bb5 | |||
| 97dcf4eef9 | |||
| 17e15033e1 | |||
| 875f482203 | |||
| df3c39cef5 | |||
| a28a20a1ba | |||
| 17a18b5c7c | |||
| 423c083038 | |||
| 468d8c0031 | |||
| 6f4c6e84ae | |||
| 4b1aae40af | |||
| 0e6863aec1 | |||
| 949d505783 | |||
| d11927046f | |||
| 9461c83511 | |||
| 532cbfce13 | |||
| 0fbd18b0dd | |||
| 3f07a830e6 | |||
| 24b01fae00 | |||
| 0817cd6dfd | |||
| 9d8b92f418 | |||
| 928a6f0c7d | |||
| 29b3caf529 | |||
| 20c8ac0272 | |||
| c99c8bccbc | |||
| 735191255d | |||
| da6ca640a7 | |||
| f6f7a9290f | |||
| 9687a9325c | |||
| 43566bfd14 | |||
| 110e6c3689 | |||
| 561b7cc58e | |||
| 5775679f64 | |||
| 560d8ffec0 | |||
| 2544c3f20e | |||
| 5a311012af | |||
| ef087f963d | |||
| a1127c3e09 | |||
| 01a57ff1d8 | |||
| 37824e2954 | |||
| 4489c8dfc2 | |||
| ee63e39ff5 | |||
| ce5bcc797b | |||
| fe5cc55b0e | |||
| 12d58ace10 | |||
| 4636aaabfe | |||
| 186cc8340a | |||
| e343f71541 | |||
| 0df0d31d83 | |||
| aaf42a1caf | |||
| d02dd67e95 | |||
| a49bd70985 | |||
| b2c27fbd25 | |||
| 9fe0e91d92 | |||
| 08b7270f5c | |||
| fc52dd85fe | |||
| 6d961d4a15 | |||
| 0bd08224bf | |||
| 2a383efbf6 | |||
| b84d70d305 | |||
| 3bade8625f | |||
| 844300b95a | |||
| dd811539a3 | |||
| 79c2ae46d8 | |||
| d023e7c581 | |||
| 4ccb08983f | |||
| 8c941d1344 | |||
| 841c032a0d | |||
| a764fd1f29 | |||
| 3687864cc1 | |||
| 4b5466629f | |||
| f19bf70b55 | |||
| 24fa94af59 | |||
| 95a584a30d | |||
| 6ba36a2bc7 | |||
| 039989a339 | |||
| a7559077a0 | |||
| bbe80192aa | |||
| 9b16b757a4 | |||
| 3680fc9d90 | |||
| 836e8bdff0 | |||
| 3d4b39be7d | |||
| 193dfd9d8b | |||
| 305e813489 | |||
| a5756fc764 | |||
| f5bf788814 | |||
| 00f7d7776d | |||
| dce685c780 | |||
| 173a39fd8b | |||
| 5d564ee510 | |||
| 24c2708d1e | |||
| d87a972c66 | |||
| f90736b6b3 | |||
| 9aeb3086cb | |||
| 9e361a8178 | |||
| c3aeef4e09 | |||
| 50090e6447 | |||
| b9e5d26e3a | |||
| 184cfab33b | |||
| fd95b2da76 | |||
| ce04a608b8 | |||
| cff69178e8 | |||
| 6c682b2258 | |||
| c1087eaecc | |||
| 8bb183bc8c | |||
| 15359befdc | |||
| 2c9e18d5a9 | |||
| 4f81e31d63 | |||
| b73c59088c | |||
| 44e4728bde | |||
| ba2629456f | |||
| 1b4779a58c | |||
| 1eaf9f3269 | |||
| 73e365d398 | |||
| d5bf508046 | |||
| 47b097038a | |||
| a4264c7849 | |||
| 463228d0bf | |||
| 1dde5d288d | |||
| 6f885b5bdb | |||
| 820feb3a04 | |||
| 46b00e1378 | |||
| eb12c16fd6 | |||
| 17c32f5ce7 | |||
| 53ef2e2955 | |||
| 7b1131b982 | |||
| 1fc969e6c8 | |||
| 49f960064c | |||
| 83a9d0590d | |||
| d8b016b92a | |||
| 608044305d | |||
| 4760b85930 | |||
| 9e2782d923 | |||
| 2dfeb0cabc | |||
| 2f9b5788d0 | |||
| be496eb4e3 | |||
| 97244557b1 | |||
| e2e5eb0169 | |||
| 6949d7ee5b | |||
| 02303904b8 | |||
| 4ad6d88888 | |||
| e226b52f21 | |||
| b1125b7f1f | |||
| 33ff92d27e | |||
| de4fd76d57 | |||
| bf6df74d44 | |||
| 8f6dd805e5 | |||
| 3235f30a98 | |||
| 7e4020c010 | |||
| 538bbd47d1 | |||
| 78583d2c8c | |||
| fa1a0a1325 | |||
| 6df1437cfc | |||
| 15ed53d4a7 | |||
| 63be191775 | |||
| 6ec505281e | |||
| 5a293e891b | |||
| b57169e221 | |||
| 045d25041f | |||
| 170923874b | |||
| 8137e95fbb | |||
| 0375af197d | |||
| babbda98a6 | |||
| 72bfbed1f1 | |||
| feeae05f1c | |||
| f88ac989ea | |||
| 41f083cded | |||
| 12ded539aa | |||
| 827a1fbd7a | |||
| e84a0ea37c | |||
| 88208bfa5d | |||
| 7073403f1b | |||
| 2501882adb | |||
| 4f2bb19b0f | |||
| de77befb23 | |||
| a5db3d72f1 | |||
| b8898ef410 |
+57
-45
@@ -25,7 +25,8 @@ env:
|
||||
- CCACHE_TEMPDIR=/tmp/.ccache-temp
|
||||
- CCACHE_COMPRESS=1
|
||||
- CASHER_TIME_OUT=599 # one second less than 10m to avoid 10m timeout error: https://github.com/Project-OSRM/osrm-backend/issues/2742
|
||||
- JOBS=4
|
||||
- CCACHE_VERSION=3.3.1
|
||||
- CMAKE_VERSION=3.6.2
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
@@ -39,7 +40,7 @@ matrix:
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' TARGET_ARCH='x86_64-asan' ENABLE_COVERAGE=ON ENABLE_SANITIZER=ON BUILD_COMPONENTS=ON
|
||||
|
||||
- os: linux
|
||||
@@ -47,34 +48,45 @@ matrix:
|
||||
addons: &clang38
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-5-dev', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CLANG_VERSION='3.8.1' CLANG_PACKAGE="clang++" BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON BUILD_COMPONENTS=ON CUCUMBER_TIMEOUT=60000
|
||||
packages: ['libstdc++-5-dev', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: CLANG_VERSION='3.8.1' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON BUILD_COMPONENTS=ON CUCUMBER_TIMEOUT=60000
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: CCOMPILER='clang' CXXCOMPILER='clang++' BUILD_TYPE='Debug' JOBS=1 CUCUMBER_TIMEOUT=60000
|
||||
osx_image: xcode8.2
|
||||
compiler: "mason-osx-release"
|
||||
# we use the xcode provides clang and don't install our own
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON
|
||||
|
||||
# Release Builds
|
||||
- os: linux
|
||||
compiler: "mason-release"
|
||||
compiler: "mason-linux-release"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-5-dev', 'ccache']
|
||||
env: BUILD_TYPE='Release' ENABLE_MASON=ON
|
||||
packages: ['libstdc++-5-dev']
|
||||
env: CLANG_VERSION='3.8.1' BUILD_TYPE='Release' ENABLE_MASON=ON
|
||||
|
||||
- os: linux
|
||||
compiler: "gcc-6-release"
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' BUILD_COMPONENTS=ON
|
||||
|
||||
- os: linux
|
||||
compiler: "gcc-6-release-i686"
|
||||
env: TARGET_ARCH='i686' CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release'
|
||||
env: >
|
||||
TARGET_ARCH='i686' CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release'
|
||||
CFLAGS='-m32 -msse2 -mfpmath=sse' CXXFLAGS='-m32 -msse2 -mfpmath=sse'
|
||||
|
||||
- os: linux
|
||||
compiler: "gcc-4.9-release"
|
||||
addons: &gcc49
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.9', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CCOMPILER='gcc-4.9' CXXCOMPILER='g++-4.9' BUILD_TYPE='Release'
|
||||
|
||||
# Disabled because of CI slowness
|
||||
#- os: linux
|
||||
@@ -85,19 +97,13 @@ matrix:
|
||||
#- packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
#- env: CCOMPILER='clang-3.8' CXXCOMPILER='clang++-3.8' BUILD_TYPE='Release'
|
||||
|
||||
# Disabled because of CI slowness
|
||||
#- os: osx
|
||||
#- osx_image: xcode7.3
|
||||
#- compiler: clang
|
||||
#- env: CCOMPILER='clang' CXXCOMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
# Shared Library
|
||||
- os: linux
|
||||
compiler: "gcc-6-release-shared"
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
|
||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON BUILD_COMPONENTS=ON
|
||||
|
||||
# Disabled because CI slowness
|
||||
@@ -111,24 +117,36 @@ matrix:
|
||||
|
||||
before_install:
|
||||
- if [[ ! -z $TARGET_ARCH ]] ; then source ./scripts/travis/before_install.$TARGET_ARCH.sh ; fi
|
||||
- if [[ $(uname -s) == 'Darwin' ]]; then sudo mdutil -i off /; fi;
|
||||
- source ./scripts/install_node.sh 4
|
||||
- npm install
|
||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||
- export PATH=${DEPS_DIR}/bin:${PATH} && mkdir -p ${DEPS_DIR}
|
||||
- CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/3.5.2.tar.gz"
|
||||
- travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
|
||||
- |
|
||||
if [[ ${CLANG_VERSION:-false} != false ]]; then
|
||||
export CCOMPILER='clang'
|
||||
export CXXCOMPILER='clang++'
|
||||
CLANG_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/${CLANG_PACKAGE}/${CLANG_VERSION}.tar.gz"
|
||||
travis_retry wget --quiet -O - ${CLANG_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR} || exit 1
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
export JOBS=$((`nproc` + 1))
|
||||
fi
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
# implicit deps, but seem to be installed by default with recent images: libxml2 GDAL boost
|
||||
brew install libzip libstxxl lua51 luabind tbb md5sha1sum ccache
|
||||
export JOBS=$((`sysctl -n hw.ncpu` + 1))
|
||||
sudo mdutil -i off /
|
||||
fi
|
||||
- echo "Using ${JOBS} jobs"
|
||||
- source ./scripts/install_node.sh 4
|
||||
- npm install -g "npm@>=3" # Upgrade to npm >v2 to reduce size of downloaded dependencies
|
||||
- npm install
|
||||
- ./third_party/mason/mason install ccache ${CCACHE_VERSION}
|
||||
- export PATH=$(./third_party/mason/mason prefix ccache ${CCACHE_VERSION})/bin:${PATH}
|
||||
- ./third_party/mason/mason install cmake ${CMAKE_VERSION}
|
||||
- export PATH=$(./third_party/mason/mason prefix cmake ${CMAKE_VERSION})/bin:${PATH}
|
||||
- |
|
||||
if [[ ! -z ${CLANG_VERSION} ]]; then
|
||||
export CCOMPILER='clang'
|
||||
export CXXCOMPILER='clang++'
|
||||
./third_party/mason/mason install clang++ ${CLANG_VERSION}
|
||||
export PATH=$(./third_party/mason/mason prefix clang++ ${CLANG_VERSION})/bin:${PATH}
|
||||
# we only enable lto for release builds
|
||||
# and therefore don't need to us ld.gold or llvm tools for linking
|
||||
# for debug builds
|
||||
if [[ ${BUILD_TYPE} == 'Release' ]]; then
|
||||
./third_party/mason/mason install binutils 2.27
|
||||
export PATH=$(./third_party/mason/mason prefix binutils 2.27)/bin:${PATH}
|
||||
fi
|
||||
fi
|
||||
- ccache --max-size=256M # limiting the cache's size to roughly the previous job's object sizes
|
||||
|
||||
@@ -137,11 +155,11 @@ install:
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
./scripts/check_taginfo.py taginfo.json profiles/car.lua
|
||||
fi
|
||||
- mkdir build && pushd build
|
||||
- export OSRM_BUILD_DIR="$(pwd)/build-osrm"
|
||||
- mkdir ${OSRM_BUILD_DIR} && pushd ${OSRM_BUILD_DIR}
|
||||
- export CC=${CCOMPILER} CXX=${CXXCOMPILER}
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_MASON=${ENABLE_MASON:-OFF} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DENABLE_COVERAGE=${ENABLE_COVERAGE:-OFF} -DENABLE_SANITIZER=${ENABLE_SANITIZER:-OFF} -DBUILD_TOOLS=ON -DBUILD_COMPONENTS=${BUILD_COMPONENTS:-OFF} -DENABLE_CCACHE=ON
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_MASON=${ENABLE_MASON:-OFF} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS:-OFF} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DENABLE_COVERAGE=${ENABLE_COVERAGE:-OFF} -DENABLE_SANITIZER=${ENABLE_SANITIZER:-OFF} -DBUILD_TOOLS=ON -DBUILD_COMPONENTS=${BUILD_COMPONENTS:-OFF} -DENABLE_CCACHE=ON
|
||||
- echo "travis_fold:start:MAKE"
|
||||
- make osrm-extract --jobs=3
|
||||
- make --jobs=${JOBS}
|
||||
- make tests --jobs=${JOBS}
|
||||
- make benchmarks --jobs=${JOBS}
|
||||
@@ -153,17 +171,11 @@ install:
|
||||
sudo ldconfig
|
||||
fi
|
||||
- popd
|
||||
- |
|
||||
if [[ ${ENABLE_MASON:-OFF} == 'ON' ]]; then
|
||||
# for mason builds we need to point the example
|
||||
# at the clang++ installed by the CMakeLists.txt automatically
|
||||
export CXX=$(./third_party/mason/mason prefix clang++ 3.8.1)/bin/clang++
|
||||
export CC=$(./third_party/mason/mason prefix clang++ 3.8.1)/bin/clang
|
||||
fi
|
||||
- mkdir example/build && pushd example/build
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
|
||||
- make
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
- npm run build-api-docs
|
||||
|
||||
script:
|
||||
- if [[ $TARGET_ARCH == armhf ]] ; then echo "Skip tests for $TARGET_ARCH" && exit 0 ; fi
|
||||
@@ -172,7 +184,7 @@ script:
|
||||
- echo "travis_fold:end:BENCHMARK"
|
||||
- ./example/build/osrm-example test/data/monaco.osrm
|
||||
# All tests assume to be run from the build directory
|
||||
- pushd build
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- ./unit_tests/library-tests ../test/data/monaco.osrm
|
||||
- ./unit_tests/extractor-tests
|
||||
- ./unit_tests/engine-tests
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
- Shared memory now allows for multiple clients (multiple instances of libosrm on the same segment)
|
||||
- Polyline geometries can now be requested with precision 5 as well as with precision 6
|
||||
- Profiles
|
||||
- the car profile has been refactored into smaller functions
|
||||
- get_value_by_key() is now guaranteed never to return empty strings, nil is returned instead.
|
||||
- debug.lua was added to make it easier to test/develop profile code.
|
||||
- `car.lua` now depends on lib/set.lua and lib/sequence.lua
|
||||
- `restrictions` is now used for namespaced restrictions and restriction exceptions (e.g. `restriction:motorcar=` as well as `except=motorcar`)
|
||||
- replaced lhs/rhs profiles by using test defined profiles
|
||||
- Handle `oneway=alternating` (routed over with penalty) separately from `oneway=reversible` (not routed over due to time dependence)
|
||||
@@ -15,6 +19,7 @@
|
||||
- Improved turn angle calculation, detecting offsets due to lanes / minor variations due to inaccuracies
|
||||
- Corrected the bearings returned for intermediate steps - requires reprocessing
|
||||
- Improved turn locations for collapsed turns
|
||||
- Sliproad classification refinements: the situations we detect as Sliproads now resemble more closely the reality
|
||||
- Trip Plugin
|
||||
- changed internal behaviour to prefer the smallest lexicographic result over the largest one
|
||||
- Bugfixes
|
||||
@@ -22,8 +27,17 @@
|
||||
- fixed compile errors in tile unit-test framework
|
||||
- fixed a bug that could result in inconsistent behaviour when collapsing instructions
|
||||
- fixed a bug that could result in crashes when leaving a ferry directly onto a motorway ramp
|
||||
- fixed a bug in the tile plugin that resulted in discovering invalid edges for connections
|
||||
- improved error messages when missing files during traffic updates (#3114)
|
||||
- For single coordinate geometries the GeoJSON `Point` encoding was broken. We now always emit `LineString`s even in the one-coordinate-case (backwards compatible) (#3425)
|
||||
- Debug Tiles
|
||||
- Added support for turn penalties
|
||||
- Internals
|
||||
- Internal/Shared memory datafacades now share common memory layout and data loading code
|
||||
- File reading now has much better error handling
|
||||
- Misc
|
||||
- Progress indicators now print newlines when stdout is not a TTY
|
||||
- Prettier API documentation now generated via `npm run build-api-docs` output `build/docs`
|
||||
|
||||
# 5.4.3
|
||||
- Changes from 5.4.2
|
||||
|
||||
+134
-64
@@ -7,6 +7,13 @@ Please create a directory and run cmake from there, passing the path to this sou
|
||||
This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.")
|
||||
endif()
|
||||
|
||||
# detect if this is included as subproject and if so expose
|
||||
# some variables to its parent scope
|
||||
get_directory_property(BUILD_AS_SUBPROJECT PARENT_DIRECTORY)
|
||||
if(BUILD_AS_SUBPROJECT)
|
||||
message(STATUS "Building libosrm as subproject.")
|
||||
endif()
|
||||
|
||||
option(ENABLE_MASON "Use mason for dependencies" OFF)
|
||||
option(ENABLE_CCACHE "Speed up incremental rebuilds via ccache" ON)
|
||||
option(BUILD_TOOLS "Build OSRM tools" OFF)
|
||||
@@ -19,43 +26,47 @@ option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF)
|
||||
option(ENABLE_GOLD_LINKER "Use GNU gold linker if available" ON)
|
||||
|
||||
if(ENABLE_MASON)
|
||||
|
||||
# versions in use
|
||||
set(MASON_CLANG_VERSION "3.8.1")
|
||||
set(MASON_BOOST_VERSION "1.61.0")
|
||||
set(MASON_STXXL_VERSION "1.4.1")
|
||||
set(MASON_EXPAT_VERSION "2.1.1")
|
||||
set(MASON_EXPAT_VERSION "2.2.0")
|
||||
set(MASON_LUA_VERSION "5.2.4")
|
||||
set(MASON_LUABIND_VERSION "e414c57bcb687bb3091b7c55bbff6947f052e46b")
|
||||
set(MASON_BZIP2_VERSION "1.0.6")
|
||||
set(MASON_TBB_VERSION "43_20150316")
|
||||
set(MASON_CCACHE_VERSION "3.3.1")
|
||||
|
||||
message(STATUS "Enabling mason")
|
||||
|
||||
find_program(CURL_FOUND curl)
|
||||
if(NOT CURL_FOUND)
|
||||
message(FATAL_ERROR "curl command required with -DENABLE_MASON")
|
||||
endif()
|
||||
|
||||
set(MASON_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/third_party/mason/mason)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/third_party/mason/mason.cmake)
|
||||
if(NOT CMAKE_CXX_COMPILER)
|
||||
mason_use(clang++ VERSION ${MASON_CLANG_VERSION})
|
||||
message(STATUS "Setting compiler to clang++ ${MASON_CLANG_VERSION} (via mason) ${MASON_PACKAGE_clang++_PREFIX}/bin/clang++")
|
||||
set(CMAKE_CXX_COMPILER "${MASON_PACKAGE_clang++_PREFIX}/bin/clang++")
|
||||
set(CMAKE_C_COMPILER "${MASON_PACKAGE_clang++_PREFIX}/bin/clang")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# be compatible with version handling before cmake 3.x
|
||||
if (POLICY CMP0048)
|
||||
cmake_policy(SET CMP0048 OLD)
|
||||
endif()
|
||||
project(OSRM C CXX)
|
||||
set(OSRM_VERSION_MAJOR 5)
|
||||
set(OSRM_VERSION_MINOR 4)
|
||||
set(OSRM_VERSION_MINOR 5)
|
||||
set(OSRM_VERSION_PATCH 0)
|
||||
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
||||
|
||||
add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
# these two functions build up custom variables:
|
||||
# OSRM_INCLUDE_PATHS and OSRM_DEFINES
|
||||
# DEPENDENCIES_INCLUDE_DIRS and OSRM_DEFINES
|
||||
# These variables we want to pass to
|
||||
# include_directories and add_definitions for both
|
||||
# this build and for sharing externally via pkg-config
|
||||
|
||||
function(add_dependency_includes includes)
|
||||
list(APPEND OSRM_INCLUDE_PATHS "${includes}")
|
||||
set(OSRM_INCLUDE_PATHS "${OSRM_INCLUDE_PATHS}" PARENT_SCOPE)
|
||||
list(APPEND DEPENDENCIES_INCLUDE_DIRS "${includes}")
|
||||
set(DEPENDENCIES_INCLUDE_DIRS "${DEPENDENCIES_INCLUDE_DIRS}" PARENT_SCOPE)
|
||||
endfunction(add_dependency_includes)
|
||||
|
||||
function(add_dependency_defines defines)
|
||||
@@ -83,7 +94,7 @@ endif()
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/)
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/variant/include)
|
||||
|
||||
add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
|
||||
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
|
||||
@@ -129,6 +140,7 @@ if(ENABLE_GOLD_LINKER)
|
||||
if("${LD_VERSION}" MATCHES "GNU gold")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
|
||||
set(OSRM_LDFLAGS "${OSRM_LDFLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
|
||||
message(STATUS "Using GNU gold as linker.")
|
||||
|
||||
# Issue 2785: check gold binutils version and don't use gc-sections for versions prior 2.25
|
||||
@@ -183,7 +195,8 @@ endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
|
||||
message(STATUS "Configuring release mode optimizations")
|
||||
# Check if LTO is available
|
||||
check_cxx_compiler_flag("-flto" LTO_AVAILABLE)
|
||||
check_cxx_compiler_flag("-Wl,-flto" LTO_AVAILABLE)
|
||||
|
||||
if(ENABLE_LTO AND LTO_AVAILABLE)
|
||||
set(OLD_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
# GCC in addition allows parallelizing LTO
|
||||
@@ -198,27 +211,57 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM
|
||||
check_cxx_source_compiles("${CHECK_LTO_SRC}" LTO_WORKS)
|
||||
if(LTO_WORKS)
|
||||
message(STATUS "LTO working")
|
||||
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -flto")
|
||||
set(OSRM_LDFLAGS "${OSRM_LDFLAGS} -flto")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -flto")
|
||||
else()
|
||||
message(STATUS "LTO broken")
|
||||
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
|
||||
set(ENABLE_LTO Off)
|
||||
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
|
||||
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0" AND NOT MINGW)
|
||||
message(STATUS "Using gcc specific binutils for LTO.")
|
||||
set(CMAKE_AR "/usr/bin/gcc-ar")
|
||||
set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
|
||||
find_program(GCC_AR gcc-ar)
|
||||
find_program(GCC_RANLIB gcc-ranlib)
|
||||
if ("${GCC_AR}" STREQUAL "GCC_AR-NOTFOUND" OR "${GCC_RANLIB}" STREQUAL "GCC_RANLIB-NOTFOUND")
|
||||
message(WARNING "GCC specific binutils not found.")
|
||||
else()
|
||||
message(STATUS "Using GCC specific binutils for LTO:")
|
||||
message(STATUS " ${GCC_AR}")
|
||||
message(STATUS " ${GCC_RANLIB}")
|
||||
set(CMAKE_AR ${GCC_AR})
|
||||
set(CMAKE_RANLIB ${GCC_RANLIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Same for clang LTO requires their own toolchain
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "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")
|
||||
message(WARNING "LLVM specific binutils not found.")
|
||||
else()
|
||||
message(STATUS "Using LLVM specific binutils for LTO:")
|
||||
message(STATUS " ${LLVM_AR}")
|
||||
message(STATUS " ${LLVM_RANLIB}")
|
||||
set(CMAKE_AR ${LLVM_AR})
|
||||
set(CMAKE_RANLIB ${LLVM_RANLIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "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)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ENABLE_MASON AND (LTO_WORKS OR ENABLE_GOLD_LINKER))
|
||||
if(UNIX AND NOT APPLE AND ENABLE_MASON AND (LTO_WORKS OR ENABLE_GOLD_LINKER))
|
||||
message(WARNING "ENABLE_MASON and ENABLE_LTO/ENABLE_GOLD_LINKER may not work on all linux systems currently")
|
||||
message(WARNING "For more details see: https://github.com/Project-OSRM/osrm-backend/issues/3202")
|
||||
endif()
|
||||
@@ -234,6 +277,7 @@ if (ENABLE_COVERAGE)
|
||||
endif()
|
||||
if (ENABLE_SANITIZER)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -fsanitize=address")
|
||||
endif()
|
||||
|
||||
# Configuring compilers
|
||||
@@ -280,9 +324,11 @@ if("${LINKER_VERSION}" MATCHES "GNU gold" OR "${LINKER_VERSION}" MATCHES "GNU ld
|
||||
endif()
|
||||
# Default linker optimization flags
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-O1 -Wl,--hash-style=gnu -Wl,--sort-common")
|
||||
|
||||
else()
|
||||
message(STATUS "Using unknown linker, not setting linker optimizations")
|
||||
endif ()
|
||||
set(OSRM_LDFLAGS "${OSRM_LDFLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
@@ -290,6 +336,7 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
# Activate C++1y
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
|
||||
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++1y")
|
||||
endif()
|
||||
|
||||
# Configuring other platform dependencies
|
||||
@@ -371,18 +418,21 @@ if(ENABLE_MASON)
|
||||
if(NOT MASON_PACKAGE_tbb_LIBRARY_DIRS)
|
||||
message(FATAL_ERROR "MASON_PACKAGE_tbb_LIBRARY_DIRS is empty, rpath will not work")
|
||||
endif()
|
||||
set(TBB_LINKER_RPATHS "")
|
||||
foreach(libpath ${MASON_PACKAGE_tbb_LIBRARY_DIRS})
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(LINKER_FLAGS "-Wl,-rpath,${libpath}")
|
||||
elseif(APPLE)
|
||||
set(LINKER_FLAGS "-Wl,-rpath, -Wl,${libpath}")
|
||||
endif()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(TBB_LINKER_RPATHS "${TBB_LINKER_RPATHS} -Wl,-rpath -Wl,${libpath}")
|
||||
file(GLOB TBBGlob ${libpath}/*.*)
|
||||
install(FILES ${TBBGlob} DESTINATION lib)
|
||||
endforeach()
|
||||
if(APPLE)
|
||||
set(LINKER_FLAGS "${TBB_LINKER_RPATHS} -Wl,-rpath -Wl,@executable_path")
|
||||
elseif(UNIX)
|
||||
set(LINKER_FLAGS "${TBB_LINKER_RPATHS} '-Wl,-rpath,$ORIGIN' -Wl,-z,origin")
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
|
||||
if(BUILD_COMPONENTS)
|
||||
message(FATAL_ERROR "BUILD_COMPONENTS is not supported with ENABLE_MASON")
|
||||
@@ -391,14 +441,9 @@ if(ENABLE_MASON)
|
||||
# current mason packages target -D_GLIBCXX_USE_CXX11_ABI=0
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
|
||||
|
||||
if(ENABLE_CCACHE)
|
||||
mason_use(ccache VERSION ${MASON_CCACHE_VERSION})
|
||||
message(STATUS "Setting ccache to ccache ${MASON_CCACHE_VERSION} (via mason) ${MASON_PACKAGE_ccache_PREFIX}/bin/ccache")
|
||||
message(STATUS "Using ccache to speed up incremental builds")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${MASON_PACKAGE_ccache_PREFIX}/bin/ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${MASON_PACKAGE_ccache_PREFIX}/bin/ccache)
|
||||
set(ENV{CCACHE_CPP2} "true")
|
||||
endif()
|
||||
# note: we avoid calling find_package(Osmium ...) here to ensure that the
|
||||
# expat and bzip2 are used from mason rather than the system
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include)
|
||||
|
||||
else()
|
||||
|
||||
@@ -439,29 +484,30 @@ 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"))
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
message(STATUS "Using ccache to speed up incremental builds")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
set(ENV{CCACHE_CPP2} "true")
|
||||
endif()
|
||||
endif()
|
||||
# note libosmium depends on expat and bzip2
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake")
|
||||
set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include")
|
||||
find_package(Osmium REQUIRED COMPONENTS io)
|
||||
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR})
|
||||
|
||||
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"))
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
message(STATUS "Using ccache to speed up incremental builds")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
set(ENV{CCACHE_CPP2} "true")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# even with mason builds we want to link to system zlib
|
||||
# to ensure that osrm binaries play well with other binaries like nodejs
|
||||
find_package(ZLIB REQUIRED)
|
||||
add_dependency_includes(${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake")
|
||||
set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include")
|
||||
find_package(Osmium REQUIRED COMPONENTS io)
|
||||
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR})
|
||||
|
||||
if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS)
|
||||
add_dependency_defines(-DBOOST_TEST_DYN_LINK)
|
||||
endif()
|
||||
@@ -483,7 +529,7 @@ if(OPENMP_FOUND)
|
||||
endif()
|
||||
|
||||
add_definitions(${OSRM_DEFINES})
|
||||
include_directories(SYSTEM ${OSRM_INCLUDE_PATHS})
|
||||
include_directories(SYSTEM ${DEPENDENCIES_INCLUDE_DIRS})
|
||||
|
||||
set(BOOST_BASE_LIBRARIES
|
||||
${Boost_DATE_TIME_LIBRARY}
|
||||
@@ -499,10 +545,10 @@ set(BOOST_ENGINE_LIBRARIES
|
||||
${BOOST_BASE_LIBRARIES})
|
||||
|
||||
# Binaries
|
||||
target_link_libraries(osrm-datastore osrm_store ${Boost_PROGRAM_OPTIONS_LIBRARY} ${BOOST_BASE_LIBRARIES})
|
||||
target_link_libraries(osrm-extract osrm_extract ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_REGEX_LIBRARY} ${BOOST_BASE_LIBRARIES})
|
||||
target_link_libraries(osrm-contract ${Boost_PROGRAM_OPTIONS_LIBRARY} ${BOOST_BASE_LIBRARIES} ${TBB_LIBRARIES} osrm_contract)
|
||||
target_link_libraries(osrm-routed osrm ${Boost_PROGRAM_OPTIONS_LIBRARY} ${BOOST_ENGINE_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY})
|
||||
target_link_libraries(osrm-datastore osrm_store ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||
target_link_libraries(osrm-extract osrm_extract ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||
target_link_libraries(osrm-contract osrm_contract ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||
target_link_libraries(osrm-routed osrm ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY})
|
||||
|
||||
set(EXTRACTOR_LIBRARIES
|
||||
${BZIP2_LIBRARIES}
|
||||
@@ -593,7 +639,7 @@ set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
|
||||
file(GLOB VariantGlob third_party/variant/*.hpp)
|
||||
file(GLOB VariantGlob third_party/variant/include/mapbox/*.hpp)
|
||||
file(GLOB LibraryGlob include/osrm/*.hpp)
|
||||
file(GLOB ParametersGlob include/engine/api/*_parameters.hpp)
|
||||
set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/phantom_node.hpp)
|
||||
@@ -608,7 +654,7 @@ install(FILES ${ExtractorHeader} DESTINATION include/osrm/extractor)
|
||||
install(FILES ${ContractorHeader} DESTINATION include/osrm/contractor)
|
||||
install(FILES ${LibraryGlob} DESTINATION include/osrm)
|
||||
install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api)
|
||||
install(FILES ${VariantGlob} DESTINATION include/variant)
|
||||
install(FILES ${VariantGlob} DESTINATION include/mapbox)
|
||||
install(TARGETS osrm-extract DESTINATION bin)
|
||||
install(TARGETS osrm-contract DESTINATION bin)
|
||||
install(TARGETS osrm-datastore DESTINATION bin)
|
||||
@@ -618,9 +664,8 @@ install(TARGETS osrm_extract DESTINATION lib)
|
||||
install(TARGETS osrm_contract DESTINATION lib)
|
||||
install(TARGETS osrm_store DESTINATION lib)
|
||||
|
||||
foreach(lib ${ENGINE_LIBRARIES})
|
||||
set(ENGINE_LIBRARY_LISTING "${ENGINE_LIBRARY_LISTING} ${lib}")
|
||||
endforeach()
|
||||
# Setup exporting variables for pkgconfig and subproject
|
||||
#
|
||||
|
||||
if(BUILD_DEBIAN_PACKAGE)
|
||||
include(CPackDebianConfig)
|
||||
@@ -632,9 +677,33 @@ function(JOIN VALUES GLUE OUTPUT)
|
||||
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Set up variables, then write to pkgconfig file
|
||||
JOIN("${OSRM_DEFINES}" " " OSRM_DEFINES_STRING)
|
||||
JOIN("-I${OSRM_INCLUDE_PATHS}" " -I" OSRM_INCLUDE_PATHS_STRING)
|
||||
JOIN("${OSRM_DEFINES}" " " TMP_OSRM_DEFINES)
|
||||
set(LibOSRM_CXXFLAGS "${OSRM_CXXFLAGS} ${TMP_OSRM_DEFINES}")
|
||||
set(LibOSRM_LDFLAGS "${OSRM_LDFLAGS}")
|
||||
|
||||
if(BUILD_AS_SUBPROJECT)
|
||||
set(LibOSRM_CXXFLAGS "${LibOSRM_CXXFLAGS}" PARENT_SCOPE)
|
||||
set(LibOSRM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
|
||||
set(LibOSRM_LIBRARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" PARENT_SCOPE)
|
||||
set(LibOSRM_LIBRARIES "osrm" PARENT_SCOPE)
|
||||
set(LibOSRM_DEPENDENT_LIBRARIES "${ENGINE_LIBRARIES}" PARENT_SCOPE)
|
||||
set(LibOSRM_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/osrm"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/third_party"
|
||||
"${DEPENDENCIES_INCLUDE_DIRS}" PARENT_SCOPE)
|
||||
set(LibOSRM_LIBRARY_DIRS "${LibOSRM_LIBRARY_DIR}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
# pkgconfig defines
|
||||
set(PKGCONFIG_OSRM_CXXFLAGS "${LibOSRM_CXXFLAGS}")
|
||||
set(PKGCONFIG_OSRM_LDFLAGS "${LibOSRM_LDFLAGS}")
|
||||
set(PKGCONFIG_LIBRARY_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
set(PKGCONFIG_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include")
|
||||
|
||||
list(APPEND DEPENDENCIES_INCLUDE_DIRS "${PKGCONFIG_INCLUDE_DIR}")
|
||||
list(APPEND DEPENDENCIES_INCLUDE_DIRS "${PKGCONFIG_INCLUDE_DIR}/osrm")
|
||||
JOIN("-I${DEPENDENCIES_INCLUDE_DIRS}" " -I" PKGCONFIG_OSRM_INCLUDE_FLAGS)
|
||||
JOIN("${ENGINE_LIBRARIES}" " " PKGCONFIG_OSRM_DEPENDENT_LIBRARIES)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
|
||||
@@ -660,6 +729,7 @@ if (ENABLE_FUZZING)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize-coverage=edge,indirect-calls,8bit-counters -fsanitize=address")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
set(OSRM_LDFLAGS "${OSRM_LDFLAGS} -fsanitize=address")
|
||||
|
||||
message(STATUS "Using -fsanitize=${FUZZ_SANITIZER} for Fuzz testing")
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ set(INFILE ${SOURCE_DIR}/include/util/fingerprint_impl.hpp.in)
|
||||
file(MD5 ${SOURCE_DIR}/src/tools/contract.cpp MD5PREPARE)
|
||||
file(MD5 ${SOURCE_DIR}/include/util/static_rtree.hpp MD5RTREE)
|
||||
file(MD5 ${SOURCE_DIR}/include/util/graph_loader.hpp MD5GRAPH)
|
||||
file(MD5 ${SOURCE_DIR}/include/engine/datafacade/internal_datafacade.hpp MD5OBJECTS)
|
||||
file(MD5 ${SOURCE_DIR}/src/storage/storage.cpp MD5OBJECTS)
|
||||
|
||||
CONFIGURE_FILE(${INFILE} ${NEWFILE})
|
||||
|
||||
|
||||
+6
-6
@@ -1,11 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
includedir=${prefix}/include
|
||||
libdir=${prefix}/lib
|
||||
includedir=@PKGCONFIG_INCLUDE_DIR@
|
||||
libdir=@PKGCONFIG_LIBRARY_DIR@
|
||||
|
||||
Name: libOSRM
|
||||
Description: Project OSRM library
|
||||
Version: v@OSRM_VERSION_MAJOR@.@OSRM_VERSION_MINOR@.@OSRM_VERSION_PATCH@
|
||||
Version: v@OSRM_VERSION@
|
||||
Requires:
|
||||
Libs: -L${libdir} -losrm
|
||||
Libs.private: @ENGINE_LIBRARY_LISTING@
|
||||
Cflags: -I${includedir} -I${includedir}/osrm @OSRM_INCLUDE_PATHS_STRING@ @OSRM_DEFINES_STRING@ @CMAKE_CXX_FLAGS@
|
||||
Libs: -L${libdir} -losrm @PKGCONFIG_OSRM_LDFLAGS@
|
||||
Libs.private: @PKGCONFIG_OSRM_DEPENDENT_LIBRARIES@
|
||||
Cflags: @PKGCONFIG_OSRM_INCLUDE_FLAGS@ @PKGCONFIG_OSRM_CXXFLAGS@
|
||||
|
||||
+336
-281
@@ -1,50 +1,43 @@
|
||||
## Environent Variables
|
||||
## General options
|
||||
|
||||
### SIGNAL_PARENT_WHEN_READY
|
||||
All OSRM HTTP requests use a common structure.
|
||||
|
||||
If the SIGNAL_PARENT_WHEN_READY environment variable is set osrm-routed will
|
||||
send the USR1 signal to its parent when it will be running and waiting for
|
||||
requests. This could be used to upgrade osrm-routed to a new binary on the fly
|
||||
without any service downtime - no incoming requests will be lost.
|
||||
The following syntax applies to all services, except as noted.
|
||||
|
||||
### DISABLE_ACCESS_LOGGING
|
||||
### Requests
|
||||
|
||||
If the DISABLE_ACCESS_LOGGING environment variable is set osrm-routed will
|
||||
**not** log any http requests to standard output. This can be useful in high
|
||||
traffic setup.
|
||||
|
||||
## HTTP API
|
||||
|
||||
`osrm-routed` supports only `GET` requests of the form. If you your response size
|
||||
exceeds the limits of a simple URL encoding, consider using our [NodeJS bindings](https://github.com/Project-OSRM/node-osrm)
|
||||
or using the [C++ library directly](libosrm.md).
|
||||
|
||||
### Request
|
||||
|
||||
```
|
||||
http://{server}/{service}/{version}/{profile}/{coordinates}[.{format}]?option=value&option=value
|
||||
```endpoint
|
||||
GET /{service}/{version}/{profile}/{coordinates}[.{format}]?option=value&option=value
|
||||
```
|
||||
|
||||
- `server`: location of the server. Example: `127.0.0.1:5000` (default)
|
||||
- `service`: Name of the service to be used. Support are the following services:
|
||||
|
||||
| Service | Description |
|
||||
|-------------|-----------------------------------------------------------|
|
||||
| [`route`](#service-route) | fastest path between given coordinates |
|
||||
| [`nearest`](#service-nearest) | returns the nearest street segment for a given coordinate |
|
||||
| [`table`](#service-table) | computes distance tables for given coordinates |
|
||||
| [`match`](#service-match) | matches given coordinates to the road network |
|
||||
| [`trip`](#service-trip) | Compute the fastest round trip between given coordinates |
|
||||
| [`tile`](#service-tile) | Return vector tiles containing debugging info |
|
||||
|
||||
- `version`: Version of the protocol implemented by the service.
|
||||
- `profile`: Mode of transportation, is determined statically by the Lua profile that is used to prepare the data using `osrm-extract`.
|
||||
- `coordinates`: String of format `{longitude},{latitude};{longitude},{latitude}[;{longitude},{latitude} ...]` or `polyline({polyline})`.
|
||||
- `format`: Only `json` is supported at the moment. This parameter is optional and defaults to `json`.
|
||||
| Parameter | Description |
|
||||
| --- | --- |
|
||||
| `service` | One of the following values: [`route`](#route-service), [`nearest`](#nearest-service), [`table`](#table-service), [`match`](#match-service), [`trip`](#trip-service), [`tile`](#tile-service) |
|
||||
| `version` | Version of the protocol implemented by the service. `v1` for all OSRM 5.x installations |
|
||||
| `profile` | Mode of transportation, is determined statically by the Lua profile that is used to prepare the data using `osrm-extract`. Typically `car`, `bike` or `foot` if using one of the supplied profiles. |
|
||||
| `coordinates`| String of format `{longitude},{latitude};{longitude},{latitude}[;{longitude},{latitude} ...]` or `polyline({polyline})`. |
|
||||
| `format`| Only `json` is supported at the moment. This parameter is optional and defaults to `json`. |
|
||||
|
||||
Passing any `option=value` is optional. `polyline` follows Google's polyline format with precision 5 by default and can be generated using [this package](https://www.npmjs.com/package/polyline).
|
||||
|
||||
Passing any `option=value` is optional. `polyline` follows Google's polyline format with precision 5 and can be generated using [this package](https://www.npmjs.com/package/polyline).
|
||||
To pass parameters to each location some options support an array like encoding:
|
||||
|
||||
**Request options**
|
||||
|
||||
| Option | Values | Description |
|
||||
|------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------|
|
||||
|bearings |`{bearing};{bearing}[;{bearing} ...]` |Limits the search to segments with given bearing in degrees towards true north in clockwise direction. |
|
||||
|radiuses |`{radius};{radius}[;{radius} ...]` |Limits the search to given radius in meters. |
|
||||
|hints |`{hint};{hint}[;{hint} ...]` |Hint from previous request to derive position in street network. |
|
||||
|
||||
Where the elements follow the following format:
|
||||
|
||||
| Element | Values |
|
||||
|------------|--------------------------------------------------------|
|
||||
|bearing |`{value},{range}` `integer 0 .. 360,integer 0 .. 180` |
|
||||
|radius |`double >= 0` or `unlimited` (default) |
|
||||
|hint |Base64 `string` |
|
||||
|
||||
```
|
||||
{option}={element};{element}[;{element} ... ]
|
||||
```
|
||||
@@ -57,48 +50,19 @@ Example: 2nd location use the default value for `option`:
|
||||
{option}={element};;{element}
|
||||
```
|
||||
|
||||
## General options
|
||||
#### Example Requests
|
||||
|
||||
| Option | Values | Description |
|
||||
|------------|--------------------------------------------------------|--------------------------------------------------|
|
||||
|bearings |`{bearing};{bearing}[;{bearing} ...]` |Limits the search to segments with given bearing in degrees towards true north in clockwise direction. |
|
||||
|radiuses |`{radius};{radius}[;{radius} ...]` |Limits the search to given radius in meters. |
|
||||
|hints |`{hint};{hint}[;{hint} ...]` |Hint to derive position in street network. |
|
||||
|
||||
Where the elements follow the following format:
|
||||
|
||||
| Element | Values |
|
||||
|------------|--------------------------------------------------------|
|
||||
|bearing |`{value},{range}` `integer 0 .. 360,integer 0 .. 180` |
|
||||
|radius |`double >= 0` or `unlimited` (default) |
|
||||
|hint |Base64 `string` |
|
||||
|
||||
#### Examples
|
||||
|
||||
Query on Berlin with three coordinates:
|
||||
|
||||
```
|
||||
http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?overview=false
|
||||
```curl
|
||||
# Query on Berlin with three coordinates:
|
||||
curl 'http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?overview=false'
|
||||
|
||||
# Using polyline:
|
||||
curl 'http://router.project-osrm.org/route/v1/driving/polyline(ofp_Ik_vpAilAyu@te@g`E)?overview=false'
|
||||
```
|
||||
|
||||
Using polyline:
|
||||
### Responses
|
||||
|
||||
```
|
||||
http://router.project-osrm.org/route/v1/driving/polyline(ofp_Ik_vpAilAyu@te@g`E)?overview=false
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
Every response object has a `code` field.
|
||||
|
||||
```json
|
||||
{
|
||||
"code": {code},
|
||||
"message": {message}
|
||||
}
|
||||
```
|
||||
|
||||
Where `code` is on one of the strings below or service dependent:
|
||||
Every response object has a `code` field containing one of the strings below or a service dependent code:
|
||||
|
||||
| Type | Description |
|
||||
|-------------------|----------------------------------------------------------------------------------|
|
||||
@@ -112,18 +76,27 @@ Where `code` is on one of the strings below or service dependent:
|
||||
| `NoSegment` | One of the supplied input coordinates could not snap to street segment. |
|
||||
| `TooBig` | The request size violates one of the service specific request size restrictions. |
|
||||
|
||||
`message` is a **optional** human-readable error message. All other status types are service dependent.
|
||||
- `message` is a **optional** human-readable error message. All other status types are service dependent.
|
||||
- In case of an error the HTTP status code will be `400`. Otherwise the HTTP status code will be `200` and `code` will be `Ok`.
|
||||
|
||||
In case of an error the HTTP status code will be `400`. Otherwise the HTTP status code will be `200` and `code` will be `Ok`.
|
||||
|
||||
## Service `nearest`
|
||||
|
||||
Snaps a coordinate to the street network and returns the nearest n matches.
|
||||
|
||||
### Request
|
||||
#### Example response
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "Ok",
|
||||
"message": "Everything worked"
|
||||
}
|
||||
```
|
||||
http://{server}/nearest/v1/{profile}/{coordinates}.json?number={number}
|
||||
|
||||
|
||||
## Services
|
||||
|
||||
### Nearest service
|
||||
|
||||
Snaps a coordinate to the street network and returns the nearest `n` matches.
|
||||
|
||||
```endpoint
|
||||
GET http://{server}/nearest/v1/{profile}/{coordinates}.json?number={number}
|
||||
```
|
||||
|
||||
Where `coordinates` only supports a single `{longitude},{latitude}` entry.
|
||||
@@ -134,26 +107,62 @@ In addition to the [general options](#general-options) the following options are
|
||||
|------------|------------------------------|----------------------------------------------------|
|
||||
|number |`integer >= 1` (default `1`) |Number of nearest segments that should be returned. |
|
||||
|
||||
### Response
|
||||
**Response**
|
||||
|
||||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
||||
- `waypoints` array of `Waypoint` objects sorted by distance to the input coordinate. Each object has at least the following additional properties:
|
||||
- `distance`: Distance in meters to the supplied input coordinate.
|
||||
|
||||
### Examples
|
||||
#### Example Requests
|
||||
|
||||
Querying nearest three snapped locations of `13.388860,52.517037` with a bearing between `20° - 340°`.
|
||||
|
||||
```
|
||||
http://router.project-osrm.org/nearest/v1/driving/13.388860,52.517037?number=3&bearings=0,20
|
||||
```curl
|
||||
# Querying nearest three snapped locations of `13.388860,52.517037` with a bearing between `20° - 340°`.
|
||||
curl 'http://router.project-osrm.org/nearest/v1/driving/13.388860,52.517037?number=3&bearings=0,20'
|
||||
```
|
||||
|
||||
## Service `route`
|
||||
|
||||
### Request
|
||||
#### Example Response
|
||||
|
||||
```json
|
||||
{
|
||||
"waypoints" : [
|
||||
{
|
||||
"hint" : "KSoKADRYroqUBAEAEAAAABkAAAAGAAAAAAAAABhnCQCLtwAA_0vMAKlYIQM8TMwArVghAwEAAQH1a66g",
|
||||
"distance" : 4.152629,
|
||||
"name" : "Friedrichstraße",
|
||||
"location" : [
|
||||
13.388799,
|
||||
52.517033
|
||||
]
|
||||
},
|
||||
{
|
||||
"hint" : "KSoKADRYroqUBAEABgAAAAAAAAAAAAAAKQAAABhnCQCLtwAA7kvMAAxZIQM8TMwArVghAwAAAQH1a66g",
|
||||
"distance" : 11.811961,
|
||||
"name" : "Friedrichstraße",
|
||||
"location" : [
|
||||
13.388782,
|
||||
52.517132
|
||||
]
|
||||
},
|
||||
{
|
||||
"hint" : "KioKgDbbDgCUBAEAAAAAABoAAAAAAAAAPAAAABlnCQCLtwAA50vMADJZIQM8TMwArVghAwAAAQH1a66g",
|
||||
"distance" : 15.872438,
|
||||
"name" : "Friedrichstraße",
|
||||
"location" : [
|
||||
13.388775,
|
||||
52.51717
|
||||
],
|
||||
}
|
||||
],
|
||||
"code" : "Ok"
|
||||
}
|
||||
```
|
||||
http://{server}/route/v1/{profile}/{coordinates}?alternatives={true|false}&steps={true|false}&geometries={polyline|polyline6|geojson}&overview={full|simplified|false}&annotations={true|false}
|
||||
|
||||
### Route service
|
||||
|
||||
Finds the fastest route between coordinates in the supplied order.
|
||||
|
||||
```endpoint
|
||||
GET /route/v1/{profile}/{coordinates}?alternatives={true|false}&steps={true|false}&geometries={polyline|polyline6|geojson}&overview={full|simplified|false}&annotations={true|false}
|
||||
```
|
||||
|
||||
In addition to the [general options](#general-options) the following options are supported for this service:
|
||||
@@ -165,11 +174,11 @@ In addition to the [general options](#general-options) the following options are
|
||||
|annotations |`true`, `false` (default) |Returns additional metadata for each coordinate along the route geometry. |
|
||||
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|
||||
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
|
||||
|continue_straight |`default` (default), `true`, `false` |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. |
|
||||
|continue\_straight |`default` (default), `true`, `false` |Forces the route to keep going straight at waypoints constraining uturns there even if it would be faster. Default value depends on the profile. |
|
||||
|
||||
\* Please note that even if an alternative route is requested, a result cannot be guaranteed.
|
||||
|
||||
### Response
|
||||
**Response**
|
||||
|
||||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
||||
- `waypoints`: Array of `Waypoint` objects representing all waypoints in order:
|
||||
@@ -183,23 +192,22 @@ In case of error the following `code`s are supported in addition to the general
|
||||
|
||||
All other fields might be undefined.
|
||||
|
||||
### Example
|
||||
#### Example Request
|
||||
|
||||
Query on Berlin with three coordinates and no overview geometry returned:
|
||||
|
||||
```
|
||||
http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?overview=false
|
||||
```curl
|
||||
# Query on Berlin with three coordinates and no overview geometry returned:
|
||||
curl 'http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?overview=false'
|
||||
```
|
||||
|
||||
## Service `table`
|
||||
### Request
|
||||
```
|
||||
http://{server}/table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&destinations=[{elem}...]`
|
||||
### Table service
|
||||
|
||||
Computes the duration of the fastest route between all pairs of supplied coordinates.
|
||||
|
||||
```endpoint
|
||||
GET /table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&destinations=[{elem}...]
|
||||
```
|
||||
|
||||
This computes duration tables for the given locations. Allows for both symmetric and asymmetric tables.
|
||||
|
||||
### Coordinates
|
||||
**Coordinates**
|
||||
|
||||
In addition to the [general options](#general-options) the following options are supported for this service:
|
||||
|
||||
@@ -211,7 +219,7 @@ In addition to the [general options](#general-options) the following options are
|
||||
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
|
||||
to number of input locations;
|
||||
|
||||
Example:
|
||||
**Example:**
|
||||
|
||||
```
|
||||
sources=0;5;7&destinations=5;1;4;2;3;6
|
||||
@@ -221,7 +229,20 @@ sources=0;5;7&destinations=5;1;4;2;3;6
|
||||
|------------|-----------------------------|
|
||||
|index |`0 <= integer < #locations` |
|
||||
|
||||
### Response
|
||||
#### Example Request
|
||||
|
||||
```curl
|
||||
# Returns a 3x3 matrix:
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219'
|
||||
|
||||
# Returns a 1x3 matrix
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?sources=0'
|
||||
|
||||
# Returns a asymmetric 3x2 matrix with from the polyline encoded locations `qikdcB}~dpXkkHz`:
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHulFzeMe`EuvKpnCglA)?sources=0;1;3&destinations=2;4'
|
||||
```
|
||||
|
||||
**Response**
|
||||
|
||||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
||||
- `durations` array of arrays that stores the matrix in row-major order. `durations[i][j]` gives the travel time from
|
||||
@@ -237,53 +258,39 @@ In case of error the following `code`s are supported in addition to the general
|
||||
|
||||
All other fields might be undefined.
|
||||
|
||||
#### Examples
|
||||
### Match service
|
||||
|
||||
Returns a `3x3` matrix:
|
||||
```
|
||||
http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219
|
||||
```
|
||||
|
||||
Returns a `1x3` matrix:
|
||||
```
|
||||
http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?sources=0
|
||||
```
|
||||
|
||||
Returns a asymmetric 3x2 matrix with from the polyline encoded locations `qikdcB}~dpXkkHz`:
|
||||
```
|
||||
http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHulFzeMe`EuvKpnCglA)?sources=0;1;3&destinations=2;4
|
||||
```
|
||||
|
||||
## Service `match`
|
||||
|
||||
Map matching matches given GPS points to the road network in the most plausible way.
|
||||
Please note the request might result multiple sub-traces. Large jumps in the timestamps (>60s) or improbable transitions lead to trace splits if a complete matching could not be found.
|
||||
Map matching matches/snaps given GPS points to the road network in the most plausible way.
|
||||
Please note the request might result multiple sub-traces. Large jumps in the timestamps (> 60s) or improbable transitions lead to trace splits if a complete matching could not be found.
|
||||
The algorithm might not be able to match all points. Outliers are removed if they can not be matched successfully.
|
||||
|
||||
### Request
|
||||
|
||||
```
|
||||
http://{server}/match/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}
|
||||
```endpoint
|
||||
GET /match/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}
|
||||
```
|
||||
|
||||
In addition to the [general options](#general-options) the following options are supported for this service:
|
||||
|
||||
|
||||
|Option |Values |Description |
|
||||
|------------|------------------------------------------------|------------------------------------------------------------------------------------------|
|
||||
|steps |`true`, `false` (default) |Return route steps for each route |
|
||||
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|
||||
|annotations |`true`, `false` (default) |Returns additional metadata for each coordinate along the route geometry. |
|
||||
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
|
||||
|timestamps |`{timestamp};{timestamp}[;{timestamp} ...]` |Timestamp of the input location. Timestamps need to be monotonically increasing. |
|
||||
|timestamps |`{timestamp};{timestamp}[;{timestamp} ...]` |Timestamps for the input locations in seconds since UNIX epoch. Timestamps need to be monotonically increasing. |
|
||||
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
|
||||
|
||||
|Parameter |Values |
|
||||
|------------|------------------------------|
|
||||
|timestamp |`integer` UNIX-like timestamp |
|
||||
|radius |`double >= 0` (default 5m) |
|
||||
|Parameter |Values |
|
||||
|------------|-----------------------------------|
|
||||
|timestamp |`integer` seconds since UNIX epoch |
|
||||
|radius |`double >= 0` (default 5m) |
|
||||
|
||||
The radius for each point should be the standard error of the location measured in meters from the true location.
|
||||
Use `Location.getAccuracy()` on Android or `CLLocation.horizontalAccuracy` on iOS.
|
||||
This value is used to determine which points should be considered as candidates (larger radius means more candidates) and how likely each candidate is (larger radius means far-away candidates are penalized less).
|
||||
The area to search is chosen such that the correct candidate should be considered 99.9% of the time (for more details see [this ticket](https://github.com/Project-OSRM/osrm-backend/pull/3184)).
|
||||
|
||||
**Response**
|
||||
|
||||
### Response
|
||||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
||||
- `tracepoints`: Array of `Waypoint` objects representing all points of the trace in order.
|
||||
If the trace point was ommited by map matching because it is an outlier, the entry will be `null`.
|
||||
@@ -301,17 +308,15 @@ In case of error the following `code`s are supported in addition to the general
|
||||
|
||||
All other fields might be undefined.
|
||||
|
||||
## Service `trip`
|
||||
### Trip service
|
||||
|
||||
The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm).
|
||||
The returned path does not have to be the fastest path, as TSP is NP-hard it is only an approximation.
|
||||
Note that if the input coordinates can not be joined by a single trip (e.g. the coordinates are on several disconnected islands)
|
||||
multiple trips for each connected component are returned.
|
||||
|
||||
### Request
|
||||
|
||||
```
|
||||
http://{server}/trip/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}
|
||||
```endpoint
|
||||
GET /trip/v1/{profile}/{coordinates}?steps={true|false}&geometries={polyline|polyline6|geojson}&overview={simplified|full|false}&annotations={true|false}'
|
||||
```
|
||||
|
||||
In addition to the [general options](#general-options) the following options are supported for this service:
|
||||
@@ -323,7 +328,7 @@ In addition to the [general options](#general-options) the following options are
|
||||
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|
||||
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
|
||||
|
||||
### Response
|
||||
**Response**
|
||||
|
||||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
||||
- `waypoints`: Array of `Waypoint` objects representing all waypoints in input order. Each `Waypoint` object has the following additional properties:
|
||||
@@ -339,23 +344,68 @@ In case of error the following `code`s are supported in addition to the general
|
||||
|
||||
All other fields might be undefined.
|
||||
|
||||
### Tile service
|
||||
|
||||
This service generates [Mapbox Vector Tiles](https://www.mapbox.com/developers/vector-tiles/) that can be viewed with a vector-tile capable slippy-map viewer. The tiles contain road geometries and metadata that can be used to examine the routing graph. The tiles are generated directly from the data in-memory, so are in sync with actual routing results, and let you examine which roads are actually routable, and what weights they have applied.
|
||||
|
||||
```endpoint
|
||||
GET /tile/v1/{profile}/tile({x},{y},{zoom}).mvt
|
||||
```
|
||||
|
||||
The `x`, `y`, and `zoom` values are the same as described at https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames, and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).
|
||||
|
||||
#### Example request
|
||||
|
||||
```curl
|
||||
# This fetches a Z=13 tile for downtown San Francisco:
|
||||
curl 'http://router.project-osrm.org/tile/v1/car/tile(1310,3166,13).mvt'
|
||||
```
|
||||
|
||||
#### Example response
|
||||
|
||||
> 
|
||||
> http://map.project-osrm.org/debug/#14.33/52.5212/13.3919
|
||||
|
||||
The response object is either a binary encoded blob with a `Content-Type` of `application/x-protobuf`, or a `404` error. Note that OSRM is hard-coded to only return tiles from zoom level 12 and higher (to avoid accidentally returning extremely large vector tiles).
|
||||
|
||||
Vector tiles contain two layers:
|
||||
|
||||
`speeds` layer:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------ | --------- | ---------------------------------------- |
|
||||
| `speed` | `integer` | the speed on that road segment, in km/h |
|
||||
| `is_small` | `boolean` | whether this segment belongs to a small (< 1000 node) [strongly connected component](https://en.wikipedia.org/wiki/Strongly_connected_component) |
|
||||
| `datasource` | `string` | the source for the speed value (normally `lua profile` unless you're using the [traffic update feature](https://github.com/Project-OSRM/osrm-backend/wiki/Traffic), in which case it contains the stem of the filename that supplied the speed value for this segment |
|
||||
| `duration` | `float` | how long this segment takes to traverse, in seconds |
|
||||
| `name` | `string` | the name of the road this segment belongs to |
|
||||
|
||||
`turns` layer:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------ | --------- | ---------------------------------------- |
|
||||
| `bearing_in` | `integer` | the absolute bearing that approaches the intersection. -180 to +180, 0 = North, 90 = East |
|
||||
| `turn_angle` | `integer` | the angle of the turn, relative to the `bearing_in`. -180 to +180, 0 = straight ahead, 90 = 90-degrees to the right |
|
||||
| `cost` | `float` | the time we think it takes to make that turn, in seconds. May be negative, depending on how the data model is constructed (some turns get a "bonus"). |
|
||||
|
||||
|
||||
## Result objects
|
||||
|
||||
### Route
|
||||
### Route object
|
||||
|
||||
Represents a route through (potentially multiple) waypoints.
|
||||
|
||||
#### Properties
|
||||
**Properties**
|
||||
|
||||
- `distance`: The distance traveled by the route, in `float` meters.
|
||||
- `duration`: The estimated travel time, in `float` number of seconds.
|
||||
- `geometry`: The whole geometry of the route value depending on `overview` parameter, format depending on the `geometries` parameter. See `RouteStep`'s `geometry` field for a parameter documentation.
|
||||
|
||||
| overview | Description |
|
||||
|------------|-----------------------------|
|
||||
| simplified | Geometry is simplified according to the highest zoom level it can still be displayed on full. |
|
||||
| full | Geometry is not simplified. |
|
||||
| false | Geometry is not added. |
|
||||
| overview | Description |
|
||||
|------------|-----------------------------|
|
||||
| simplified | Geometry is simplified according to the highest zoom level it can still be displayed on full. |
|
||||
| full | Geometry is not simplified. |
|
||||
| false | Geometry is not added. |
|
||||
|
||||
- `legs`: The legs between the given waypoints, an array of `RouteLeg` objects.
|
||||
|
||||
@@ -383,34 +433,34 @@ Three input coordinates, `geometry=geojson`, `steps=false`:
|
||||
}
|
||||
```
|
||||
|
||||
### RouteLeg
|
||||
### RouteLeg object
|
||||
|
||||
Represents a route between two waypoints.
|
||||
|
||||
#### Properties
|
||||
**Properties**
|
||||
|
||||
- `distance`: The distance traveled by this route leg, in `float` meters.
|
||||
- `duration`: The estimated travel time, in `float` number of seconds.
|
||||
- `summary`: Summary of the route taken as `string`. Depends on the `steps` parameter:
|
||||
|
||||
| steps | |
|
||||
|--------------|-----------------------------------------------------------------------|
|
||||
| true | Names of the two major roads used. Can be empty if route is too short.|
|
||||
| false | empty `string` |
|
||||
| steps | |
|
||||
|--------------|-----------------------------------------------------------------------|
|
||||
| true | Names of the two major roads used. Can be empty if route is too short.|
|
||||
| false | empty `string` |
|
||||
|
||||
- `steps`: Depends on the `steps` parameter.
|
||||
|
||||
| steps | |
|
||||
|--------------|-----------------------------------------------------------------------|
|
||||
| true | array of `RouteStep` objects describing the turn-by-turn instructions |
|
||||
| false | empty array |
|
||||
| steps | |
|
||||
|--------------|-----------------------------------------------------------------------|
|
||||
| true | array of `RouteStep` objects describing the turn-by-turn instructions |
|
||||
| false | empty array |
|
||||
|
||||
- `annotation`: Additional details about each coordinate along the route geometry:
|
||||
|
||||
| annotations | |
|
||||
|--------------|-----------------------------------------------------------------------|
|
||||
| true | An `Annotation` object containing node ids, durations and distances |
|
||||
| false | `undefined` |
|
||||
| annotations | |
|
||||
|--------------|-----------------------------------------------------------------------|
|
||||
| true | An `Annotation` object containing node ids, durations and distances |
|
||||
| false | `undefined` |
|
||||
|
||||
#### Example
|
||||
|
||||
@@ -430,11 +480,11 @@ With `steps=false` and `annotations=true`:
|
||||
}
|
||||
```
|
||||
|
||||
### Annotation
|
||||
### Annotation object
|
||||
|
||||
Annotation of the whole route leg with fine-grained information about each segment or node id.
|
||||
|
||||
#### Properties
|
||||
**Properties**
|
||||
|
||||
- `distance`: The distance, in metres, between each pair of coordinates
|
||||
- `duration`: The duration between each pair of coordinates, in seconds
|
||||
@@ -453,24 +503,24 @@ Annotation of the whole route leg with fine-grained information about each segme
|
||||
```
|
||||
|
||||
|
||||
### RouteStep
|
||||
### RouteStep object
|
||||
|
||||
A step consists of a maneuver such as a turn or merge, followed
|
||||
by a distance of travel along a single way to the subsequent
|
||||
step.
|
||||
|
||||
#### Properties
|
||||
**Properties**
|
||||
|
||||
- `distance`: The distance of travel from the maneuver to the subsequent step, in `float` meters.
|
||||
- `duration`: The estimated travel time, in `float` number of seconds.
|
||||
- `geometry`: The unsimplified geometry of the route segment, depending on the `geometries` parameter.
|
||||
|
||||
| geometries | |
|
||||
|------------|--------------------------------------------------------------------|
|
||||
| polyline | [polyline](https://www.npmjs.com/package/polyline) with precision 5 in [latitude,longitude] encoding |
|
||||
| polyline6 | [polyline](https://www.npmjs.com/package/polyline) with precision 6 in [latitude,longitude] encoding |
|
||||
| geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) or [GeoJSON `Point`](http://geojson.org/geojson-spec.html#point) if it is only one coordinate (not wrapped by a GeoJSON feature)|
|
||||
|
||||
|
||||
| `geometry` | |
|
||||
|------------|--------------------------------------------------------------------|
|
||||
| polyline | [polyline](https://www.npmjs.com/package/polyline) with precision 5 in [latitude,longitude] encoding |
|
||||
| polyline6 | [polyline](https://www.npmjs.com/package/polyline) with precision 6 in [latitude,longitude] encoding |
|
||||
| geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) |
|
||||
|
||||
- `name`: The name of the way along which travel proceeds.
|
||||
- `ref`: A reference number or code for the way. Optionally included, if ref data is available for the given way.
|
||||
- `pronunciation`: The pronunciation hint of the way name. Will be `undefined` if there is no pronunciation hit.
|
||||
@@ -481,42 +531,49 @@ step.
|
||||
|
||||
#### Example
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"distance":152.3,
|
||||
"duration":15.6,
|
||||
"name":"Lortzingstraße",
|
||||
"maneuver":{
|
||||
"type":"turn",
|
||||
"modifier":"right",
|
||||
},
|
||||
"geometry":"{lu_IypwpAVrAvAdI",
|
||||
"mode":"driving",
|
||||
"intersections":[
|
||||
{"location":[13.39677,52.54366],
|
||||
"in":3,
|
||||
"out":2,
|
||||
"bearings":[10,92,184,270],
|
||||
"entry":["true","true","true","false"],
|
||||
"lanes":[
|
||||
{"indications":["left","straight"], "valid":"false"},
|
||||
{"indications":["right"], "valid":"true"}
|
||||
]},
|
||||
{"location":[13.394718,52.543096],
|
||||
"in":0,
|
||||
"out":1,
|
||||
"bearings":[60,240,330],
|
||||
"entry":["false","true","true"]
|
||||
"lanes":[
|
||||
{"indications":["straight"], "valid":"true"},
|
||||
{"indications":["right"], "valid":"false"}
|
||||
]}
|
||||
]}
|
||||
"geometry" : "{lu_IypwpAVrAvAdI",
|
||||
"mode" : "driving",
|
||||
"duration" : 15.6,
|
||||
"intersections" : [
|
||||
{ "bearings" : [ 10, 92, 184, 270 ],
|
||||
"lanes" : [
|
||||
{ "indications" : [ "left", "straight" ],
|
||||
"valid" : "false" },
|
||||
{ "valid" : "true",
|
||||
"indications" : [ "right" ] }
|
||||
],
|
||||
"out" : 2,
|
||||
"in" : 3,
|
||||
"entry" : [ "true", "true", "true", "false" ],
|
||||
"location" : [ 13.39677, 52.54366 ]
|
||||
},
|
||||
{ "out" : 1,
|
||||
"lanes" : [
|
||||
{ "indications" : [ "straight" ],
|
||||
"valid" : "true" },
|
||||
{ "indications" : [ "right" ],
|
||||
"valid" : "false" }
|
||||
],
|
||||
"bearings" : [ 60, 240, 330 ],
|
||||
"in" : 0,
|
||||
"entry" : [ "false", "true", "true" ],
|
||||
"location" : [ 13.394718, 52.543096 ]
|
||||
}
|
||||
],
|
||||
"name" : "Lortzingstraße",
|
||||
"distance" : 152.3,
|
||||
"maneuver" : {
|
||||
"modifier" : "right",
|
||||
"type" : "turn"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### StepManeuver
|
||||
### StepManeuver object
|
||||
|
||||
#### Properties
|
||||
**Properties**
|
||||
|
||||
- `location`: A `[longitude, latitude]` pair describing the location of the turn.
|
||||
- `bearing_before`: The clockwise angle from true north to the
|
||||
@@ -526,79 +583,79 @@ step.
|
||||
- `type` A string indicating the type of maneuver. **new identifiers might be introduced without API change**
|
||||
Types unknown to the client should be handled like the `turn` type, the existance of correct `modifier` values is guranteed.
|
||||
|
||||
| `type` | Description |
|
||||
|------------------|--------------------------------------------------------------|
|
||||
| `turn` | a basic turn into direction of the `modifier` |
|
||||
| `new name` | no turn is taken/possible, but the road name changes. The road can take a turn itself, following `modifier`. |
|
||||
| `depart` | indicates the departure of the leg |
|
||||
| `arrive` | indicates the destination of the leg |
|
||||
| `merge` | merge onto a street (e.g. getting on the highway from a ramp, the `modifier specifies the direction of the merge`) |
|
||||
| `ramp` | **Deprecated**. Replaced by `on_ramp` and `off_ramp`. |
|
||||
| `on ramp` | take a ramp to enter a highway (direction given my `modifier`) |
|
||||
| `off ramp` | take a ramp to exit a highway (direction given my `modifier`) |
|
||||
| `fork` | take the left/right side at a fork depending on `modifier` |
|
||||
| `end of road` | road ends in a T intersection turn in direction of `modifier`|
|
||||
| `use lane` | going straight on a specific lane |
|
||||
| `continue` | Turn in direction of `modifier` to stay on the same road |
|
||||
| `roundabout` | traverse roundabout, has additional field `exit` with NR if the roundabout is left. `the modifier specifies the direction of entering the roundabout` |
|
||||
| `rotary` | a larger version of a roundabout, can offer `rotary_name/rotary_pronunciation` in addition to the `exit` parameter. |
|
||||
| `roundabout turn`| Describes a turn at a small roundabout that should be treated as normal turn. The `modifier` indicates the turn direciton. Example instruction: `At the roundabout turn left`. |
|
||||
| `notification` | not an actual turn but a change in the driving conditions. For example the travel mode. If the road takes a turn itself, the `modifier` describes the direction |
|
||||
| `type` | Description |
|
||||
|------------------|--------------------------------------------------------------|
|
||||
| `turn` | a basic turn into direction of the `modifier` |
|
||||
| `new name` | no turn is taken/possible, but the road name changes. The road can take a turn itself, following `modifier`. |
|
||||
| `depart` | indicates the departure of the leg |
|
||||
| `arrive` | indicates the destination of the leg |
|
||||
| `merge` | merge onto a street (e.g. getting on the highway from a ramp, the `modifier specifies the direction of the merge`) |
|
||||
| `ramp` | **Deprecated**. Replaced by `on_ramp` and `off_ramp`. |
|
||||
| `on ramp` | take a ramp to enter a highway (direction given my `modifier`) |
|
||||
| `off ramp` | take a ramp to exit a highway (direction given my `modifier`) |
|
||||
| `fork` | take the left/right side at a fork depending on `modifier` |
|
||||
| `end of road` | road ends in a T intersection turn in direction of `modifier`|
|
||||
| `use lane` | going straight on a specific lane |
|
||||
| `continue` | Turn in direction of `modifier` to stay on the same road |
|
||||
| `roundabout` | traverse roundabout, has additional field `exit` with NR if the roundabout is left. `the modifier specifies the direction of entering the roundabout` |
|
||||
| `rotary` | a traffic circle. While very similar to a larger version of a roundabout, it does not necessarily follow roundabout rules for right of way. It can offer `rotary_name/rotary_pronunciation` in addition to the `exit` parameter. |
|
||||
| `roundabout turn`| Describes a turn at a small roundabout that should be treated as normal turn. The `modifier` indicates the turn direciton. Example instruction: `At the roundabout turn left`. |
|
||||
| `notification` | not an actual turn but a change in the driving conditions. For example the travel mode. If the road takes a turn itself, the `modifier` describes the direction |
|
||||
|
||||
Please note that even though there are `new name` and `notification` instructions, the `mode` and `name` can change
|
||||
between all instructions. They only offer a fallback in case nothing else is to report.
|
||||
|
||||
- `modifier` An optional `string` indicating the direction change of the maneuver.
|
||||
|
||||
| `modifier` | Description |
|
||||
|-------------------|-------------------------------------------|
|
||||
| `uturn` | indicates reversal of direction |
|
||||
| `sharp right` | a sharp right turn |
|
||||
| `right` | a normal turn to the right |
|
||||
| `slight right` | a slight turn to the right |
|
||||
| `straight` | no relevant change in direction |
|
||||
| `slight left` | a slight turn to the left |
|
||||
| `left` | a normal turn to the left |
|
||||
| `sharp left` | a sharp turn to the left |
|
||||
| `modifier` | Description |
|
||||
|-------------------|-------------------------------------------|
|
||||
| `uturn` | indicates reversal of direction |
|
||||
| `sharp right` | a sharp right turn |
|
||||
| `right` | a normal turn to the right |
|
||||
| `slight right` | a slight turn to the right |
|
||||
| `straight` | no relevant change in direction |
|
||||
| `slight left` | a slight turn to the left |
|
||||
| `left` | a normal turn to the left |
|
||||
| `sharp left` | a sharp turn to the left |
|
||||
|
||||
The list of turns without a modifier is limited to: `depart/arrive`. If the source/target location is close enough to the `depart/arrive` location, no modifier will be given.
|
||||
|
||||
The meaning depends on the `type` field.
|
||||
|
||||
| `type` | Description |
|
||||
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `turn` | `modifier` indicates the change in direction accomplished through the turn |
|
||||
| `depart`/`arrive` | `modifier` indicates the position of departure point and arrival point in relation to the current direction of travel |
|
||||
| `type` | Description |
|
||||
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `turn` | `modifier` indicates the change in direction accomplished through the turn |
|
||||
| `depart`/`arrive` | `modifier` indicates the position of departure point and arrival point in relation to the current direction of travel |
|
||||
|
||||
- `exit` An optional `integer` indicating number of the exit to take. The field exists for the following `type` field:
|
||||
|
||||
| `type` | Description |
|
||||
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `roundabout`/`rotary` | Number of the roundabout exit to take. If exit is `undefined` the destination is on the roundabout. |
|
||||
| else | Indicates the number of intersections passed until the turn. Example instruction: `at the fourth intersection, turn left` |
|
||||
| `type` | Description |
|
||||
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `roundabout`/`rotary` | Number of the roundabout exit to take. If exit is `undefined` the destination is on the roundabout. |
|
||||
| else | Indicates the number of intersections passed until the turn. Example instruction: `at the fourth intersection, turn left` |
|
||||
|
||||
|
||||
New properties (potentially depending on `type`) may be introduced in the future without an API version change.
|
||||
|
||||
### Lane
|
||||
### Lane object
|
||||
|
||||
A `Lane` represents a turn lane at the corresponding turn location.
|
||||
|
||||
#### Properties
|
||||
**Properties**
|
||||
|
||||
- `indications`: a indication (e.g. marking on the road) specifying the turn lane. A road can have multiple indications (e.g. an arrow pointing straight and left). The indications are given in an array, each containing one of the following types. Further indications might be added on without an API version change.
|
||||
|
||||
| `value` | Description |
|
||||
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `none` | No dedicated indication is shown. |
|
||||
| `uturn` | An indication signaling the possibility to reverse (i.e. fully bend arrow). |
|
||||
| `sharp right` | An indication indicating a sharp right turn (i.e. strongly bend arrow). |
|
||||
| `right` | An indication indicating a right turn (i.e. bend arrow). |
|
||||
| `slight right` | An indication indicating a slight right turn (i.e. slightly bend arrow). |
|
||||
| `straight` | No dedicated indication is shown (i.e. straight arrow). |
|
||||
| `slight left` | An indication indicating a slight left turn (i.e. slightly bend arrow). |
|
||||
| `left` | An indication indicating a left turn (i.e. bend arrow). |
|
||||
| `sharp left` | An indication indicating a sharp left turn (i.e. strongly bend arrow). |
|
||||
| `value` | Description |
|
||||
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `none` | No dedicated indication is shown. |
|
||||
| `uturn` | An indication signaling the possibility to reverse (i.e. fully bend arrow). |
|
||||
| `sharp right` | An indication indicating a sharp right turn (i.e. strongly bend arrow). |
|
||||
| `right` | An indication indicating a right turn (i.e. bend arrow). |
|
||||
| `slight right` | An indication indicating a slight right turn (i.e. slightly bend arrow). |
|
||||
| `straight` | No dedicated indication is shown (i.e. straight arrow). |
|
||||
| `slight left` | An indication indicating a slight left turn (i.e. slightly bend arrow). |
|
||||
| `left` | An indication indicating a left turn (i.e. bend arrow). |
|
||||
| `sharp left` | An indication indicating a sharp left turn (i.e. strongly bend arrow). |
|
||||
|
||||
- `valid`: a boolean flag indicating whether the lane is a valid choice in the current maneuver
|
||||
|
||||
@@ -611,12 +668,12 @@ A `Lane` represents a turn lane at the corresponding turn location.
|
||||
}
|
||||
```
|
||||
|
||||
### Intersection
|
||||
### Intersection object
|
||||
|
||||
An intersection gives a full representation of any cross-way the path passes bay. For every step, the very first intersection (`intersections[0]`) corresponds to the
|
||||
location of the StepManeuver. Further intersections are listed for every cross-way until the next turn instruction.
|
||||
|
||||
#### Properties
|
||||
**Properties**
|
||||
|
||||
- `location`: A `[longitude, latitude]` pair describing the location of the turn.
|
||||
- `bearings`: A list of bearing values (e.g. [0,90,180,270]) that are available at the intersection. The bearings describe all available roads at the intersection.
|
||||
@@ -630,7 +687,8 @@ location of the StepManeuver. Further intersections are listed for every cross-w
|
||||
- `lanes`: Array of `Lane` objects that denote the available turn lanes at the intersection. If no lane information is available for an intersection, the `lanes` property will not be present.
|
||||
|
||||
#### Example
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"location":[13.394718,52.543096],
|
||||
"in":0,
|
||||
@@ -641,35 +699,32 @@ location of the StepManeuver. Further intersections are listed for every cross-w
|
||||
"indications": ["left", "straight"],
|
||||
"valid": "false"
|
||||
}
|
||||
]}
|
||||
}
|
||||
```
|
||||
|
||||
### Waypoint
|
||||
### Waypoint object
|
||||
|
||||
Object used to describe waypoint on a route.
|
||||
|
||||
#### Properties
|
||||
**Properties**
|
||||
|
||||
- `name` Name of the street the coordinate snapped to
|
||||
- `location` Array that contains the `[longitude, latitude]` pair of the snapped coordinate
|
||||
- `distance` The distance of the snapped point from the original
|
||||
- `hint` Unique internal identifier of the segment (ephemeral, not constant over data updates)
|
||||
This can be used on subsequent request to significantly speed up the query and to connect multiple services.
|
||||
E.g. you can use the `hint` value obtained by the `nearest` query as `hint` values for `route` inputs.
|
||||
|
||||
## Service `tile`
|
||||
#### Example
|
||||
|
||||
This generates [Mapbox Vector Tiles](https://www.mapbox.com/developers/vector-tiles/) that can be viewed with a vector-tile capable slippy-map viewer. The tiles contain road geometries and metadata that can be used to examine the routing graph. The tiles are generated directly from the data in-memory, so are in sync with actual routing results, and let you examine which roads are actually routable, and what weights they have applied.
|
||||
|
||||
### Request
|
||||
```json
|
||||
{
|
||||
"hint" : "KSoKADRYroqUBAEAEAAAABkAAAAGAAAAAAAAABhnCQCLtwAA_0vMAKlYIQM8TMwArVghAwEAAQH1a66g",
|
||||
"distance" : 4.152629,
|
||||
"name" : "Friedrichstraße",
|
||||
"location" : [
|
||||
13.388799,
|
||||
52.517033
|
||||
]
|
||||
}
|
||||
```
|
||||
http://{server}/tile/v1/{profile}/tile({x},{y},{zoom}).mvt
|
||||
```
|
||||
|
||||
The `x`, `y`, and `zoom` values are the same as described at https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames, and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).
|
||||
|
||||
### Response
|
||||
|
||||
The response object is either a binary encoded blob with a `Content-Type` of `application/x-protobuf`, or a `404` error. Note that OSRM is hard-coded to only return tiles from zoom level 12 and higher (to avoid accidentally returning extremely large vector tiles).
|
||||
|
||||
Vector tiles contain just a single layer named `speeds`. Within that layer, features can have `speed` (int) and `is_small` (boolean) attributes.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 694 KiB |
+13
-6
@@ -1,7 +1,11 @@
|
||||
## Introduction
|
||||
|
||||
OSRM can be used as a library (libosrm) via C++ instead of using it through the HTTP interface and `osrm-routed`. This allows for fine-tuning OSRM and has much less overhead. Here is a quick introduction into how to use `libosrm` in the upcoming v5 release.
|
||||
|
||||
Take a look at the example code that lives in the [example directory](https://github.com/Project-OSRM/osrm-backend/tree/master/example). Here is all you ever wanted to know about `libosrm`, that is a short description of what the types do and where to find documentation on it:
|
||||
|
||||
## Important interface objects
|
||||
|
||||
- [`EngineConfig`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/engine/engine_config.hpp) - for initializing an OSRM instance we can configure certain properties and constraints. E.g. the storage config is the base path such as `france.osm.osrm` from which we derive and load `france.osm.osrm.*` auxiliary files. This also lets you set constraints such as the maximum number of locations allowed for specific services.
|
||||
|
||||
- [`OSRM`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/osrm/osrm.hpp) - this is the main Routing Machine type with functions such as `Route` and `Table`. You initialize it with a `EngineConfig`. It does all the heavy lifting for you. Each function takes its own parameters, e.g. the `Route` function takes `RouteParameters`, and a out-reference to a JSON result that gets filled. The return value is a `Status`, indicating error or success.
|
||||
@@ -16,11 +20,14 @@ Take a look at the example code that lives in the [example directory](https://gi
|
||||
|
||||
- [Parameters for other services](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api) - here are all other `*Parameters` you need for other Routing Machine services.
|
||||
|
||||
- [JSON](https://github.com/Project-OSRM/osrm-backend/blob/master/include/util/json_container.hpp) - this is a sum type resembling JSON. The Routing Machine service functions take a out-ref to a JSON result and fill it accordingly. It is currently implemented using [mapbox/variant](https://github.com/mapbox/variant) which is similar to [Boost.Variant](http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html) (Boost documentation is great). There are two ways to work with this sum type: either provide a visitor that acts on each type on visitation or use the `get` function in case you're sure about the structure. The JSON structure is written down in the [[v5 server API|Server-API-v5,-current]].
|
||||
- [JSON](https://github.com/Project-OSRM/osrm-backend/blob/master/include/util/json_container.hpp) - this is a sum type resembling JSON. The Routing Machine service functions take a out-ref to a JSON result and fill it accordingly. It is currently implemented using [mapbox/variant](https://github.com/mapbox/variant) which is similar to [Boost.Variant](http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html). There are two ways to work with this sum type: either provide a visitor that acts on each type on visitation or use the `get` function in case you're sure about the structure. The JSON structure is written down in the [HTTP API](#http-api).
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------
|
||||
## Example
|
||||
|
||||
To summarize:
|
||||
- create an `OSRM` instance initialized with a `EngineConfig`
|
||||
- call the service function on the `OSRM` object providing service specific `*Parameters`
|
||||
- check the return code and use the JSON result
|
||||
See [the example folder](https://github.com/Project-OSRM/osrm-backend/tree/master/example) in the OSRM repository.
|
||||
|
||||
## Workflow
|
||||
|
||||
- Create an `OSRM` instance initialized with a `EngineConfig`
|
||||
- Call the service function on the `OSRM` object providing service specific `*Parameters`
|
||||
- Check the return code and use the JSON result
|
||||
|
||||
@@ -32,6 +32,7 @@ We may introduce forward-compatible changes: query parameters and response prope
|
||||
|
||||
- The `master` branch is for the bleeding edge development
|
||||
- We create and maintain release branches `x.y` to control the release flow
|
||||
- We create the release branch once we tagged the final version `x.y.0` version, RCs go on master
|
||||
- No minor or major version will be released without a code-equal release candidates
|
||||
- For quality assurance, release candidates will be run on the demo server for 24 hours before releaseing the version proper
|
||||
- Patch versions may be released without a release candidate
|
||||
@@ -44,6 +45,7 @@ We may introduce forward-compatible changes: query parameters and response prope
|
||||
3. Make sure `CHANGELOG.md` is up to date.
|
||||
4. Make sure the OSRM version in `CMakeLists.txt` is up to date
|
||||
5. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries.
|
||||
6. 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
|
||||
6. Push tags and commits: `git push; git push --tags`
|
||||
8. Proceede with the `node-osrm` release as [outlined in the repository](https://github.com/Project-OSRM/node-osrm/blob/master/docs/releasing.md).
|
||||
9. If not a release-candidate: Write a mailing-list post to osrm-talk@openstreetmap.org to announce the release
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
## Environment Variables
|
||||
|
||||
### SIGNAL_PARENT_WHEN_READY
|
||||
|
||||
If the SIGNAL_PARENT_WHEN_READY environment variable is set osrm-routed will
|
||||
send the USR1 signal to its parent when it will be running and waiting for
|
||||
requests. This could be used to upgrade osrm-routed to a new binary on the fly
|
||||
without any service downtime - no incoming requests will be lost.
|
||||
|
||||
### DISABLE_ACCESS_LOGGING
|
||||
|
||||
If the DISABLE_ACCESS_LOGGING environment variable is set osrm-routed will
|
||||
**not** log any http requests to standard output. This can be useful in high
|
||||
traffic setup.
|
||||
@@ -0,0 +1,16 @@
|
||||
var fs = require('fs');
|
||||
|
||||
/**
|
||||
* This file exports the content of your website, as a bunch of concatenated
|
||||
* Markdown files. By doing this explicitly, you can control the order
|
||||
* of content without any level of abstraction.
|
||||
*
|
||||
* Using the brfs module, fs.readFileSync calls in this file are translated
|
||||
* into strings of those files' content before the file is delivered to a
|
||||
* browser: the content is read ahead-of-time and included in bundle.js.
|
||||
*/
|
||||
module.exports =
|
||||
'# HTTP API\n' +
|
||||
fs.readFileSync('./content/http.md', 'utf8') + '\n'+
|
||||
'# libosrm C++ API\n' +
|
||||
fs.readFileSync('./content/libosrm.md', 'utf8') + '\n';
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8' />
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=11' />
|
||||
<title>OSRM API Documentation</title>
|
||||
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
|
||||
<link href='css/base.css' rel='stylesheet' />
|
||||
<link href='css/style.css' rel='stylesheet' />
|
||||
<link href='css/railscasts.css' rel='stylesheet' />
|
||||
</head>
|
||||
<body>
|
||||
<!--START--><div id='app'></div><!--STOP-->
|
||||
<script src='bundle.js'></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Brand names, in order to decreasing length, for different
|
||||
* media queries.
|
||||
*/
|
||||
module.exports.brandNames = {
|
||||
desktop: 'OSRM API Documentation',
|
||||
tablet: 'OSRM API Docs',
|
||||
mobile: 'OSRM API'
|
||||
};
|
||||
|
||||
/**
|
||||
* Classes that define the top-left brand box.
|
||||
*/
|
||||
module.exports.brandClasses = 'fill-red';
|
||||
|
||||
|
||||
/**
|
||||
* Text for the link back to the linking website.
|
||||
*/
|
||||
module.exports.backLink = 'Back to project-osrm.org';
|
||||
|
||||
/**
|
||||
* Runs after highlighting code samples. You can use this
|
||||
* hook to, for instance, highlight a token and link it
|
||||
* to some canonical part of documentation.
|
||||
*/
|
||||
module.exports.postHighlight = function(html) {
|
||||
return html;
|
||||
};
|
||||
|
||||
/**
|
||||
* Highlight tokens in endpoint URLs, optionally linking to documentation
|
||||
* or adding detail. This is the equivalent of postHighlight but it
|
||||
* operates on endpoint URLs only.
|
||||
*/
|
||||
function highlightTokens(str) {
|
||||
return str.replace(/{[\w_]+}/g,
|
||||
(str) => '<span class="strong">' + str + '</span>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform endpoints given as strings in a highlighted block like
|
||||
*
|
||||
* ```endpoint
|
||||
* GET /foo/bar
|
||||
* ```
|
||||
*
|
||||
* Into HTML nodes that format those endpoints in nice ways.
|
||||
*/
|
||||
module.exports.transformURL = function(value) {
|
||||
let parts = value.split(/\s+/);
|
||||
return {
|
||||
type: 'html',
|
||||
value: `<div class='endpoint dark fill-dark round '>
|
||||
<div class='round-left pad0y pad1x fill-lighten0 code small endpoint-method'>${parts[0]}</div>
|
||||
<div class='pad0 code small endpoint-url'>${highlightTokens(parts[1])}</div>
|
||||
</div>`
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.remarkPlugins = [];
|
||||
@@ -309,3 +309,81 @@ And the relations
|
||||
```
|
||||
|
||||
Unless this format is used, OSRM will omit the (then ambiguous) turn restrictions and ignore them.
|
||||
|
||||
## My Guidance Tests are Failing - Understanding what you can change
|
||||
|
||||
If you change some stuff in guidance, you will easily see tests change their result. E.g. if you change the angles for which we report `right`, then obviously some tests might not report a `direction modifier` named `right` anymore.
|
||||
|
||||
This small section will try to guide you in making the correct decisions for changing the behaviour of tests.
|
||||
|
||||
The difficulty in guidance tests is that not all items can be translated 1:1 from the ascii art into turn-angles.
|
||||
|
||||
The turn-angle calculation tries to find turn angles that would represent perceived turn angles, not the exact angle at the connection.
|
||||
|
||||
This is necessary, since connections in OSM are always bound by the paradigm that the way is supposed to be in the middle of the actual road.
|
||||
For broad streets, you will see stronger angles than the actual turns.
|
||||
|
||||
### Don't change the test, change the expected behaviour
|
||||
|
||||
If we have a test that looks like this:
|
||||
|
||||
```
|
||||
Given a grid size of 5 m
|
||||
Given the node map
|
||||
"""
|
||||
a - b - - - - - - c
|
||||
\
|
||||
d - - - - - e
|
||||
"""
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | abc,bde,bde | depart,turn slight right,arrive|
|
||||
```
|
||||
|
||||
And the test reports `turn right` for the route `a->e`, where before it said `slight right`.
|
||||
|
||||
If you changed the turn angles, obviously you can expect changes in the distinction between `slight right` and `right`.
|
||||
In such a case it is, of course, reasonable to change the expected route to report `right` instead of `slight right`. You should consider inspecting the actual turn angles at `b` to see if you feel that change is justified.
|
||||
|
||||
However, you should never adjust the test itself.
|
||||
If you look at a failure, the other way around
|
||||
|
||||
```
|
||||
Given a grid size of 5 m
|
||||
Given the node map
|
||||
"""
|
||||
a - b - - - - - - c
|
||||
\
|
||||
d - - - - - e
|
||||
"""
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | abc,bde,bde | depart,turn right,arrive|
|
||||
```
|
||||
|
||||
where we see a `slight right`, over the expected `right`.
|
||||
We could be tempted to adjust the grid size (e.g. from `10 m` to `20` meters).
|
||||
|
||||
Such a change would fundamentally alter the tests, though.
|
||||
Since the part `b-d` is a short offset, when we are looking at a grid of size `5 m`, the angle calculation will try and compensate for this offset.
|
||||
|
||||
In this case we would see a very slight turn angle. If your change now reports different turn angles, you can of course change the expected result. But you should not adjust the grid size. The test would be testing turn angles of `180` and `100` degrees, instead of `180` and `160`.
|
||||
|
||||
### Consider Post-Processing Impacts
|
||||
|
||||
Some changes you might see could look completely unrelated. To understand the impact of your changes, you can make use of the debugging utilities you can finde in `util/debug.hpp` (and potentially other related headers).
|
||||
|
||||
If your test is inspecting a series of turns (remember, a turn not necessarily equals an instruction), you could see interaction with post-processing.
|
||||
To see the unprocessed turns, you should print the steps at the end of step assembly (`assembleSteps` in `engine/guidance/assemble_steps.hpp`).
|
||||
|
||||
If you see unexpected changes, you can consider adding the `locations` field to your test to study what location a turn is reported at.
|
||||
|
||||
To study a test without post-processing impacts, you can create a copy of the case on a very large grid (like 2000 meters). In such a grid, `turn collapsing` would be essentially disable.
|
||||
|
||||
Sadly, there is no general guideline.
|
||||
|
||||
### Use Caution
|
||||
|
||||
If in doubt, ask another person. Inspect as much of the data as possible (e.g. print un-collapsed steps, turn angles and so on) and use your best judgement, if the new result seems justified.
|
||||
|
||||
@@ -19,7 +19,7 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(bitness 64)
|
||||
message(STATUS "Building on a 64 bit system")
|
||||
else()
|
||||
message(WARNING "Building on a 32 bit system is unsupported")
|
||||
message(STATUS "Building on a 32 bit system")
|
||||
endif()
|
||||
|
||||
if(WIN32 AND MSVC_VERSION LESS 1900)
|
||||
@@ -33,4 +33,4 @@ find_package(LibOSRM REQUIRED)
|
||||
|
||||
target_link_libraries(osrm-example ${LibOSRM_LIBRARIES} ${LibOSRM_DEPENDENT_LIBRARIES})
|
||||
include_directories(SYSTEM ${LibOSRM_INCLUDE_DIRS})
|
||||
set(CMAKE_CXX_FLAGS ${LibOSRM_CXXFLAGS})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LibOSRM_CXXFLAGS}")
|
||||
|
||||
@@ -174,3 +174,11 @@ Feature: Bike - Access tags on ways
|
||||
| cycleway | | no | | x |
|
||||
| runway | | | yes | |
|
||||
| cycleway | | | no | x |
|
||||
|
||||
Scenario: Bike - Bridleways when access is explicit
|
||||
Then routability should be
|
||||
| highway | horse | foot | bicycle | bothw |
|
||||
| bridleway | | | yes | x |
|
||||
| bridleway | | yes | | x |
|
||||
| bridleway | designated | | | |
|
||||
| bridleway | | | | |
|
||||
|
||||
@@ -8,7 +8,7 @@ Feature: Bike - Surfaces
|
||||
Then routability should be
|
||||
| highway | surface | bothw |
|
||||
| cycleway | | 48 s |
|
||||
| cycleway | asphalt | 48 s |
|
||||
| cycleway | asphalt | 47.9 s|
|
||||
| cycleway | cobblestone:flattened | 72 s |
|
||||
| cycleway | paving_stones | 72 s |
|
||||
| cycleway | compacted | 72 s |
|
||||
@@ -26,7 +26,7 @@ Feature: Bike - Surfaces
|
||||
Then routability should be
|
||||
| highway | surface | bothw |
|
||||
| cycleway | | 48 s |
|
||||
| path | | 60 s |
|
||||
| path | | 59.9 s|
|
||||
| track | | 60 s |
|
||||
| track | asphalt | 60 s |
|
||||
| path | asphalt | 60 s |
|
||||
|
||||
@@ -30,6 +30,35 @@ Feature: Car - Restricted access
|
||||
| | | no | yes | x |
|
||||
| | | yes | no | |
|
||||
|
||||
Scenario: Car - Access tag hierarchy and forward/backward
|
||||
Then routability should be
|
||||
| access | access:forward | access:backward | motorcar | motorcar:forward | motorcar:backward | forw | backw |
|
||||
| | | | | | | x | x |
|
||||
| yes | | | | | | x | x |
|
||||
| yes | no | | | | | | x |
|
||||
| yes | yes | | no | | | | |
|
||||
| yes | yes | | yes | no | | | x |
|
||||
| yes | | | | | | x | x |
|
||||
| yes | | no | | | | x | |
|
||||
| yes | | yes | no | | | | |
|
||||
| yes | | yes | yes | | no | x | |
|
||||
| no | | | | | | | |
|
||||
| no | yes | | | | | x | |
|
||||
| no | no | | yes | | | x | x |
|
||||
| no | no | | no | yes | | x | |
|
||||
| no | | | | | | | |
|
||||
| no | | yes | | | | | x |
|
||||
| no | | no | yes | | | x | x |
|
||||
| no | | no | no | | yes | | x |
|
||||
| | no | | | no | | | x |
|
||||
| | | no | | | no | x | |
|
||||
| | no | | | | no | | |
|
||||
| | | no | no | | | | |
|
||||
| | no | | | yes | | x | x |
|
||||
| | | no | | | yes | x | x |
|
||||
| | yes | | | no | | | x |
|
||||
| | | yes | | | no | x | |
|
||||
|
||||
Scenario: Car - Access tag hierarchy on nodes
|
||||
Then routability should be
|
||||
| node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
|
||||
@@ -149,6 +178,7 @@ Feature: Car - Restricted access
|
||||
| runway | | | | yes | |
|
||||
| primary | | | | no | x |
|
||||
|
||||
@hov
|
||||
Scenario: Car - only designated HOV ways are ignored by default
|
||||
Then routability should be
|
||||
| highway | hov | bothw |
|
||||
@@ -156,6 +186,7 @@ Feature: Car - Restricted access
|
||||
| primary | yes | x |
|
||||
| primary | no | x |
|
||||
|
||||
@hov
|
||||
Scenario: Car - a way with all lanes HOV-designated is inaccessible by default (similar to hov=designated)
|
||||
Then routability should be
|
||||
| highway | hov:lanes:forward | hov:lanes:backward | hov:lanes | oneway | forw | backw |
|
||||
@@ -166,8 +197,8 @@ Feature: Car - Restricted access
|
||||
| primary | designated\|no | designated\|no | | | x | x |
|
||||
| primary | yes\|no | yes\|no | | | x | x |
|
||||
| primary | | | | | x | x |
|
||||
| primary | designated | | | -1 | | |
|
||||
| primary | | designated | | -1 | | x |
|
||||
| primary | designated | | | -1 | | x |
|
||||
| primary | | designated | | -1 | | |
|
||||
| primary | | | designated | yes | | |
|
||||
| primary | | | designated | -1 | | |
|
||||
| primary | | | designated\| | yes | x | |
|
||||
|
||||
@@ -90,7 +90,7 @@ OSRM will use 4/5 of the projected free-flow speed.
|
||||
| primary | | 3 | 60 | | 29 km/h | 32 km/h |
|
||||
| primary | | | | 60 | 52 km/h | 47 km/h |
|
||||
| primary | | 3 | | 60 | 32 km/h | 29 km/h |
|
||||
| primary | 15 | | 60 | | 47 km/h | 12 km/h |
|
||||
| primary | 15 | | 60 | | 47 km/h | 11 km/h |
|
||||
| primary | 15 | 3 | 60 | | 29 km/h | 7 km/h |
|
||||
| primary | 15 | | | 60 | 12 km/h | 47 km/h |
|
||||
| primary | 15 | 3 | | 60 | 7 km/h | 29 km/h |
|
||||
@@ -109,7 +109,7 @@ OSRM will use 4/5 of the projected free-flow speed.
|
||||
| primary | | 1 | 60 | | 29 km/h | 32 km/h |
|
||||
| primary | | | | 60 | 52 km/h | 47 km/h |
|
||||
| primary | | 1 | | 60 | 32 km/h | 29 km/h |
|
||||
| primary | 15 | | 60 | | 47 km/h | 12 km/h |
|
||||
| primary | 15 | | 60 | | 47 km/h | 11 km/h |
|
||||
| primary | 15 | 1 | 60 | | 29 km/h | 7 km/h |
|
||||
| primary | 15 | | | 60 | 12 km/h | 47 km/h |
|
||||
| primary | 15 | 1 | | 60 | 7 km/h | 29 km/h |
|
||||
@@ -123,3 +123,14 @@ OSRM will use 4/5 of the projected free-flow speed.
|
||||
| primary | 30 | 1 | -1 | | 23 km/h |
|
||||
| primary | 30 | 1 | | 15 km/h | 15 km/h |
|
||||
| primary | 30 | 2 | | 23 km/h | 23 km/h |
|
||||
|
||||
Scenario: Car - Forwward/backward maxspeed on reverse oneways
|
||||
Then routability should be
|
||||
| highway | maxspeed | maxspeed:forward | maxspeed:backward | oneway | forw | backw |
|
||||
| primary | | | | -1 | | 52 km/h |
|
||||
| primary | 30 | | | -1 | | 23 km/h |
|
||||
| primary | | 30 | | -1 | | 52 km/h |
|
||||
| primary | | | 30 | -1 | | 23 km/h |
|
||||
| primary | 20 | 30 | | -1 | | 16 km/h |
|
||||
| primary | 20 | | 30 | -1 | | 23 km/h |
|
||||
|
||||
|
||||
+13
-13
@@ -78,24 +78,24 @@ Feature: Car - Street names in instructions
|
||||
Scenario: Inner city expressway with on road
|
||||
Given the node map
|
||||
"""
|
||||
a b c g
|
||||
f
|
||||
|
||||
|
||||
|
||||
a b . . . c g
|
||||
`f .
|
||||
`
|
||||
.
|
||||
.
|
||||
d
|
||||
|
||||
|
||||
|
||||
.
|
||||
.
|
||||
.
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | name:pronunciation |
|
||||
| abc | primary | road | roooaad |
|
||||
| cg | primary | road | roooaad |
|
||||
| bfd | trunk_link | | |
|
||||
| cde | trunk | trunk | truank |
|
||||
| nodes | highway | name | name:pronunciation | oneway |
|
||||
| abc | primary | road | roooaad | |
|
||||
| cg | primary | road | roooaad | |
|
||||
| bfd | trunk_link | sliproad | | yes |
|
||||
| cde | trunk | trunk | truank | yes |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
|
||||
@@ -27,7 +27,10 @@ Feature: Basic Routing
|
||||
When I route I should get
|
||||
| waypoints | route | summary |
|
||||
| a,e | road,,1 st,1 st | road, 1 st |
|
||||
| a,d,f | road,,,street,street | road;street |
|
||||
# The via node `d` belongs to `cd`, `de`, `df`, `dg` and depending on the edge
|
||||
# summary can be "road;street", "road, 1 st;1 st, street", "road, blvd;blvd, street"
|
||||
# The test must be fixed by #2287
|
||||
#| a,d,f | road,,,street,street | road;street |
|
||||
| a,e,f | road,,1 st,1 st,1 st,street,street | road, 1 st;1 st, street |
|
||||
|
||||
Scenario: Name Empty
|
||||
|
||||
@@ -111,7 +111,9 @@ Feature: Traffic - turn penalties
|
||||
"""
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| a | d | ad,ad | 10s +-1 |
|
||||
# The target point `d` can be in `ad`, `cd`, `deh` and `dhk`
|
||||
# The test must be fixed by #2287
|
||||
#| a | d | ad,ad | 10s +-1 |
|
||||
| a | e | ad,def,def | 10s +-1 |
|
||||
| b | f | bf,bf | 10s +-1 |
|
||||
| b | g | bf,fg,fg | 20s +-1 |
|
||||
|
||||
@@ -95,3 +95,11 @@ Feature: Foot - Access tags on ways
|
||||
| footway | | no | | x |
|
||||
| motorway | | | yes | |
|
||||
| footway | | | no | x |
|
||||
|
||||
Scenario: Foot - Bridleways when access is explicit
|
||||
Then routability should be
|
||||
| highway | horse | bicycle | foot | bothw |
|
||||
| bridleway | | | yes | x |
|
||||
| bridleway | | yes | | |
|
||||
| bridleway | designated | | | |
|
||||
| bridleway | | | | |
|
||||
|
||||
@@ -5,13 +5,17 @@ Feature: Turn Lane Guidance
|
||||
Given the profile "car"
|
||||
Given a grid size of 3 meters
|
||||
|
||||
|
||||
@sliproads
|
||||
Scenario: Separate Turn Lanes
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a b c g
|
||||
d
|
||||
.
|
||||
a ... b ..... c . g
|
||||
` .
|
||||
`... d
|
||||
.
|
||||
f
|
||||
"""
|
||||
|
||||
@@ -41,8 +45,10 @@ Feature: Turn Lane Guidance
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a b c g
|
||||
d
|
||||
a . . b . . . c g
|
||||
` .
|
||||
` .
|
||||
` d
|
||||
f
|
||||
"""
|
||||
|
||||
@@ -67,21 +73,22 @@ Feature: Turn Lane Guidance
|
||||
| a,g | in,straight,straight | depart,new name straight,arrive | ,left:false straight:true right:false, |
|
||||
| a,f | in,cross,cross | depart,turn right,arrive | ,left:false straight:false right:true, |
|
||||
|
||||
|
||||
@sliproads
|
||||
Scenario: Separate Turn Lanes Next to other turns
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a b c g
|
||||
d
|
||||
f
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
i h j
|
||||
. e
|
||||
a . . b . . . c g
|
||||
. ` .
|
||||
. ` .
|
||||
. d
|
||||
. f
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
i . . h . . . j
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -109,6 +116,7 @@ Feature: Turn Lane Guidance
|
||||
| a,j | in,turn,other,other | depart,turn right,turn left,arrive | ,,left:true right:false, |
|
||||
| a,i | in,turn,other,other | depart,turn right,turn right,arrive | ,,left:false right:true, |
|
||||
|
||||
|
||||
@todo @2654 @none
|
||||
#https://github.com/Project-OSRM/osrm-backend/issues/2645
|
||||
#http://www.openstreetmap.org/export#map=19/52.56054/13.32152
|
||||
@@ -231,6 +239,7 @@ Feature: Turn Lane Guidance
|
||||
| a,j | ghough,market,market | depart,turn left,arrive | ,none:true straight:false straight:false straight:false, |
|
||||
| a,f | ghough,ghough,ghough | depart,continue slight left,arrive | ,none:true straight:true straight:false straight:false, |
|
||||
|
||||
|
||||
Scenario: Check sliproad handler loop's exit condition, Issue #2896
|
||||
# http://www.openstreetmap.org/way/198481519
|
||||
Given the node locations
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
@routing @guidance @staggered-intersections
|
||||
Feature: Staggered Intersections
|
||||
|
||||
Background:
|
||||
Given the profile "bicycle"
|
||||
Given a grid size of 1 meters
|
||||
# Note the one meter grid size: staggered intersections make zig-zags of a couple of meters only
|
||||
|
||||
Scenario: Staggered Intersection - pushing in the middle
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
a b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | residential | Oak St | |
|
||||
| efg | residential | Oak St | |
|
||||
| ihedcj | residential | Cedar Dr | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | modes |
|
||||
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | cycling,pushing bike,cycling,cycling |
|
||||
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
|
||||
|
||||
Scenario: Staggered Intersection - pushing at start
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
a b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| cba | residential | Oak St | yes |
|
||||
| efg | residential | Oak St | |
|
||||
| ihedcj | residential | Cedar Dr | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | modes |
|
||||
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | pushing bike,cycling,cycling,cycling |
|
||||
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
|
||||
|
||||
Scenario: Staggered Intersection - pushing at end
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
a b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | residential | Oak St | |
|
||||
| gfe | residential | Oak St | yes |
|
||||
| ihedcj | residential | Cedar Dr | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | modes |
|
||||
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | cycling,cycling,pushing bike,pushing bike |
|
||||
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
|
||||
|
||||
Scenario: Staggered Intersection - pushing at start and end
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
a b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| cba | residential | Oak St | yes |
|
||||
| gfe | residential | Oak St | yes |
|
||||
| ihedcj | residential | Cedar Dr | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | modes |
|
||||
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | pushing bike,cycling,pushing bike,pushing bike |
|
||||
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
|
||||
|
||||
Scenario: Staggered Intersection - pushing at start and end
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
a b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| cba | pedestrian | Oak St |
|
||||
| gfe | pedestrian | Oak St |
|
||||
| ihedcj | residential | Cedar Dr |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | modes |
|
||||
| a,g | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | pushing bike,cycling,pushing bike,pushing bike |
|
||||
| g,a | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive | pushing bike,cycling,pushing bike,pushing bike |
|
||||
|
||||
Scenario: Staggered Intersection - control, all cycling on staggered intersection
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
a b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| cba | residential | Oak St |
|
||||
| gfe | residential | Oak St |
|
||||
| ihedcj | residential | Cedar Dr |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | modes |
|
||||
| a,g | Oak St,Oak St | depart,arrive | cycling,cycling |
|
||||
| g,a | Oak St,Oak St | depart,arrive | cycling,cycling |
|
||||
@@ -0,0 +1,282 @@
|
||||
@routing @guidance
|
||||
Feature: Rotary
|
||||
|
||||
Background:
|
||||
Given the profile "car"
|
||||
Given a grid size of 30 meters
|
||||
|
||||
Scenario: Enter and Exit
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
b
|
||||
h g c d
|
||||
e
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ab | |
|
||||
| cd | |
|
||||
| ef | |
|
||||
| gh | |
|
||||
| bgecb | circular |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | ab,cd,cd | depart,bgecb-exit-3,arrive |
|
||||
| a,f | ab,ef,ef | depart,bgecb-exit-2,arrive |
|
||||
| a,h | ab,gh,gh | depart,bgecb-exit-1,arrive |
|
||||
| d,f | cd,ef,ef | depart,bgecb-exit-3,arrive |
|
||||
| d,h | cd,gh,gh | depart,bgecb-exit-2,arrive |
|
||||
| d,a | cd,ab,ab | depart,bgecb-exit-1,arrive |
|
||||
| f,h | ef,gh,gh | depart,bgecb-exit-3,arrive |
|
||||
| f,a | ef,ab,ab | depart,bgecb-exit-2,arrive |
|
||||
| f,d | ef,cd,cd | depart,bgecb-exit-1,arrive |
|
||||
| h,a | gh,ab,ab | depart,bgecb-exit-3,arrive |
|
||||
| h,d | gh,cd,cd | depart,bgecb-exit-2,arrive |
|
||||
| h,f | gh,ef,ef | depart,bgecb-exit-1,arrive |
|
||||
|
||||
Scenario: Only Enter
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
b
|
||||
d c g h
|
||||
e
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ab | |
|
||||
| cd | |
|
||||
| ef | |
|
||||
| gh | |
|
||||
| bcegb | circular |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| a,e | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| a,g | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| d,e | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| d,g | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| d,b | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| f,g | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| f,b | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| f,c | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| h,b | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| h,c | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
| h,e | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
|
||||
|
||||
Scenario: Only Exit
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
b
|
||||
d c g h
|
||||
e
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ab | |
|
||||
| cd | |
|
||||
| ef | |
|
||||
| gh | |
|
||||
| bcegb | circular |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| b,d | bcegb,cd,cd | depart,bcegb-exit-1,arrive |
|
||||
| b,f | bcegb,ef,ef | depart,bcegb-exit-2,arrive |
|
||||
| b,h | bcegb,gh,gh | depart,bcegb-exit-3,arrive |
|
||||
| c,f | bcegb,ef,ef | depart,bcegb-exit-1,arrive |
|
||||
| c,h | bcegb,gh,gh | depart,bcegb-exit-2,arrive |
|
||||
| c,a | bcegb,ab,ab | depart,bcegb-exit-3,arrive |
|
||||
| e,h | bcegb,gh,gh | depart,bcegb-exit-1,arrive |
|
||||
| e,a | bcegb,ab,ab | depart,bcegb-exit-2,arrive |
|
||||
| e,d | bcegb,cd,cd | depart,bcegb-exit-3,arrive |
|
||||
| g,a | bcegb,ab,ab | depart,bcegb-exit-1,arrive |
|
||||
| g,d | bcegb,cd,cd | depart,bcegb-exit-2,arrive |
|
||||
| g,f | bcegb,ef,ef | depart,bcegb-exit-3,arrive |
|
||||
#phantom node snapping can result in a full round-trip here, therefore we cannot test b->a and the other direct exits
|
||||
|
||||
Scenario: Drive Around
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
b
|
||||
d c g h
|
||||
e
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ab | |
|
||||
| cd | |
|
||||
| ef | |
|
||||
| gh | |
|
||||
| bcegb | circular |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| b,c | bcegb,bcegb | depart,arrive |
|
||||
| b,e | bcegb,bcegb | depart,arrive |
|
||||
| b,g | bcegb,bcegb | depart,arrive |
|
||||
| c,e | bcegb,bcegb | depart,arrive |
|
||||
| c,g | bcegb,bcegb | depart,arrive |
|
||||
| c,b | bcegb,bcegb | depart,arrive |
|
||||
| e,g | bcegb,bcegb | depart,arrive |
|
||||
| e,b | bcegb,bcegb | depart,arrive |
|
||||
| e,c | bcegb,bcegb | depart,arrive |
|
||||
| g,b | bcegb,bcegb | depart,arrive |
|
||||
| g,c | bcegb,bcegb | depart,arrive |
|
||||
| g,e | bcegb,bcegb | depart,arrive |
|
||||
|
||||
#needs to be adjusted when name-discovery works for entrys
|
||||
Scenario: Mixed Entry and Exit
|
||||
Given the node map
|
||||
"""
|
||||
c a
|
||||
j b f
|
||||
k e
|
||||
l h d
|
||||
g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction | oneway |
|
||||
| abc | | yes |
|
||||
| def | | yes |
|
||||
| ghi | | yes |
|
||||
| jkl | | yes |
|
||||
| bkheb | circular | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | abc,abc,abc | depart,rotary-exit-1,arrive |
|
||||
| a,l | abc,jkl,jkl | depart,bkheb-exit-2,arrive |
|
||||
| a,i | abc,ghi,ghi | depart,bkheb-exit-3,arrive |
|
||||
| a,f | abc,def,def | depart,bkheb-exit-4,arrive |
|
||||
| d,f | def,def,def | depart,rotary-exit-1,arrive |
|
||||
| d,c | def,abc,abc | depart,bkheb-exit-2,arrive |
|
||||
| d,l | def,jkl,jkl | depart,bkheb-exit-3,arrive |
|
||||
| d,i | def,ghi,ghi | depart,bkheb-exit-4,arrive |
|
||||
| g,i | ghi,ghi,ghi | depart,rotary-exit-1,arrive |
|
||||
| g,f | ghi,def,def | depart,bkheb-exit-2,arrive |
|
||||
| g,c | ghi,abc,abc | depart,bkheb-exit-3,arrive |
|
||||
| g,l | ghi,jkl,jkl | depart,bkheb-exit-4,arrive |
|
||||
| j,l | jkl,jkl,jkl | depart,rotary-exit-1,arrive |
|
||||
| j,i | jkl,ghi,ghi | depart,bkheb-exit-2,arrive |
|
||||
| j,f | jkl,def,def | depart,bkheb-exit-3,arrive |
|
||||
| j,c | jkl,abc,abc | depart,bkheb-exit-4,arrive |
|
||||
|
||||
Scenario: Collinear in X,Y
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
b
|
||||
c d f
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ab | |
|
||||
| bcdb | circular |
|
||||
| ce | |
|
||||
| df | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
|
||||
| a,f | ab,df,df | depart,bcdb-exit-2,arrive |
|
||||
|
||||
Scenario: Collinear in X,Y
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
d
|
||||
b c f
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ad | |
|
||||
| bcdb | circular |
|
||||
| be | |
|
||||
| cf | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | ad,be,be | depart,bcdb-exit-1,arrive |
|
||||
| a,f | ad,cf,cf | depart,bcdb-exit-2,arrive |
|
||||
|
||||
Scenario: Collinear in X,Y
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
c
|
||||
d b f
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ac | |
|
||||
| bcdb | circular |
|
||||
| de | |
|
||||
| bf | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | ac,de,de | depart,bcdb-exit-1,arrive |
|
||||
| a,f | ac,bf,bf | depart,bcdb-exit-2,arrive |
|
||||
|
||||
Scenario: Collinear in X,Y
|
||||
Given the node map
|
||||
"""
|
||||
f
|
||||
d c e
|
||||
b
|
||||
a
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ab | |
|
||||
| bcdb | circular |
|
||||
| ce | |
|
||||
| df | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
|
||||
| a,f | ab,df,df | depart,bcdb-exit-2,arrive |
|
||||
|
||||
Scenario: Collinear in X,Y
|
||||
Given the node map
|
||||
"""
|
||||
f
|
||||
d c e
|
||||
b
|
||||
a
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ab | |
|
||||
| bcdb | circular |
|
||||
| ce | |
|
||||
| df | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | ab,ce,ce | depart,bcdb-exit-1,arrive |
|
||||
| a,f | ab,df,df | depart,bcdb-exit-2,arrive |
|
||||
@@ -55,3 +55,38 @@ Feature: Collapse
|
||||
| waypoints | route | turns |
|
||||
| a,g | road,road,road | depart,continue uturn,arrive |
|
||||
| d,c | road,road,road | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Forking before a turn (forky)
|
||||
Given the node map
|
||||
"""
|
||||
g
|
||||
.
|
||||
c
|
||||
a . . b .'
|
||||
`d.
|
||||
f e
|
||||
"""
|
||||
# note: check clooapse.feature for a similar test case where we do not
|
||||
# classify the situation as Sliproad and therefore keep the fork inst.
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway | highway |
|
||||
| ab | road | yes | primary |
|
||||
| bd | road | yes | primary |
|
||||
| bc | road | yes | primary |
|
||||
| de | road | yes | primary |
|
||||
| fd | cross | no | secondary |
|
||||
| dc | cross | no | secondary |
|
||||
| cg | cross | no | secondary |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | bd | dc | d | no_left_turn |
|
||||
| restriction | bc | dc | c | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | road,cross,cross | depart,turn left,arrive |
|
||||
| a,e | road,road,road | depart,continue right,arrive |
|
||||
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
|
||||
| a,f | road,road,cross,cross | depart,continue slight right,turn right,arrive |
|
||||
|
||||
@@ -338,10 +338,10 @@ Feature: Collapse
|
||||
Given the node map
|
||||
"""
|
||||
a f g
|
||||
|
||||
b e
|
||||
|
||||
|
||||
| | . '
|
||||
b-e '
|
||||
/ /
|
||||
/ /
|
||||
c d
|
||||
"""
|
||||
|
||||
@@ -353,13 +353,13 @@ Feature: Collapse
|
||||
| ge | primary | second | no |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| d,c | first,first,first | depart,continue uturn,arrive |
|
||||
| a,f | first,first,first | depart,continue uturn,arrive |
|
||||
| a,g | first,second,second | depart,turn left,arrive |
|
||||
| d,g | first,second,second | depart,turn right,arrive |
|
||||
| g,f | second,first,first | depart,turn right,arrive |
|
||||
| g,c | second,first,first | depart,end of road left,arrive |
|
||||
| waypoints | route | turns |
|
||||
| d,c | first,first,first | depart,continue uturn,arrive |
|
||||
| a,f | first,first,first | depart,continue uturn,arrive |
|
||||
| a,g | first,second,second | depart,turn left,arrive |
|
||||
| d,g | first,second,second | depart,turn right,arrive |
|
||||
| g,f | second,first,first | depart,turn right,arrive |
|
||||
| g,c | second,first,first | depart,turn left,arrive |
|
||||
|
||||
Scenario: Do not collapse turning roads
|
||||
Given the node map
|
||||
@@ -484,6 +484,23 @@ Feature: Collapse
|
||||
| waypoints | route | turns |
|
||||
| a,d | road,road | depart,arrive |
|
||||
|
||||
Scenario: No Name During Turns - Ferry
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | route |
|
||||
| ab | tertiary | road | |
|
||||
| bc | tertiary | | ferry |
|
||||
| cd | tertiary | road | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | road,,road,road | depart,notification right,notification left,arrive |
|
||||
|
||||
Scenario: No Name During Turns, Random Oneway
|
||||
Given the node map
|
||||
"""
|
||||
@@ -684,12 +701,15 @@ Feature: Collapse
|
||||
Given the node map
|
||||
"""
|
||||
g
|
||||
|
||||
.
|
||||
c
|
||||
a b
|
||||
d
|
||||
a . . b .'
|
||||
` d.
|
||||
f e
|
||||
"""
|
||||
# as it is right now we don't classify this as a sliproad,
|
||||
# check collapse-detail.feature for a similar test case
|
||||
# which removes the fork here due to it being a Sliproad.
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway | highway |
|
||||
@@ -707,11 +727,10 @@ Feature: Collapse
|
||||
| restriction | bc | dc | c | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | road,cross,cross | depart,turn left,arrive |
|
||||
| a,e | road,road,road | depart,continue slight right,arrive |
|
||||
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
|
||||
| a,f | road,road,cross,cross | depart,continue slight right,turn right,arrive |
|
||||
| waypoints | route | turns |
|
||||
| a,g | road,cross,cross | depart,fork left,arrive |
|
||||
| a,e | road,road,road | depart,fork slight right,arrive |
|
||||
| a,f | road,road,cross,cross | depart,fork slight right,turn right,arrive |
|
||||
|
||||
Scenario: On-Off on Highway
|
||||
Given the node map
|
||||
@@ -738,12 +757,13 @@ Feature: Collapse
|
||||
Scenario: Don't collapse going straight if actual turn
|
||||
Given the node map
|
||||
"""
|
||||
c e
|
||||
d f
|
||||
|
||||
e
|
||||
c |
|
||||
\ d - - - f
|
||||
\|
|
||||
b
|
||||
|
||||
|
||||
|
|
||||
|
|
||||
a
|
||||
"""
|
||||
|
||||
@@ -754,10 +774,10 @@ Feature: Collapse
|
||||
| df | right | residential |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | main,main | depart,arrive |
|
||||
| a,e | main,straight,straight | depart,turn straight,arrive |
|
||||
| a,f | main,straight,right,right | depart,turn straight,turn right,arrive |
|
||||
| waypoints | route | turns | locations |
|
||||
| a,c | main,main | depart,arrive | a,c |
|
||||
| a,e | main,straight,straight | depart,turn straight,arrive | a,b,e |
|
||||
| a,f | main,straight,right,right | depart,turn straight,turn right,arrive | a,b,d,f |
|
||||
|
||||
Scenario: Entering a segregated road
|
||||
Given the node map
|
||||
@@ -929,16 +949,17 @@ Feature: Collapse
|
||||
|
||||
#http://www.openstreetmap.org/#map=19/52.48778/13.30024
|
||||
Scenario: Hohenzollerdammbrücke
|
||||
Given a grid size of 10 meters
|
||||
Given the node map
|
||||
"""
|
||||
q s
|
||||
p o
|
||||
.. . .
|
||||
. . . .
|
||||
.. ..
|
||||
. . . .
|
||||
j - i - - - h - - - g - f
|
||||
> k < > l <
|
||||
a - b - - - c - - - d - e
|
||||
. . . .
|
||||
. . . .
|
||||
.. ..
|
||||
m n
|
||||
t r
|
||||
@@ -995,13 +1016,13 @@ Feature: Collapse
|
||||
| restriction | ph | hi | h | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | hohe,hohe | depart,arrive |
|
||||
| a,s | hohe,a100,a100 | depart,on ramp left,arrive |
|
||||
| a,t | hohe,a100,a100 | depart,on ramp right,arrive |
|
||||
| a,j | | |
|
||||
| f,j | hohe,hohe | depart,arrive |
|
||||
| a,t | hohe,a100,a100 | depart,on ramp right,arrive |
|
||||
| f,e | | |
|
||||
| q,j | a100,hohe,hohe | depart,turn right,arrive |
|
||||
| q,e | a100,a100,hohe | depart,continue left,arrive |
|
||||
| waypoints | route | turns | locations |
|
||||
| a,e | hohe,hohe | depart,arrive | a,e |
|
||||
| a,s | hohe,a100,a100 | depart,on ramp left,arrive | a,b,s |
|
||||
| a,t | hohe,a100,a100 | depart,on ramp right,arrive | a,b,t |
|
||||
| a,j | | | |
|
||||
| f,j | hohe,hohe | depart,arrive | f,j |
|
||||
| a,t | hohe,a100,a100 | depart,on ramp right,arrive | a,b,t |
|
||||
| f,e | | | |
|
||||
| q,j | a100,hohe,hohe | depart,turn right,arrive | q,p,j |
|
||||
| q,e | a100,hohebruecke,hohe | depart,turn left,arrive | q,p,e |
|
||||
|
||||
@@ -9,32 +9,32 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a b c d
|
||||
h
|
||||
|
||||
1
|
||||
|
||||
a b . . c d
|
||||
`h .
|
||||
`
|
||||
1 `
|
||||
.
|
||||
f
|
||||
|
||||
.
|
||||
g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | trunk | first |
|
||||
| cd | trunk | first |
|
||||
| bhf | trunk_link | |
|
||||
| cfg | primary | second |
|
||||
| ec | primary | second |
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | trunk | first | |
|
||||
| cd | trunk | first | |
|
||||
| bhf | trunk_link | | yes |
|
||||
| cfg | primary | second | yes |
|
||||
| ec | primary | second | |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | abc | cfg | c | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,second,second | depart,turn right,arrive |
|
||||
| a,1 | first,, | depart,turn slight right,arrive |
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,second,second | depart,turn right,arrive |
|
||||
| a,1 | first,, | depart,turn right,arrive |
|
||||
|
||||
Scenario: Turn Instead of Ramp - Max-Speed
|
||||
Given the node map
|
||||
@@ -51,21 +51,21 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | maxspeed |
|
||||
| abc | trunk | first | 70 |
|
||||
| cd | trunk | first | 2 |
|
||||
| bhf | trunk_link | | 2 |
|
||||
| cfg | primary | second | 50 |
|
||||
| ec | primary | second | 50 |
|
||||
| nodes | highway | name | maxspeed | oneway |
|
||||
| abc | trunk | first | 70 | |
|
||||
| cd | trunk | first | 2 | |
|
||||
| bhf | trunk_link | | 2 | yes |
|
||||
| cfg | primary | second | 50 | yes |
|
||||
| ec | primary | second | 50 | |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | abc | cfg | c | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,second,second | depart,turn right,arrive |
|
||||
| a,1 | first,, | depart,turn slight right,arrive |
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,second,second | depart,turn right,arrive |
|
||||
| a,1 | first,, | depart,turn right,arrive |
|
||||
|
||||
|
||||
Scenario: Turn Instead of Ramp
|
||||
@@ -94,8 +94,8 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| efg | primary | second |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,,second,second | depart,off ramp slight right,turn straight,arrive |
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,,second,second | depart,off ramp right,turn straight,arrive |
|
||||
|
||||
Scenario: Turn Instead of Ramp
|
||||
Given the node map
|
||||
@@ -119,30 +119,30 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| efg | primary | second |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,,second,second | depart,off ramp slight right,turn straight,arrive |
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,,second,second | depart,off ramp right,turn straight,arrive |
|
||||
|
||||
Scenario: Inner city expressway with on road
|
||||
Given the node map
|
||||
"""
|
||||
a b c g
|
||||
f
|
||||
|
||||
|
||||
|
||||
a b . . . c g
|
||||
`f .
|
||||
`
|
||||
.
|
||||
.
|
||||
d
|
||||
|
||||
|
||||
|
||||
.
|
||||
.
|
||||
.
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | primary | road |
|
||||
| cg | primary | road |
|
||||
| bfd | trunk_link | |
|
||||
| cde | trunk | trunk |
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | primary | road | |
|
||||
| cg | primary | road | |
|
||||
| bfd | trunk_link | | yes |
|
||||
| cde | trunk | trunk | yes |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
@@ -240,8 +240,8 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| qe | secondary_link | Ettlinger Allee | | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | ref |
|
||||
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
|
||||
| waypoints | route | turns | ref |
|
||||
| a,o | Schwarzwaldstrasse,Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive | L561,L561, |
|
||||
|
||||
Scenario: Traffic Lights everywhere
|
||||
#http://map.project-osrm.org/?z=18¢er=48.995336%2C8.383813&loc=48.995467%2C8.384548&loc=48.995115%2C8.382761&hl=en&alt=0
|
||||
@@ -271,11 +271,11 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| jcghf | primary | Brauerstrasse | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
|
||||
| a,1 | Ebertstrasse,, | depart,turn right,arrive |
|
||||
| waypoints | route | turns |
|
||||
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
|
||||
| a,1 | Ebertstrasse,, | depart,turn slight right,arrive |
|
||||
|
||||
#2839
|
||||
Scenario: Self-Loop
|
||||
@@ -431,3 +431,354 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,i | road,road,road | depart,fork slight left,arrive |
|
||||
|
||||
|
||||
# The following tests are current false positives / false negatives #3199
|
||||
|
||||
@sliproads
|
||||
# http://www.openstreetmap.org/#map=19/52.59847/13.14815
|
||||
Scenario: Sliproad Detection
|
||||
Given the node map
|
||||
"""
|
||||
a . . .
|
||||
. .
|
||||
b . . . . . . c . . . d
|
||||
` . .
|
||||
e . .
|
||||
` . .
|
||||
f . .
|
||||
` . .
|
||||
g i
|
||||
` h .
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abefgh | residential | Nachtigallensteig |
|
||||
| bcd | residential | Kiebitzsteig |
|
||||
| cg | residential | Haenflingsteig |
|
||||
| hid | residential | Waldkauzsteig |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | Nachtigallensteig,Kiebitzsteig,Kiebitzsteig | depart,turn left,arrive |
|
||||
| a,h | Nachtigallensteig,Nachtigallensteig | depart,arrive |
|
||||
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a obvious Sliproad
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
` e
|
||||
.`
|
||||
. `
|
||||
f g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbef | primary | dbef | yes |
|
||||
| aeg | primary | aeg | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,aeg,dbef,dbef | depart,turn right,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Through Street, not a Sliproad although obvious
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
` e
|
||||
. `
|
||||
. `
|
||||
f g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbef | primary | dbef | yes |
|
||||
| aeg | primary | aeg | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,aeg,dbef,dbef | depart,turn right,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Sliproad target turn is restricted
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . . . b . . c
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
`.
|
||||
e
|
||||
.`
|
||||
f `
|
||||
. ` g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sa | primary | sabc | |
|
||||
| abc | primary | sabc | |
|
||||
| dbe | primary | dbef | yes |
|
||||
| ef | primary | dbef | |
|
||||
| ae | primary | aeg | yes |
|
||||
| eg | primary | aeg | |
|
||||
# the reason we have to split ways at e is that otherwise we can't handle restrictions via e
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | ae | ef | e | no_right_turn |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,dbef,dbef | depart,turn right,arrive |
|
||||
| s,g | sabc,aeg,aeg | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a Sliproad, road not continuing straight
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
` e . . g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbe | primary | dbe | yes |
|
||||
| aeg | primary | aeg | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,c | sabc,sabc | depart,arrive |
|
||||
| s,g | sabc,aeg,aeg | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Intersection too far away with Traffic Light shortly after initial split
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . . . . . . . . . . . . t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . b . . c
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . . . . . . . . . . .
|
||||
` . . .
|
||||
` e
|
||||
.
|
||||
f
|
||||
.
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| t | traffic_signals |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| satbc | primary | sabc | |
|
||||
| dbef | primary | dbef | yes |
|
||||
| ae | primary | ae | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,ae,dbef,dbef | depart,turn slight right,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Traffic Signal on Sliproad
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . . . . b . . c
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
t .
|
||||
` .
|
||||
e
|
||||
.
|
||||
.
|
||||
f
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
| node | highway |
|
||||
| t | traffic_signals |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | sabc | |
|
||||
| dbe | primary | dbe | yes |
|
||||
| ef | primary | ef | |
|
||||
| ate | primary | ate | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,ef,ef | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Sliproad tagged as link
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . . . . b . . c
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
` .
|
||||
e
|
||||
.
|
||||
.
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | motorway | sabc | |
|
||||
| dbef | motorway | dbef | yes |
|
||||
| ae | motorway_link | ae | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,f | sabc,dbef,dbef | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Sliproad with same-ish names
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
. e
|
||||
..
|
||||
.
|
||||
f
|
||||
.
|
||||
t
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | ref | oneway |
|
||||
| sabc | primary | main | | |
|
||||
| dbe | primary | crossing | r0 | yes |
|
||||
| eft | primary | crossing | r0;r1 | yes |
|
||||
| af | primary | sliproad | | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,t | main,crossing,crossing | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a Sliproad, name mismatch
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
. e
|
||||
. .
|
||||
..
|
||||
.
|
||||
f
|
||||
.
|
||||
t
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | main | |
|
||||
| dbe | primary | top | yes |
|
||||
| ef | primary | bottom | yes |
|
||||
| ft | primary | away | yes |
|
||||
| af | primary | sliproad | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,t | main,away,away | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a Sliproad, low road priority
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
. e
|
||||
. .
|
||||
..
|
||||
.
|
||||
f
|
||||
.
|
||||
t
|
||||
"""
|
||||
|
||||
And the ways
|
||||
# maxspeed otherwise service road will never be routed over and we won't see instructions
|
||||
| nodes | highway | name | maxspeed | oneway |
|
||||
| sabc | primary | main | 30 km/h | |
|
||||
| dbe | primary | crossing | 30 km/h | yes |
|
||||
| eft | primary | crossing | 30 km/h | yes |
|
||||
| ft | primary | away | 30 km/h | yes |
|
||||
| af | service | sliproad | 30 km/h | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,t | main,away,away | depart,turn right,arrive |
|
||||
|
||||
@sliproads
|
||||
Scenario: Not a Sliproad, more than three roads at target intersection
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
.
|
||||
s . a . . b . . c
|
||||
` .
|
||||
. e
|
||||
. .
|
||||
..
|
||||
. h
|
||||
f .
|
||||
. g
|
||||
t
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| sabc | primary | main | |
|
||||
| dbe | primary | top | yes |
|
||||
| eft | primary | bottom | yes |
|
||||
| fh | primary | another | |
|
||||
| fg | primary | another | |
|
||||
| af | primary | sliproad | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| s,g | main,sliproad,another,another | depart,turn right,turn left,arrive |
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
@routing @guidance
|
||||
Feature: Exceptions for routing onto low-priority roads
|
||||
|
||||
Background:
|
||||
Given the profile "car"
|
||||
Given a grid size of 10 meters
|
||||
|
||||
Scenario: Straight onto low-priority: same name
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
||||
a b d
|
||||
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abd | residential | road |
|
||||
| eb | service | service |
|
||||
| bc | service | service |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| c,e | service,service | depart,arrive |
|
||||
| e,c | service,service | depart,arrive |
|
||||
|
||||
Scenario: Straight onto low-priority: onto and from unnamed
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
||||
a b d
|
||||
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abd | residential | road |
|
||||
| eb | service | |
|
||||
| bc | service | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| e,c | , | depart,arrive |
|
||||
| c,e | , | depart,arrive |
|
||||
|
||||
Scenario: Straight onto low-priority: unnamed
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
|
||||
a b d
|
||||
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abd | residential | road |
|
||||
| eb | service | service |
|
||||
| bc | service | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| e,c | service, | depart,arrive |
|
||||
| c,e | ,service,service | depart,turn straight,arrive |
|
||||
|
||||
Scenario: Straight onto low-priority
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| ab | residential | road |
|
||||
| bc | service | service |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | road,service,service | depart,new name straight,arrive |
|
||||
|
||||
Scenario: Straight onto low-priority, with driveway
|
||||
Given the node map
|
||||
"""
|
||||
f
|
||||
a b c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| ab | residential | road |
|
||||
| bc | service | road |
|
||||
| bf | driveway | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | road,road | depart,arrive |
|
||||
|
||||
Scenario: Straight onto low-priority, with driveway
|
||||
Given the node map
|
||||
"""
|
||||
f
|
||||
a b c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| ab | residential | road |
|
||||
| bc | service | |
|
||||
| bf | driveway | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | road, | depart,arrive |
|
||||
| c,a | ,road,road | depart,new name straight,arrive |
|
||||
@@ -10,12 +10,12 @@ Feature: Simple Turns
|
||||
"""
|
||||
a
|
||||
b
|
||||
|
||||
|
||||
^
|
||||
/ \
|
||||
c d
|
||||
|
||||
e
|
||||
|
||||
|\
|
||||
| e
|
||||
|
|
||||
f
|
||||
"""
|
||||
|
||||
@@ -96,16 +96,16 @@ Feature: Simple Turns
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
|
||||
b
|
||||
|
|
||||
.b.
|
||||
c h
|
||||
|
||||
|
||||
| |
|
||||
| |
|
||||
1 2
|
||||
|
||||
| |
|
||||
d g
|
||||
e
|
||||
|
||||
'e'
|
||||
|
|
||||
f
|
||||
"""
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
@routing @guidance @left-handed
|
||||
Feature: Basic Roundabout
|
||||
|
||||
Background:
|
||||
Given a grid size of 10 meters
|
||||
Given the profile file
|
||||
"""
|
||||
require 'car'
|
||||
properties.left_hand_driving = true
|
||||
"""
|
||||
|
||||
Scenario: Roundabout exit counting for left sided driving
|
||||
And a grid size of 10 meters
|
||||
And the node map
|
||||
"""
|
||||
a
|
||||
b
|
||||
h g c d
|
||||
e
|
||||
f
|
||||
"""
|
||||
And the ways
|
||||
| nodes | junction |
|
||||
| ab | |
|
||||
| cd | |
|
||||
| ef | |
|
||||
| gh | |
|
||||
| bcegb | roundabout |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | ab,cd,cd | depart,roundabout turn left exit-1,arrive |
|
||||
| a,f | ab,ef,ef | depart,roundabout turn straight exit-2,arrive |
|
||||
| a,h | ab,gh,gh | depart,roundabout turn right exit-3,arrive |
|
||||
|
||||
Scenario: Mixed Entry and Exit
|
||||
And a grid size of 10 meters
|
||||
And the node map
|
||||
"""
|
||||
c a
|
||||
j b f
|
||||
k e
|
||||
l h d
|
||||
g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction | oneway |
|
||||
| cba | | yes |
|
||||
| fed | | yes |
|
||||
| ihg | | yes |
|
||||
| lkj | | yes |
|
||||
| behkb | roundabout | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| c,a | cba,cba,cba | depart,roundabout-exit-1,arrive |
|
||||
| l,a | lkj,cba,cba | depart,roundabout-exit-2,arrive |
|
||||
| i,a | ihg,cba,cba | depart,roundabout-exit-3,arrive |
|
||||
@@ -38,6 +38,30 @@ Feature: Basic Roundabout
|
||||
| h,c | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||
| h,e | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||
|
||||
Scenario: Roundabout With Service
|
||||
Given the node map
|
||||
"""
|
||||
a h
|
||||
bg
|
||||
d c
|
||||
e
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction | highway |
|
||||
| ab | | primary |
|
||||
| cd | | primary |
|
||||
| ef | | service |
|
||||
| gh | | primary |
|
||||
| bcegb | roundabout | primary |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,d | ab,cd,cd | depart,roundabout-exit-1,arrive |
|
||||
| a,h | ab,gh,gh | depart,roundabout-exit-2,arrive |
|
||||
| a,f | ab,ef,ef | depart,roundabout-exit-2,arrive |
|
||||
|
||||
#2927
|
||||
Scenario: Only Roundabout
|
||||
Given the node map
|
||||
@@ -468,3 +492,46 @@ Feature: Basic Roundabout
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| e,h | left,right,right | depart,roundabout-exit-2,arrive |
|
||||
|
||||
@3361
|
||||
Scenario: Bersarinplatz (Not a Roundabout)
|
||||
Given the node map
|
||||
"""
|
||||
a n
|
||||
|
||||
b m
|
||||
|
||||
c l
|
||||
|
||||
d e j k
|
||||
|
||||
f h
|
||||
|
||||
g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction | name | ref | highway | oneway |
|
||||
| ab | | Petersburger Strasse | B 96a | primary | yes |
|
||||
| bc | circular | Bersarinplatz | B 96a | primary | |
|
||||
| ce | circular | Bersarinplatz | B 96a | primary | |
|
||||
| ed | | Weidenweg | | residential | |
|
||||
| ef | circular | Bersarinplatz | B 96a | primary | |
|
||||
| fg | | Petersburger Strasse | B 96a | primary | yes |
|
||||
| fh | circular | Bersarinplatz | | secondary | |
|
||||
| ih | | Petersburger Strasse | B 96a | primary | yes |
|
||||
| hj | circular | Bersarinplatz | | secondary | |
|
||||
| jk | | Rigaer Strasse | | residential | |
|
||||
| jl | circular | Bersarinplatz | | secondary | |
|
||||
| lm | circular | Bersarinplatz | | secondary | |
|
||||
| mb | circular | Bersarinplatz | | secondary | |
|
||||
| mn | | Petersburger Strasse | B 96a | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | Petersburger Strasse,Petersburger Strasse,Petersburger Strasse | depart,Bersarinplatz-exit-2,arrive |
|
||||
| d,g | Weidenweg,Petersburger Strasse,Petersburger Strasse | depart,Bersarinplatz-exit-1,arrive |
|
||||
| i,k | Petersburger Strasse,Rigaer Strasse,Rigaer Strasse | depart,Bersarinplatz-exit-1,arrive |
|
||||
| i,n | Petersburger Strasse,Petersburger Strasse,Petersburger Strasse | depart,Bersarinplatz-exit-2,arrive |
|
||||
| i,d | Petersburger Strasse,Weidenweg,Weidenweg | depart,Bersarinplatz-exit-3,arrive |
|
||||
| i,g | Petersburger Strasse,Petersburger Strasse,Petersburger Strasse | depart,Bersarinplatz-exit-4,arrive |
|
||||
|
||||
@@ -25,7 +25,7 @@ Feature: Staggered Intersections
|
||||
| jcdehi | residential | Cedar Dr |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| waypoints | route | turns |
|
||||
| a,g | Oak St,Oak St | depart,arrive |
|
||||
| g,a | Oak St,Oak St | depart,arrive |
|
||||
|
||||
@@ -98,3 +98,48 @@ Feature: Staggered Intersections
|
||||
| waypoints | route | turns |
|
||||
| a,g | Oak St,Cedar Dr,Elm St,Elm St | depart,turn right,turn left,arrive |
|
||||
| g,a | Elm St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
|
||||
|
||||
Scenario: Staggered Intersection: do not collapse if a mode change is involved
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
a b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | route |
|
||||
| abc | primary | to_sea | |
|
||||
| ef | | to_sea | ferry |
|
||||
| fg | primary | road | |
|
||||
| jcdeh | primary | road | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | modes |
|
||||
| a,g | to_sea,road,to_sea,road,road | depart,turn right,turn left,notification straight,arrive | driving,driving,ferry,driving,driving |
|
||||
| g,a | road,to_sea,road,to_sea,to_sea | depart,notification straight,turn right,turn left,arrive | driving,ferry,driving,driving,driving |
|
||||
|
||||
Scenario: Staggered Intersection: do not collapse intermediary intersections
|
||||
Given the node map
|
||||
"""
|
||||
j
|
||||
a b c
|
||||
e f g
|
||||
d
|
||||
k l m
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | primary | Oak St |
|
||||
| efg | residential | Elm St |
|
||||
| klm | residential | Oak St |
|
||||
| jcedki | residential | Cedar Dr |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,m | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
|
||||
| m,a | Oak St,Cedar Dr,Oak St,Oak St | depart,turn right,turn left,arrive |
|
||||
|
||||
@@ -201,14 +201,14 @@ Feature: Simple Turns
|
||||
| ef | residential | road | 2 | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,c | road,road | depart,arrive |
|
||||
| c,a | road,road | depart,arrive |
|
||||
| g,a | turn,road,road | depart,turn left,arrive |
|
||||
| g,c | turn,road,road | depart,turn right,arrive |
|
||||
| g,f | turn,road | depart,arrive |
|
||||
| c,f | road,road,road | depart,continue right,arrive |
|
||||
| a,f | road,road,road | depart,continue uturn,arrive |
|
||||
| waypoints | route | turns | locations |
|
||||
| a,c | road,road | depart,arrive | a,c |
|
||||
| c,a | road,road | depart,arrive | c,a |
|
||||
| g,a | turn,road,road | depart,turn left,arrive | g,b,a |
|
||||
| g,c | turn,road,road | depart,turn right,arrive | g,b,c |
|
||||
| g,f | turn,road,road | depart,turn left,arrive | g,e,f |
|
||||
| c,f | road,road,road | depart,continue right,arrive | c,b,f |
|
||||
| a,f | road,road,road | depart,continue uturn,arrive | a,b,f |
|
||||
|
||||
# http://www.openstreetmap.org/#map=19/52.48753/13.52838
|
||||
Scenario: Traffic Circle
|
||||
@@ -249,7 +249,7 @@ Feature: Simple Turns
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns | intersections |
|
||||
| a,p | road,road,road | depart,roundabout turn straight exit-1,arrive | true:90;true:135 false:270 false:345,true:90 false:180 true:345;true:270 |
|
||||
| a,p | road,road,road | depart,roundabout turn straight exit-1,arrive | true:90;true:165 false:270 false:345,true:90 false:180 true:345;true:270 |
|
||||
|
||||
Scenario: Splitting Road with many lanes
|
||||
Given the node map
|
||||
@@ -317,30 +317,30 @@ Feature: Simple Turns
|
||||
Scenario: Curved Turn At Cross
|
||||
Given the node map
|
||||
"""
|
||||
h
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
| . b - - - - - - - - - - - - - - - - - - a
|
||||
| .
|
||||
| .
|
||||
| c
|
||||
|
|
||||
|
|
||||
|
|
||||
d
|
||||
|
|
||||
|
|
||||
|
|
||||
e |
|
||||
. |
|
||||
. |
|
||||
g - - - - - - - - - - - - - f |
|
||||
|
|
||||
|
|
||||
|
|
||||
i
|
||||
h
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
| . b - - - - - - - - - - - - - - - - - - - - - - - a
|
||||
| .
|
||||
| .
|
||||
| c
|
||||
|
|
||||
|
|
||||
|
|
||||
d
|
||||
|
|
||||
|
|
||||
|
|
||||
e |
|
||||
. |
|
||||
. |
|
||||
g - - - - - - - - - - - - - - - - - - f |
|
||||
|
|
||||
|
|
||||
|
|
||||
i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -443,9 +443,9 @@ Feature: Simple Turns
|
||||
| ef | residential | road | 2 | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| g,f | turn,road,road | depart,turn left,arrive |
|
||||
| c,f | road,road,road | depart,continue right,arrive |
|
||||
| waypoints | route | turns | locations | # |
|
||||
| g,f | turn,road | depart,arrive | g,f | #could offer an additional turn at `e` if you don't detect the turn in between as curve |
|
||||
| c,f | road,road,road | depart,continue right,arrive | c,b,f | |
|
||||
|
||||
#http://www.openstreetmap.org/search?query=52.479264%2013.295617#map=19/52.47926/13.29562
|
||||
Scenario: Splitting Roads with curved split
|
||||
@@ -627,12 +627,14 @@ Feature: Simple Turns
|
||||
| 1,h | ,allee,allee | depart,turn left,arrive |
|
||||
| 2,h | ,allee,allee | depart,turn left,arrive |
|
||||
|
||||
|
||||
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
|
||||
@todo
|
||||
Scenario: Curved Turn on Separated Directions
|
||||
Given the node map
|
||||
"""
|
||||
e d
|
||||
f - - - - - - - - - - - - - - - c - - - - - - - - - - - j
|
||||
f c - - - - - - - - - - - j
|
||||
| l ' |
|
||||
| ' |
|
||||
| ' |
|
||||
@@ -680,6 +682,58 @@ Feature: Simple Turns
|
||||
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
|
||||
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
|
||||
|
||||
#http://www.openstreetmap.org/#map=18/52.56251/13.32650
|
||||
Scenario: Curved Turn on Separated Directions
|
||||
Given the node map
|
||||
"""
|
||||
e d
|
||||
f c - - - - - - - - - - - j
|
||||
| l ' |
|
||||
| ' |
|
||||
| ' |
|
||||
| ' |
|
||||
| ' |
|
||||
| n |
|
||||
| |
|
||||
| ' |
|
||||
| |
|
||||
| ' |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
|' |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
g |
|
||||
h - - - - - - - - - - - - - - - b - - - - - - - - - - - o
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
i a
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | oneway | lanes | highway |
|
||||
| jc | Kapweg | yes | 3 | primary |
|
||||
| clngh | Kapweg | yes | | primary_link |
|
||||
| hbo | Kapweg | yes | 2 | primary |
|
||||
| efh | Kurt | yes | 4 | secondary |
|
||||
| hi | Kurt | yes | 3 | primary |
|
||||
| ab | Kurt | yes | 4 | primary |
|
||||
| cd | Kurt | yes | 3 | secondary |
|
||||
| bc | Kurt | yes | 2 | primary |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| j,i | Kapweg,Kurt,Kurt | depart,turn left,arrive |
|
||||
| j,o | Kapweg,Kapweg,Kapweg | depart,continue uturn,arrive |
|
||||
| a,i | Kurt,Kurt,Kurt | depart,continue uturn,arrive |
|
||||
|
||||
#http://www.openstreetmap.org/#map=19/52.53731/13.36033
|
||||
Scenario: Splitting Road to Left
|
||||
Given the node map
|
||||
@@ -775,7 +829,7 @@ Feature: Simple Turns
|
||||
| waypoints | route | turns |
|
||||
| a,j | Siemens,Siemens,Siemens | depart,continue slight right,arrive |
|
||||
| a,g | Siemens,Erna,Erna | depart,new name slight left,arrive |
|
||||
| g,j | Erna,Siemens,Siemens | depart,turn sharp left,arrive |
|
||||
| g,j | Erna,Siemens,Siemens | depart,turn left,arrive |
|
||||
| g,a | Erna,Siemens,Siemens | depart,new name slight right,arrive |
|
||||
|
||||
#http://www.openstreetmap.org/#map=19/52.51303/13.32170
|
||||
@@ -1112,8 +1166,9 @@ Feature: Simple Turns
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | highway | lanes |
|
||||
| abcdefghijklmnopc | circled | residential | 1 |
|
||||
| nodes | name | highway | lanes | oneway |
|
||||
| abc | circled | residential | 1 | no |
|
||||
| cdefghijklmnopc | circled | residential | 1 | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | bearings | route | turns |
|
||||
@@ -1168,3 +1223,40 @@ Feature: Simple Turns
|
||||
When I route I should get
|
||||
| waypoints | route |
|
||||
| a,e | ab,bcde,bcde |
|
||||
|
||||
|
||||
@3401
|
||||
Scenario: Curve With Duplicated Coordinates
|
||||
Given the node locations
|
||||
| node | lat | lon | # |
|
||||
| a | 0.9999280745650984 | 1.0 | |
|
||||
| b | 0.9999280745650984 | 1.0000179813587253 | |
|
||||
| c | 0.9999280745650984 | 1.0000359627174509 | |
|
||||
| d | 0.9999460559238238 | 1.0000674300952204 | |
|
||||
| e | 0.9999640372825492 | 1.0000809161142643 | |
|
||||
| f | 0.9999820186412746 | 1.0000854114539457 | |
|
||||
| g | 1.0 | 1.0000854114539457 | |
|
||||
| h | 1.0 | 1.0000854114539457 | #same as g |
|
||||
| z | 0.9999100932063729 | 1.0000179813587253 | |
|
||||
# g
|
||||
# |
|
||||
# f
|
||||
# '
|
||||
# e
|
||||
# '
|
||||
# d
|
||||
# '
|
||||
#a - b - c
|
||||
# |
|
||||
# z
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | lanes | # |
|
||||
| ab | yes | 1 | |
|
||||
| zb | yes | 1 | |
|
||||
| bcdefgh | yes | 1 | #intentional duplication |
|
||||
|
||||
# we don't care for turn instructions, this is a coordinate extraction bug check
|
||||
When I route I should get
|
||||
| waypoints | route | intersections |
|
||||
| a,g | ab,bcdefgh,bcdefgh | true:90;true:45 false:180 false:270;true:180 |
|
||||
|
||||
@@ -44,6 +44,27 @@ Feature: Turn Lane Guidance
|
||||
| a,c | in,straight,straight | depart,new name straight,arrive | ,straight:true right:false, |
|
||||
| a,d | in,right,right | depart,turn right,arrive | ,straight:false right:true, |
|
||||
|
||||
# Turn Lane onto a ferry could end up breaking in intersection generation
|
||||
Scenario: Basic Turn Lane 3-way Turn with designated lane
|
||||
Given the node map
|
||||
"""
|
||||
a - b ~ ~ c - e
|
||||
| |
|
||||
d f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | turn:lanes:forward | name | route |
|
||||
| ab | through\|through\|right | ferry-route | |
|
||||
| bc | through\|through\|right | ferry-route | ferry |
|
||||
| ce | | ferry-route | |
|
||||
| bd | | right | |
|
||||
| cf | | right | |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | ferry-route,ferry-route,ferry-route,ferry-route | depart,notification straight,notification straight,arrive |
|
||||
|
||||
@simple
|
||||
Scenario: Basic Turn Lane 4-Way Turn
|
||||
Given the node map
|
||||
@@ -95,24 +116,25 @@ Feature: Turn Lane Guidance
|
||||
Scenario: Basic Turn Lane 4-Way With U-Turn Lane
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a 1 b c
|
||||
d
|
||||
e
|
||||
f a-1-b---c
|
||||
d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | turn:lanes | turn:lanes:forward | name |
|
||||
| ab | | reverse;left\|through;right | in |
|
||||
| bc | | | straight |
|
||||
| bd | | | right |
|
||||
| be | | | left |
|
||||
| nodes | turn:lanes | turn:lanes:forward | name | # |
|
||||
| ab | | reverse;left\|through;right | in | |
|
||||
| bc | | | straight | |
|
||||
| bd | | | right | |
|
||||
| be | | | left | |
|
||||
| fa | | | uturn-avoider | #due to https://github.com/Project-OSRM/osrm-backend/issues/3359 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | bearings | route | turns | lanes |
|
||||
| a | c | 180,180 180,180 | in,straight,straight | depart,new name straight,arrive | ,left;uturn:false straight;right:true, |
|
||||
| a | d | 180,180 180,180 | in,right,right | depart,turn right,arrive | ,left;uturn:false straight;right:true, |
|
||||
| a | e | 180,180 180,180 | in,left,left | depart,turn left,arrive | ,left;uturn:true straight;right:false, |
|
||||
| 1 | a | 90,2 270,2 | in,in,in | depart,turn uturn,arrive | ,left;uturn:true straight;right:false, |
|
||||
| from | to | bearings | route | turns | lanes | locations |
|
||||
| a | c | 180,180 180,180 | in,straight,straight | depart,new name straight,arrive | ,left;uturn:false straight;right:true, | a,b,c |
|
||||
| a | d | 180,180 180,180 | in,right,right | depart,turn right,arrive | ,left;uturn:false straight;right:true, | a,b,d |
|
||||
| a | e | 180,180 180,180 | in,left,left | depart,turn left,arrive | ,left;uturn:true straight;right:false, | a,b,e |
|
||||
| 1 | a | 90,2 270,2 | in,in,in | depart,turn uturn,arrive | ,left;uturn:true straight;right:false, | _,b,a |
|
||||
|
||||
|
||||
#this next test requires decision on how to announce lanes for going straight if there is no turn
|
||||
|
||||
@@ -1179,8 +1179,8 @@ Feature: Simple Turns
|
||||
Scenario: Obvious Index wigh very narrow turn to the right
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
d
|
||||
a - b -.-.- - - c
|
||||
' ' 'd
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -1198,8 +1198,8 @@ Feature: Simple Turns
|
||||
Scenario: Obvious Index wigh very narrow turn to the right
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
e d f
|
||||
a - b - . -.- - c
|
||||
e - -'-'d-f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -1218,8 +1218,8 @@ Feature: Simple Turns
|
||||
Scenario: Obvious Index wigh very narrow turn to the left
|
||||
Given the node map
|
||||
"""
|
||||
d
|
||||
a b c
|
||||
. . .d
|
||||
a - b -'-'- - - c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -1237,8 +1237,8 @@ Feature: Simple Turns
|
||||
Scenario: Obvious Index wigh very narrow turn to the left
|
||||
Given the node map
|
||||
"""
|
||||
e d f
|
||||
a b c
|
||||
e - -.- d-f
|
||||
a - b - ' - - - c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
@@ -1373,5 +1373,5 @@ Feature: Simple Turns
|
||||
| kchm | Alexanderstr | primary | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | turns | route |
|
||||
| a,d | depart,new name straight,arrive | Stralauer Str,Holzmarktstr,Holzmarktstr |
|
||||
| waypoints | turns | route |
|
||||
| a,d | depart,arrive | Stralauer Str,Holzmarktstr |
|
||||
|
||||
@@ -3,6 +3,14 @@ Feature: osrm-contract command line options: invalid options
|
||||
|
||||
Background:
|
||||
Given the profile "testbot"
|
||||
And the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
And the data has been extracted
|
||||
|
||||
Scenario: osrm-contract - Non-existing option
|
||||
When I try to run "osrm-contract --fly-me-to-the-moon"
|
||||
@@ -10,3 +18,11 @@ Feature: osrm-contract command line options: invalid options
|
||||
And stderr should contain "option"
|
||||
And stderr should contain "fly-me-to-the-moon"
|
||||
And it should exit with an error
|
||||
|
||||
# This tests the error messages when you try to use --segment-speed-file,
|
||||
# but osrm-extract has not been run with --generate-edge-lookup
|
||||
Scenario: osrm-contract - Someone forgot --generate-edge-lookup on osrm-extract
|
||||
When I try to run "osrm-contract --segment-speed-file /dev/null {processed_file}"
|
||||
Then stderr should contain "Error while trying to mmap"
|
||||
Then stderr should contain ".osrm.edge_penalties"
|
||||
And it should exit with an error
|
||||
|
||||
@@ -37,7 +37,7 @@ module.exports = function () {
|
||||
outputRow[direction] = result[direction].status ?
|
||||
result[direction].status.toString() : '';
|
||||
break;
|
||||
case /^\d+ s/.test(want):
|
||||
case /^[\d\.]+ s/.test(want):
|
||||
// the result here can come back as a non-number value like
|
||||
// `diff`, but we only want to apply the unit when it comes
|
||||
// back as a number, for tableDiff's literal comparison
|
||||
@@ -127,23 +127,6 @@ module.exports = function () {
|
||||
var parseRes = (key, scb) => {
|
||||
if (result.forw[key] === result.backw[key]) {
|
||||
result.bothw[key] = result.forw[key];
|
||||
// FIXME these time and speed checks are stopgaps for precision errors in how
|
||||
// OSRM returns inconsistent durations for rev/for requests along the same way
|
||||
} else if (key === 'time') {
|
||||
var range = [result.forw[key] - 1, result.forw[key] + 1];
|
||||
if (result.backw[key] >= range[0] && result.backw[key] <= range[1])
|
||||
// usually when we see minor differences here there's an integer
|
||||
// duration value and one that comes back with a .9 or .1 rounding.
|
||||
// This returns the integer one
|
||||
result.bothw[key] = parseInt(result.forw[key]) === result.forw[key] ? result.forw[key] : result.backw[key];
|
||||
else
|
||||
result.bothw[key] = 'diff';
|
||||
} else if (key === 'speed') {
|
||||
if (Math.abs(result.backw.time - result.forw.time) < 0.2) {
|
||||
result.bothw[key] = parseInt(result.forw[key]) === result.forw[key] ? result.forw[key] : result.backw[key];
|
||||
} else {
|
||||
result.bothw[key] = 'diff';
|
||||
}
|
||||
} else {
|
||||
result.bothw[key] = 'diff';
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ Feature: Bearing parameter
|
||||
Scenario: Testbot - Initial bearing on split way
|
||||
Given the node map
|
||||
"""
|
||||
g d 1 c f
|
||||
g d 2 1 c f
|
||||
h a 0 b e
|
||||
"""
|
||||
|
||||
@@ -64,21 +64,17 @@ Feature: Bearing parameter
|
||||
| ha | yes |
|
||||
|
||||
When I route I should get
|
||||
| from | to | bearings | route | bearing |
|
||||
| 0 | b | 10 10 | bc,bc | 0->0,0->0 |
|
||||
| 0 | b | 90 90 | ab,ab | 0->90,90->0 |
|
||||
# The returned bearing is wrong here, it's based on the snapped
|
||||
# coordinates, not the acutal edge bearing. This should be
|
||||
# fixed one day, but it's only a problem when we snap two vias
|
||||
# to the same point - DP
|
||||
#| 0 | b | 170 170 | da | 180 |
|
||||
#| 0 | b | 189 189 | da | 180 |
|
||||
| 0 | 1 | 90 270 | ab,bc,cd,cd | 0->90,90->0,0->270,270->0 |
|
||||
| 1 | d | 10 10 | bc,bc | 0->0,0->0 |
|
||||
| 1 | d | 90 90 | ab,bc,cd,da,da | 0->90,90->0,0->270,270->180,180->0 |
|
||||
| 1 | 0 | 189 189 | da,da | 0->180,180->0 |
|
||||
| 1 | d | 270 270 | cd,cd | 0->270,270->0 |
|
||||
| 1 | d | 349 349 | | |
|
||||
| from | to | bearings | route | bearing |
|
||||
| 0 | b | 10 10 | bc,bc | 0->0,0->0 |
|
||||
| 0 | b | 90 90 | ab,ab | 0->90,90->0 |
|
||||
| 0 | b | 170 170 | da,da | 0->0,0->0 |
|
||||
| 0 | b | 189 189 | da,da | 0->0,0->0 |
|
||||
| 0 | 1 | 90 270 | ab,bc,cd,cd | 0->90,90->0,0->270,270->0 |
|
||||
| 1 | 2 | 10 10 | bc,bc | 0->0,0->0 |
|
||||
| 1 | 2 | 90 90 | ab,bc,cd,da,ab,ab | 0->90,90->0,0->270,270->180,180->90,90->0 |
|
||||
| 1 | 0 | 189 189 | da,da | 0->180,180->0 |
|
||||
| 1 | 2 | 270 270 | cd,cd | 0->270,270->0 |
|
||||
| 1 | 2 | 349 349 | | |
|
||||
|
||||
Scenario: Testbot - Initial bearing in all direction
|
||||
Given the node map
|
||||
|
||||
@@ -20,5 +20,5 @@ Feature: Geometry Compression
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | distance | speed |
|
||||
| b | e | abcdef,abcdef | 588.8m | 36 km/h |
|
||||
| e | b | abcdef,abcdef | 588.8m | 36 km/h |
|
||||
| b | e | abcdef,abcdef | 588.6m | 36 km/h |
|
||||
| e | b | abcdef,abcdef | 588.6m | 36 km/h |
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
@routing @testbot @nil
|
||||
Feature: Testbot - Check assigning nil values
|
||||
Scenario: Assign nil values to all way strings
|
||||
Given the profile file "testbot" extended with
|
||||
"""
|
||||
function way_function (way, result)
|
||||
result.name = "name"
|
||||
result.ref = "ref"
|
||||
result.destinations = "destinations"
|
||||
result.pronunciation = "pronunciation"
|
||||
result.turn_lanes_forward = "turn_lanes_forward"
|
||||
result.turn_lanes_backward = "turn_lanes_backward"
|
||||
|
||||
result.name = nil
|
||||
result.ref = nil
|
||||
result.destinations = nil
|
||||
result.pronunciation = nil
|
||||
result.turn_lanes_forward = nil
|
||||
result.turn_lanes_backward = nil
|
||||
|
||||
result.forward_speed = 10
|
||||
result.backward_speed = 10
|
||||
result.forward_mode = mode.driving
|
||||
result.backward_mode = mode.driving
|
||||
end
|
||||
"""
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
|
||||
d
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| bd |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | d | ,, |
|
||||
| d | a | ,, |
|
||||
@@ -83,28 +83,3 @@ Feature: Testbot - side bias
|
||||
| a,d | ab,cd,cd | depart,roundabout turn left exit-1,arrive |
|
||||
| a,f | ab,ef,ef | depart,roundabout turn straight exit-2,arrive |
|
||||
| a,h | ab,gh,gh | depart,roundabout turn right exit-3,arrive |
|
||||
|
||||
Scenario: Mixed Entry and Exit
|
||||
And a grid size of 10 meters
|
||||
And the node map
|
||||
"""
|
||||
c a
|
||||
j b f
|
||||
k e
|
||||
l h d
|
||||
g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | junction | oneway |
|
||||
| cba | | yes |
|
||||
| fed | | yes |
|
||||
| ihg | | yes |
|
||||
| lkj | | yes |
|
||||
| behkb | roundabout | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| c,a | cba,cba,cba | depart,roundabout-exit-1,arrive |
|
||||
| l,a | lkj,cba,cba | depart,roundabout-exit-2,arrive |
|
||||
| i,a | ihg,cba,cba | depart,roundabout-exit-3,arrive |
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include "util/deallocating_vector.hpp"
|
||||
#include "util/dynamic_graph.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/percent.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include "util/xor_fast_hash.hpp"
|
||||
@@ -156,11 +156,10 @@ class GraphContractor
|
||||
#ifndef NDEBUG
|
||||
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING)
|
||||
<< "Edge weight large -> "
|
||||
<< static_cast<unsigned int>(std::max(diter->weight, 1)) << " : "
|
||||
<< static_cast<unsigned int>(diter->source) << " -> "
|
||||
<< static_cast<unsigned int>(diter->target);
|
||||
util::Log(logWARNING) << "Edge weight large -> "
|
||||
<< static_cast<unsigned int>(std::max(diter->weight, 1))
|
||||
<< " : " << static_cast<unsigned int>(diter->source) << " -> "
|
||||
<< static_cast<unsigned int>(diter->target);
|
||||
}
|
||||
#endif
|
||||
edges.emplace_back(diter->source,
|
||||
@@ -245,15 +244,14 @@ class GraphContractor
|
||||
}
|
||||
}
|
||||
}
|
||||
util::SimpleLogger().Write() << "merged " << edges.size() - edge << " edges out of "
|
||||
<< edges.size();
|
||||
util::Log() << "merged " << edges.size() - edge << " edges out of " << edges.size();
|
||||
edges.resize(edge);
|
||||
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
|
||||
edges.clear();
|
||||
edges.shrink_to_fit();
|
||||
|
||||
BOOST_ASSERT(0 == edges.capacity());
|
||||
util::SimpleLogger().Write() << "contractor finished initalization";
|
||||
util::Log() << "contractor finished initalization";
|
||||
}
|
||||
|
||||
void Run(double core_factor = 1.0)
|
||||
@@ -270,7 +268,6 @@ class GraphContractor
|
||||
const constexpr size_t DeleteGrainSize = 1;
|
||||
|
||||
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
util::Percent p(number_of_nodes);
|
||||
|
||||
ThreadDataContainer thread_data_list(number_of_nodes);
|
||||
|
||||
@@ -292,9 +289,10 @@ class GraphContractor
|
||||
bool use_cached_node_priorities = !node_levels.empty();
|
||||
if (use_cached_node_priorities)
|
||||
{
|
||||
std::cout << "using cached node priorities ..." << std::flush;
|
||||
util::UnbufferedLog log;
|
||||
log << "using cached node priorities ...";
|
||||
node_priorities.swap(node_levels);
|
||||
std::cout << "ok" << std::endl;
|
||||
log << "ok";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -302,7 +300,8 @@ class GraphContractor
|
||||
node_priorities.resize(number_of_nodes);
|
||||
node_levels.resize(number_of_nodes);
|
||||
|
||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||
util::UnbufferedLog log;
|
||||
log << "initializing elimination PQ ...";
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
|
||||
[this, &node_priorities, &node_depth, &thread_data_list](
|
||||
const tbb::blocked_range<int> &range) {
|
||||
@@ -313,11 +312,14 @@ class GraphContractor
|
||||
this->EvaluateNodePriority(data, node_depth[x], x);
|
||||
}
|
||||
});
|
||||
std::cout << "ok" << std::endl;
|
||||
log << "ok";
|
||||
}
|
||||
BOOST_ASSERT(node_priorities.size() == number_of_nodes);
|
||||
|
||||
std::cout << "preprocessing " << number_of_nodes << " nodes ..." << std::flush;
|
||||
util::Log() << "preprocessing " << number_of_nodes << " nodes ...";
|
||||
|
||||
util::UnbufferedLog log;
|
||||
util::Percent p(log, number_of_nodes);
|
||||
|
||||
unsigned current_level = 0;
|
||||
bool flushed_contractor = false;
|
||||
@@ -331,7 +333,7 @@ class GraphContractor
|
||||
new_edge_set; // this one is not explicitely
|
||||
// cleared since it goes out of
|
||||
// scope anywa
|
||||
std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
|
||||
log << " [flush " << number_of_contracted_nodes << " nodes] ";
|
||||
|
||||
// Delete old heap data to free memory that we need for the coming operations
|
||||
thread_data_list.data.clear();
|
||||
@@ -599,9 +601,8 @@ class GraphContractor
|
||||
is_core_node.clear();
|
||||
}
|
||||
|
||||
util::SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes "
|
||||
<< contractor_graph->GetNumberOfEdges() << " edges."
|
||||
<< std::endl;
|
||||
util::Log() << "[core] " << remaining_nodes.size() << " nodes "
|
||||
<< contractor_graph->GetNumberOfEdges() << " edges.";
|
||||
|
||||
thread_data_list.data.clear();
|
||||
}
|
||||
@@ -618,8 +619,9 @@ class GraphContractor
|
||||
|
||||
template <class Edge> inline void GetEdges(util::DeallocatingVector<Edge> &edges)
|
||||
{
|
||||
util::Percent p(contractor_graph->GetNumberOfNodes());
|
||||
util::SimpleLogger().Write() << "Getting edges of minimized graph";
|
||||
util::UnbufferedLog log;
|
||||
log << "Getting edges of minimized graph ";
|
||||
util::Percent p(log, contractor_graph->GetNumberOfNodes());
|
||||
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
if (contractor_graph->GetNumberOfNodes())
|
||||
{
|
||||
|
||||
@@ -26,6 +26,9 @@ struct QueryEdge
|
||||
forward = other.forward;
|
||||
backward = other.backward;
|
||||
}
|
||||
// this ID is either the middle node of the shortcut, or the ID of the edge based node (node
|
||||
// based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle
|
||||
// node. Otherwise we see the edge based node to access node data.
|
||||
NodeID id : 31;
|
||||
bool shortcut : 1;
|
||||
int weight : 30;
|
||||
|
||||
@@ -42,7 +42,8 @@ std::string modeToString(const extractor::TravelMode mode);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <unsigned POLYLINE_PRECISION, typename ForwardIter> util::json::String makePolyline(ForwardIter begin, ForwardIter end)
|
||||
template <unsigned POLYLINE_PRECISION, typename ForwardIter>
|
||||
util::json::String makePolyline(ForwardIter begin, ForwardIter end)
|
||||
{
|
||||
return {encodePolyline<POLYLINE_PRECISION>(begin, end)};
|
||||
}
|
||||
@@ -53,22 +54,25 @@ util::json::Object makeGeoJSONGeometry(ForwardIter begin, ForwardIter end)
|
||||
auto num_coordinates = std::distance(begin, end);
|
||||
BOOST_ASSERT(num_coordinates != 0);
|
||||
util::json::Object geojson;
|
||||
geojson.values["type"] = "LineString";
|
||||
util::json::Array coordinates;
|
||||
if (num_coordinates > 1)
|
||||
{
|
||||
geojson.values["type"] = "LineString";
|
||||
util::json::Array coordinates;
|
||||
coordinates.values.reserve(num_coordinates);
|
||||
std::transform(
|
||||
begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat);
|
||||
geojson.values["coordinates"] = std::move(coordinates);
|
||||
auto into = std::back_inserter(coordinates.values);
|
||||
std::transform(begin, end, into, &detail::coordinateToLonLat);
|
||||
}
|
||||
else if (num_coordinates > 0)
|
||||
{
|
||||
geojson.values["type"] = "Point";
|
||||
util::json::Array coordinates;
|
||||
coordinates.values.push_back(detail::coordinateToLonLat(*begin));
|
||||
geojson.values["coordinates"] = std::move(coordinates);
|
||||
// For a single location we create a [location, location] LineString
|
||||
// instead of a single Point making the GeoJSON output consistent.
|
||||
coordinates.values.reserve(2);
|
||||
auto location = detail::coordinateToLonLat(*begin);
|
||||
coordinates.values.push_back(location);
|
||||
coordinates.values.push_back(location);
|
||||
}
|
||||
geojson.values["coordinates"] = std::move(coordinates);
|
||||
|
||||
return geojson;
|
||||
}
|
||||
|
||||
|
||||
@@ -196,16 +196,16 @@ class RouteAPI : public BaseAPI
|
||||
[this, &leg_geometry](const guidance::RouteStep &step) {
|
||||
if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
|
||||
{
|
||||
return static_cast<util::json::Value>(
|
||||
json::makePolyline<100000>(leg_geometry.locations.begin() + step.geometry_begin,
|
||||
leg_geometry.locations.begin() + step.geometry_end));
|
||||
return static_cast<util::json::Value>(json::makePolyline<100000>(
|
||||
leg_geometry.locations.begin() + step.geometry_begin,
|
||||
leg_geometry.locations.begin() + step.geometry_end));
|
||||
}
|
||||
|
||||
if (parameters.geometries == RouteParameters::GeometriesType::Polyline6)
|
||||
{
|
||||
return static_cast<util::json::Value>(
|
||||
json::makePolyline<1000000>(leg_geometry.locations.begin() + step.geometry_begin,
|
||||
leg_geometry.locations.begin() + step.geometry_end));
|
||||
return static_cast<util::json::Value>(json::makePolyline<1000000>(
|
||||
leg_geometry.locations.begin() + step.geometry_begin,
|
||||
leg_geometry.locations.begin() + step.geometry_end));
|
||||
}
|
||||
|
||||
BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef OSRM_ENGINE_DATA_WATCHDOG_HPP
|
||||
#define OSRM_ENGINE_DATA_WATCHDOG_HPP
|
||||
|
||||
#include "engine/datafacade/shared_datafacade.hpp"
|
||||
#include "engine/datafacade/shared_memory_datafacade.hpp"
|
||||
|
||||
#include "storage/shared_barriers.hpp"
|
||||
#include "storage/shared_datatype.hpp"
|
||||
@@ -102,10 +102,10 @@ class DataWatchdog
|
||||
boost::upgrade_to_unique_lock<boost::upgrade_mutex> unique_facade_lock(facade_lock);
|
||||
|
||||
current_timestamp = *shared_timestamp;
|
||||
facade = std::make_shared<datafacade::SharedDataFacade>(shared_barriers,
|
||||
current_timestamp.layout,
|
||||
current_timestamp.data,
|
||||
current_timestamp.timestamp);
|
||||
facade = std::make_shared<datafacade::SharedMemoryDataFacade>(shared_barriers,
|
||||
current_timestamp.layout,
|
||||
current_timestamp.data,
|
||||
current_timestamp.timestamp);
|
||||
|
||||
return get_locked_facade();
|
||||
}
|
||||
@@ -119,7 +119,7 @@ class DataWatchdog
|
||||
std::unique_ptr<storage::SharedMemory> shared_regions;
|
||||
|
||||
mutable boost::shared_mutex facade_mutex;
|
||||
std::shared_ptr<datafacade::SharedDataFacade> facade;
|
||||
std::shared_ptr<datafacade::SharedMemoryDataFacade> facade;
|
||||
storage::SharedDataTimestamp current_timestamp;
|
||||
};
|
||||
}
|
||||
|
||||
+155
-221
@@ -1,11 +1,6 @@
|
||||
#ifndef SHARED_DATAFACADE_HPP
|
||||
#define SHARED_DATAFACADE_HPP
|
||||
#ifndef CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
|
||||
#define CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
|
||||
|
||||
// implements all data storage when shared memory _IS_ used
|
||||
|
||||
#include "storage/shared_barriers.hpp"
|
||||
#include "storage/shared_datatype.hpp"
|
||||
#include "storage/shared_memory.hpp"
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
@@ -17,11 +12,13 @@
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
|
||||
#include "engine/geospatial_query.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/guidance/turn_bearing.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/packed_vector.hpp"
|
||||
#include "util/range_table.hpp"
|
||||
#include "util/rectangle.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
#include "util/static_rtree.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
@@ -47,9 +44,15 @@ namespace engine
|
||||
namespace datafacade
|
||||
{
|
||||
|
||||
class SharedDataFacade final : public BaseDataFacade
|
||||
/**
|
||||
* This base class implements the Datafacade interface for accessing
|
||||
* data that's stored in a single large block of memory (RAM).
|
||||
*
|
||||
* In this case "internal memory" refers to RAM - as opposed to "external memory",
|
||||
* which usually refers to disk.
|
||||
*/
|
||||
class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
{
|
||||
|
||||
private:
|
||||
using super = BaseDataFacade;
|
||||
using QueryGraph = util::StaticGraph<EdgeData, true>;
|
||||
@@ -63,18 +66,8 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade>;
|
||||
using RTreeNode = SharedRTree::TreeNode;
|
||||
|
||||
storage::SharedDataLayout *data_layout;
|
||||
char *shared_memory;
|
||||
|
||||
std::shared_ptr<storage::SharedBarriers> shared_barriers;
|
||||
storage::SharedDataType layout_region;
|
||||
storage::SharedDataType data_region;
|
||||
unsigned shared_timestamp;
|
||||
|
||||
unsigned m_check_sum;
|
||||
std::unique_ptr<QueryGraph> m_query_graph;
|
||||
std::unique_ptr<storage::SharedMemory> m_layout_memory;
|
||||
std::unique_ptr<storage::SharedMemory> m_large_memory;
|
||||
std::string m_timestamp;
|
||||
extractor::ProfileProperties *m_profile_properties;
|
||||
|
||||
@@ -121,362 +114,303 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
std::shared_ptr<util::RangeTable<16, true>> m_bearing_ranges_table;
|
||||
util::ShM<DiscreteBearing, true>::vector m_bearing_values_table;
|
||||
|
||||
void LoadChecksum()
|
||||
void InitializeChecksumPointer(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
m_check_sum = *data_layout->GetBlockPtr<unsigned>(shared_memory,
|
||||
storage::SharedDataLayout::HSGR_CHECKSUM);
|
||||
util::SimpleLogger().Write() << "set checksum: " << m_check_sum;
|
||||
m_check_sum =
|
||||
*data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::HSGR_CHECKSUM);
|
||||
util::Log() << "set checksum: " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadProfileProperties()
|
||||
void InitializeProfilePropertiesPointer(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
m_profile_properties = data_layout->GetBlockPtr<extractor::ProfileProperties>(
|
||||
shared_memory, storage::SharedDataLayout::PROPERTIES);
|
||||
m_profile_properties = data_layout.GetBlockPtr<extractor::ProfileProperties>(
|
||||
memory_block, storage::DataLayout::PROPERTIES);
|
||||
}
|
||||
|
||||
void LoadTimestamp()
|
||||
void InitializeTimestampPointer(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
auto timestamp_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, storage::SharedDataLayout::TIMESTAMP);
|
||||
m_timestamp.resize(data_layout->GetBlockSize(storage::SharedDataLayout::TIMESTAMP));
|
||||
data_layout.GetBlockPtr<char>(memory_block, storage::DataLayout::TIMESTAMP);
|
||||
m_timestamp.resize(data_layout.GetBlockSize(storage::DataLayout::TIMESTAMP));
|
||||
std::copy(timestamp_ptr,
|
||||
timestamp_ptr + data_layout->GetBlockSize(storage::SharedDataLayout::TIMESTAMP),
|
||||
timestamp_ptr + data_layout.GetBlockSize(storage::DataLayout::TIMESTAMP),
|
||||
m_timestamp.begin());
|
||||
}
|
||||
|
||||
void LoadRTree()
|
||||
void InitializeRTreePointers(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list.empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
const auto file_index_ptr = data_layout->GetBlockPtr<char>(
|
||||
shared_memory, storage::SharedDataLayout::FILE_INDEX_PATH);
|
||||
const auto file_index_ptr =
|
||||
data_layout.GetBlockPtr<char>(memory_block, storage::DataLayout::FILE_INDEX_PATH);
|
||||
file_index_path = boost::filesystem::path(file_index_ptr);
|
||||
if (!boost::filesystem::exists(file_index_path))
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
|
||||
util::Log(logDEBUG) << "Leaf file name " << file_index_path.string();
|
||||
throw util::exception("Could not load " + file_index_path.string() +
|
||||
"Is any data loaded into shared memory?");
|
||||
"Is any data loaded into shared memory?" + SOURCE_REF);
|
||||
}
|
||||
|
||||
auto tree_ptr = data_layout->GetBlockPtr<RTreeNode>(
|
||||
shared_memory, storage::SharedDataLayout::R_SEARCH_TREE);
|
||||
auto tree_ptr =
|
||||
data_layout.GetBlockPtr<RTreeNode>(memory_block, storage::DataLayout::R_SEARCH_TREE);
|
||||
m_static_rtree.reset(
|
||||
new SharedRTree(tree_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::R_SEARCH_TREE],
|
||||
data_layout.num_entries[storage::DataLayout::R_SEARCH_TREE],
|
||||
file_index_path,
|
||||
m_coordinate_list));
|
||||
m_geospatial_query.reset(
|
||||
new SharedGeospatialQuery(*m_static_rtree, m_coordinate_list, *this));
|
||||
}
|
||||
|
||||
void LoadGraph()
|
||||
void InitializeGraphPointer(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
auto graph_nodes_ptr = data_layout->GetBlockPtr<GraphNode>(
|
||||
shared_memory, storage::SharedDataLayout::GRAPH_NODE_LIST);
|
||||
auto graph_nodes_ptr =
|
||||
data_layout.GetBlockPtr<GraphNode>(memory_block, storage::DataLayout::GRAPH_NODE_LIST);
|
||||
|
||||
auto graph_edges_ptr = data_layout->GetBlockPtr<GraphEdge>(
|
||||
shared_memory, storage::SharedDataLayout::GRAPH_EDGE_LIST);
|
||||
auto graph_edges_ptr =
|
||||
data_layout.GetBlockPtr<GraphEdge>(memory_block, storage::DataLayout::GRAPH_EDGE_LIST);
|
||||
|
||||
util::ShM<GraphNode, true>::vector node_list(
|
||||
graph_nodes_ptr, data_layout->num_entries[storage::SharedDataLayout::GRAPH_NODE_LIST]);
|
||||
graph_nodes_ptr, data_layout.num_entries[storage::DataLayout::GRAPH_NODE_LIST]);
|
||||
util::ShM<GraphEdge, true>::vector edge_list(
|
||||
graph_edges_ptr, data_layout->num_entries[storage::SharedDataLayout::GRAPH_EDGE_LIST]);
|
||||
graph_edges_ptr, data_layout.num_entries[storage::DataLayout::GRAPH_EDGE_LIST]);
|
||||
m_query_graph.reset(new QueryGraph(node_list, edge_list));
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation()
|
||||
void InitializeNodeAndEdgeInformationPointers(storage::DataLayout &data_layout,
|
||||
char *memory_block)
|
||||
{
|
||||
const auto coordinate_list_ptr = data_layout->GetBlockPtr<util::Coordinate>(
|
||||
shared_memory, storage::SharedDataLayout::COORDINATE_LIST);
|
||||
m_coordinate_list.reset(
|
||||
coordinate_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
|
||||
const auto coordinate_list_ptr = data_layout.GetBlockPtr<util::Coordinate>(
|
||||
memory_block, storage::DataLayout::COORDINATE_LIST);
|
||||
m_coordinate_list.reset(coordinate_list_ptr,
|
||||
data_layout.num_entries[storage::DataLayout::COORDINATE_LIST]);
|
||||
|
||||
for (unsigned i = 0; i < m_coordinate_list.size(); ++i)
|
||||
{
|
||||
BOOST_ASSERT(GetCoordinateOfNode(i).IsValid());
|
||||
}
|
||||
|
||||
const auto osmnodeid_list_ptr = data_layout->GetBlockPtr<std::uint64_t>(
|
||||
shared_memory, storage::SharedDataLayout::OSM_NODE_ID_LIST);
|
||||
m_osmnodeid_list.reset(
|
||||
osmnodeid_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::OSM_NODE_ID_LIST]);
|
||||
const auto osmnodeid_list_ptr = data_layout.GetBlockPtr<std::uint64_t>(
|
||||
memory_block, storage::DataLayout::OSM_NODE_ID_LIST);
|
||||
m_osmnodeid_list.reset(osmnodeid_list_ptr,
|
||||
data_layout.num_entries[storage::DataLayout::OSM_NODE_ID_LIST]);
|
||||
// We (ab)use the number of coordinates here because we know we have the same amount of ids
|
||||
m_osmnodeid_list.set_number_of_entries(
|
||||
data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
|
||||
data_layout.num_entries[storage::DataLayout::COORDINATE_LIST]);
|
||||
|
||||
const auto travel_mode_list_ptr = data_layout->GetBlockPtr<extractor::TravelMode>(
|
||||
shared_memory, storage::SharedDataLayout::TRAVEL_MODE);
|
||||
const auto travel_mode_list_ptr = data_layout.GetBlockPtr<extractor::TravelMode>(
|
||||
memory_block, storage::DataLayout::TRAVEL_MODE);
|
||||
util::ShM<extractor::TravelMode, true>::vector travel_mode_list(
|
||||
travel_mode_list_ptr, data_layout->num_entries[storage::SharedDataLayout::TRAVEL_MODE]);
|
||||
travel_mode_list_ptr, data_layout.num_entries[storage::DataLayout::TRAVEL_MODE]);
|
||||
m_travel_mode_list = std::move(travel_mode_list);
|
||||
|
||||
const auto lane_data_id_ptr = data_layout->GetBlockPtr<LaneDataID>(
|
||||
shared_memory, storage::SharedDataLayout::LANE_DATA_ID);
|
||||
const auto lane_data_id_ptr =
|
||||
data_layout.GetBlockPtr<LaneDataID>(memory_block, storage::DataLayout::LANE_DATA_ID);
|
||||
util::ShM<LaneDataID, true>::vector lane_data_id(
|
||||
lane_data_id_ptr, data_layout->num_entries[storage::SharedDataLayout::LANE_DATA_ID]);
|
||||
lane_data_id_ptr, data_layout.num_entries[storage::DataLayout::LANE_DATA_ID]);
|
||||
m_lane_data_id = std::move(lane_data_id);
|
||||
|
||||
const auto lane_tupel_id_pair_ptr =
|
||||
data_layout->GetBlockPtr<util::guidance::LaneTupleIdPair>(
|
||||
shared_memory, storage::SharedDataLayout::TURN_LANE_DATA);
|
||||
data_layout.GetBlockPtr<util::guidance::LaneTupleIdPair>(
|
||||
memory_block, storage::DataLayout::TURN_LANE_DATA);
|
||||
util::ShM<util::guidance::LaneTupleIdPair, true>::vector lane_tupel_id_pair(
|
||||
lane_tupel_id_pair_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::TURN_LANE_DATA]);
|
||||
lane_tupel_id_pair_ptr, data_layout.num_entries[storage::DataLayout::TURN_LANE_DATA]);
|
||||
m_lane_tupel_id_pairs = std::move(lane_tupel_id_pair);
|
||||
|
||||
const auto turn_instruction_list_ptr =
|
||||
data_layout->GetBlockPtr<extractor::guidance::TurnInstruction>(
|
||||
shared_memory, storage::SharedDataLayout::TURN_INSTRUCTION);
|
||||
data_layout.GetBlockPtr<extractor::guidance::TurnInstruction>(
|
||||
memory_block, storage::DataLayout::TURN_INSTRUCTION);
|
||||
util::ShM<extractor::guidance::TurnInstruction, true>::vector turn_instruction_list(
|
||||
turn_instruction_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]);
|
||||
data_layout.num_entries[storage::DataLayout::TURN_INSTRUCTION]);
|
||||
m_turn_instruction_list = std::move(turn_instruction_list);
|
||||
|
||||
const auto name_id_list_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, storage::SharedDataLayout::NAME_ID_LIST);
|
||||
const auto name_id_list_ptr =
|
||||
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::NAME_ID_LIST);
|
||||
util::ShM<unsigned, true>::vector name_id_list(
|
||||
name_id_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_ID_LIST]);
|
||||
name_id_list_ptr, data_layout.num_entries[storage::DataLayout::NAME_ID_LIST]);
|
||||
m_name_ID_list = std::move(name_id_list);
|
||||
|
||||
const auto entry_class_id_list_ptr = data_layout->GetBlockPtr<EntryClassID>(
|
||||
shared_memory, storage::SharedDataLayout::ENTRY_CLASSID);
|
||||
const auto entry_class_id_list_ptr =
|
||||
data_layout.GetBlockPtr<EntryClassID>(memory_block, storage::DataLayout::ENTRY_CLASSID);
|
||||
typename util::ShM<EntryClassID, true>::vector entry_class_id_list(
|
||||
entry_class_id_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::ENTRY_CLASSID]);
|
||||
entry_class_id_list_ptr, data_layout.num_entries[storage::DataLayout::ENTRY_CLASSID]);
|
||||
m_entry_class_id_list = std::move(entry_class_id_list);
|
||||
|
||||
const auto pre_turn_bearing_ptr = data_layout->GetBlockPtr<util::guidance::TurnBearing>(
|
||||
shared_memory, storage::SharedDataLayout::PRE_TURN_BEARING);
|
||||
const auto pre_turn_bearing_ptr = data_layout.GetBlockPtr<util::guidance::TurnBearing>(
|
||||
memory_block, storage::DataLayout::PRE_TURN_BEARING);
|
||||
typename util::ShM<util::guidance::TurnBearing, true>::vector pre_turn_bearing(
|
||||
pre_turn_bearing_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::PRE_TURN_BEARING]);
|
||||
pre_turn_bearing_ptr, data_layout.num_entries[storage::DataLayout::PRE_TURN_BEARING]);
|
||||
m_pre_turn_bearing = std::move(pre_turn_bearing);
|
||||
|
||||
const auto post_turn_bearing_ptr = data_layout->GetBlockPtr<util::guidance::TurnBearing>(
|
||||
shared_memory, storage::SharedDataLayout::POST_TURN_BEARING);
|
||||
const auto post_turn_bearing_ptr = data_layout.GetBlockPtr<util::guidance::TurnBearing>(
|
||||
memory_block, storage::DataLayout::POST_TURN_BEARING);
|
||||
typename util::ShM<util::guidance::TurnBearing, true>::vector post_turn_bearing(
|
||||
post_turn_bearing_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::POST_TURN_BEARING]);
|
||||
post_turn_bearing_ptr, data_layout.num_entries[storage::DataLayout::POST_TURN_BEARING]);
|
||||
m_post_turn_bearing = std::move(post_turn_bearing);
|
||||
}
|
||||
|
||||
void LoadViaNodeList()
|
||||
void InitializeViaNodeListPointer(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
auto via_geometry_list_ptr = data_layout->GetBlockPtr<GeometryID>(
|
||||
shared_memory, storage::SharedDataLayout::VIA_NODE_LIST);
|
||||
auto via_geometry_list_ptr =
|
||||
data_layout.GetBlockPtr<GeometryID>(memory_block, storage::DataLayout::VIA_NODE_LIST);
|
||||
util::ShM<GeometryID, true>::vector via_geometry_list(
|
||||
via_geometry_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::VIA_NODE_LIST]);
|
||||
via_geometry_list_ptr, data_layout.num_entries[storage::DataLayout::VIA_NODE_LIST]);
|
||||
m_via_geometry_list = std::move(via_geometry_list);
|
||||
}
|
||||
|
||||
void LoadNames()
|
||||
void InitializeNamePointers(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
auto offsets_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, storage::SharedDataLayout::NAME_OFFSETS);
|
||||
auto blocks_ptr = data_layout->GetBlockPtr<IndexBlock>(
|
||||
shared_memory, storage::SharedDataLayout::NAME_BLOCKS);
|
||||
auto offsets_ptr =
|
||||
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::NAME_OFFSETS);
|
||||
auto blocks_ptr =
|
||||
data_layout.GetBlockPtr<IndexBlock>(memory_block, storage::DataLayout::NAME_BLOCKS);
|
||||
util::ShM<unsigned, true>::vector name_offsets(
|
||||
offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_OFFSETS]);
|
||||
offsets_ptr, data_layout.num_entries[storage::DataLayout::NAME_OFFSETS]);
|
||||
util::ShM<IndexBlock, true>::vector name_blocks(
|
||||
blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_BLOCKS]);
|
||||
blocks_ptr, data_layout.num_entries[storage::DataLayout::NAME_BLOCKS]);
|
||||
|
||||
auto names_list_ptr = data_layout->GetBlockPtr<char>(
|
||||
shared_memory, storage::SharedDataLayout::NAME_CHAR_LIST);
|
||||
auto names_list_ptr =
|
||||
data_layout.GetBlockPtr<char>(memory_block, storage::DataLayout::NAME_CHAR_LIST);
|
||||
util::ShM<char, true>::vector names_char_list(
|
||||
names_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_CHAR_LIST]);
|
||||
names_list_ptr, data_layout.num_entries[storage::DataLayout::NAME_CHAR_LIST]);
|
||||
m_name_table = std::make_unique<util::RangeTable<16, true>>(
|
||||
name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
|
||||
|
||||
m_names_char_list = std::move(names_char_list);
|
||||
}
|
||||
|
||||
void LoadTurnLaneDescriptions()
|
||||
void InitializeTurnLaneDescriptionsPointers(storage::DataLayout &data_layout,
|
||||
char *memory_block)
|
||||
{
|
||||
auto offsets_ptr = data_layout->GetBlockPtr<std::uint32_t>(
|
||||
shared_memory, storage::SharedDataLayout::LANE_DESCRIPTION_OFFSETS);
|
||||
auto offsets_ptr = data_layout.GetBlockPtr<std::uint32_t>(
|
||||
memory_block, storage::DataLayout::LANE_DESCRIPTION_OFFSETS);
|
||||
util::ShM<std::uint32_t, true>::vector offsets(
|
||||
offsets_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::LANE_DESCRIPTION_OFFSETS]);
|
||||
offsets_ptr, data_layout.num_entries[storage::DataLayout::LANE_DESCRIPTION_OFFSETS]);
|
||||
m_lane_description_offsets = std::move(offsets);
|
||||
|
||||
auto masks_ptr = data_layout->GetBlockPtr<extractor::guidance::TurnLaneType::Mask>(
|
||||
shared_memory, storage::SharedDataLayout::LANE_DESCRIPTION_MASKS);
|
||||
auto masks_ptr = data_layout.GetBlockPtr<extractor::guidance::TurnLaneType::Mask>(
|
||||
memory_block, storage::DataLayout::LANE_DESCRIPTION_MASKS);
|
||||
|
||||
util::ShM<extractor::guidance::TurnLaneType::Mask, true>::vector masks(
|
||||
masks_ptr, data_layout->num_entries[storage::SharedDataLayout::LANE_DESCRIPTION_MASKS]);
|
||||
masks_ptr, data_layout.num_entries[storage::DataLayout::LANE_DESCRIPTION_MASKS]);
|
||||
m_lane_description_masks = std::move(masks);
|
||||
}
|
||||
|
||||
void LoadCoreInformation()
|
||||
void InitializeCoreInformationPointer(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
auto core_marker_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, storage::SharedDataLayout::CORE_MARKER);
|
||||
auto core_marker_ptr =
|
||||
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::CORE_MARKER);
|
||||
util::ShM<bool, true>::vector is_core_node(
|
||||
core_marker_ptr, data_layout->num_entries[storage::SharedDataLayout::CORE_MARKER]);
|
||||
core_marker_ptr, data_layout.num_entries[storage::DataLayout::CORE_MARKER]);
|
||||
m_is_core_node = std::move(is_core_node);
|
||||
}
|
||||
|
||||
void LoadGeometries()
|
||||
void InitializeGeometryPointers(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
auto geometries_index_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, storage::SharedDataLayout::GEOMETRIES_INDEX);
|
||||
auto geometries_index_ptr =
|
||||
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::GEOMETRIES_INDEX);
|
||||
util::ShM<unsigned, true>::vector geometry_begin_indices(
|
||||
geometries_index_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_INDEX]);
|
||||
geometries_index_ptr, data_layout.num_entries[storage::DataLayout::GEOMETRIES_INDEX]);
|
||||
m_geometry_indices = std::move(geometry_begin_indices);
|
||||
|
||||
auto geometries_node_list_ptr = data_layout->GetBlockPtr<NodeID>(
|
||||
shared_memory, storage::SharedDataLayout::GEOMETRIES_NODE_LIST);
|
||||
auto geometries_node_list_ptr = data_layout.GetBlockPtr<NodeID>(
|
||||
memory_block, storage::DataLayout::GEOMETRIES_NODE_LIST);
|
||||
util::ShM<NodeID, true>::vector geometry_node_list(
|
||||
geometries_node_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_NODE_LIST]);
|
||||
data_layout.num_entries[storage::DataLayout::GEOMETRIES_NODE_LIST]);
|
||||
m_geometry_node_list = std::move(geometry_node_list);
|
||||
|
||||
auto geometries_fwd_weight_list_ptr = data_layout->GetBlockPtr<EdgeWeight>(
|
||||
shared_memory, storage::SharedDataLayout::GEOMETRIES_FWD_WEIGHT_LIST);
|
||||
auto geometries_fwd_weight_list_ptr = data_layout.GetBlockPtr<EdgeWeight>(
|
||||
memory_block, storage::DataLayout::GEOMETRIES_FWD_WEIGHT_LIST);
|
||||
util::ShM<EdgeWeight, true>::vector geometry_fwd_weight_list(
|
||||
geometries_fwd_weight_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_FWD_WEIGHT_LIST]);
|
||||
data_layout.num_entries[storage::DataLayout::GEOMETRIES_FWD_WEIGHT_LIST]);
|
||||
m_geometry_fwd_weight_list = std::move(geometry_fwd_weight_list);
|
||||
|
||||
auto geometries_rev_weight_list_ptr = data_layout->GetBlockPtr<EdgeWeight>(
|
||||
shared_memory, storage::SharedDataLayout::GEOMETRIES_REV_WEIGHT_LIST);
|
||||
auto geometries_rev_weight_list_ptr = data_layout.GetBlockPtr<EdgeWeight>(
|
||||
memory_block, storage::DataLayout::GEOMETRIES_REV_WEIGHT_LIST);
|
||||
util::ShM<EdgeWeight, true>::vector geometry_rev_weight_list(
|
||||
geometries_rev_weight_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_REV_WEIGHT_LIST]);
|
||||
data_layout.num_entries[storage::DataLayout::GEOMETRIES_REV_WEIGHT_LIST]);
|
||||
m_geometry_rev_weight_list = std::move(geometry_rev_weight_list);
|
||||
|
||||
auto datasources_list_ptr = data_layout->GetBlockPtr<uint8_t>(
|
||||
shared_memory, storage::SharedDataLayout::DATASOURCES_LIST);
|
||||
auto datasources_list_ptr =
|
||||
data_layout.GetBlockPtr<uint8_t>(memory_block, storage::DataLayout::DATASOURCES_LIST);
|
||||
util::ShM<uint8_t, true>::vector datasources_list(
|
||||
datasources_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::DATASOURCES_LIST]);
|
||||
datasources_list_ptr, data_layout.num_entries[storage::DataLayout::DATASOURCES_LIST]);
|
||||
m_datasource_list = std::move(datasources_list);
|
||||
|
||||
auto datasource_name_data_ptr = data_layout->GetBlockPtr<char>(
|
||||
shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_DATA);
|
||||
auto datasource_name_data_ptr =
|
||||
data_layout.GetBlockPtr<char>(memory_block, storage::DataLayout::DATASOURCE_NAME_DATA);
|
||||
util::ShM<char, true>::vector datasource_name_data(
|
||||
datasource_name_data_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_DATA]);
|
||||
data_layout.num_entries[storage::DataLayout::DATASOURCE_NAME_DATA]);
|
||||
m_datasource_name_data = std::move(datasource_name_data);
|
||||
|
||||
auto datasource_name_offsets_ptr = data_layout->GetBlockPtr<std::size_t>(
|
||||
shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_OFFSETS);
|
||||
auto datasource_name_offsets_ptr = data_layout.GetBlockPtr<std::size_t>(
|
||||
memory_block, storage::DataLayout::DATASOURCE_NAME_OFFSETS);
|
||||
util::ShM<std::size_t, true>::vector datasource_name_offsets(
|
||||
datasource_name_offsets_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_OFFSETS]);
|
||||
data_layout.num_entries[storage::DataLayout::DATASOURCE_NAME_OFFSETS]);
|
||||
m_datasource_name_offsets = std::move(datasource_name_offsets);
|
||||
|
||||
auto datasource_name_lengths_ptr = data_layout->GetBlockPtr<std::size_t>(
|
||||
shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_LENGTHS);
|
||||
auto datasource_name_lengths_ptr = data_layout.GetBlockPtr<std::size_t>(
|
||||
memory_block, storage::DataLayout::DATASOURCE_NAME_LENGTHS);
|
||||
util::ShM<std::size_t, true>::vector datasource_name_lengths(
|
||||
datasource_name_lengths_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_LENGTHS]);
|
||||
data_layout.num_entries[storage::DataLayout::DATASOURCE_NAME_LENGTHS]);
|
||||
m_datasource_name_lengths = std::move(datasource_name_lengths);
|
||||
}
|
||||
|
||||
void LoadIntersectionClasses()
|
||||
void InitializeIntersectionClassPointers(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
auto bearing_class_id_ptr = data_layout->GetBlockPtr<BearingClassID>(
|
||||
shared_memory, storage::SharedDataLayout::BEARING_CLASSID);
|
||||
auto bearing_class_id_ptr = data_layout.GetBlockPtr<BearingClassID>(
|
||||
memory_block, storage::DataLayout::BEARING_CLASSID);
|
||||
typename util::ShM<BearingClassID, true>::vector bearing_class_id_table(
|
||||
bearing_class_id_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::BEARING_CLASSID]);
|
||||
bearing_class_id_ptr, data_layout.num_entries[storage::DataLayout::BEARING_CLASSID]);
|
||||
m_bearing_class_id_table = std::move(bearing_class_id_table);
|
||||
|
||||
auto bearing_class_ptr = data_layout->GetBlockPtr<DiscreteBearing>(
|
||||
shared_memory, storage::SharedDataLayout::BEARING_VALUES);
|
||||
auto bearing_class_ptr = data_layout.GetBlockPtr<DiscreteBearing>(
|
||||
memory_block, storage::DataLayout::BEARING_VALUES);
|
||||
typename util::ShM<DiscreteBearing, true>::vector bearing_class_table(
|
||||
bearing_class_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_VALUES]);
|
||||
bearing_class_ptr, data_layout.num_entries[storage::DataLayout::BEARING_VALUES]);
|
||||
m_bearing_values_table = std::move(bearing_class_table);
|
||||
|
||||
auto offsets_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, storage::SharedDataLayout::BEARING_OFFSETS);
|
||||
auto blocks_ptr = data_layout->GetBlockPtr<IndexBlock>(
|
||||
shared_memory, storage::SharedDataLayout::BEARING_BLOCKS);
|
||||
auto offsets_ptr =
|
||||
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::BEARING_OFFSETS);
|
||||
auto blocks_ptr =
|
||||
data_layout.GetBlockPtr<IndexBlock>(memory_block, storage::DataLayout::BEARING_BLOCKS);
|
||||
util::ShM<unsigned, true>::vector bearing_offsets(
|
||||
offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_OFFSETS]);
|
||||
offsets_ptr, data_layout.num_entries[storage::DataLayout::BEARING_OFFSETS]);
|
||||
util::ShM<IndexBlock, true>::vector bearing_blocks(
|
||||
blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_BLOCKS]);
|
||||
blocks_ptr, data_layout.num_entries[storage::DataLayout::BEARING_BLOCKS]);
|
||||
|
||||
m_bearing_ranges_table = std::make_unique<util::RangeTable<16, true>>(
|
||||
bearing_offsets, bearing_blocks, static_cast<unsigned>(m_bearing_values_table.size()));
|
||||
|
||||
auto entry_class_ptr = data_layout->GetBlockPtr<util::guidance::EntryClass>(
|
||||
shared_memory, storage::SharedDataLayout::ENTRY_CLASS);
|
||||
auto entry_class_ptr = data_layout.GetBlockPtr<util::guidance::EntryClass>(
|
||||
memory_block, storage::DataLayout::ENTRY_CLASS);
|
||||
typename util::ShM<util::guidance::EntryClass, true>::vector entry_class_table(
|
||||
entry_class_ptr, data_layout->num_entries[storage::SharedDataLayout::ENTRY_CLASS]);
|
||||
entry_class_ptr, data_layout.num_entries[storage::DataLayout::ENTRY_CLASS]);
|
||||
m_entry_class_table = std::move(entry_class_table);
|
||||
}
|
||||
|
||||
public:
|
||||
// this function handle the deallocation of the shared memory it we can prove it will not be
|
||||
// used anymore
|
||||
virtual ~SharedDataFacade()
|
||||
void InitializeInternalPointers(storage::DataLayout &data_layout, char *memory_block)
|
||||
{
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
|
||||
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
|
||||
: shared_barriers->regions_2_mutex,
|
||||
boost::interprocess::defer_lock);
|
||||
|
||||
// if this returns false this is still in use
|
||||
if (exclusive_lock.try_lock())
|
||||
{
|
||||
// Now check if this is still the newest dataset
|
||||
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
|
||||
lock(shared_barriers->current_regions_mutex);
|
||||
|
||||
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
|
||||
const auto current_timestamp =
|
||||
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
||||
|
||||
if (current_timestamp->timestamp == shared_timestamp)
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "Retaining data with shared timestamp "
|
||||
<< shared_timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
storage::SharedMemory::Remove(data_region);
|
||||
storage::SharedMemory::Remove(layout_region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SharedDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
|
||||
storage::SharedDataType layout_region_,
|
||||
storage::SharedDataType data_region_,
|
||||
unsigned shared_timestamp_)
|
||||
: shared_barriers(shared_barriers_), layout_region(layout_region_),
|
||||
data_region(data_region_), shared_timestamp(shared_timestamp_)
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "Loading new data with shared timestamp "
|
||||
<< shared_timestamp;
|
||||
|
||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
||||
m_layout_memory = storage::makeSharedMemory(layout_region);
|
||||
|
||||
data_layout = static_cast<storage::SharedDataLayout *>(m_layout_memory->Ptr());
|
||||
|
||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
|
||||
m_large_memory = storage::makeSharedMemory(data_region);
|
||||
shared_memory = (char *)(m_large_memory->Ptr());
|
||||
|
||||
LoadGraph();
|
||||
LoadChecksum();
|
||||
LoadNodeAndEdgeInformation();
|
||||
LoadGeometries();
|
||||
LoadTimestamp();
|
||||
LoadViaNodeList();
|
||||
LoadNames();
|
||||
LoadTurnLaneDescriptions();
|
||||
LoadCoreInformation();
|
||||
LoadProfileProperties();
|
||||
LoadRTree();
|
||||
LoadIntersectionClasses();
|
||||
InitializeGraphPointer(data_layout, memory_block);
|
||||
InitializeChecksumPointer(data_layout, memory_block);
|
||||
InitializeNodeAndEdgeInformationPointers(data_layout, memory_block);
|
||||
InitializeGeometryPointers(data_layout, memory_block);
|
||||
InitializeTimestampPointer(data_layout, memory_block);
|
||||
InitializeViaNodeListPointer(data_layout, memory_block);
|
||||
InitializeNamePointers(data_layout, memory_block);
|
||||
InitializeTurnLaneDescriptionsPointers(data_layout, memory_block);
|
||||
InitializeCoreInformationPointer(data_layout, memory_block);
|
||||
InitializeProfilePropertiesPointer(data_layout, memory_block);
|
||||
InitializeRTreePointers(data_layout, memory_block);
|
||||
InitializeIntersectionClassPointers(data_layout, memory_block);
|
||||
}
|
||||
|
||||
// search graph access
|
||||
@@ -1000,4 +934,4 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SHARED_DATAFACADE_HPP
|
||||
#endif // CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
|
||||
@@ -1,974 +0,0 @@
|
||||
#ifndef INTERNAL_DATAFACADE_HPP
|
||||
#define INTERNAL_DATAFACADE_HPP
|
||||
|
||||
// implements all data storage when shared memory is _NOT_ used
|
||||
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "util/guidance/bearing_class.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/original_edge_data.hpp"
|
||||
#include "extractor/profile_properties.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "storage/io.hpp"
|
||||
#include "storage/storage_config.hpp"
|
||||
#include "engine/geospatial_query.hpp"
|
||||
#include "util/graph_loader.hpp"
|
||||
#include "util/guidance/turn_bearing.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
#include "util/io.hpp"
|
||||
#include "util/packed_vector.hpp"
|
||||
#include "util/range_table.hpp"
|
||||
#include "util/rectangle.hpp"
|
||||
#include "util/shared_memory_vector_wrapper.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
#include "util/static_rtree.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "osrm/coordinate.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace datafacade
|
||||
{
|
||||
|
||||
class InternalDataFacade final : public BaseDataFacade
|
||||
{
|
||||
|
||||
private:
|
||||
using super = BaseDataFacade;
|
||||
using QueryGraph = util::StaticGraph<typename super::EdgeData>;
|
||||
using InputEdge = QueryGraph::InputEdge;
|
||||
using RTreeLeaf = super::RTreeLeaf;
|
||||
using InternalRTree =
|
||||
util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, false>::vector, false>;
|
||||
using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade>;
|
||||
|
||||
InternalDataFacade() {}
|
||||
|
||||
unsigned m_check_sum;
|
||||
std::unique_ptr<QueryGraph> m_query_graph;
|
||||
std::string m_timestamp;
|
||||
|
||||
util::ShM<util::Coordinate, false>::vector m_coordinate_list;
|
||||
util::PackedVector<OSMNodeID, false> m_osmnodeid_list;
|
||||
util::ShM<GeometryID, false>::vector m_via_geometry_list;
|
||||
util::ShM<unsigned, false>::vector m_name_ID_list;
|
||||
util::ShM<extractor::guidance::TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
util::ShM<LaneDataID, false>::vector m_lane_data_id;
|
||||
util::ShM<util::guidance::LaneTupleIdPair, false>::vector m_lane_tuple_id_pairs;
|
||||
util::ShM<extractor::TravelMode, false>::vector m_travel_mode_list;
|
||||
util::ShM<char, false>::vector m_names_char_list;
|
||||
util::ShM<unsigned, false>::vector m_geometry_indices;
|
||||
util::ShM<NodeID, false>::vector m_geometry_node_list;
|
||||
util::ShM<EdgeWeight, false>::vector m_geometry_fwd_weight_list;
|
||||
util::ShM<EdgeWeight, false>::vector m_geometry_rev_weight_list;
|
||||
util::ShM<bool, false>::vector m_is_core_node;
|
||||
util::ShM<uint8_t, false>::vector m_datasource_list;
|
||||
util::ShM<std::string, false>::vector m_datasource_names;
|
||||
util::ShM<std::uint32_t, false>::vector m_lane_description_offsets;
|
||||
util::ShM<extractor::guidance::TurnLaneType::Mask, false>::vector m_lane_description_masks;
|
||||
extractor::ProfileProperties m_profile_properties;
|
||||
|
||||
std::unique_ptr<InternalRTree> m_static_rtree;
|
||||
std::unique_ptr<InternalGeospatialQuery> m_geospatial_query;
|
||||
boost::filesystem::path ram_index_path;
|
||||
boost::filesystem::path file_index_path;
|
||||
util::RangeTable<16, false> m_name_table;
|
||||
|
||||
// bearing classes by node based node
|
||||
util::ShM<BearingClassID, false>::vector m_bearing_class_id_table;
|
||||
// entry class IDs by edge based egde
|
||||
util::ShM<EntryClassID, false>::vector m_entry_class_id_list;
|
||||
// bearings pre/post turn
|
||||
util::ShM<util::guidance::TurnBearing, false>::vector m_pre_turn_bearing;
|
||||
util::ShM<util::guidance::TurnBearing, false>::vector m_post_turn_bearing;
|
||||
// the look-up table for entry classes. An entry class lists the possibility of entry for all
|
||||
// available turns. For every turn, there is an associated entry class.
|
||||
util::ShM<util::guidance::EntryClass, false>::vector m_entry_class_table;
|
||||
// the look-up table for distinct bearing classes. A bearing class lists the available bearings
|
||||
// at an intersection
|
||||
util::RangeTable<16, false> m_bearing_ranges_table;
|
||||
util::ShM<DiscreteBearing, false>::vector m_bearing_values_table;
|
||||
|
||||
void LoadProfileProperties(const boost::filesystem::path &properties_path)
|
||||
{
|
||||
boost::filesystem::ifstream in_stream(properties_path);
|
||||
if (!in_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + properties_path.string() + " for reading.");
|
||||
}
|
||||
const auto properties_size = storage::io::readPropertiesCount();
|
||||
storage::io::readProperties(in_stream, &m_profile_properties, properties_size);
|
||||
}
|
||||
|
||||
void LoadLaneTupleIdPairs(const boost::filesystem::path &lane_data_path)
|
||||
{
|
||||
boost::filesystem::ifstream in_stream(lane_data_path);
|
||||
if (!in_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + lane_data_path.string() + " for reading.");
|
||||
}
|
||||
std::uint64_t size;
|
||||
in_stream.read(reinterpret_cast<char *>(&size), sizeof(size));
|
||||
m_lane_tuple_id_pairs.resize(size);
|
||||
in_stream.read(reinterpret_cast<char *>(&m_lane_tuple_id_pairs[0]),
|
||||
sizeof(m_lane_tuple_id_pairs) * size);
|
||||
}
|
||||
|
||||
void LoadTimestamp(const boost::filesystem::path ×tamp_path)
|
||||
{
|
||||
util::SimpleLogger().Write() << "Loading Timestamp";
|
||||
|
||||
boost::filesystem::ifstream timestamp_stream(timestamp_path);
|
||||
if (!timestamp_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + timestamp_path.string() + " for reading.");
|
||||
}
|
||||
|
||||
const auto timestamp_size = storage::io::readNumberOfBytes(timestamp_stream);
|
||||
m_timestamp.resize(timestamp_size);
|
||||
storage::io::readTimestamp(timestamp_stream, &m_timestamp.front(), timestamp_size);
|
||||
}
|
||||
|
||||
void LoadGraph(const boost::filesystem::path &hsgr_path)
|
||||
{
|
||||
boost::filesystem::ifstream hsgr_input_stream(hsgr_path);
|
||||
if (!hsgr_input_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + hsgr_path.string() + " for reading.");
|
||||
}
|
||||
|
||||
const auto header = storage::io::readHSGRHeader(hsgr_input_stream);
|
||||
m_check_sum = header.checksum;
|
||||
|
||||
util::ShM<QueryGraph::NodeArrayEntry, false>::vector node_list(header.number_of_nodes);
|
||||
util::ShM<QueryGraph::EdgeArrayEntry, false>::vector edge_list(header.number_of_edges);
|
||||
|
||||
storage::io::readHSGR(hsgr_input_stream,
|
||||
node_list.data(),
|
||||
header.number_of_nodes,
|
||||
edge_list.data(),
|
||||
header.number_of_edges);
|
||||
|
||||
m_query_graph = std::unique_ptr<QueryGraph>(new QueryGraph(node_list, edge_list));
|
||||
|
||||
util::SimpleLogger().Write() << "Data checksum is " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file_path,
|
||||
const boost::filesystem::path &edges_file_path)
|
||||
{
|
||||
boost::filesystem::ifstream nodes_input_stream(nodes_file_path, std::ios::binary);
|
||||
if (!nodes_input_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + nodes_file_path.string() + " for reading.");
|
||||
}
|
||||
|
||||
const auto number_of_coordinates = storage::io::readElementCount(nodes_input_stream);
|
||||
m_coordinate_list.resize(number_of_coordinates);
|
||||
m_osmnodeid_list.reserve(number_of_coordinates);
|
||||
storage::io::readNodes(
|
||||
nodes_input_stream, m_coordinate_list.data(), m_osmnodeid_list, number_of_coordinates);
|
||||
|
||||
boost::filesystem::ifstream edges_input_stream(edges_file_path, std::ios::binary);
|
||||
if (!edges_input_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + edges_file_path.string() + " for reading.");
|
||||
}
|
||||
const auto number_of_edges = storage::io::readElementCount(edges_input_stream);
|
||||
m_via_geometry_list.resize(number_of_edges);
|
||||
m_name_ID_list.resize(number_of_edges);
|
||||
m_turn_instruction_list.resize(number_of_edges);
|
||||
m_lane_data_id.resize(number_of_edges);
|
||||
m_travel_mode_list.resize(number_of_edges);
|
||||
m_entry_class_id_list.resize(number_of_edges);
|
||||
m_pre_turn_bearing.resize(number_of_edges);
|
||||
m_post_turn_bearing.resize(number_of_edges);
|
||||
|
||||
storage::io::readEdges(edges_input_stream,
|
||||
m_via_geometry_list.data(),
|
||||
m_name_ID_list.data(),
|
||||
m_turn_instruction_list.data(),
|
||||
m_lane_data_id.data(),
|
||||
m_travel_mode_list.data(),
|
||||
m_entry_class_id_list.data(),
|
||||
m_pre_turn_bearing.data(),
|
||||
m_post_turn_bearing.data(),
|
||||
number_of_edges);
|
||||
}
|
||||
|
||||
void LoadCoreInformation(const boost::filesystem::path &core_data_file)
|
||||
{
|
||||
std::ifstream core_stream(core_data_file.string().c_str(), std::ios::binary);
|
||||
unsigned number_of_markers;
|
||||
core_stream.read((char *)&number_of_markers, sizeof(unsigned));
|
||||
|
||||
std::vector<char> unpacked_core_markers(number_of_markers);
|
||||
core_stream.read((char *)unpacked_core_markers.data(), sizeof(char) * number_of_markers);
|
||||
|
||||
// in this case we have nothing to do
|
||||
if (number_of_markers <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_is_core_node.resize(number_of_markers);
|
||||
for (auto i = 0u; i < number_of_markers; ++i)
|
||||
{
|
||||
BOOST_ASSERT(unpacked_core_markers[i] == 0 || unpacked_core_markers[i] == 1);
|
||||
m_is_core_node[i] = unpacked_core_markers[i] == 1;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadGeometries(const boost::filesystem::path &geometry_file)
|
||||
{
|
||||
std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
|
||||
unsigned number_of_indices = 0;
|
||||
unsigned number_of_compressed_geometries = 0;
|
||||
|
||||
geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
|
||||
|
||||
m_geometry_indices.resize(number_of_indices);
|
||||
if (number_of_indices > 0)
|
||||
{
|
||||
geometry_stream.read((char *)&(m_geometry_indices[0]),
|
||||
number_of_indices * sizeof(unsigned));
|
||||
}
|
||||
|
||||
geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
|
||||
|
||||
BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
|
||||
m_geometry_node_list.resize(number_of_compressed_geometries);
|
||||
m_geometry_fwd_weight_list.resize(number_of_compressed_geometries);
|
||||
m_geometry_rev_weight_list.resize(number_of_compressed_geometries);
|
||||
|
||||
if (number_of_compressed_geometries > 0)
|
||||
{
|
||||
geometry_stream.read((char *)&(m_geometry_node_list[0]),
|
||||
number_of_compressed_geometries * sizeof(NodeID));
|
||||
|
||||
geometry_stream.read((char *)&(m_geometry_fwd_weight_list[0]),
|
||||
number_of_compressed_geometries * sizeof(EdgeWeight));
|
||||
|
||||
geometry_stream.read((char *)&(m_geometry_rev_weight_list[0]),
|
||||
number_of_compressed_geometries * sizeof(EdgeWeight));
|
||||
}
|
||||
}
|
||||
|
||||
void LoadDatasourceInfo(const boost::filesystem::path &datasource_names_file,
|
||||
const boost::filesystem::path &datasource_indexes_file)
|
||||
{
|
||||
boost::filesystem::ifstream datasources_stream(datasource_indexes_file, std::ios::binary);
|
||||
if (!datasources_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + datasource_indexes_file.string() +
|
||||
" for reading!");
|
||||
}
|
||||
BOOST_ASSERT(datasources_stream);
|
||||
|
||||
const auto number_of_datasources = storage::io::readElementCount(datasources_stream);
|
||||
if (number_of_datasources > 0)
|
||||
{
|
||||
m_datasource_list.resize(number_of_datasources);
|
||||
storage::io::readDatasourceIndexes(
|
||||
datasources_stream, &m_datasource_list.front(), number_of_datasources);
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream datasourcenames_stream(datasource_names_file, std::ios::binary);
|
||||
if (!datasourcenames_stream)
|
||||
{
|
||||
throw util::exception("Could not open " + datasource_names_file.string() +
|
||||
" for reading!");
|
||||
}
|
||||
BOOST_ASSERT(datasourcenames_stream);
|
||||
|
||||
const auto datasource_names_data = storage::io::readDatasourceNames(datasourcenames_stream);
|
||||
m_datasource_names.resize(datasource_names_data.lengths.size());
|
||||
for (std::size_t i = 0; i < datasource_names_data.lengths.size(); ++i)
|
||||
{
|
||||
auto name_begin =
|
||||
datasource_names_data.names.begin() + datasource_names_data.offsets[i];
|
||||
auto name_end = datasource_names_data.names.begin() + datasource_names_data.offsets[i] +
|
||||
datasource_names_data.lengths[i];
|
||||
m_datasource_names[i] = std::string(name_begin, name_end);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadRTree()
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list.empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list));
|
||||
m_geospatial_query.reset(
|
||||
new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list, *this));
|
||||
}
|
||||
|
||||
void LoadLaneDescriptions(const boost::filesystem::path &lane_description_file)
|
||||
{
|
||||
if (!util::deserializeAdjacencyArray(lane_description_file.string(),
|
||||
m_lane_description_offsets,
|
||||
m_lane_description_masks))
|
||||
util::SimpleLogger().Write(logWARNING) << "Failed to read turn lane descriptions from "
|
||||
<< lane_description_file.string();
|
||||
}
|
||||
|
||||
void LoadStreetNames(const boost::filesystem::path &names_file)
|
||||
{
|
||||
boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
|
||||
|
||||
name_stream >> m_name_table;
|
||||
|
||||
unsigned number_of_chars = 0;
|
||||
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
|
||||
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
|
||||
name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
|
||||
if (0 == m_names_char_list.size())
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
|
||||
}
|
||||
}
|
||||
|
||||
void LoadIntersectionClasses(const boost::filesystem::path &intersection_class_file)
|
||||
{
|
||||
std::ifstream intersection_stream(intersection_class_file.string(), std::ios::binary);
|
||||
if (!intersection_stream)
|
||||
throw util::exception("Could not open " + intersection_class_file.string() +
|
||||
" for reading.");
|
||||
|
||||
if (!util::readAndCheckFingerprint(intersection_stream))
|
||||
throw util::exception("Fingeprint does not match in " +
|
||||
intersection_class_file.string());
|
||||
|
||||
{
|
||||
util::SimpleLogger().Write(logINFO) << "Loading Bearing Class IDs";
|
||||
std::vector<BearingClassID> bearing_class_id;
|
||||
if (!util::deserializeVector(intersection_stream, bearing_class_id))
|
||||
throw util::exception("Reading from " + intersection_class_file.string() +
|
||||
" failed.");
|
||||
|
||||
m_bearing_class_id_table.resize(bearing_class_id.size());
|
||||
std::copy(
|
||||
bearing_class_id.begin(), bearing_class_id.end(), &m_bearing_class_id_table[0]);
|
||||
}
|
||||
{
|
||||
util::SimpleLogger().Write(logINFO) << "Loading Bearing Classes";
|
||||
// read the range table
|
||||
intersection_stream >> m_bearing_ranges_table;
|
||||
std::vector<util::guidance::BearingClass> bearing_classes;
|
||||
// and the actual bearing values
|
||||
std::uint64_t num_bearings;
|
||||
intersection_stream.read(reinterpret_cast<char *>(&num_bearings), sizeof(num_bearings));
|
||||
m_bearing_values_table.resize(num_bearings);
|
||||
intersection_stream.read(reinterpret_cast<char *>(&m_bearing_values_table[0]),
|
||||
sizeof(m_bearing_values_table[0]) * num_bearings);
|
||||
if (!static_cast<bool>(intersection_stream))
|
||||
throw util::exception("Reading from " + intersection_class_file.string() +
|
||||
" failed.");
|
||||
}
|
||||
{
|
||||
util::SimpleLogger().Write(logINFO) << "Loading Entry Classes";
|
||||
std::vector<util::guidance::EntryClass> entry_classes;
|
||||
if (!util::deserializeVector(intersection_stream, entry_classes))
|
||||
throw util::exception("Reading from " + intersection_class_file.string() +
|
||||
" failed.");
|
||||
|
||||
m_entry_class_table.resize(entry_classes.size());
|
||||
std::copy(entry_classes.begin(), entry_classes.end(), &m_entry_class_table[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~InternalDataFacade()
|
||||
{
|
||||
m_static_rtree.reset();
|
||||
m_geospatial_query.reset();
|
||||
}
|
||||
|
||||
explicit InternalDataFacade(const storage::StorageConfig &config)
|
||||
{
|
||||
ram_index_path = config.ram_index_path;
|
||||
file_index_path = config.file_index_path;
|
||||
|
||||
util::SimpleLogger().Write() << "loading graph data";
|
||||
LoadGraph(config.hsgr_data_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading edge information";
|
||||
LoadNodeAndEdgeInformation(config.nodes_data_path, config.edges_data_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading core information";
|
||||
LoadCoreInformation(config.core_data_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading geometries";
|
||||
LoadGeometries(config.geometries_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading datasource info";
|
||||
LoadDatasourceInfo(config.datasource_names_path, config.datasource_indexes_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading timestamp";
|
||||
LoadTimestamp(config.timestamp_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading profile properties";
|
||||
LoadProfileProperties(config.properties_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading street names";
|
||||
LoadStreetNames(config.names_data_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading lane tags";
|
||||
LoadLaneDescriptions(config.turn_lane_description_path);
|
||||
|
||||
util::SimpleLogger().Write() << "loading rtree";
|
||||
LoadRTree();
|
||||
|
||||
util::SimpleLogger().Write() << "loading intersection class data";
|
||||
LoadIntersectionClasses(config.intersection_class_path);
|
||||
|
||||
util::SimpleLogger().Write() << "Loading Lane Data Pairs";
|
||||
LoadLaneTupleIdPairs(config.turn_lane_data_path);
|
||||
}
|
||||
|
||||
// search graph access
|
||||
unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
|
||||
|
||||
unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
|
||||
|
||||
unsigned GetOutDegree(const NodeID n) const override final
|
||||
{
|
||||
return m_query_graph->GetOutDegree(n);
|
||||
}
|
||||
|
||||
NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeData &GetEdgeData(const EdgeID e) const override final
|
||||
{
|
||||
return m_query_graph->GetEdgeData(e);
|
||||
}
|
||||
|
||||
EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
|
||||
{
|
||||
return m_query_graph->GetAdjacentEdgeRange(node);
|
||||
}
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const override final
|
||||
{
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
|
||||
{
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID
|
||||
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
|
||||
{
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
EdgeID FindSmallestEdge(const NodeID from,
|
||||
const NodeID to,
|
||||
std::function<bool(EdgeData)> filter) const override final
|
||||
{
|
||||
return m_query_graph->FindSmallestEdge(from, to, filter);
|
||||
}
|
||||
|
||||
// node and edge information access
|
||||
util::Coordinate GetCoordinateOfNode(const unsigned id) const override final
|
||||
{
|
||||
return m_coordinate_list[id];
|
||||
}
|
||||
|
||||
OSMNodeID GetOSMNodeIDOfNode(const unsigned id) const override final
|
||||
{
|
||||
return m_osmnodeid_list.at(id);
|
||||
}
|
||||
|
||||
extractor::guidance::TurnInstruction
|
||||
GetTurnInstructionForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_travel_mode_list.at(id);
|
||||
}
|
||||
|
||||
std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
|
||||
const util::Coordinate north_east) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
const util::RectangleInt2D bbox{
|
||||
south_west.lon, north_east.lon, south_west.lat, north_east.lat};
|
||||
return m_geospatial_query->Search(bbox);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(
|
||||
input_coordinate, max_distance, bearing, bearing_range);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const double max_distance) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing,
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(
|
||||
input_coordinate, max_results, bearing, bearing_range);
|
||||
}
|
||||
|
||||
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 override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(
|
||||
input_coordinate, max_results, max_distance, bearing, bearing_range);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
const util::Coordinate input_coordinate, const double max_distance) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, max_distance);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
const util::Coordinate input_coordinate) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, max_distance, bearing, bearing_range);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const int bearing,
|
||||
const int bearing_range) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, bearing, bearing_range);
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const override final { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_name_ID_list.at(id);
|
||||
}
|
||||
|
||||
std::string GetNameForID(const unsigned name_id) const override final
|
||||
{
|
||||
if (std::numeric_limits<unsigned>::max() == name_id)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
auto range = m_name_table.GetRange(name_id);
|
||||
|
||||
std::string result;
|
||||
result.reserve(range.size());
|
||||
if (range.begin() != range.end())
|
||||
{
|
||||
result.resize(range.back() - range.front() + 1);
|
||||
std::copy(m_names_char_list.begin() + range.front(),
|
||||
m_names_char_list.begin() + range.back() + 1,
|
||||
result.begin());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetRefForID(const unsigned name_id) const override final
|
||||
{
|
||||
// We store the ref after the name, destination and pronunciation of a street.
|
||||
// We do this to get around the street length limit of 255 which would hit
|
||||
// if we concatenate these. Order (see extractor_callbacks):
|
||||
// name (0), destination (1), pronunciation (2), ref (3)
|
||||
return GetNameForID(name_id + 3);
|
||||
}
|
||||
|
||||
std::string GetPronunciationForID(const unsigned name_id) const override final
|
||||
{
|
||||
// We store the pronunciation after the name and destination of a street.
|
||||
// We do this to get around the street length limit of 255 which would hit
|
||||
// if we concatenate these. Order (see extractor_callbacks):
|
||||
// name (0), destination (1), pronunciation (2)
|
||||
return GetNameForID(name_id + 2);
|
||||
}
|
||||
|
||||
std::string GetDestinationsForID(const unsigned name_id) const override final
|
||||
{
|
||||
// We store the destination after the name of a street.
|
||||
// We do this to get around the street length limit of 255 which would hit
|
||||
// if we concatenate these. Order (see extractor_callbacks):
|
||||
// name (0), destination (1), pronunciation (2)
|
||||
return GetNameForID(name_id + 1);
|
||||
}
|
||||
|
||||
virtual GeometryID GetGeometryIndexForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_via_geometry_list.at(id);
|
||||
}
|
||||
|
||||
virtual std::size_t GetCoreSize() const override final { return m_is_core_node.size(); }
|
||||
|
||||
virtual bool IsCoreNode(const NodeID id) const override final
|
||||
{
|
||||
if (m_is_core_node.size() > 0)
|
||||
{
|
||||
return m_is_core_node[id];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<NodeID> GetUncompressedForwardGeometry(const EdgeID id) const override final
|
||||
{
|
||||
/*
|
||||
* NodeID's for geometries are stored in one place for
|
||||
* both forward and reverse segments along the same bi-
|
||||
* directional edge. The m_geometry_indices stores
|
||||
* refences to where to find the beginning of the bi-
|
||||
* directional edge in the m_geometry_node_list vector. For
|
||||
* forward geometries of bi-directional edges, edges 2 to
|
||||
* n of that edge need to be read.
|
||||
*/
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id + 1);
|
||||
|
||||
std::vector<NodeID> result_nodes;
|
||||
|
||||
result_nodes.resize(end - begin);
|
||||
|
||||
std::copy(m_geometry_node_list.begin() + begin,
|
||||
m_geometry_node_list.begin() + end,
|
||||
result_nodes.begin());
|
||||
|
||||
return result_nodes;
|
||||
}
|
||||
|
||||
virtual std::vector<NodeID> GetUncompressedReverseGeometry(const EdgeID id) const override final
|
||||
{
|
||||
/*
|
||||
* NodeID's for geometries are stored in one place for
|
||||
* both forward and reverse segments along the same bi-
|
||||
* directional edge. The m_geometry_indices stores
|
||||
* refences to where to find the beginning of the bi-
|
||||
* directional edge in the m_geometry_node_list vector.
|
||||
* */
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id + 1);
|
||||
|
||||
std::vector<NodeID> result_nodes;
|
||||
|
||||
result_nodes.resize(end - begin);
|
||||
|
||||
std::copy(m_geometry_node_list.rbegin() + (m_geometry_node_list.size() - end),
|
||||
m_geometry_node_list.rbegin() + (m_geometry_node_list.size() - begin),
|
||||
result_nodes.begin());
|
||||
|
||||
return result_nodes;
|
||||
}
|
||||
|
||||
virtual std::vector<EdgeWeight>
|
||||
GetUncompressedForwardWeights(const EdgeID id) const override final
|
||||
{
|
||||
/*
|
||||
* EdgeWeights's for geometries are stored in one place for
|
||||
* both forward and reverse segments along the same bi-
|
||||
* directional edge. The m_geometry_indices stores
|
||||
* refences to where to find the beginning of the bi-
|
||||
* directional edge in the m_geometry_fwd_weight_list vector.
|
||||
* */
|
||||
const unsigned begin = m_geometry_indices.at(id) + 1;
|
||||
const unsigned end = m_geometry_indices.at(id + 1);
|
||||
|
||||
std::vector<EdgeWeight> result_weights;
|
||||
result_weights.resize(end - begin);
|
||||
|
||||
std::copy(m_geometry_fwd_weight_list.begin() + begin,
|
||||
m_geometry_fwd_weight_list.begin() + end,
|
||||
result_weights.begin());
|
||||
|
||||
return result_weights;
|
||||
}
|
||||
|
||||
virtual std::vector<EdgeWeight>
|
||||
GetUncompressedReverseWeights(const EdgeID id) const override final
|
||||
{
|
||||
/*
|
||||
* EdgeWeights for geometries are stored in one place for
|
||||
* both forward and reverse segments along the same bi-
|
||||
* directional edge. The m_geometry_indices stores
|
||||
* refences to where to find the beginning of the bi-
|
||||
* directional edge in the m_geometry_rev_weight_list vector. For
|
||||
* reverse weights of bi-directional edges, edges 1 to
|
||||
* n-1 of that edge need to be read in reverse.
|
||||
*/
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id + 1) - 1;
|
||||
|
||||
std::vector<EdgeWeight> result_weights;
|
||||
result_weights.resize(end - begin);
|
||||
|
||||
std::copy(m_geometry_rev_weight_list.rbegin() + (m_geometry_rev_weight_list.size() - end),
|
||||
m_geometry_rev_weight_list.rbegin() + (m_geometry_rev_weight_list.size() - begin),
|
||||
result_weights.begin());
|
||||
|
||||
return result_weights;
|
||||
}
|
||||
|
||||
// Returns the data source ids that were used to supply the edge
|
||||
// weights.
|
||||
virtual std::vector<uint8_t>
|
||||
GetUncompressedForwardDatasources(const EdgeID id) const override final
|
||||
{
|
||||
/*
|
||||
* Data sources for geometries are stored in one place for
|
||||
* both forward and reverse segments along the same bi-
|
||||
* directional edge. The m_geometry_indices stores
|
||||
* refences to where to find the beginning of the bi-
|
||||
* directional edge in the m_geometry_list vector. For
|
||||
* forward datasources of bi-directional edges, edges 2 to
|
||||
* n of that edge need to be read.
|
||||
*/
|
||||
const unsigned begin = m_geometry_indices.at(id) + 1;
|
||||
const unsigned end = m_geometry_indices.at(id + 1);
|
||||
|
||||
std::vector<uint8_t> result_datasources;
|
||||
result_datasources.resize(end - begin);
|
||||
|
||||
// If there was no datasource info, return an array of 0's.
|
||||
if (m_datasource_list.empty())
|
||||
{
|
||||
for (unsigned i = 0; i < end - begin; ++i)
|
||||
{
|
||||
result_datasources.push_back(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(m_datasource_list.begin() + begin,
|
||||
m_datasource_list.begin() + end,
|
||||
result_datasources.begin());
|
||||
}
|
||||
|
||||
return result_datasources;
|
||||
}
|
||||
|
||||
// Returns the data source ids that were used to supply the edge
|
||||
// weights.
|
||||
virtual std::vector<uint8_t>
|
||||
GetUncompressedReverseDatasources(const EdgeID id) const override final
|
||||
{
|
||||
/*
|
||||
* Datasources for geometries are stored in one place for
|
||||
* both forward and reverse segments along the same bi-
|
||||
* directional edge. The m_geometry_indices stores
|
||||
* refences to where to find the beginning of the bi-
|
||||
* directional edge in the m_geometry_list vector. For
|
||||
* reverse datasources of bi-directional edges, edges 1 to
|
||||
* n-1 of that edge need to be read in reverse.
|
||||
*/
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id + 1) - 1;
|
||||
|
||||
std::vector<uint8_t> result_datasources;
|
||||
result_datasources.resize(end - begin);
|
||||
|
||||
// If there was no datasource info, return an array of 0's.
|
||||
if (m_datasource_list.empty())
|
||||
{
|
||||
for (unsigned i = 0; i < end - begin; ++i)
|
||||
{
|
||||
result_datasources.push_back(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(m_datasource_list.rbegin() + (m_datasource_list.size() - end),
|
||||
m_datasource_list.rbegin() + (m_datasource_list.size() - begin),
|
||||
result_datasources.begin());
|
||||
}
|
||||
|
||||
return result_datasources;
|
||||
}
|
||||
|
||||
virtual std::string GetDatasourceName(const uint8_t datasource_name_id) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_datasource_names.size() >= 1);
|
||||
BOOST_ASSERT(m_datasource_names.size() > datasource_name_id);
|
||||
return m_datasource_names[datasource_name_id];
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const override final { return m_timestamp; }
|
||||
|
||||
bool GetContinueStraightDefault() const override final
|
||||
{
|
||||
return m_profile_properties.continue_straight_at_waypoint;
|
||||
}
|
||||
|
||||
double GetMapMatchingMaxSpeed() const override final
|
||||
{
|
||||
return m_profile_properties.max_speed_for_map_matching;
|
||||
}
|
||||
|
||||
BearingClassID GetBearingClassID(const NodeID nid) const override final
|
||||
{
|
||||
return m_bearing_class_id_table.at(nid);
|
||||
}
|
||||
|
||||
util::guidance::BearingClass
|
||||
GetBearingClass(const BearingClassID bearing_class_id) const override final
|
||||
{
|
||||
BOOST_ASSERT(bearing_class_id != INVALID_BEARING_CLASSID);
|
||||
auto range = m_bearing_ranges_table.GetRange(bearing_class_id);
|
||||
|
||||
util::guidance::BearingClass result;
|
||||
|
||||
for (auto itr = m_bearing_values_table.begin() + range.front();
|
||||
itr != m_bearing_values_table.begin() + range.back() + 1;
|
||||
++itr)
|
||||
result.add(*itr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EntryClassID GetEntryClassID(const EdgeID eid) const override final
|
||||
{
|
||||
return m_entry_class_id_list.at(eid);
|
||||
}
|
||||
|
||||
util::guidance::TurnBearing PreTurnBearing(const EdgeID eid) const override final
|
||||
{
|
||||
return m_pre_turn_bearing.at(eid);
|
||||
}
|
||||
util::guidance::TurnBearing PostTurnBearing(const EdgeID eid) const override final
|
||||
{
|
||||
return m_post_turn_bearing.at(eid);
|
||||
}
|
||||
|
||||
util::guidance::EntryClass GetEntryClass(const EntryClassID entry_class_id) const override final
|
||||
{
|
||||
return m_entry_class_table.at(entry_class_id);
|
||||
}
|
||||
|
||||
bool hasLaneData(const EdgeID id) const override final
|
||||
{
|
||||
return m_lane_data_id[id] != INVALID_LANE_DATAID;
|
||||
}
|
||||
|
||||
util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const override final
|
||||
{
|
||||
BOOST_ASSERT(hasLaneData(id));
|
||||
return m_lane_tuple_id_pairs[m_lane_data_id[id]];
|
||||
}
|
||||
|
||||
extractor::guidance::TurnLaneDescription
|
||||
GetTurnDescription(const LaneDescriptionID lane_description_id) const override final
|
||||
{
|
||||
if (lane_description_id == INVALID_LANE_DESCRIPTIONID)
|
||||
return {};
|
||||
else
|
||||
return extractor::guidance::TurnLaneDescription(
|
||||
m_lane_description_masks.begin() + m_lane_description_offsets[lane_description_id],
|
||||
m_lane_description_masks.begin() +
|
||||
m_lane_description_offsets[lane_description_id + 1]);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INTERNAL_DATAFACADE_HPP
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef PROCESS_MEMORY_DATAFACADE_HPP
|
||||
#define PROCESS_MEMORY_DATAFACADE_HPP
|
||||
|
||||
// implements all data storage when shared memory is _NOT_ used
|
||||
|
||||
#include "storage/storage.hpp"
|
||||
#include "engine/datafacade/contiguous_internalmem_datafacade_base.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace datafacade
|
||||
{
|
||||
|
||||
/**
|
||||
* This datafacade uses a process-local memory block to load
|
||||
* data into. The structure and layout is the same as when using
|
||||
* shared memory, so this class, and the SharedMemoryDataFacade both
|
||||
* share a common base.
|
||||
* This class holds a unique_ptr to the memory block, so it
|
||||
* is auto-freed upon destruction.
|
||||
*/
|
||||
class ProcessMemoryDataFacade final : public ContiguousInternalMemoryDataFacadeBase
|
||||
{
|
||||
|
||||
private:
|
||||
std::unique_ptr<char[]> internal_memory;
|
||||
std::unique_ptr<storage::DataLayout> internal_layout;
|
||||
|
||||
public:
|
||||
explicit ProcessMemoryDataFacade(const storage::StorageConfig &config)
|
||||
{
|
||||
storage::Storage storage(config);
|
||||
|
||||
// Calculate the layout/size of the memory block
|
||||
internal_layout = std::make_unique<storage::DataLayout>();
|
||||
storage.PopulateLayout(*internal_layout);
|
||||
|
||||
// Allocate the memory block, then load data from files into it
|
||||
internal_memory = std::make_unique<char[]>(internal_layout->GetSizeOfLayout());
|
||||
storage.PopulateData(*internal_layout, internal_memory.get());
|
||||
|
||||
// Adjust all the private m_* members to point to the right places
|
||||
InitializeInternalPointers(*internal_layout.get(), internal_memory.get());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PROCESS_MEMORY_DATAFACADE_HPP
|
||||
@@ -0,0 +1,97 @@
|
||||
#ifndef SHARED_MEMORY_DATAFACADE_HPP
|
||||
#define SHARED_MEMORY_DATAFACADE_HPP
|
||||
|
||||
// implements all data storage when shared memory _IS_ used
|
||||
|
||||
#include "storage/shared_barriers.hpp"
|
||||
#include "storage/shared_datatype.hpp"
|
||||
#include "storage/shared_memory.hpp"
|
||||
#include "engine/datafacade/contiguous_internalmem_datafacade_base.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace datafacade
|
||||
{
|
||||
|
||||
/**
|
||||
* This datafacade uses an IPC shared memory block as the data location.
|
||||
* Many SharedMemoryDataFacade objects can be created that point to the same shared
|
||||
* memory block.
|
||||
*/
|
||||
class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
|
||||
{
|
||||
|
||||
protected:
|
||||
std::unique_ptr<storage::SharedMemory> m_layout_memory;
|
||||
std::unique_ptr<storage::SharedMemory> m_large_memory;
|
||||
std::shared_ptr<storage::SharedBarriers> shared_barriers;
|
||||
storage::SharedDataType layout_region;
|
||||
storage::SharedDataType data_region;
|
||||
unsigned shared_timestamp;
|
||||
|
||||
SharedMemoryDataFacade() {}
|
||||
|
||||
public:
|
||||
// this function handle the deallocation of the shared memory it we can prove it will not be
|
||||
// used anymore. We crash hard here if something goes wrong (noexcept).
|
||||
virtual ~SharedMemoryDataFacade() noexcept
|
||||
{
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
|
||||
data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
|
||||
: shared_barriers->regions_2_mutex,
|
||||
boost::interprocess::defer_lock);
|
||||
|
||||
// if this returns false this is still in use
|
||||
if (exclusive_lock.try_lock())
|
||||
{
|
||||
if (storage::SharedMemory::RegionExists(data_region))
|
||||
{
|
||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
||||
|
||||
// Now check if this is still the newest dataset
|
||||
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
|
||||
lock(shared_barriers->current_regions_mutex);
|
||||
|
||||
auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
|
||||
const auto current_timestamp =
|
||||
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
||||
|
||||
if (current_timestamp->timestamp == shared_timestamp)
|
||||
{
|
||||
util::Log(logDEBUG) << "Retaining data with shared timestamp " << shared_timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
storage::SharedMemory::Remove(data_region);
|
||||
storage::SharedMemory::Remove(layout_region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SharedMemoryDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
|
||||
storage::SharedDataType layout_region_,
|
||||
storage::SharedDataType data_region_,
|
||||
unsigned shared_timestamp_)
|
||||
: shared_barriers(shared_barriers_), layout_region(layout_region_),
|
||||
data_region(data_region_), shared_timestamp(shared_timestamp_)
|
||||
{
|
||||
util::Log(logDEBUG) << "Loading new data with shared timestamp " << shared_timestamp;
|
||||
|
||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
||||
m_layout_memory = storage::makeSharedMemory(layout_region);
|
||||
|
||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
|
||||
m_large_memory = storage::makeSharedMemory(data_region);
|
||||
|
||||
InitializeInternalPointers(*reinterpret_cast<storage::DataLayout *>(m_layout_memory->Ptr()),
|
||||
reinterpret_cast<char *>(m_large_memory->Ptr()));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SHARED_MEMORY_DATAFACADE_HPP
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "engine/plugins/trip.hpp"
|
||||
#include "engine/plugins/viaroute.hpp"
|
||||
#include "engine/status.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -400,7 +400,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
}
|
||||
if (data.reverse_segment_id.id != SPECIAL_SEGMENTID)
|
||||
{
|
||||
reverse_weight *= 1.0 - ratio;
|
||||
const EdgeWeight difference = reverse_weight * ratio;
|
||||
reverse_weight -= difference;
|
||||
}
|
||||
|
||||
auto transformed = PhantomNodeWithDistance{PhantomNode{data,
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
#include "engine/guidance/leg_geometry.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
|
||||
@@ -8,14 +8,12 @@
|
||||
#include "engine/guidance/leg_geometry.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
#include "engine/guidance/step_maneuver.hpp"
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
@@ -156,7 +154,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
intersection.entry.push_back(entry_class.allowsEntry(idx));
|
||||
}
|
||||
std::int16_t bearing_in_driving_direction =
|
||||
util::bearing::reverseBearing(std::round(bearings.first));
|
||||
util::reverseBearing(std::round(bearings.first));
|
||||
maneuver = {intersection.location,
|
||||
bearing_in_driving_direction,
|
||||
bearings.second,
|
||||
@@ -216,14 +214,13 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
BOOST_ASSERT(segment_index == number_of_segments - 1);
|
||||
bearings = detail::getArriveBearings(leg_geometry);
|
||||
|
||||
intersection = {
|
||||
target_node.location,
|
||||
std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}),
|
||||
std::vector<bool>({true}),
|
||||
0,
|
||||
Intersection::NO_INDEX,
|
||||
util::guidance::LaneTuple(),
|
||||
{}};
|
||||
intersection = {target_node.location,
|
||||
std::vector<short>({static_cast<short>(util::reverseBearing(bearings.first))}),
|
||||
std::vector<bool>({true}),
|
||||
0,
|
||||
Intersection::NO_INDEX,
|
||||
util::guidance::LaneTuple(),
|
||||
{}};
|
||||
|
||||
// This step has length zero, the only reason we need it is the target location
|
||||
maneuver = {intersection.location,
|
||||
@@ -233,7 +230,6 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
WaypointType::Arrive,
|
||||
0};
|
||||
|
||||
|
||||
BOOST_ASSERT(!leg_geometry.locations.empty());
|
||||
steps.push_back(RouteStep{target_node.name_id,
|
||||
facade.GetNameForID(target_node.name_id),
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_
|
||||
#define OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Runs fn on RouteStep sub-ranges determined to be roundabouts.
|
||||
// The function fn is getting called with a roundabout range as in: [enter, .., leave].
|
||||
//
|
||||
// The following situations are taken care for (i.e. we discard them):
|
||||
// - partial roundabout: enter without exit or exit without enter
|
||||
// - data issues: no roundabout, exit before enter
|
||||
template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, Iter last, Fn fn)
|
||||
{
|
||||
while (first != last)
|
||||
{
|
||||
const auto enter = std::find_if(first, last, [](const RouteStep &step) {
|
||||
return entersRoundabout(step.maneuver.instruction);
|
||||
});
|
||||
|
||||
// enter has to come before leave, otherwise: faulty data / partial roundabout, skip those
|
||||
const auto leave = std::find_if(enter, last, [](const RouteStep &step) {
|
||||
return leavesRoundabout(step.maneuver.instruction);
|
||||
});
|
||||
|
||||
// No roundabouts, or partial one (like start / end inside a roundabout)
|
||||
if (enter == last || leave == last)
|
||||
break;
|
||||
|
||||
(void)fn(std::make_pair(enter, leave));
|
||||
|
||||
// Skip to first step after the currently handled enter / leave pair
|
||||
first = std::next(leave);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_ENGINE_GUIDANCE_POSTPROCESSING_TOOLKIT_HPP_ */
|
||||
@@ -11,10 +11,11 @@
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
@@ -71,6 +72,33 @@ struct RouteStep
|
||||
std::size_t geometry_begin;
|
||||
std::size_t geometry_end;
|
||||
std::vector<Intersection> intersections;
|
||||
|
||||
LaneID numLanesToTheRight() const
|
||||
{
|
||||
return intersections.front().lanes.first_lane_from_the_right;
|
||||
}
|
||||
|
||||
LaneID numLanesToTheLeft() const
|
||||
{
|
||||
LaneID const total = intersections.front().lane_description.size();
|
||||
return total - (intersections.front().lanes.lanes_in_turn +
|
||||
intersections.front().lanes.first_lane_from_the_right);
|
||||
}
|
||||
|
||||
auto lanesToTheLeft() const
|
||||
{
|
||||
const auto &description = intersections.front().lane_description;
|
||||
LaneID num_lanes_left = numLanesToTheLeft();
|
||||
return boost::make_iterator_range(description.begin(),
|
||||
description.begin() + num_lanes_left);
|
||||
}
|
||||
|
||||
auto lanesToTheRight() const
|
||||
{
|
||||
const auto &description = intersections.front().lane_description;
|
||||
LaneID num_lanes_right = numLanesToTheRight();
|
||||
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
|
||||
}
|
||||
};
|
||||
|
||||
inline RouteStep getInvalidRouteStep()
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
#ifndef OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
|
||||
#define OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
using util::guidance::entersRoundabout;
|
||||
using util::guidance::leavesRoundabout;
|
||||
using util::guidance::staysOnRoundabout;
|
||||
|
||||
// Silent Turn Instructions are not to be mentioned to the outside world but
|
||||
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::NoTurn ||
|
||||
instruction.type == extractor::guidance::TurnType::Suppressed ||
|
||||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
|
||||
}
|
||||
|
||||
inline extractor::guidance::DirectionModifier::Enum angleToDirectionModifier(const double bearing)
|
||||
{
|
||||
if (bearing < 135)
|
||||
{
|
||||
return extractor::guidance::DirectionModifier::Right;
|
||||
}
|
||||
|
||||
if (bearing <= 225)
|
||||
{
|
||||
return extractor::guidance::DirectionModifier::Straight;
|
||||
}
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
}
|
||||
|
||||
// Runs fn on RouteStep sub-ranges determined to be roundabouts.
|
||||
// The function fn is getting called with a roundabout range as in: [enter, .., leave].
|
||||
//
|
||||
// The following situations are taken care for (i.e. we discard them):
|
||||
// - partial roundabout: enter without exit or exit without enter
|
||||
// - data issues: no roundabout, exit before enter
|
||||
template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, Iter last, Fn fn)
|
||||
{
|
||||
while (first != last)
|
||||
{
|
||||
const auto enter = std::find_if(first, last, [](const RouteStep &step) {
|
||||
return entersRoundabout(step.maneuver.instruction);
|
||||
});
|
||||
|
||||
// enter has to come before leave, otherwise: faulty data / partial roundabout, skip those
|
||||
const auto leave = std::find_if(enter, last, [](const RouteStep &step) {
|
||||
return leavesRoundabout(step.maneuver.instruction);
|
||||
});
|
||||
|
||||
// No roundabouts, or partial one (like start / end inside a roundabout)
|
||||
if (enter == last || leave == last)
|
||||
break;
|
||||
|
||||
(void)fn(std::make_pair(enter, leave));
|
||||
|
||||
// Skip to first step after the currently handled enter / leave pair
|
||||
first = std::next(leave);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
LaneID inline numLanesToTheRight(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
return step.intersections.front().lanes.first_lane_from_the_right;
|
||||
}
|
||||
|
||||
LaneID inline numLanesToTheLeft(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
LaneID const total = step.intersections.front().lane_description.size();
|
||||
return total - (step.intersections.front().lanes.lanes_in_turn +
|
||||
step.intersections.front().lanes.first_lane_from_the_right);
|
||||
}
|
||||
|
||||
auto inline lanesToTheLeft(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
const auto &description = step.intersections.front().lane_description;
|
||||
LaneID num_lanes_left = numLanesToTheLeft(step);
|
||||
return boost::make_iterator_range(description.begin(), description.begin() + num_lanes_left);
|
||||
}
|
||||
|
||||
auto inline lanesToTheRight(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
const auto &description = step.intersections.front().lane_description;
|
||||
LaneID num_lanes_right = numLanesToTheRight(step);
|
||||
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_ */
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -13,17 +13,17 @@ namespace osrm
|
||||
namespace engine
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
constexpr double POLYLINE_DECODING_PRECISION = 1e5;
|
||||
constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_DECODING_PRECISION;
|
||||
{
|
||||
constexpr double POLYLINE_DECODING_PRECISION = 1e5;
|
||||
constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_DECODING_PRECISION;
|
||||
|
||||
std::string encode(std::vector<int> &numbers);
|
||||
}
|
||||
std::string encode(std::vector<int> &numbers);
|
||||
}
|
||||
using CoordVectorForwardIter = std::vector<util::Coordinate>::const_iterator;
|
||||
// Encodes geometry into polyline format.
|
||||
// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
||||
|
||||
template<unsigned POLYLINE_PRECISION=100000>
|
||||
template <unsigned POLYLINE_PRECISION = 100000>
|
||||
std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end)
|
||||
{
|
||||
double coordinate_to_polyline = POLYLINE_PRECISION / COORDINATE_PRECISION;
|
||||
@@ -39,7 +39,10 @@ std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter
|
||||
int current_lat = 0;
|
||||
int current_lon = 0;
|
||||
std::for_each(
|
||||
begin, end, [&delta_numbers, ¤t_lat, ¤t_lon, coordinate_to_polyline](const util::Coordinate loc) {
|
||||
begin,
|
||||
end,
|
||||
[&delta_numbers, ¤t_lat, ¤t_lon, coordinate_to_polyline](
|
||||
const util::Coordinate loc) {
|
||||
const int lat_diff =
|
||||
std::round(static_cast<int>(loc.lat) * coordinate_to_polyline) - current_lat;
|
||||
const int lon_diff =
|
||||
|
||||
@@ -235,10 +235,10 @@ class AlternativeRouting final
|
||||
}
|
||||
}
|
||||
|
||||
// util::SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
|
||||
// util::Log(logDEBUG) << "fwd_search_space size: " <<
|
||||
// forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
|
||||
// nodes";
|
||||
// util::SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
|
||||
// util::Log(logDEBUG) << "rev_search_space size: " <<
|
||||
// reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
|
||||
// nodes";
|
||||
|
||||
@@ -601,7 +601,7 @@ class AlternativeRouting final
|
||||
// //compute forward sharing
|
||||
// while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
|
||||
// (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
|
||||
// // util::SimpleLogger().Write() << "retrieving edge (" <<
|
||||
// // util::Log() << "retrieving edge (" <<
|
||||
// packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
|
||||
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
|
||||
// packed_alternate_path[aindex+1]);
|
||||
@@ -640,7 +640,7 @@ class AlternativeRouting final
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int weight = forward_heap.GetKey(node);
|
||||
// const NodeID parentnode = forward_heap.GetData(node).parent;
|
||||
// util::SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
|
||||
// util::Log() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
|
||||
// edge ("
|
||||
// << parentnode << "," << node << "), dist: " << weight;
|
||||
|
||||
@@ -665,11 +665,11 @@ class AlternativeRouting final
|
||||
{
|
||||
*middle_node = node;
|
||||
*upper_bound_to_shortest_path_weight = new_weight;
|
||||
// util::SimpleLogger().Write() << "accepted middle_node " << *middle_node
|
||||
// util::Log() << "accepted middle_node " << *middle_node
|
||||
// << " at
|
||||
// weight " << new_weight;
|
||||
// } else {
|
||||
// util::SimpleLogger().Write() << "discarded middle_node " << *middle_node
|
||||
// util::Log() << "discarded middle_node " << *middle_node
|
||||
// << "
|
||||
// at weight " << new_weight;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define TRIP_BRUTE_FORCE_HPP
|
||||
|
||||
#include "util/dist_table_wrapper.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "util/dist_table_wrapper.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define TRIP_NEAREST_NEIGHBOUR_HPP
|
||||
|
||||
#include "util/dist_table_wrapper.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "extractor/travel_mode.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include <tuple>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -60,19 +61,12 @@ inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
|
||||
|
||||
inline bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
|
||||
{
|
||||
if (source == other.source)
|
||||
{
|
||||
if (target == other.target)
|
||||
{
|
||||
if (weight == other.weight)
|
||||
{
|
||||
return forward && backward && ((!other.forward) || (!other.backward));
|
||||
}
|
||||
return weight < other.weight;
|
||||
}
|
||||
return target < other.target;
|
||||
}
|
||||
return source < other.source;
|
||||
const auto unidirectional = (!forward || !backward);
|
||||
const auto other_is_unidirectional = (!other.forward || !other.backward);
|
||||
// if all items are the same, we want to keep bidirectional edges. due to the `<` operator,
|
||||
// preferring 0 (false) over 1 (true), we need to compare the inverse of `bidirectional`
|
||||
return std::tie(source, target, weight, unidirectional) <
|
||||
std::tie(other.source, other.target, other.weight, other_is_unidirectional);
|
||||
}
|
||||
} // ns extractor
|
||||
} // ns osrm
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
@@ -32,6 +32,7 @@ class ExtractionContainers
|
||||
#else
|
||||
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
|
||||
#endif
|
||||
void FlushVectors();
|
||||
void PrepareNodes();
|
||||
void PrepareRestrictions();
|
||||
void PrepareEdges(ScriptingEnvironment &scripting_environment);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/parsing_toolkit.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -109,13 +109,13 @@ inline unsigned parseDuration(const std::string &s)
|
||||
inline std::string
|
||||
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
|
||||
{
|
||||
return extractor::guidance::trimLaneString(std::move(lane_string), count_left, count_right);
|
||||
return guidance::trimLaneString(std::move(lane_string), count_left, count_right);
|
||||
}
|
||||
|
||||
inline std::string applyAccessTokens(const std::string &lane_string,
|
||||
const std::string &access_tokens)
|
||||
{
|
||||
return extractor::guidance::applyAccessTokens(lane_string, access_tokens);
|
||||
return guidance::applyAccessTokens(lane_string, access_tokens);
|
||||
}
|
||||
|
||||
// Takes a string representing a list separated by delim and canonicalizes containing spaces.
|
||||
|
||||
@@ -13,6 +13,20 @@ namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline void maybeSetString(std::string &str, const char *value)
|
||||
{
|
||||
if (value == nullptr)
|
||||
{
|
||||
str.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
str = std::string(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This struct is the direct result of the call to ```way_function```
|
||||
@@ -30,8 +44,8 @@ struct ExtractionWay
|
||||
backward_speed = -1;
|
||||
duration = -1;
|
||||
roundabout = false;
|
||||
circular = false;
|
||||
is_startpoint = true;
|
||||
is_access_restricted = false;
|
||||
name.clear();
|
||||
ref.clear();
|
||||
pronunciation.clear();
|
||||
@@ -50,6 +64,26 @@ struct ExtractionWay
|
||||
void set_backward_mode(const TravelMode m) { backward_travel_mode = m; }
|
||||
TravelMode get_backward_mode() const { return backward_travel_mode; }
|
||||
|
||||
// wrappers to allow assigning nil (nullptr) to string values
|
||||
void SetName(const char *value) { detail::maybeSetString(name, value); }
|
||||
const char *GetName() const { return name.c_str(); }
|
||||
void SetRef(const char *value) { detail::maybeSetString(ref, value); }
|
||||
const char *GetRef() const { return ref.c_str(); }
|
||||
void SetDestinations(const char *value) { detail::maybeSetString(destinations, value); }
|
||||
const char *GetDestinations() const { return destinations.c_str(); }
|
||||
void SetPronunciation(const char *value) { detail::maybeSetString(pronunciation, value); }
|
||||
const char *GetPronunciation() const { return pronunciation.c_str(); }
|
||||
void SetTurnLanesForward(const char *value)
|
||||
{
|
||||
detail::maybeSetString(turn_lanes_forward, value);
|
||||
}
|
||||
const char *GetTurnLanesForward() const { return turn_lanes_forward.c_str(); }
|
||||
void SetTurnLanesBackward(const char *value)
|
||||
{
|
||||
detail::maybeSetString(turn_lanes_backward, value);
|
||||
}
|
||||
const char *GetTurnLanesBackward() const { return turn_lanes_backward.c_str(); }
|
||||
|
||||
double forward_speed;
|
||||
double backward_speed;
|
||||
double duration;
|
||||
@@ -60,7 +94,7 @@ struct ExtractionWay
|
||||
std::string turn_lanes_forward;
|
||||
std::string turn_lanes_backward;
|
||||
bool roundabout;
|
||||
bool is_access_restricted;
|
||||
bool circular;
|
||||
bool is_startpoint;
|
||||
TravelMode forward_travel_mode : 4;
|
||||
TravelMode backward_travel_mode : 4;
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
|
||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef OSRM_EXTRACTOR_COORDINATE_EXTRACTOR_HPP_
|
||||
#define OSRM_EXTRACTOR_COORDINATE_EXTRACTOR_HPP_
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
namespace osrm
|
||||
@@ -27,24 +28,51 @@ class CoordinateExtractor
|
||||
/* Find a interpolated coordinate a long the compressed geometries. The desired coordinate
|
||||
* should be in a certain distance. This method is dedicated to find representative coordinates
|
||||
* at turns.
|
||||
* Since we are computing the length of the segment anyhow, we also return it.
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
util::Coordinate GetCoordinateAlongRoad(const NodeID intersection_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node,
|
||||
const std::uint8_t number_of_in_lanes) const;
|
||||
|
||||
// instead of finding only a single coordinate, we can also list all coordinates along a road.
|
||||
std::vector<util::Coordinate> GetCoordinatesAlongRoad(const NodeID intersection_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node) const;
|
||||
// Given a set of precomputed coordinates, select the representative coordinate along the road
|
||||
// that best describes the turn
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
util::Coordinate
|
||||
ExtractRepresentativeCoordinate(const NodeID intersection_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node,
|
||||
const std::uint8_t intersection_lanes,
|
||||
std::vector<util::Coordinate> coordinates) const;
|
||||
|
||||
// instead of finding only a single coordinate, we can also list all coordinates along a
|
||||
// road.
|
||||
OSRM_ATTR_WARN_UNUSED std::vector<util::Coordinate>
|
||||
GetCoordinatesAlongRoad(const NodeID intersection_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node) const;
|
||||
|
||||
// wrapper in case of normal forward edges (traversed_in_reverse = false, to_node =
|
||||
// node_based_graph.GetTarget(turn_edge)
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<util::Coordinate> GetForwardCoordinatesAlongRoad(const NodeID from,
|
||||
const EdgeID turn_edge) const;
|
||||
|
||||
// a less precise way to compute coordinates along a route. Due to the heavy interaction of
|
||||
// graph traversal and turn instructions, we often don't care for high precision. We only want
|
||||
// to check for available connections in order, or find (with room for error) the straightmost
|
||||
// turn. This function will offer a bit more error potential but allow for much higher
|
||||
// performance
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
util::Coordinate GetCoordinateCloseToTurn(const NodeID from_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node) const;
|
||||
|
||||
/* When extracting the coordinates, we first extract all coordinates. We don't care about most
|
||||
* of them, though.
|
||||
*
|
||||
@@ -61,14 +89,25 @@ class CoordinateExtractor
|
||||
* For calculating the turn angle for the intersection at `a`, we do not care about the turn
|
||||
* between `v` and `b`. This calculation trims the coordinates to the ones immediately at the
|
||||
* intersection.
|
||||
*
|
||||
* The optional length cache needs to store the accumulated distance up to the respective
|
||||
* coordinate index [0,d(0,1),...]
|
||||
*/
|
||||
std::vector<util::Coordinate> TrimCoordinatesToLength(std::vector<util::Coordinate> coordinates,
|
||||
const double desired_length) const;
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<util::Coordinate>
|
||||
TrimCoordinatesToLength(std::vector<util::Coordinate> coordinates,
|
||||
const double desired_length,
|
||||
const std::vector<double> &length_cache = {}) const;
|
||||
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<double> PrepareLengthCache(const std::vector<util::Coordinate> &coordinates,
|
||||
const double limit) const;
|
||||
|
||||
/* when looking at a set of coordinates, this function allows trimming the vector to a smaller,
|
||||
* only containing coordinates up to a given distance along the path. The last coordinate might
|
||||
* be interpolated
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<util::Coordinate>
|
||||
TrimCoordinatesByLengthFront(std::vector<util::Coordinate> coordinates,
|
||||
const double desired_length) const;
|
||||
@@ -94,6 +133,7 @@ class CoordinateExtractor
|
||||
*
|
||||
* for fixpoint `b`, vector_base `d` and vector_head `e`
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
util::Coordinate GetCorrectedCoordinate(const util::Coordinate fixpoint,
|
||||
const util::Coordinate vector_base,
|
||||
const util::Coordinate vector_head) const;
|
||||
@@ -106,6 +146,7 @@ class CoordinateExtractor
|
||||
* Into:
|
||||
* x -- x -- x -- x -- x - x
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<util::Coordinate>
|
||||
SampleCoordinates(const std::vector<util::Coordinate> &coordinates,
|
||||
const double length,
|
||||
@@ -199,6 +240,14 @@ class CoordinateExtractor
|
||||
const double segment_length,
|
||||
const std::vector<double> &segment_distances,
|
||||
const std::uint8_t considered_lanes) const;
|
||||
|
||||
// find the coordinate at a specific location in the vector
|
||||
util::Coordinate ExtractCoordinateAtLength(const double distance,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const std::vector<double> &length_cache) const;
|
||||
util::Coordinate
|
||||
ExtractCoordinateAtLength(const double distance,
|
||||
const std::vector<util::Coordinate> &coordinates) const;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp" // EdgeID
|
||||
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/range/algorithm/find_if.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -16,22 +25,50 @@ namespace extractor
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Every Turn Operation describes a way of switching onto a segment, indicated by an EdgeID. The
|
||||
// associated turn is described by an angle and an instruction that is used to announce it.
|
||||
// The Turn Operation indicates what is exposed to the outside of the turn analysis.
|
||||
struct TurnOperation
|
||||
// the shape of an intersection only knows about edge IDs and bearings
|
||||
struct IntersectionShapeData
|
||||
{
|
||||
EdgeID eid;
|
||||
double angle;
|
||||
double bearing;
|
||||
TurnInstruction instruction;
|
||||
LaneDataID lane_data_id;
|
||||
double segment_length;
|
||||
};
|
||||
|
||||
inline auto makeCompareShapeDataByBearing(const double base_bearing)
|
||||
{
|
||||
return [base_bearing](const auto &lhs, const auto &rhs) {
|
||||
return util::angleBetweenBearings(base_bearing, lhs.bearing) <
|
||||
util::angleBetweenBearings(base_bearing, rhs.bearing);
|
||||
};
|
||||
}
|
||||
|
||||
inline auto makeCompareAngularDeviation(const double angle)
|
||||
{
|
||||
return [angle](const auto &lhs, const auto &rhs) {
|
||||
return util::angularDeviation(lhs.angle, angle) < util::angularDeviation(rhs.angle, angle);
|
||||
};
|
||||
}
|
||||
|
||||
// When viewing an intersection from an incoming edge, we can transform a shape into a view which
|
||||
// gives additional information on angles and whether a turn is allowed
|
||||
struct IntersectionViewData : IntersectionShapeData
|
||||
{
|
||||
IntersectionViewData(const IntersectionShapeData &shape,
|
||||
const bool entry_allowed,
|
||||
const double angle)
|
||||
: IntersectionShapeData(shape), entry_allowed(entry_allowed), angle(angle)
|
||||
{
|
||||
}
|
||||
|
||||
bool entry_allowed;
|
||||
double angle;
|
||||
|
||||
bool CompareByAngle(const IntersectionViewData &other) const;
|
||||
};
|
||||
|
||||
// A Connected Road is the internal representation of a potential turn. Internally, we require
|
||||
// full list of all connected roads to determine the outcome.
|
||||
// The reasoning behind is that even invalid turns can influence the perceived angles, or even
|
||||
// instructions themselves. An pososible example can be described like this:
|
||||
// instructions themselves. An possible example can be described like this:
|
||||
//
|
||||
// aaa(2)aa
|
||||
// a - bbbbb
|
||||
@@ -39,8 +76,7 @@ struct TurnOperation
|
||||
//
|
||||
// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
|
||||
// In addition, they can influence whether a turn is obvious or not. b->(2) would also be no
|
||||
// turn-operation,
|
||||
// but rather a name change.
|
||||
// turn-operation, but rather a name change.
|
||||
//
|
||||
// If this were a normal intersection with
|
||||
//
|
||||
@@ -49,14 +85,17 @@ struct TurnOperation
|
||||
// aaaaaaaa
|
||||
//
|
||||
// We would perceive a->c as a sharp turn, a->b as a slight turn, and b->c as a slight turn.
|
||||
struct ConnectedRoad final : public TurnOperation
|
||||
struct ConnectedRoad final : IntersectionViewData
|
||||
{
|
||||
using Base = TurnOperation;
|
||||
ConnectedRoad(const IntersectionViewData &view,
|
||||
const TurnInstruction instruction,
|
||||
const LaneDataID lane_data_id)
|
||||
: IntersectionViewData(view), instruction(instruction), lane_data_id(lane_data_id)
|
||||
{
|
||||
}
|
||||
|
||||
ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
|
||||
|
||||
// a turn may be relevant to good instructions, even if we cannot enter the road
|
||||
bool entry_allowed;
|
||||
TurnInstruction instruction;
|
||||
LaneDataID lane_data_id;
|
||||
|
||||
// used to sort the set of connected roads (we require sorting throughout turn handling)
|
||||
bool compareByAngle(const ConnectedRoad &other) const;
|
||||
@@ -71,32 +110,116 @@ struct ConnectedRoad final : public TurnOperation
|
||||
// small helper function to print the content of a connected road
|
||||
std::string toString(const ConnectedRoad &road);
|
||||
|
||||
struct Intersection final : public std::vector<ConnectedRoad>
|
||||
// Intersections are sorted roads: [0] being the UTurn road, then from sharp right to sharp left.
|
||||
|
||||
using IntersectionShape = std::vector<IntersectionShapeData>;
|
||||
|
||||
// Common operations shared among IntersectionView and Intersections.
|
||||
// Inherit to enable those operations on your compatible type. CRTP pattern.
|
||||
template <typename Self> struct EnableIntersectionOps
|
||||
{
|
||||
using Base = std::vector<ConnectedRoad>;
|
||||
// Find the turn whose angle offers the least angular deviation to the specified angle
|
||||
// For turn angles [0, 90, 260] and a query of 180 we return the 260 degree turn.
|
||||
auto findClosestTurn(double angle) const
|
||||
{
|
||||
auto comp = makeCompareAngularDeviation(angle);
|
||||
return std::min_element(self()->begin(), self()->end(), comp);
|
||||
}
|
||||
|
||||
/*
|
||||
* find the turn whose angle offers the least angularDeviation to the specified angle
|
||||
* E.g. for turn angles [0,90,260] and a query of 180 we return the 260 degree turn (difference
|
||||
* 80 over the difference of 90 to the 90 degree turn)
|
||||
*/
|
||||
Base::iterator findClosestTurn(double angle);
|
||||
Base::const_iterator findClosestTurn(double angle) const;
|
||||
// Check validity of the intersection object. We assume a few basic properties every set of
|
||||
// connected roads should follow throughout guidance pre-processing. This utility function
|
||||
// allows checking intersections for validity
|
||||
auto valid() const
|
||||
{
|
||||
if (self()->empty())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Check validity of the intersection object. We assume a few basic properties every set of
|
||||
* connected roads should follow throughout guidance pre-processing. This utility function
|
||||
* allows checking intersections for validity
|
||||
*/
|
||||
bool valid() const;
|
||||
auto comp = [](const auto &lhs, const auto &rhs) { return lhs.CompareByAngle(rhs); };
|
||||
|
||||
// given all possible turns, which is the highest connected number of lanes per turn. This value
|
||||
// is used, for example, during generation of intersections.
|
||||
std::uint8_t getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &) const;
|
||||
const auto ordered = std::is_sorted(self()->begin(), self()->end(), comp);
|
||||
|
||||
if (!ordered)
|
||||
return false;
|
||||
|
||||
const auto uturn = self()->operator[](0).angle < std::numeric_limits<double>::epsilon();
|
||||
|
||||
if (!uturn)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Given all possible turns which is the highest connected number of lanes per turn.
|
||||
// This value is used for example during generation of intersections.
|
||||
auto getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &graph) const
|
||||
{
|
||||
const std::function<std::uint8_t(const ConnectedRoad &)> to_lane_count =
|
||||
[&](const ConnectedRoad &road) {
|
||||
return graph.GetEdgeData(road.eid).road_classification.GetNumberOfLanes();
|
||||
};
|
||||
|
||||
std::uint8_t max_lanes = 0;
|
||||
const auto extract_maximal_value = [&max_lanes](std::uint8_t value) {
|
||||
max_lanes = std::max(max_lanes, value);
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto view = *self() | boost::adaptors::transformed(to_lane_count);
|
||||
boost::range::find_if(view, extract_maximal_value);
|
||||
return max_lanes;
|
||||
}
|
||||
|
||||
// Returns the UTurn road we took to arrive at this intersection.
|
||||
const auto &getUTurnRoad() const { return self()->operator[](0); }
|
||||
|
||||
// Returns the right-most road at this intersection.
|
||||
const auto &getRightmostRoad() const
|
||||
{
|
||||
return self()->size() > 1 ? self()->operator[](1) : self()->getUTurnRoad();
|
||||
}
|
||||
|
||||
// Returns the left-most road at this intersection.
|
||||
const auto &getLeftmostRoad() const
|
||||
{
|
||||
return self()->size() > 1 ? self()->back() : self()->getUTurnRoad();
|
||||
}
|
||||
|
||||
// Can this be skipped over?
|
||||
auto isTrafficSignalOrBarrier() const { return self()->size() == 2; }
|
||||
|
||||
// Checks if there is at least one road available (except UTurn road) on which to continue.
|
||||
auto isDeadEnd() const
|
||||
{
|
||||
auto pred = [](const auto &road) { return road.entry_allowed; };
|
||||
return !std::any_of(self()->begin() + 1, self()->end(), pred);
|
||||
}
|
||||
|
||||
// Returns the number of roads we can enter at this intersection, respectively.
|
||||
auto countEnterable() const
|
||||
{
|
||||
auto pred = [](const auto &road) { return road.entry_allowed; };
|
||||
return std::count_if(self()->begin(), self()->end(), pred);
|
||||
}
|
||||
|
||||
// Returns the number of roads we can not enter at this intersection, respectively.
|
||||
auto countNonEnterable() const { return self()->size() - self()->countEnterable(); }
|
||||
|
||||
private:
|
||||
auto self() { return static_cast<Self *>(this); }
|
||||
auto self() const { return static_cast<const Self *>(this); }
|
||||
};
|
||||
|
||||
Intersection::const_iterator findClosestTurn(const Intersection &intersection, const double angle);
|
||||
Intersection::iterator findClosestTurn(Intersection &intersection, const double angle);
|
||||
struct IntersectionView final : std::vector<IntersectionViewData>, //
|
||||
EnableIntersectionOps<IntersectionView> //
|
||||
{
|
||||
using Base = std::vector<IntersectionViewData>;
|
||||
};
|
||||
|
||||
struct Intersection final : std::vector<ConnectedRoad>, //
|
||||
EnableIntersectionOps<Intersection> //
|
||||
{
|
||||
using Base = std::vector<ConnectedRoad>;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
|
||||
@@ -6,15 +6,16 @@
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -25,7 +26,6 @@ namespace guidance
|
||||
// from it. For this all turn possibilities are analysed.
|
||||
// We consider turn restrictions to indicate possible turns. U-turns are generated based on profile
|
||||
// decisions.
|
||||
|
||||
class IntersectionGenerator
|
||||
{
|
||||
public:
|
||||
@@ -33,80 +33,89 @@ class IntersectionGenerator
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
const CompressedEdgeContainer &compressed_edge_container);
|
||||
|
||||
Intersection operator()(const NodeID nid, const EdgeID via_eid) const;
|
||||
// For a source node `a` and a via edge `ab` creates an intersection at target `b`.
|
||||
//
|
||||
// a . . . b . .
|
||||
// .
|
||||
// .
|
||||
//
|
||||
IntersectionView operator()(const NodeID nid, const EdgeID via_eid) const;
|
||||
|
||||
/*
|
||||
* Compute the shape of an intersection, returning a set of connected roads, without any further
|
||||
* concern for which of the entries are actually allowed.
|
||||
* The shape also only comes with turn bearings, not with turn angles. All turn angles will be
|
||||
* set to zero
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
IntersectionShape
|
||||
ComputeIntersectionShape(const NodeID center_node,
|
||||
const boost::optional<NodeID> sorting_base = boost::none,
|
||||
bool use_low_precision_angles = false) const;
|
||||
|
||||
// Graph Compression cannot compress every setting. For example any barrier/traffic light cannot
|
||||
// be compressed. As a result, a simple road of the form `a ----- b` might end up as having an
|
||||
// intermediate intersection, if there is a traffic light in between. If we want to look farther
|
||||
// down a road, finding the next actual decision requires the look at multiple intersections.
|
||||
// Here we follow the road until we either reach a dead end or find the next intersection with
|
||||
// more than a single next road.
|
||||
Intersection GetActualNextIntersection(const NodeID starting_node,
|
||||
const EdgeID via_edge,
|
||||
NodeID *resulting_from_node,
|
||||
EdgeID *resulting_via_edge) const;
|
||||
// more than a single next road. This function skips over degree two nodes to find coorect input
|
||||
// for GetConnectedRoads.
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::pair<NodeID, EdgeID> SkipDegreeTwoNodes(const NodeID starting_node,
|
||||
const EdgeID via_edge) const;
|
||||
|
||||
// Allow access to the coordinate extractor for all owners
|
||||
const CoordinateExtractor &GetCoordinateExtractor() const;
|
||||
|
||||
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
|
||||
// the
|
||||
// node reached
|
||||
// from `from_node` via `via_eid`
|
||||
// The resulting candidates have to be analysed for their actual instructions later on.
|
||||
// the node reached from `from_node` via `via_eid`. The resulting candidates have to be analysed
|
||||
// for their actual instructions later on.
|
||||
// The switch for `use_low_precision_angles` enables a faster mode that will procude less
|
||||
// accurate coordinates. It should be good enough to check order of turns, find striaghtmost
|
||||
// turns. Even good enough to do some simple angle verifications. It is mostly available to
|
||||
// allow for faster graph traversal in the extraction phase.
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
Intersection GetConnectedRoads(const NodeID from_node, const EdgeID via_eid) const;
|
||||
IntersectionView GetConnectedRoads(const NodeID from_node,
|
||||
const EdgeID via_eid,
|
||||
const bool use_low_precision_angles = false) const;
|
||||
|
||||
/*
|
||||
* To be used in the road network, we need to check for valid/restricted turns. These two
|
||||
* functions transform a basic intersection / a normalised intersection into the
|
||||
* correct view when entering via a given edge.
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
IntersectionView
|
||||
TransformIntersectionShapeIntoView(const NodeID previous_node,
|
||||
const EdgeID entering_via_edge,
|
||||
const IntersectionShape &intersection) const;
|
||||
// version for normalised intersection
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
IntersectionView TransformIntersectionShapeIntoView(
|
||||
const NodeID previous_node,
|
||||
const EdgeID entering_via_edge,
|
||||
const IntersectionShape &normalised_intersection,
|
||||
const IntersectionShape &intersection,
|
||||
const std::vector<std::pair<EdgeID, EdgeID>> &merging_map) const;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const RestrictionMap &restriction_map;
|
||||
const std::unordered_set<NodeID> &barrier_nodes;
|
||||
const std::vector<QueryNode> &node_info_list;
|
||||
|
||||
// own state, used to find the correct coordinates along a road
|
||||
const CoordinateExtractor coordinate_extractor;
|
||||
const util::NameTable &name_table;
|
||||
const SuffixTable &street_name_suffix_table;
|
||||
|
||||
// check if two indices in an intersection can be seen as a single road in the perceived
|
||||
// intersection representation. See below for an example. Utility function for
|
||||
// MergeSegregatedRoads
|
||||
bool CanMerge(const NodeID intersection_node,
|
||||
const Intersection &intersection,
|
||||
std::size_t first_index,
|
||||
std::size_t second_index) const;
|
||||
|
||||
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
|
||||
// one.
|
||||
// This function combines roads the following way:
|
||||
//
|
||||
// * *
|
||||
// * is converted to *
|
||||
// v ^ +
|
||||
// v ^ +
|
||||
//
|
||||
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
|
||||
// 160
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
Intersection MergeSegregatedRoads(const NodeID intersection_node,
|
||||
Intersection intersection) const;
|
||||
|
||||
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
|
||||
// intersection itself, it can also happen that intersections are connected to joining roads.
|
||||
//
|
||||
// * *
|
||||
// * is converted to *
|
||||
// v a --- a ---
|
||||
// v ^ +
|
||||
// v ^ +
|
||||
// b
|
||||
//
|
||||
// for the local view of b at a.
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
Intersection AdjustForJoiningRoads(const NodeID node_at_intersection,
|
||||
Intersection intersection) const;
|
||||
// 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
|
||||
|
||||
@@ -3,15 +3,22 @@
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/guidance/node_based_graph_walker.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/guidance/name_announcements.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -48,9 +55,7 @@ class IntersectionHandler
|
||||
const util::NameTable &name_table;
|
||||
const SuffixTable &street_name_suffix_table;
|
||||
const IntersectionGenerator &intersection_generator;
|
||||
|
||||
// counts the number on allowed entry roads
|
||||
std::size_t countValid(const Intersection &intersection) const;
|
||||
const NodeBasedGraphWalker graph_walker; // for skipping traffic signal, distances etc.
|
||||
|
||||
// Decide on a basic turn types
|
||||
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
|
||||
@@ -59,7 +64,8 @@ class IntersectionHandler
|
||||
// determining whether there is a road that can be seen as obvious turn in the presence of many
|
||||
// other possible turns. The function will consider road categories and other inputs like the
|
||||
// turn angles.
|
||||
std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
|
||||
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||
std::size_t findObviousTurn(const EdgeID via_edge, const IntersectionType &intersection) const;
|
||||
|
||||
// Obvious turns can still take multiple forms. This function looks at the turn onto a road
|
||||
// candidate when coming from a via_edge and determines the best instruction to emit.
|
||||
@@ -83,9 +89,458 @@ class IntersectionHandler
|
||||
const std::size_t begin,
|
||||
const std::size_t end) const;
|
||||
|
||||
// Checks the intersection for a through street connected to `intersection[index]`
|
||||
bool isThroughStreet(const std::size_t index, const Intersection &intersection) const;
|
||||
|
||||
// See `getNextIntersection`
|
||||
struct IntersectionViewAndNode final
|
||||
{
|
||||
IntersectionView intersection; // < actual intersection
|
||||
NodeID node; // < node at this intersection
|
||||
};
|
||||
|
||||
// Skips over artificial intersections i.e. traffic lights, barriers etc.
|
||||
// Returns the next non-artificial intersection and its node in the node based
|
||||
// graph if an intersection could be found or none otherwise.
|
||||
//
|
||||
// a ... tl ... b .. c
|
||||
// .
|
||||
// .
|
||||
// d
|
||||
//
|
||||
// ^ at
|
||||
// ^ via
|
||||
//
|
||||
// For this scenario returns intersection at `b` and `b`.
|
||||
boost::optional<IntersectionHandler::IntersectionViewAndNode>
|
||||
getNextIntersection(const NodeID at, const EdgeID via) const;
|
||||
};
|
||||
|
||||
// Impl.
|
||||
|
||||
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||
std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
const IntersectionType &intersection) const
|
||||
{
|
||||
using Road = typename IntersectionType::value_type;
|
||||
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
|
||||
using osrm::util::angularDeviation;
|
||||
|
||||
// no obvious road
|
||||
if (intersection.size() == 1)
|
||||
return 0;
|
||||
|
||||
// a single non u-turn is obvious
|
||||
if (intersection.size() == 2)
|
||||
return 1;
|
||||
|
||||
const EdgeData &in_way_data = node_based_graph.GetEdgeData(via_edge);
|
||||
|
||||
// the strategy for picking the most obvious turn involves deciding between
|
||||
// an overall best candidate and a best candidate that shares the same name
|
||||
// as the in road, i.e. a continue road
|
||||
std::size_t best_option = 0;
|
||||
double best_option_deviation = 180;
|
||||
std::size_t best_continue = 0;
|
||||
double best_continue_deviation = 180;
|
||||
|
||||
/* helper functions */
|
||||
const auto IsContinueRoad = [&](const EdgeData &way_data) {
|
||||
return !util::guidance::requiresNameAnnounced(
|
||||
in_way_data.name_id, way_data.name_id, name_table, street_name_suffix_table);
|
||||
};
|
||||
auto sameOrHigherPriority = [&in_way_data](const auto &way_data) {
|
||||
return way_data.road_classification.GetPriority() <=
|
||||
in_way_data.road_classification.GetPriority();
|
||||
};
|
||||
auto IsLowPriority = [](const auto &way_data) {
|
||||
return way_data.road_classification.IsLowPriorityRoadClass();
|
||||
};
|
||||
// These two Compare functions are used for sifting out best option and continue
|
||||
// candidates by evaluating all the ways in an intersection by what they share
|
||||
// with the in way. Ideal candidates are of similar road class with the in way
|
||||
// and are require relatively straight turns.
|
||||
const auto RoadCompare = [&](const auto &lhs, const auto &rhs) {
|
||||
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto lhs_deviation = angularDeviation(lhs.angle, STRAIGHT_ANGLE);
|
||||
const auto rhs_deviation = angularDeviation(rhs.angle, STRAIGHT_ANGLE);
|
||||
|
||||
const bool rhs_same_classification =
|
||||
rhs_data.road_classification == in_way_data.road_classification;
|
||||
const bool lhs_same_classification =
|
||||
lhs_data.road_classification == in_way_data.road_classification;
|
||||
const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_data);
|
||||
const bool rhs_low_priority = IsLowPriority(rhs_data);
|
||||
const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_data);
|
||||
const bool lhs_low_priority = IsLowPriority(lhs_data);
|
||||
auto left_tie = std::tie(lhs.entry_allowed,
|
||||
lhs_same_or_higher_priority,
|
||||
rhs_low_priority,
|
||||
rhs_deviation,
|
||||
lhs_same_classification);
|
||||
auto right_tie = std::tie(rhs.entry_allowed,
|
||||
rhs_same_or_higher_priority,
|
||||
lhs_low_priority,
|
||||
lhs_deviation,
|
||||
rhs_same_classification);
|
||||
return left_tie > right_tie;
|
||||
};
|
||||
const auto RoadCompareSameName = [&](const auto &lhs, const auto &rhs) {
|
||||
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto lhs_continues = IsContinueRoad(lhs_data);
|
||||
const auto rhs_continues = IsContinueRoad(rhs_data);
|
||||
const auto left_tie = std::tie(lhs.entry_allowed, lhs_continues);
|
||||
const auto right_tie = std::tie(rhs.entry_allowed, rhs_continues);
|
||||
return left_tie > right_tie || (left_tie == right_tie && RoadCompare(lhs, rhs));
|
||||
};
|
||||
|
||||
auto best_option_it = std::min_element(begin(intersection), end(intersection), RoadCompare);
|
||||
|
||||
// min element should only return end() when vector is empty
|
||||
BOOST_ASSERT(best_option_it != end(intersection));
|
||||
|
||||
best_option = std::distance(begin(intersection), best_option_it);
|
||||
best_option_deviation = angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
|
||||
const auto &best_option_data = node_based_graph.GetEdgeData(intersection[best_option].eid);
|
||||
|
||||
// Unless the in way is also low priority, it is generally undesirable to
|
||||
// indicate that a low priority road is obvious
|
||||
if (IsLowPriority(best_option_data) &&
|
||||
best_option_data.road_classification != in_way_data.road_classification)
|
||||
{
|
||||
best_option = 0;
|
||||
best_option_deviation = 180;
|
||||
}
|
||||
|
||||
// double check if the way with the lowest deviation from straight is still be better choice
|
||||
const auto straightest = intersection.findClosestTurn(STRAIGHT_ANGLE);
|
||||
if (straightest != best_option_it)
|
||||
{
|
||||
const EdgeData &straightest_data = node_based_graph.GetEdgeData(straightest->eid);
|
||||
double straightest_data_deviation = angularDeviation(straightest->angle, STRAIGHT_ANGLE);
|
||||
const auto deviation_diff =
|
||||
std::abs(best_option_deviation - straightest_data_deviation) > FUZZY_ANGLE_DIFFERENCE;
|
||||
const auto not_ramp_class = !straightest_data.road_classification.IsRampClass();
|
||||
const auto not_link_class = !straightest_data.road_classification.IsLinkClass();
|
||||
if (deviation_diff && !IsLowPriority(straightest_data) && not_ramp_class &&
|
||||
not_link_class && !IsContinueRoad(best_option_data))
|
||||
{
|
||||
best_option = std::distance(begin(intersection), straightest);
|
||||
best_option_deviation =
|
||||
angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
|
||||
}
|
||||
}
|
||||
|
||||
// No non-low priority roads? Declare no obvious turn
|
||||
if (best_option == 0)
|
||||
return 0;
|
||||
|
||||
auto best_continue_it =
|
||||
std::min_element(begin(intersection), end(intersection), RoadCompareSameName);
|
||||
const auto best_continue_data = node_based_graph.GetEdgeData(best_continue_it->eid);
|
||||
if (IsContinueRoad(best_continue_data) ||
|
||||
(in_way_data.name_id == EMPTY_NAMEID && best_continue_data.name_id == EMPTY_NAMEID))
|
||||
{
|
||||
best_continue = std::distance(begin(intersection), best_continue_it);
|
||||
best_continue_deviation =
|
||||
angularDeviation(intersection[best_continue].angle, STRAIGHT_ANGLE);
|
||||
}
|
||||
|
||||
// if the best angle is going straight but the road is turning, declare no obvious turn
|
||||
if (0 != best_continue && best_option != best_continue &&
|
||||
best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
||||
node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification ==
|
||||
best_option_data.road_classification)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get a count of number of ways from that intersection that qualify to have
|
||||
// continue instruction because they share a name with the approaching way
|
||||
const std::int64_t continue_count =
|
||||
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
|
||||
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid));
|
||||
});
|
||||
const std::int64_t continue_count_valid =
|
||||
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
|
||||
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid)) && way.entry_allowed;
|
||||
});
|
||||
|
||||
// checks if continue candidates are sharp turns
|
||||
const bool all_continues_are_narrow = [&]() {
|
||||
return std::count_if(begin(intersection), end(intersection), [&](const Road &road) {
|
||||
const EdgeData &road_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const double &road_angle = angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||
return IsContinueRoad(road_data) && (road_angle < NARROW_TURN_ANGLE);
|
||||
}) == continue_count;
|
||||
}();
|
||||
|
||||
// return true if the best_option candidate is more promising than the best_continue candidate
|
||||
// otherwise return false, the best_continue candidate is more promising
|
||||
const auto best_over_best_continue = [&]() {
|
||||
// no continue road exists
|
||||
if (best_continue == 0)
|
||||
return true;
|
||||
|
||||
// we have multiple continues and not all are narrow. This suggests that
|
||||
// the continue candidates are ambiguous
|
||||
if (!all_continues_are_narrow && (continue_count >= 2 && intersection.size() >= 4))
|
||||
return true;
|
||||
|
||||
// if the best continue is not narrow and we also have at least 2 possible choices, the
|
||||
// intersection size does not matter anymore
|
||||
if (continue_count_valid >= 2 && best_continue_deviation >= 2 * NARROW_TURN_ANGLE)
|
||||
return true;
|
||||
|
||||
// continue data now most certainly exists
|
||||
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
|
||||
|
||||
// best_continue is obvious by road class
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
continue_data.road_classification,
|
||||
best_option_data.road_classification))
|
||||
return false;
|
||||
|
||||
// best_option is obvious by road class
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
continue_data.road_classification))
|
||||
return true;
|
||||
|
||||
// the best_option deviation is very straight and not a ramp
|
||||
if (best_option_deviation < best_continue_deviation &&
|
||||
best_option_deviation < FUZZY_ANGLE_DIFFERENCE &&
|
||||
!best_option_data.road_classification.IsRampClass())
|
||||
return true;
|
||||
|
||||
// the continue road is of a lower priority, while the road continues on the same priority
|
||||
// with a better angle
|
||||
if (best_option_deviation < best_continue_deviation &&
|
||||
in_way_data.road_classification == best_option_data.road_classification &&
|
||||
continue_data.road_classification.GetPriority() >
|
||||
best_option_data.road_classification.GetPriority())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (best_over_best_continue)
|
||||
{
|
||||
// Find left/right deviation
|
||||
// skipping over service roads
|
||||
const std::size_t left_index = [&]() {
|
||||
const auto index_candidate = (best_option + 1) % intersection.size();
|
||||
if (index_candidate == 0)
|
||||
return index_candidate;
|
||||
const auto &candidate_data =
|
||||
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
candidate_data.road_classification))
|
||||
return (index_candidate + 1) % intersection.size();
|
||||
else
|
||||
return index_candidate;
|
||||
|
||||
}();
|
||||
const auto right_index = [&]() {
|
||||
BOOST_ASSERT(best_option > 0);
|
||||
const auto index_candidate = best_option - 1;
|
||||
if (index_candidate == 0)
|
||||
return index_candidate;
|
||||
const auto candidate_data =
|
||||
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
candidate_data.road_classification))
|
||||
return index_candidate - 1;
|
||||
else
|
||||
return index_candidate;
|
||||
}();
|
||||
|
||||
const double left_deviation =
|
||||
angularDeviation(intersection[left_index].angle, STRAIGHT_ANGLE);
|
||||
const double right_deviation =
|
||||
angularDeviation(intersection[right_index].angle, STRAIGHT_ANGLE);
|
||||
|
||||
// return best_option candidate if it is nearly straight and distinct from the nearest other
|
||||
// out
|
||||
// way
|
||||
if (best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
||||
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
|
||||
return best_option;
|
||||
|
||||
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid);
|
||||
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid);
|
||||
|
||||
const bool obvious_to_left =
|
||||
left_index == 0 || obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
left_data.road_classification);
|
||||
const bool obvious_to_right =
|
||||
right_index == 0 || obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
right_data.road_classification);
|
||||
|
||||
// if the best_option turn isn't narrow, but there is a nearly straight turn, we don't
|
||||
// consider the
|
||||
// turn obvious
|
||||
const auto check_narrow = [&intersection, best_option_deviation](const std::size_t index) {
|
||||
return angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) <=
|
||||
FUZZY_ANGLE_DIFFERENCE &&
|
||||
(best_option_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed);
|
||||
};
|
||||
|
||||
// other narrow turns?
|
||||
if (check_narrow(right_index) && !obvious_to_right)
|
||||
return 0;
|
||||
|
||||
if (check_narrow(left_index) && !obvious_to_left)
|
||||
return 0;
|
||||
|
||||
// checks if a given way in the intersection is distinct enough from the best_option
|
||||
// candidate
|
||||
const auto isDistinct = [&](const std::size_t index, const double deviation) {
|
||||
/*
|
||||
If the neighbor is not possible to enter, we allow for a lower
|
||||
distinction rate. If the road category is smaller, its also adjusted. Only
|
||||
roads of the same priority require the full distinction ratio.
|
||||
*/
|
||||
const auto &best_option_data =
|
||||
node_based_graph.GetEdgeData(intersection[best_option].eid);
|
||||
const auto adjusted_distinction_ratio = [&]() {
|
||||
// not allowed competitors are easily distinct
|
||||
if (!intersection[index].entry_allowed)
|
||||
return 0.7 * DISTINCTION_RATIO;
|
||||
// a bit less obvious are road classes
|
||||
else if (in_way_data.road_classification == best_option_data.road_classification &&
|
||||
best_option_data.road_classification.GetPriority() <
|
||||
node_based_graph.GetEdgeData(intersection[index].eid)
|
||||
.road_classification.GetPriority())
|
||||
return 0.8 * DISTINCTION_RATIO;
|
||||
// if road classes are the same, we use the full ratio
|
||||
else
|
||||
return DISTINCTION_RATIO;
|
||||
}();
|
||||
return index == 0 || deviation / best_option_deviation >= adjusted_distinction_ratio ||
|
||||
(deviation <= NARROW_TURN_ANGLE && !intersection[index].entry_allowed);
|
||||
};
|
||||
|
||||
const bool distinct_to_left = isDistinct(left_index, left_deviation);
|
||||
const bool distinct_to_right = isDistinct(right_index, right_deviation);
|
||||
// Well distinct turn that is nearly straight
|
||||
if ((distinct_to_left || obvious_to_left) && (distinct_to_right || obvious_to_right))
|
||||
return best_option;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
|
||||
if (std::abs(best_continue_deviation) < 1)
|
||||
return best_continue;
|
||||
|
||||
// check if any other similar best continues exist
|
||||
std::size_t i, last = intersection.size();
|
||||
for (i = 1; i < last; ++i)
|
||||
{
|
||||
if (i == best_continue || !intersection[i].entry_allowed)
|
||||
continue;
|
||||
|
||||
const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid);
|
||||
const bool is_obvious_by_road_class =
|
||||
obviousByRoadClass(in_way_data.road_classification,
|
||||
continue_data.road_classification,
|
||||
turn_data.road_classification);
|
||||
|
||||
// if the main road is obvious by class, we ignore the current road as a potential
|
||||
// prevention of obviousness
|
||||
if (is_obvious_by_road_class)
|
||||
continue;
|
||||
|
||||
// continuation could be grouped with a straight turn and the turning road is a ramp
|
||||
if (turn_data.road_classification.IsRampClass() &&
|
||||
best_continue_deviation < GROUP_ANGLE &&
|
||||
!continue_data.road_classification.IsRampClass())
|
||||
continue;
|
||||
|
||||
// perfectly straight turns prevent obviousness
|
||||
const auto turn_deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
|
||||
if (turn_deviation < FUZZY_ANGLE_DIFFERENCE)
|
||||
return 0;
|
||||
|
||||
const auto deviation_ratio = turn_deviation / best_continue_deviation;
|
||||
|
||||
// in comparison to normal deviations, a continue road can offer a smaller distinction
|
||||
// ratio. Other roads close to the turn angle are not as obvious, if one road continues.
|
||||
if (deviation_ratio < DISTINCTION_RATIO / 1.5)
|
||||
return 0;
|
||||
|
||||
/* in comparison to another continuing road, we need a better distinction. This prevents
|
||||
situations where the turn is probably less obvious. An example are places that have a
|
||||
road with the same name entering/exiting:
|
||||
|
||||
d
|
||||
/
|
||||
/
|
||||
a -- b
|
||||
\
|
||||
\
|
||||
c
|
||||
*/
|
||||
|
||||
const auto same_name = !util::guidance::requiresNameAnnounced(
|
||||
turn_data.name_id, continue_data.name_id, name_table, street_name_suffix_table);
|
||||
|
||||
if (same_name && deviation_ratio < 1.5 * DISTINCTION_RATIO)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Segregated intersections can result in us finding an obvious turn, even though its only
|
||||
// obvious due to a very short segment in between. So if the segment coming in is very
|
||||
// short, we check the previous intersection for other continues in the opposite bearing.
|
||||
const auto node_at_intersection = node_based_graph.GetTarget(via_edge);
|
||||
|
||||
const double constexpr MAX_COLLAPSE_DISTANCE = 30;
|
||||
const auto distance_at_u_turn = intersection[0].segment_length;
|
||||
if (distance_at_u_turn < MAX_COLLAPSE_DISTANCE)
|
||||
{
|
||||
// this request here actually goes against the direction of the ingoing edgeid. This can
|
||||
// even reverse the direction. Since we don't want to compute actual turns but simply
|
||||
// try to find whether there is a turn going to the opposite direction of our obvious
|
||||
// turn, this should be alright.
|
||||
NodeID new_node;
|
||||
const auto previous_intersection = [&]() {
|
||||
EdgeID turn_edge;
|
||||
std::tie(new_node, turn_edge) = intersection_generator.SkipDegreeTwoNodes(
|
||||
node_at_intersection, intersection[0].eid);
|
||||
return intersection_generator.GetConnectedRoads(new_node, turn_edge);
|
||||
}();
|
||||
|
||||
if (new_node != node_at_intersection)
|
||||
{
|
||||
const auto continue_road = intersection[best_continue];
|
||||
for (const auto &comparison_road : previous_intersection)
|
||||
{
|
||||
// since we look at the intersection in the wrong direction, a similar angle
|
||||
// actually represents a near 180 degree different in bearings between the two
|
||||
// roads. So if there is a road that is enterable in the opposite direction just
|
||||
// prior, a turn is not obvious
|
||||
const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.eid);
|
||||
if (angularDeviation(comparison_road.angle, STRAIGHT_ANGLE) > GROUP_ANGLE &&
|
||||
angularDeviation(comparison_road.angle, continue_road.angle) <
|
||||
FUZZY_ANGLE_DIFFERENCE &&
|
||||
!turn_data.reversed && continue_data.CanCombineWith(turn_data))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best_continue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
|
||||
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
|
||||
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "extractor/suffix_table.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
/*
|
||||
* An intersection is a central part in computing guidance decisions. However the model in OSM and
|
||||
* the view we want to use in guidance are not necessarily the same thing. We have to account for
|
||||
* some models that are chosen explicitly in OSM and that don't actually describe how a human would
|
||||
* experience an intersection.
|
||||
*
|
||||
* For example, if a small pedestrian island is located at a traffic light right in the middle of a
|
||||
* road, OSM tends to model the road as two separate ways. A human would consider these two ways a
|
||||
* single road, though. In this normalizer, we try to account for these subtle differences between
|
||||
* OSM data and human perception to improve our decision base for guidance later on.
|
||||
*/
|
||||
class IntersectionNormalizer
|
||||
{
|
||||
public:
|
||||
IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const std::vector<extractor::QueryNode> &node_coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const IntersectionGenerator &intersection_generator);
|
||||
|
||||
// The function takes an intersection an converts it to a `perceived` intersection which closer
|
||||
// represents how a human might experience the intersection
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::pair<IntersectionShape, std::vector<std::pair<EdgeID, EdgeID>>>
|
||||
operator()(const NodeID node_at_intersection, IntersectionShape intersection) const;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const std::vector<extractor::QueryNode> &node_coordinates;
|
||||
const util::NameTable &name_table;
|
||||
const SuffixTable &street_name_suffix_table;
|
||||
|
||||
const IntersectionGenerator &intersection_generator;
|
||||
|
||||
/* check if two indices in an intersection can be seen as a single road in the perceived
|
||||
* intersection representation. See below for an example. Utility function for
|
||||
* MergeSegregatedRoads. It also checks for neighboring merges.
|
||||
* This is due possible segments where multiple roads could end up being merged into one.
|
||||
* We only support merging two roads, not three or more, though.
|
||||
* c c
|
||||
* / /
|
||||
* a - b -> a - b - (c,d) but not a - b d -> a,b,(cde)
|
||||
* \ \
|
||||
* d e
|
||||
*/
|
||||
bool CanMerge(const NodeID intersection_node,
|
||||
const IntersectionShape &intersection,
|
||||
std::size_t first_index,
|
||||
std::size_t second_index) const;
|
||||
|
||||
// A tool called by CanMerge. It checks whether two indices can be merged, not concerned without
|
||||
// remaining parts of the intersection.
|
||||
bool InnerCanMerge(const NodeID intersection_node,
|
||||
const IntersectionShape &intersection,
|
||||
std::size_t first_index,
|
||||
std::size_t second_index) const;
|
||||
|
||||
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
|
||||
// one.
|
||||
// This function combines roads the following way:
|
||||
//
|
||||
// * *
|
||||
// * is converted to *
|
||||
// v ^ +
|
||||
// v ^ +
|
||||
//
|
||||
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
|
||||
// 160
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::pair<IntersectionShape, std::vector<std::pair<EdgeID, EdgeID>>>
|
||||
MergeSegregatedRoads(const NodeID intersection_node, IntersectionShape intersection) const;
|
||||
|
||||
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
|
||||
// intersection itself, it can also happen that intersections are connected to joining roads.
|
||||
//
|
||||
// * *
|
||||
// * is converted to *
|
||||
// v a --- a ---
|
||||
// v ^ +
|
||||
// v ^ +
|
||||
// b
|
||||
//
|
||||
// for the local view of b at a.
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
IntersectionShape AdjustBearingsForMergeAtDestination(const NodeID node_at_intersection,
|
||||
IntersectionShape intersection) const;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_ */
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_SCENARIO_THREE_WAY_HPP_
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_SCENARIO_THREE_WAY_HPP_
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Ending in a T-Intersection
|
||||
bool isEndOfRoad(const ConnectedRoad &uturn,
|
||||
const ConnectedRoad &possible_right_turn,
|
||||
const ConnectedRoad &possible_left_turn);
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif /*OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_SCENARIO_THREE_WAY_HPP_*/
|
||||
@@ -3,9 +3,8 @@
|
||||
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
@@ -21,9 +20,6 @@ namespace extractor
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// forward declaration to allow interaction between the intersection generator and the graph hopper
|
||||
class IntersectionGenerator;
|
||||
|
||||
/*
|
||||
* The graph hopper is a utility that lets you find certain intersections with a node based graph,
|
||||
* accumulating information along the way
|
||||
@@ -46,7 +42,7 @@ class NodeBasedGraphWalker
|
||||
boost::optional<std::pair<NodeID, EdgeID>> TraverseRoad(NodeID starting_at_node_id,
|
||||
EdgeID following_edge_id,
|
||||
accumulator_type &accumulator,
|
||||
const selector_type &selector);
|
||||
const selector_type &selector) const;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
@@ -90,7 +86,8 @@ struct LengthLimitedCoordinateAccumulator
|
||||
};
|
||||
|
||||
/*
|
||||
* The SelectRoadByNameOnlyChoiceAndStraightness tries to follow a given name along a route. We offer methods to skip
|
||||
* The SelectRoadByNameOnlyChoiceAndStraightness tries to follow a given name along a route. We
|
||||
* offer methods to skip
|
||||
* over bridges/similar situations if desired, following narrow turns
|
||||
* This struct offers an example implementation of a possible road selector for traversing the
|
||||
* node-based graph using the NodeBasedGraphWalker
|
||||
@@ -118,14 +115,13 @@ struct SelectRoadByNameOnlyChoiceAndStraightness
|
||||
// find the next intersection given a hop limit
|
||||
struct IntersectionFinderAccumulator
|
||||
{
|
||||
IntersectionFinderAccumulator(const std::uint8_t hop_limit, const IntersectionGenerator &intersection_generator);
|
||||
IntersectionFinderAccumulator(const std::uint8_t hop_limit,
|
||||
const IntersectionGenerator &intersection_generator);
|
||||
// true if the path has traversed enough distance
|
||||
bool terminate();
|
||||
|
||||
// update the accumulator
|
||||
void update(const NodeID from_node,
|
||||
const EdgeID via_edge,
|
||||
const NodeID to_node);
|
||||
void update(const NodeID from_node, const EdgeID via_edge, const NodeID to_node);
|
||||
|
||||
std::uint8_t hops;
|
||||
const std::uint8_t hop_limit;
|
||||
@@ -136,17 +132,15 @@ struct IntersectionFinderAccumulator
|
||||
// the result we are looking for
|
||||
NodeID nid;
|
||||
EdgeID via_edge_id;
|
||||
Intersection intersection;
|
||||
IntersectionView intersection;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <class accumulator_type, class selector_type>
|
||||
boost::optional<std::pair<NodeID, EdgeID>>
|
||||
NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
|
||||
EdgeID current_edge_id,
|
||||
accumulator_type &accumulator,
|
||||
const selector_type &selector)
|
||||
const selector_type &selector) const
|
||||
{
|
||||
/*
|
||||
* since graph hopping is used in many ways, we don't generate an adjusted intersection
|
||||
@@ -197,6 +191,60 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
|
||||
return {};
|
||||
}
|
||||
|
||||
struct SkipTrafficSignalBarrierRoadSelector
|
||||
{
|
||||
boost::optional<EdgeID> operator()(const NodeID,
|
||||
const EdgeID,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &) const
|
||||
{
|
||||
if (intersection.isTrafficSignalOrBarrier())
|
||||
{
|
||||
return boost::make_optional(intersection[1].eid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DistanceToNextIntersectionAccumulator
|
||||
{
|
||||
DistanceToNextIntersectionAccumulator(
|
||||
const extractor::guidance::CoordinateExtractor &extractor_,
|
||||
const util::NodeBasedDynamicGraph &graph_,
|
||||
const double threshold)
|
||||
: extractor{extractor_}, graph{graph_}, threshold{threshold}
|
||||
{
|
||||
}
|
||||
|
||||
bool terminate()
|
||||
{
|
||||
if (distance > threshold)
|
||||
{
|
||||
too_far_away = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void update(const NodeID start, const EdgeID onto, const NodeID)
|
||||
{
|
||||
using namespace util::coordinate_calculation;
|
||||
|
||||
const auto coords = extractor.GetForwardCoordinatesAlongRoad(start, onto);
|
||||
distance += getLength(coords, &haversineDistance);
|
||||
}
|
||||
|
||||
const extractor::guidance::CoordinateExtractor &extractor;
|
||||
const util::NodeBasedDynamicGraph &graph;
|
||||
const double threshold;
|
||||
bool too_far_away = false;
|
||||
double distance = 0.;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
#ifndef OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
|
||||
#define OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// Public service vehicle lanes and similar can introduce additional lanes into the lane string that
|
||||
// are not specifically marked for left/right turns. This function can be used from the profile to
|
||||
// trim the lane string appropriately
|
||||
//
|
||||
// left|throught|
|
||||
// in combination with lanes:psv:forward=1
|
||||
// will be corrected to left|throught, since the final lane is not drivable.
|
||||
// This is in contrast to a situation with lanes:psv:forward=0 (or not set) where left|through|
|
||||
// represents left|through|through
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string
|
||||
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
|
||||
{
|
||||
if (count_left)
|
||||
{
|
||||
bool sane = count_left < static_cast<std::int32_t>(lane_string.size());
|
||||
for (std::int32_t i = 0; i < count_left; ++i)
|
||||
// this is adjusted for our fake pipe. The moment cucumber can handle multiple escaped
|
||||
// pipes, the '&' part can be removed
|
||||
if (lane_string[i] != '|')
|
||||
{
|
||||
sane = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sane)
|
||||
{
|
||||
lane_string.erase(lane_string.begin(), lane_string.begin() + count_left);
|
||||
}
|
||||
}
|
||||
if (count_right)
|
||||
{
|
||||
bool sane = count_right < static_cast<std::int32_t>(lane_string.size());
|
||||
for (auto itr = lane_string.rbegin();
|
||||
itr != lane_string.rend() && itr != lane_string.rbegin() + count_right;
|
||||
++itr)
|
||||
{
|
||||
if (*itr != '|')
|
||||
{
|
||||
sane = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sane)
|
||||
lane_string.resize(lane_string.size() - count_right);
|
||||
}
|
||||
return lane_string;
|
||||
}
|
||||
|
||||
// https://github.com/Project-OSRM/osrm-backend/issues/2638
|
||||
// It can happen that some lanes are not drivable by car. Here we handle this tagging scheme
|
||||
// (vehicle:lanes) to filter out not-allowed roads
|
||||
// lanes=3
|
||||
// turn:lanes=left|through|through|right
|
||||
// vehicle:lanes=yes|yes|no|yes
|
||||
// bicycle:lanes=yes|no|designated|yes
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
|
||||
{
|
||||
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
|
||||
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
|
||||
tokenizer tokens(lane_string, sep);
|
||||
tokenizer access(access_tokens, sep);
|
||||
|
||||
// strings don't match, don't do anything
|
||||
if (std::distance(std::begin(tokens), std::end(tokens)) !=
|
||||
std::distance(std::begin(access), std::end(access)))
|
||||
return lane_string;
|
||||
|
||||
std::string result_string = "";
|
||||
const static std::string yes = "yes";
|
||||
|
||||
for (auto token_itr = std::begin(tokens), access_itr = std::begin(access);
|
||||
token_itr != std::end(tokens);
|
||||
++token_itr, ++access_itr)
|
||||
{
|
||||
if (*access_itr == yes)
|
||||
{
|
||||
// we have to add this in front, because the next token could be invalid. Doing this on
|
||||
// non-empty strings makes sure that the token string will be valid in the end
|
||||
if (!result_string.empty())
|
||||
result_string += '|';
|
||||
|
||||
result_string += *token_itr;
|
||||
}
|
||||
}
|
||||
return result_string;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_GUIDANCE_PARSING_TOOLKIT_HPP_
|
||||
@@ -4,9 +4,8 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <osmium/osm.hpp>
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -65,7 +64,7 @@ class RoadClassification
|
||||
public:
|
||||
// default construction
|
||||
RoadClassification()
|
||||
: motorway_class(0), link_class(0), may_be_ignored(1),
|
||||
: motorway_class(0), link_class(0), may_be_ignored(0),
|
||||
road_priority_class(RoadPriorityClass::CONNECTIVITY), number_of_lanes(0)
|
||||
{
|
||||
}
|
||||
@@ -126,6 +125,22 @@ inline bool canBeSeenAsFork(const RoadClassification first, const RoadClassifica
|
||||
return std::abs(static_cast<int>(first.GetPriority()) -
|
||||
static_cast<int>(second.GetPriority())) <= 1;
|
||||
}
|
||||
|
||||
inline bool obviousByRoadClass(const RoadClassification in_classification,
|
||||
const RoadClassification obvious_candidate,
|
||||
const RoadClassification compare_candidate)
|
||||
{
|
||||
// lower numbers are of higher priority
|
||||
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
|
||||
compare_candidate.GetPriority();
|
||||
|
||||
const bool continues_on_same_class = in_classification == obvious_candidate;
|
||||
return (has_high_priority && continues_on_same_class) ||
|
||||
(!obvious_candidate.IsLowPriorityRoadClass() &&
|
||||
!in_classification.IsLowPriorityRoadClass() &&
|
||||
compare_candidate.IsLowPriorityRoadClass());
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -22,7 +22,7 @@ namespace guidance
|
||||
|
||||
// Intersection handlers deal with all issues related to intersections.
|
||||
// They assign appropriate turn operations to the TurnOperations.
|
||||
class SliproadHandler : public IntersectionHandler
|
||||
class SliproadHandler final : public IntersectionHandler
|
||||
{
|
||||
public:
|
||||
SliproadHandler(const IntersectionGenerator &intersection_generator,
|
||||
@@ -42,6 +42,37 @@ class SliproadHandler : public IntersectionHandler
|
||||
Intersection operator()(const NodeID nid,
|
||||
const EdgeID via_eid,
|
||||
Intersection intersection) const override final;
|
||||
|
||||
private:
|
||||
boost::optional<std::size_t> getObviousIndexWithSliproads(const EdgeID from,
|
||||
const Intersection &intersection,
|
||||
const NodeID at) const;
|
||||
|
||||
// Next intersection from `start` onto `onto` is too far away for a Siproad scenario
|
||||
bool nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const;
|
||||
|
||||
// Through street: does a road continue with from's name at the intersection
|
||||
bool isThroughStreet(const EdgeID from, const IntersectionView &intersection) const;
|
||||
|
||||
// Does the road from `current` to `next` continue
|
||||
bool roadContinues(const EdgeID current, const EdgeID next) const;
|
||||
|
||||
// Is the area under the triangle a valid Sliproad triangle
|
||||
bool isValidSliproadArea(const double max_area, const NodeID, const NodeID, const NodeID) const;
|
||||
|
||||
// Is the Sliproad a link the both roads it shortcuts must not be links
|
||||
bool isValidSliproadLink(const IntersectionViewData &sliproad,
|
||||
const IntersectionViewData &first,
|
||||
const IntersectionViewData &second) const;
|
||||
|
||||
// Could a Sliproad reach this intersection?
|
||||
static bool canBeTargetOfSliproad(const IntersectionView &intersection);
|
||||
|
||||
// Scales a threshold based on the underlying road classification.
|
||||
// Example: a 100 m threshold for a highway if different on living streets.
|
||||
// The return value is guaranteed to not be larger than `threshold`.
|
||||
static double scaledThresholdByRoadClass(const double max_threshold,
|
||||
const RoadClassification &classification);
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
#ifndef OSRM_GUIDANCE_TOOLKIT_HPP_
|
||||
#define OSRM_GUIDANCE_TOOLKIT_HPP_
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/road_classification.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
using util::guidance::LaneTupleIdPair;
|
||||
using LaneDataIdMap = std::unordered_map<LaneTupleIdPair, LaneDataID, boost::hash<LaneTupleIdPair>>;
|
||||
|
||||
using util::guidance::angularDeviation;
|
||||
using util::guidance::entersRoundabout;
|
||||
using util::guidance::leavesRoundabout;
|
||||
|
||||
// To simplify handling of Left/Right hand turns, we can mirror turns and write an intersection
|
||||
// handler only for one side. The mirror function turns a left-hand turn in a equivalent right-hand
|
||||
// turn and vice versa.
|
||||
|
||||
inline bool hasRoundaboutType(const TurnInstruction instruction)
|
||||
{
|
||||
using namespace extractor::guidance::TurnType;
|
||||
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
|
||||
TurnType::EnterAndExitRoundabout,
|
||||
TurnType::EnterRotary,
|
||||
TurnType::EnterAndExitRotary,
|
||||
TurnType::EnterRoundaboutIntersection,
|
||||
TurnType::EnterAndExitRoundaboutIntersection,
|
||||
TurnType::EnterRoundaboutAtExit,
|
||||
TurnType::ExitRoundabout,
|
||||
TurnType::EnterRotaryAtExit,
|
||||
TurnType::ExitRotary,
|
||||
TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
TurnType::ExitRoundaboutIntersection,
|
||||
TurnType::StayOnRoundabout};
|
||||
|
||||
const auto *first = valid_types;
|
||||
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
|
||||
|
||||
return std::find(first, last, instruction.type) != last;
|
||||
}
|
||||
|
||||
// Public service vehicle lanes and similar can introduce additional lanes into the lane string that
|
||||
// are not specifically marked for left/right turns. This function can be used from the profile to
|
||||
// trim the lane string appropriately
|
||||
//
|
||||
// left|throught|
|
||||
// in combination with lanes:psv:forward=1
|
||||
// will be corrected to left|throught, since the final lane is not drivable.
|
||||
// This is in contrast to a situation with lanes:psv:forward=0 (or not set) where left|through|
|
||||
// represents left|through|through
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string
|
||||
trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t count_right)
|
||||
{
|
||||
if (count_left)
|
||||
{
|
||||
bool sane = count_left < static_cast<std::int32_t>(lane_string.size());
|
||||
for (std::int32_t i = 0; i < count_left; ++i)
|
||||
// this is adjusted for our fake pipe. The moment cucumber can handle multiple escaped
|
||||
// pipes, the '&' part can be removed
|
||||
if (lane_string[i] != '|')
|
||||
{
|
||||
sane = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sane)
|
||||
{
|
||||
lane_string.erase(lane_string.begin(), lane_string.begin() + count_left);
|
||||
}
|
||||
}
|
||||
if (count_right)
|
||||
{
|
||||
bool sane = count_right < static_cast<std::int32_t>(lane_string.size());
|
||||
for (auto itr = lane_string.rbegin();
|
||||
itr != lane_string.rend() && itr != lane_string.rbegin() + count_right;
|
||||
++itr)
|
||||
{
|
||||
if (*itr != '|')
|
||||
{
|
||||
sane = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sane)
|
||||
lane_string.resize(lane_string.size() - count_right);
|
||||
}
|
||||
return lane_string;
|
||||
}
|
||||
|
||||
// https://github.com/Project-OSRM/osrm-backend/issues/2638
|
||||
// It can happen that some lanes are not drivable by car. Here we handle this tagging scheme
|
||||
// (vehicle:lanes) to filter out not-allowed roads
|
||||
// lanes=3
|
||||
// turn:lanes=left|through|through|right
|
||||
// vehicle:lanes=yes|yes|no|yes
|
||||
// bicycle:lanes=yes|no|designated|yes
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
|
||||
{
|
||||
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
|
||||
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
|
||||
tokenizer tokens(lane_string, sep);
|
||||
tokenizer access(access_tokens, sep);
|
||||
|
||||
// strings don't match, don't do anything
|
||||
if (std::distance(std::begin(tokens), std::end(tokens)) !=
|
||||
std::distance(std::begin(access), std::end(access)))
|
||||
return lane_string;
|
||||
|
||||
std::string result_string = "";
|
||||
const static std::string yes = "yes";
|
||||
|
||||
for (auto token_itr = std::begin(tokens), access_itr = std::begin(access);
|
||||
token_itr != std::end(tokens);
|
||||
++token_itr, ++access_itr)
|
||||
{
|
||||
if (*access_itr == yes)
|
||||
{
|
||||
// we have to add this in front, because the next token could be invalid. Doing this on
|
||||
// non-empty strings makes sure that the token string will be valid in the end
|
||||
if (!result_string.empty())
|
||||
result_string += '|';
|
||||
|
||||
result_string += *token_itr;
|
||||
}
|
||||
}
|
||||
return result_string;
|
||||
}
|
||||
|
||||
inline bool obviousByRoadClass(const RoadClassification in_classification,
|
||||
const RoadClassification obvious_candidate,
|
||||
const RoadClassification compare_candidate)
|
||||
{
|
||||
const bool has_high_priority = PRIORITY_DISTINCTION_FACTOR * obvious_candidate.GetPriority() <
|
||||
compare_candidate.GetPriority();
|
||||
|
||||
const bool continues_on_same_class = in_classification == obvious_candidate;
|
||||
return (has_high_priority && continues_on_same_class) ||
|
||||
(!obvious_candidate.IsLowPriorityRoadClass() &&
|
||||
!in_classification.IsLowPriorityRoadClass() &&
|
||||
compare_candidate.IsLowPriorityRoadClass());
|
||||
}
|
||||
|
||||
/* We use the sum of least squares to calculate a linear regression through our
|
||||
* coordinates.
|
||||
* This regression gives a good idea of how the road can be perceived and corrects for
|
||||
* initial and final corrections
|
||||
*/
|
||||
inline std::pair<util::Coordinate, util::Coordinate>
|
||||
leastSquareRegression(const std::vector<util::Coordinate> &coordinates)
|
||||
{
|
||||
BOOST_ASSERT(coordinates.size() >= 2);
|
||||
double sum_lon = 0, sum_lat = 0, sum_lon_lat = 0, sum_lon_lon = 0;
|
||||
double min_lon = static_cast<double>(toFloating(coordinates.front().lon));
|
||||
double max_lon = static_cast<double>(toFloating(coordinates.front().lon));
|
||||
for (const auto coord : coordinates)
|
||||
{
|
||||
min_lon = std::min(min_lon, static_cast<double>(toFloating(coord.lon)));
|
||||
max_lon = std::max(max_lon, static_cast<double>(toFloating(coord.lon)));
|
||||
sum_lon += static_cast<double>(toFloating(coord.lon));
|
||||
sum_lon_lon +=
|
||||
static_cast<double>(toFloating(coord.lon)) * static_cast<double>(toFloating(coord.lon));
|
||||
sum_lat += static_cast<double>(toFloating(coord.lat));
|
||||
sum_lon_lat +=
|
||||
static_cast<double>(toFloating(coord.lon)) * static_cast<double>(toFloating(coord.lat));
|
||||
}
|
||||
|
||||
const auto dividend = coordinates.size() * sum_lon_lat - sum_lon * sum_lat;
|
||||
const auto divisor = coordinates.size() * sum_lon_lon - sum_lon * sum_lon;
|
||||
if (std::abs(divisor) < std::numeric_limits<double>::epsilon())
|
||||
return std::make_pair(coordinates.front(), coordinates.back());
|
||||
|
||||
// slope of the regression line
|
||||
const auto slope = dividend / divisor;
|
||||
const auto intercept = (sum_lat - slope * sum_lon) / coordinates.size();
|
||||
|
||||
const auto GetLatAtLon = [intercept,
|
||||
slope](const util::FloatLongitude longitude) -> util::FloatLatitude {
|
||||
return {intercept + slope * static_cast<double>((longitude))};
|
||||
};
|
||||
|
||||
const util::Coordinate regression_first = {
|
||||
toFixed(util::FloatLongitude{min_lon - 1}),
|
||||
toFixed(util::FloatLatitude(GetLatAtLon(util::FloatLongitude{min_lon - 1})))};
|
||||
const util::Coordinate regression_end = {
|
||||
toFixed(util::FloatLongitude{max_lon + 1}),
|
||||
toFixed(util::FloatLatitude(GetLatAtLon(util::FloatLongitude{max_lon + 1})))};
|
||||
|
||||
return {regression_first, regression_end};
|
||||
}
|
||||
|
||||
inline std::uint8_t getLaneCountAtIntersection(const NodeID intersection_node,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
std::uint8_t lanes = 0;
|
||||
for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(intersection_node))
|
||||
lanes = std::max(
|
||||
lanes, node_based_graph.GetEdgeData(onto_edge).road_classification.GetNumberOfLanes());
|
||||
return lanes;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_GUIDANCE_TOOLKIT_HPP_
|
||||
@@ -4,16 +4,17 @@
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/guidance/intersection_normalizer.hpp"
|
||||
#include "extractor/guidance/motorway_handler.hpp"
|
||||
#include "extractor/guidance/roundabout_handler.hpp"
|
||||
#include "extractor/guidance/sliproad_handler.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_classification.hpp"
|
||||
#include "extractor/guidance/turn_handler.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
@@ -21,6 +22,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -34,7 +36,6 @@ namespace guidance
|
||||
|
||||
class TurnAnalysis
|
||||
{
|
||||
|
||||
public:
|
||||
TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
@@ -45,19 +46,42 @@ class TurnAnalysis
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const ProfileProperties &profile_properties);
|
||||
|
||||
// the entry into the turn analysis
|
||||
Intersection getIntersection(const NodeID from_node, const EdgeID via_eid) const;
|
||||
Intersection
|
||||
assignTurnTypes(const NodeID from_node, const EdgeID via_eid, Intersection intersection) const;
|
||||
/* Full Analysis Process for a single node/edge combination. Use with caution, as the process is
|
||||
* relatively expensive */
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
Intersection operator()(const NodeID node_prior_to_intersection,
|
||||
const EdgeID entering_via_edge) const;
|
||||
|
||||
std::vector<TurnOperation>
|
||||
transformIntersectionIntoTurns(const Intersection &intersection) const;
|
||||
/*
|
||||
* Returns a normalized intersection without any assigned turn types.
|
||||
* This intersection can be used as input for intersection classification, turn lane assignment
|
||||
* and similar.
|
||||
*/
|
||||
struct ShapeResult
|
||||
{
|
||||
// the basic shape, containing all turns
|
||||
IntersectionShape intersection_shape;
|
||||
// normalised shape, merged some roads into others, adjusted bearings
|
||||
// see intersection_normaliser for further explanations
|
||||
IntersectionShape normalised_intersection_shape;
|
||||
// map containing information about which road was merged into which
|
||||
std::vector<std::pair<EdgeID, EdgeID>> merging_map;
|
||||
};
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
ShapeResult ComputeIntersectionShapes(const NodeID node_at_center_of_intersection) const;
|
||||
|
||||
const IntersectionGenerator &getGenerator() const;
|
||||
// Select turn types based on the intersection shape
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
Intersection AssignTurnTypes(const NodeID from_node,
|
||||
const EdgeID via_eid,
|
||||
const IntersectionView &intersection) const;
|
||||
|
||||
const IntersectionGenerator &GetIntersectionGenerator() const;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const IntersectionGenerator intersection_generator;
|
||||
const IntersectionNormalizer intersection_normalizer;
|
||||
const RoundaboutHandler roundabout_handler;
|
||||
const MotorwayHandler motorway_handler;
|
||||
const TurnHandler turn_handler;
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
|
||||
#define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/guidance/bearing_class.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_TURN_DISCOVERY_HPP_
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -22,13 +20,13 @@ namespace lanes
|
||||
bool findPreviousIntersection(
|
||||
const NodeID node,
|
||||
const EdgeID via_edge,
|
||||
const Intersection intersection,
|
||||
const TurnAnalysis &turn_analysis, // to generate other intersections
|
||||
const Intersection &intersection,
|
||||
const IntersectionGenerator &intersection_generator,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph, // query edge data
|
||||
// output parameters, will be in an arbitrary state on failure
|
||||
NodeID &result_node,
|
||||
EdgeID &result_via_edge,
|
||||
Intersection &result_intersection);
|
||||
IntersectionView &result_intersection);
|
||||
|
||||
} // namespace lanes
|
||||
} // namespace guidance
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
|
||||
#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "extractor/guidance/roundabout_type.hpp"
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
namespace osrm
|
||||
@@ -150,6 +150,162 @@ inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs)
|
||||
return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier;
|
||||
}
|
||||
|
||||
// check if a instruction is associated in any form with a roundabout
|
||||
inline bool hasRoundaboutType(const TurnInstruction instruction)
|
||||
{
|
||||
using namespace extractor::guidance::TurnType;
|
||||
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
|
||||
TurnType::EnterAndExitRoundabout,
|
||||
TurnType::EnterRotary,
|
||||
TurnType::EnterAndExitRotary,
|
||||
TurnType::EnterRoundaboutIntersection,
|
||||
TurnType::EnterAndExitRoundaboutIntersection,
|
||||
TurnType::EnterRoundaboutAtExit,
|
||||
TurnType::ExitRoundabout,
|
||||
TurnType::EnterRotaryAtExit,
|
||||
TurnType::ExitRotary,
|
||||
TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
TurnType::ExitRoundaboutIntersection,
|
||||
TurnType::StayOnRoundabout};
|
||||
|
||||
const auto *first = valid_types;
|
||||
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
|
||||
|
||||
return std::find(first, last, instruction.type) != last;
|
||||
}
|
||||
|
||||
inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersection ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
|
||||
}
|
||||
|
||||
inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::ExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::ExitRoundaboutIntersection ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
|
||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
|
||||
}
|
||||
|
||||
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
|
||||
}
|
||||
|
||||
// Silent Turn Instructions are not to be mentioned to the outside world but
|
||||
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::NoTurn ||
|
||||
instruction.type == extractor::guidance::TurnType::Suppressed ||
|
||||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
|
||||
}
|
||||
|
||||
inline bool hasRampType(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.type == extractor::guidance::TurnType::OffRamp ||
|
||||
instruction.type == extractor::guidance::TurnType::OnRamp;
|
||||
}
|
||||
|
||||
inline extractor::guidance::DirectionModifier::Enum getTurnDirection(const double angle)
|
||||
{
|
||||
// An angle of zero is a u-turn
|
||||
// 180 goes perfectly straight
|
||||
// 0-180 are right turns
|
||||
// 180-360 are left turns
|
||||
if (angle > 0 && angle < 60)
|
||||
return extractor::guidance::DirectionModifier::SharpRight;
|
||||
if (angle >= 60 && angle < 140)
|
||||
return extractor::guidance::DirectionModifier::Right;
|
||||
if (angle >= 140 && angle < 160)
|
||||
return extractor::guidance::DirectionModifier::SlightRight;
|
||||
if (angle >= 160 && angle <= 200)
|
||||
return extractor::guidance::DirectionModifier::Straight;
|
||||
if (angle > 200 && angle <= 220)
|
||||
return extractor::guidance::DirectionModifier::SlightLeft;
|
||||
if (angle > 220 && angle <= 300)
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
if (angle > 300 && angle < 360)
|
||||
return extractor::guidance::DirectionModifier::SharpLeft;
|
||||
return extractor::guidance::DirectionModifier::UTurn;
|
||||
}
|
||||
|
||||
// swaps left <-> right modifier types
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline extractor::guidance::DirectionModifier::Enum
|
||||
mirrorDirectionModifier(const extractor::guidance::DirectionModifier::Enum modifier)
|
||||
{
|
||||
const constexpr extractor::guidance::DirectionModifier::Enum results[] = {
|
||||
extractor::guidance::DirectionModifier::UTurn,
|
||||
extractor::guidance::DirectionModifier::SharpLeft,
|
||||
extractor::guidance::DirectionModifier::Left,
|
||||
extractor::guidance::DirectionModifier::SlightLeft,
|
||||
extractor::guidance::DirectionModifier::Straight,
|
||||
extractor::guidance::DirectionModifier::SlightRight,
|
||||
extractor::guidance::DirectionModifier::Right,
|
||||
extractor::guidance::DirectionModifier::SharpRight};
|
||||
return results[modifier];
|
||||
}
|
||||
|
||||
inline bool hasLeftModifier(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpLeft ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Left ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightLeft;
|
||||
}
|
||||
|
||||
inline bool hasRightModifier(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
return instruction.direction_modifier == extractor::guidance::DirectionModifier::SharpRight ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::Right ||
|
||||
instruction.direction_modifier == extractor::guidance::DirectionModifier::SlightRight;
|
||||
}
|
||||
|
||||
inline bool isLeftTurn(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
switch (instruction.type)
|
||||
{
|
||||
case TurnType::Merge:
|
||||
return hasRightModifier(instruction);
|
||||
default:
|
||||
return hasLeftModifier(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isRightTurn(const extractor::guidance::TurnInstruction instruction)
|
||||
{
|
||||
switch (instruction.type)
|
||||
{
|
||||
case TurnType::Merge:
|
||||
return hasLeftModifier(instruction);
|
||||
default:
|
||||
return hasRightModifier(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
inline DirectionModifier::Enum bearingToDirectionModifier(const double bearing)
|
||||
{
|
||||
if (bearing < 135)
|
||||
{
|
||||
return extractor::guidance::DirectionModifier::Right;
|
||||
}
|
||||
|
||||
if (bearing <= 225)
|
||||
{
|
||||
return extractor::guidance::DirectionModifier::Straight;
|
||||
}
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "extractor/guidance/turn_lane_types.hpp"
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_HANDLER_HPP_
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
#include "extractor/guidance/turn_lane_data.hpp"
|
||||
#include "extractor/guidance/turn_lane_types.hpp"
|
||||
@@ -74,7 +73,7 @@ class TurnLaneHandler
|
||||
std::vector<TurnLaneType::Mask> &turn_lane_masks,
|
||||
LaneDescriptionMap &lane_description_map,
|
||||
const TurnAnalysis &turn_analysis,
|
||||
LaneDataIdMap &id_map);
|
||||
util::guidance::LaneDataIdMap &id_map);
|
||||
|
||||
~TurnLaneHandler();
|
||||
|
||||
@@ -91,7 +90,7 @@ class TurnLaneHandler
|
||||
std::vector<TurnLaneType::Mask> &turn_lane_masks;
|
||||
LaneDescriptionMap &lane_description_map;
|
||||
const TurnAnalysis &turn_analysis;
|
||||
LaneDataIdMap &id_map;
|
||||
util::guidance::LaneDataIdMap &id_map;
|
||||
|
||||
// Find out which scenario we have to handle
|
||||
TurnLaneScenario deduceScenario(const NodeID at,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_MATCHER_HPP_
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/guidance/turn_lane_data.hpp"
|
||||
|
||||
@@ -10,8 +9,6 @@
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
@@ -47,7 +44,7 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
|
||||
const LaneDataVector &lane_data,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const LaneDescriptionID lane_string_id,
|
||||
LaneDataIdMap &lane_data_to_id);
|
||||
util::guidance::LaneDataIdMap &lane_data_to_id);
|
||||
|
||||
} // namespace lanes
|
||||
} // namespace guidance
|
||||
|
||||
@@ -8,11 +8,9 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#include "util/json_container.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
namespace osrm
|
||||
|
||||
@@ -43,11 +43,11 @@ struct InternalExtractorEdge
|
||||
MIN_OSM_NODEID,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
guidance::TurnLaneType::empty,
|
||||
@@ -62,7 +62,7 @@ struct InternalExtractorEdge
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool access_restricted,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
@@ -75,7 +75,7 @@ struct InternalExtractorEdge
|
||||
forward,
|
||||
backward,
|
||||
roundabout,
|
||||
access_restricted,
|
||||
circular,
|
||||
startpoint,
|
||||
travel_mode,
|
||||
is_split,
|
||||
@@ -99,11 +99,11 @@ struct InternalExtractorEdge
|
||||
MIN_OSM_NODEID,
|
||||
0,
|
||||
WeightData(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
INVALID_LANE_DESCRIPTIONID,
|
||||
@@ -115,11 +115,11 @@ struct InternalExtractorEdge
|
||||
MAX_OSM_NODEID,
|
||||
SPECIAL_NODEID,
|
||||
WeightData(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
INVALID_LANE_DESCRIPTIONID,
|
||||
|
||||
@@ -22,7 +22,7 @@ struct NodeBasedEdge
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool access_restricted,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
@@ -38,7 +38,7 @@ struct NodeBasedEdge
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool roundabout : 1;
|
||||
bool access_restricted : 1;
|
||||
bool circular : 1;
|
||||
bool startpoint : 1;
|
||||
bool is_split : 1;
|
||||
TravelMode travel_mode : 4;
|
||||
@@ -55,7 +55,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool access_restricted,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
@@ -70,8 +70,8 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
|
||||
inline NodeBasedEdge::NodeBasedEdge()
|
||||
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
|
||||
backward(false), roundabout(false), access_restricted(false), startpoint(true),
|
||||
is_split(false), travel_mode(false), lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
backward(false), roundabout(false), circular(false), startpoint(true), is_split(false),
|
||||
travel_mode(false), lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -82,16 +82,16 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool access_restricted,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
const LaneDescriptionID lane_description_id,
|
||||
guidance::RoadClassification road_classification)
|
||||
: source(source), target(target), name_id(name_id), weight(weight), forward(forward),
|
||||
backward(backward), roundabout(roundabout), access_restricted(access_restricted),
|
||||
startpoint(startpoint), is_split(is_split), travel_mode(travel_mode),
|
||||
lane_description_id(lane_description_id), road_classification(std::move(road_classification))
|
||||
backward(backward), roundabout(roundabout), circular(circular), startpoint(startpoint),
|
||||
is_split(is_split), travel_mode(travel_mode), lane_description_id(lane_description_id),
|
||||
road_classification(std::move(road_classification))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool access_restricted,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split,
|
||||
@@ -132,7 +132,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
forward,
|
||||
backward,
|
||||
roundabout,
|
||||
access_restricted,
|
||||
circular,
|
||||
startpoint,
|
||||
travel_mode,
|
||||
is_split,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/qi_int.hpp>
|
||||
#include <storage/io.hpp>
|
||||
|
||||
#include <iterator>
|
||||
#include <unordered_map>
|
||||
@@ -43,20 +44,14 @@ class RasterGrid
|
||||
ydim = _ydim;
|
||||
_data.reserve(ydim * xdim);
|
||||
|
||||
boost::filesystem::ifstream stream(filepath, std::ios::binary);
|
||||
if (!stream)
|
||||
{
|
||||
throw util::exception("Unable to open raster file.");
|
||||
}
|
||||
storage::io::FileReader file_reader(filepath, storage::io::FileReader::HasNoFingerprint);
|
||||
|
||||
stream.seekg(0, std::ios_base::end);
|
||||
std::string buffer;
|
||||
buffer.resize(static_cast<std::size_t>(stream.tellg()));
|
||||
|
||||
stream.seekg(0, std::ios_base::beg);
|
||||
buffer.resize(file_reader.Size());
|
||||
|
||||
BOOST_ASSERT(buffer.size() > 1);
|
||||
stream.read(&buffer[0], static_cast<std::streamsize>(buffer.size()));
|
||||
|
||||
file_reader.ReadInto(&buffer[0], buffer.size());
|
||||
|
||||
boost::algorithm::trim(buffer);
|
||||
|
||||
@@ -71,13 +66,14 @@ class RasterGrid
|
||||
}
|
||||
catch (std::exception const &ex)
|
||||
{
|
||||
throw util::exception(
|
||||
std::string("Failed to read from raster source with exception: ") + ex.what());
|
||||
throw util::exception("Failed to read from raster source " + filepath.string() + ": " +
|
||||
ex.what() + SOURCE_REF);
|
||||
}
|
||||
|
||||
if (!r || itr != end)
|
||||
{
|
||||
throw util::exception("Failed to parse raster source correctly.");
|
||||
throw util::exception("Failed to parse raster source: " + filepath.string() +
|
||||
SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/std_hash.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
@@ -146,8 +146,8 @@ template <typename GraphT> class TarjanSCC
|
||||
|
||||
if (size_of_current_component > 1000)
|
||||
{
|
||||
util::SimpleLogger().Write() << "large component [" << component_index
|
||||
<< "]=" << size_of_current_component;
|
||||
util::Log() << "large component [" << component_index
|
||||
<< "]=" << size_of_current_component;
|
||||
}
|
||||
|
||||
++component_index;
|
||||
@@ -158,7 +158,7 @@ template <typename GraphT> class TarjanSCC
|
||||
}
|
||||
|
||||
TIMER_STOP(SCC_RUN);
|
||||
util::SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
|
||||
util::Log() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
|
||||
|
||||
size_one_counter = std::count_if(component_size_vector.begin(),
|
||||
component_size_vector.end(),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "server/service_handler.hpp"
|
||||
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
@@ -36,8 +36,7 @@ class Server
|
||||
static std::shared_ptr<Server>
|
||||
CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
|
||||
{
|
||||
util::SimpleLogger().Write() << "http 1.1 compression handled by zlib version "
|
||||
<< zlibVersion();
|
||||
util::Log() << "http 1.1 compression handled by zlib version " << zlibVersion();
|
||||
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
|
||||
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
|
||||
return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
|
||||
@@ -62,7 +61,7 @@ class Server
|
||||
acceptor.bind(endpoint);
|
||||
acceptor.listen();
|
||||
|
||||
util::SimpleLogger().Write() << "Listening on: " << acceptor.local_endpoint();
|
||||
util::Log() << "Listening on: " << acceptor.local_endpoint();
|
||||
|
||||
acceptor.async_accept(
|
||||
new_connection->socket(),
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "osrm/osrm.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
|
||||
#include <variant/variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
+211
-184
@@ -1,17 +1,17 @@
|
||||
#ifndef OSRM_STORAGE_IO_HPP_
|
||||
#define OSRM_STORAGE_IO_HPP_
|
||||
|
||||
#include "contractor/query_edge.hpp"
|
||||
#include "extractor/extractor.hpp"
|
||||
#include "extractor/original_edge_data.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/fingerprint.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/iostreams/seek.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -20,201 +20,228 @@ namespace storage
|
||||
namespace io
|
||||
{
|
||||
|
||||
// Reads the count of elements that is written in the file header and returns the number
|
||||
inline std::uint64_t readElementCount(boost::filesystem::ifstream &input_stream)
|
||||
class FileReader
|
||||
{
|
||||
std::uint64_t number_of_elements = 0;
|
||||
input_stream.read((char *)&number_of_elements, sizeof(std::uint64_t));
|
||||
return number_of_elements;
|
||||
}
|
||||
private:
|
||||
const boost::filesystem::path filepath;
|
||||
boost::filesystem::ifstream input_stream;
|
||||
|
||||
// To make function calls consistent, this function returns the fixed number of properties
|
||||
inline std::size_t readPropertiesCount() { return 1; }
|
||||
public:
|
||||
class LineWrapper : public std::string
|
||||
{
|
||||
friend std::istream &operator>>(std::istream &is, LineWrapper &line)
|
||||
{
|
||||
return std::getline(is, line);
|
||||
}
|
||||
};
|
||||
auto GetLineIteratorBegin() { return std::istream_iterator<LineWrapper>(input_stream); }
|
||||
auto GetLineIteratorEnd() { return std::istream_iterator<LineWrapper>(); }
|
||||
|
||||
// Returns the number of bytes in a file
|
||||
inline std::size_t readNumberOfBytes(boost::filesystem::ifstream &input_stream)
|
||||
{
|
||||
input_stream.seekg(0, input_stream.end);
|
||||
auto length = input_stream.tellg();
|
||||
input_stream.seekg(0, input_stream.beg);
|
||||
return length;
|
||||
}
|
||||
enum FingerprintFlag
|
||||
{
|
||||
VerifyFingerprint,
|
||||
HasNoFingerprint
|
||||
};
|
||||
FileReader(const std::string &filename, const FingerprintFlag flag)
|
||||
: FileReader(boost::filesystem::path(filename), flag)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct HSGRHeader
|
||||
{
|
||||
std::uint32_t checksum;
|
||||
std::uint64_t number_of_nodes;
|
||||
std::uint64_t number_of_edges;
|
||||
FileReader(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
|
||||
: filepath(filepath_)
|
||||
{
|
||||
input_stream.open(filepath, std::ios::binary);
|
||||
if (!input_stream)
|
||||
throw util::exception("Error opening " + filepath.string());
|
||||
|
||||
if (flag == VerifyFingerprint && !ReadAndCheckFingerprint())
|
||||
{
|
||||
throw util::exception("Fingerprint mismatch in " + filepath_.string() + SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read count objects of type T into pointer dest */
|
||||
template <typename T> void ReadInto(T *dest, const std::size_t count)
|
||||
{
|
||||
#if not defined __GNUC__ or __GNUC__ > 4
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"bytewise reading requires trivially copyable type");
|
||||
#endif
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
const auto &result = input_stream.read(reinterpret_cast<char *>(dest), count * sizeof(T));
|
||||
|
||||
if (!result)
|
||||
{
|
||||
if (result.eof())
|
||||
{
|
||||
throw util::exception("Error reading from " + filepath.string() +
|
||||
": Unexpected end of file " + SOURCE_REF);
|
||||
}
|
||||
throw util::exception("Error reading from " + filepath.string() + " " + SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void ReadInto(std::vector<T> &target)
|
||||
{
|
||||
ReadInto(target.data(), target.size());
|
||||
}
|
||||
|
||||
template <typename T> void ReadInto(T &target) { ReadInto(&target, 1); }
|
||||
|
||||
template <typename T> T ReadOne()
|
||||
{
|
||||
T tmp;
|
||||
ReadInto(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <typename T> void Skip(const std::size_t element_count)
|
||||
{
|
||||
boost::iostreams::seek(input_stream, element_count * sizeof(T), BOOST_IOS::cur);
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
||||
std::uint32_t ReadElementCount32() { return ReadOne<std::uint32_t>(); }
|
||||
std::uint64_t ReadElementCount64() { return ReadOne<std::uint64_t>(); }
|
||||
|
||||
template <typename T> void DeserializeVector(std::vector<T> &data)
|
||||
{
|
||||
const auto count = ReadElementCount64();
|
||||
data.resize(count);
|
||||
ReadInto(data.data(), count);
|
||||
}
|
||||
|
||||
bool ReadAndCheckFingerprint()
|
||||
{
|
||||
auto fingerprint = ReadOne<util::FingerPrint>();
|
||||
const auto valid = util::FingerPrint::GetValid();
|
||||
// compare the compilation state stored in the fingerprint
|
||||
return valid.IsMagicNumberOK(fingerprint) && valid.TestContractor(fingerprint) &&
|
||||
valid.TestGraphUtil(fingerprint) && valid.TestRTree(fingerprint) &&
|
||||
valid.TestQueryObjects(fingerprint);
|
||||
}
|
||||
|
||||
std::size_t Size()
|
||||
{
|
||||
auto current_pos = input_stream.tellg();
|
||||
input_stream.seekg(0, input_stream.end);
|
||||
auto length = input_stream.tellg();
|
||||
input_stream.seekg(current_pos, input_stream.beg);
|
||||
return length;
|
||||
}
|
||||
|
||||
std::vector<std::string> ReadLines()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::string thisline;
|
||||
try
|
||||
{
|
||||
while (std::getline(input_stream, thisline))
|
||||
{
|
||||
result.push_back(thisline);
|
||||
}
|
||||
}
|
||||
catch (const std::ios_base::failure &e)
|
||||
{
|
||||
// EOF is OK here, everything else, re-throw
|
||||
if (!input_stream.eof())
|
||||
throw;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ReadLine()
|
||||
{
|
||||
std::string thisline;
|
||||
try
|
||||
{
|
||||
std::getline(input_stream, thisline);
|
||||
}
|
||||
catch (const std::ios_base::failure & /*e*/)
|
||||
{
|
||||
// EOF is OK here, everything else, re-throw
|
||||
if (!input_stream.eof())
|
||||
throw;
|
||||
}
|
||||
return thisline;
|
||||
}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(HSGRHeader) == 20, "HSGRHeader is not packed");
|
||||
|
||||
// Reads the checksum, number of nodes and number of edges written in the header file of a `.hsgr`
|
||||
// file and returns them in a HSGRHeader struct
|
||||
inline HSGRHeader readHSGRHeader(boost::filesystem::ifstream &input_stream)
|
||||
class FileWriter
|
||||
{
|
||||
const util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
|
||||
util::FingerPrint fingerprint_loaded;
|
||||
input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(util::FingerPrint));
|
||||
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
|
||||
private:
|
||||
const boost::filesystem::path filepath;
|
||||
boost::filesystem::ofstream output_stream;
|
||||
|
||||
public:
|
||||
enum FingerprintFlag
|
||||
{
|
||||
GenerateFingerprint,
|
||||
HasNoFingerprint
|
||||
};
|
||||
|
||||
FileWriter(const std::string &filename, const FingerprintFlag flag)
|
||||
: FileWriter(boost::filesystem::path(filename), flag)
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
HSGRHeader header;
|
||||
input_stream.read(reinterpret_cast<char *>(&header.checksum), sizeof(header.checksum));
|
||||
input_stream.read(reinterpret_cast<char *>(&header.number_of_nodes),
|
||||
sizeof(header.number_of_nodes));
|
||||
input_stream.read(reinterpret_cast<char *>(&header.number_of_edges),
|
||||
sizeof(header.number_of_edges));
|
||||
|
||||
BOOST_ASSERT_MSG(0 != header.number_of_nodes, "number of nodes is zero");
|
||||
// number of edges can be zero, this is the case in a few test fixtures
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
// Reads the graph data of a `.hsgr` file into memory
|
||||
// Needs to be called after readHSGRHeader() to get the correct offset in the stream
|
||||
using NodeT = typename util::StaticGraph<contractor::QueryEdge::EdgeData>::NodeArrayEntry;
|
||||
using EdgeT = typename util::StaticGraph<contractor::QueryEdge::EdgeData>::EdgeArrayEntry;
|
||||
inline void readHSGR(boost::filesystem::ifstream &input_stream,
|
||||
NodeT *node_buffer,
|
||||
const std::uint64_t number_of_nodes,
|
||||
EdgeT *edge_buffer,
|
||||
const std::uint64_t number_of_edges)
|
||||
{
|
||||
BOOST_ASSERT(node_buffer);
|
||||
BOOST_ASSERT(edge_buffer);
|
||||
input_stream.read(reinterpret_cast<char *>(node_buffer), number_of_nodes * sizeof(NodeT));
|
||||
input_stream.read(reinterpret_cast<char *>(edge_buffer), number_of_edges * sizeof(EdgeT));
|
||||
}
|
||||
|
||||
// Loads properties from a `.properties` file into memory
|
||||
inline void readProperties(boost::filesystem::ifstream &properties_stream,
|
||||
extractor::ProfileProperties *properties,
|
||||
const std::size_t properties_size)
|
||||
{
|
||||
BOOST_ASSERT(properties);
|
||||
properties_stream.read(reinterpret_cast<char *>(properties), properties_size);
|
||||
}
|
||||
|
||||
// Reads the timestamp in a `.timestamp` file
|
||||
// Use readNumberOfBytes() beforehand to get the length of the file
|
||||
inline void readTimestamp(boost::filesystem::ifstream ×tamp_input_stream,
|
||||
char *timestamp,
|
||||
const std::size_t timestamp_length)
|
||||
{
|
||||
BOOST_ASSERT(timestamp);
|
||||
timestamp_input_stream.read(timestamp, timestamp_length * sizeof(char));
|
||||
}
|
||||
|
||||
// Loads datasource_indexes from .datasource_indexes into memory
|
||||
// Needs to be called after readElementCount() to get the correct offset in the stream
|
||||
inline void readDatasourceIndexes(boost::filesystem::ifstream &datasource_indexes_input_stream,
|
||||
uint8_t *datasource_buffer,
|
||||
const std::uint64_t number_of_datasource_indexes)
|
||||
{
|
||||
BOOST_ASSERT(datasource_buffer);
|
||||
datasource_indexes_input_stream.read(reinterpret_cast<char *>(datasource_buffer),
|
||||
number_of_datasource_indexes * sizeof(std::uint8_t));
|
||||
}
|
||||
|
||||
// Loads edge data from .edge files into memory which includes its
|
||||
// geometry, name ID, turn instruction, lane data ID, travel mode, entry class ID
|
||||
// Needs to be called after readElementCount() to get the correct offset in the stream
|
||||
inline void readEdges(boost::filesystem::ifstream &edges_input_stream,
|
||||
GeometryID *geometry_list,
|
||||
NameID *name_id_list,
|
||||
extractor::guidance::TurnInstruction *turn_instruction_list,
|
||||
LaneDataID *lane_data_id_list,
|
||||
extractor::TravelMode *travel_mode_list,
|
||||
EntryClassID *entry_class_id_list,
|
||||
util::guidance::TurnBearing *pre_turn_bearing_list,
|
||||
util::guidance::TurnBearing *post_turn_bearing_list,
|
||||
const std::uint64_t number_of_edges)
|
||||
{
|
||||
BOOST_ASSERT(geometry_list);
|
||||
BOOST_ASSERT(name_id_list);
|
||||
BOOST_ASSERT(turn_instruction_list);
|
||||
BOOST_ASSERT(lane_data_id_list);
|
||||
BOOST_ASSERT(travel_mode_list);
|
||||
BOOST_ASSERT(entry_class_id_list);
|
||||
extractor::OriginalEdgeData current_edge_data;
|
||||
for (std::uint64_t i = 0; i < number_of_edges; ++i)
|
||||
FileWriter(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
|
||||
: filepath(filepath_)
|
||||
{
|
||||
edges_input_stream.read((char *)&(current_edge_data), sizeof(extractor::OriginalEdgeData));
|
||||
output_stream.open(filepath, std::ios::binary);
|
||||
if (!output_stream)
|
||||
throw util::exception("Error opening " + filepath.string());
|
||||
|
||||
geometry_list[i] = current_edge_data.via_geometry;
|
||||
name_id_list[i] = current_edge_data.name_id;
|
||||
turn_instruction_list[i] = current_edge_data.turn_instruction;
|
||||
lane_data_id_list[i] = current_edge_data.lane_data_id;
|
||||
travel_mode_list[i] = current_edge_data.travel_mode;
|
||||
entry_class_id_list[i] = current_edge_data.entry_classid;
|
||||
pre_turn_bearing_list[i] = current_edge_data.pre_turn_bearing;
|
||||
post_turn_bearing_list[i] = current_edge_data.post_turn_bearing;
|
||||
if (flag == GenerateFingerprint)
|
||||
{
|
||||
WriteFingerprint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loads coordinates and OSM node IDs from .nodes files into memory
|
||||
// Needs to be called after readElementCount() to get the correct offset in the stream
|
||||
template <typename OSMNodeIDVectorT>
|
||||
void readNodes(boost::filesystem::ifstream &nodes_input_stream,
|
||||
util::Coordinate *coordinate_list,
|
||||
OSMNodeIDVectorT &osmnodeid_list,
|
||||
const std::uint64_t number_of_coordinates)
|
||||
{
|
||||
BOOST_ASSERT(coordinate_list);
|
||||
extractor::QueryNode current_node;
|
||||
for (std::uint64_t i = 0; i < number_of_coordinates; ++i)
|
||||
/* Write count objects of type T from pointer src to output stream */
|
||||
template <typename T> bool WriteFrom(T *src, const std::size_t count)
|
||||
{
|
||||
nodes_input_stream.read((char *)¤t_node, sizeof(extractor::QueryNode));
|
||||
coordinate_list[i] = util::Coordinate(current_node.lon, current_node.lat);
|
||||
osmnodeid_list.push_back(current_node.node_id);
|
||||
BOOST_ASSERT(coordinate_list[i].IsValid());
|
||||
}
|
||||
}
|
||||
#if not defined __GNUC__ or __GNUC__ > 4
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"bytewise writing requires trivially copyable type");
|
||||
#endif
|
||||
|
||||
// Reads datasource names out of .datasource_names files and metadata such as
|
||||
// the length and offset of each name
|
||||
struct DatasourceNamesData
|
||||
{
|
||||
std::vector<char> names;
|
||||
std::vector<std::size_t> offsets;
|
||||
std::vector<std::size_t> lengths;
|
||||
if (count == 0)
|
||||
return true;
|
||||
|
||||
const auto &result = output_stream.write(reinterpret_cast<char *>(src), count * sizeof(T));
|
||||
if (!result)
|
||||
{
|
||||
throw util::exception("Error writing to " + filepath.string());
|
||||
}
|
||||
|
||||
return static_cast<bool>(output_stream);
|
||||
}
|
||||
|
||||
template <typename T> bool WriteFrom(T &target) { return WriteFrom(&target, 1); }
|
||||
|
||||
template <typename T> bool WriteOne(T tmp) { return WriteFrom(tmp); }
|
||||
|
||||
bool WriteElementCount32(const std::uint32_t count) { return WriteOne<std::uint32_t>(count); }
|
||||
bool WriteElementCount64(const std::uint64_t count) { return WriteOne<std::uint64_t>(count); }
|
||||
|
||||
template <typename T> bool SerializeVector(std::vector<T> &data)
|
||||
{
|
||||
const auto count = data.size();
|
||||
WriteElementCount64(count);
|
||||
return WriteFrom(data.data(), count);
|
||||
}
|
||||
|
||||
bool WriteFingerprint()
|
||||
{
|
||||
const auto fingerprint = util::FingerPrint::GetValid();
|
||||
return WriteOne(fingerprint);
|
||||
}
|
||||
};
|
||||
inline DatasourceNamesData
|
||||
readDatasourceNames(boost::filesystem::ifstream &datasource_names_input_stream)
|
||||
{
|
||||
DatasourceNamesData datasource_names_data;
|
||||
std::string name;
|
||||
while (std::getline(datasource_names_input_stream, name))
|
||||
{
|
||||
datasource_names_data.offsets.push_back(datasource_names_data.names.size());
|
||||
datasource_names_data.lengths.push_back(name.size());
|
||||
std::copy(name.c_str(),
|
||||
name.c_str() + name.size(),
|
||||
std::back_inserter(datasource_names_data.names));
|
||||
}
|
||||
return datasource_names_data;
|
||||
}
|
||||
|
||||
// Loads ram indexes of R-Trees from `.ramIndex` files into memory
|
||||
// Needs to be called after readElementCount() to get the correct offset in the stream
|
||||
// template <bool UseSharedMemory>
|
||||
// NB Cannot be written without templated type because of cyclic depencies between
|
||||
// `static_rtree.hpp` and `io.hpp`
|
||||
template <typename RTreeNodeT>
|
||||
void readRamIndex(boost::filesystem::ifstream &ram_index_input_stream,
|
||||
RTreeNodeT *rtree_buffer,
|
||||
const std::uint64_t tree_size)
|
||||
{
|
||||
BOOST_ASSERT(rtree_buffer);
|
||||
ram_index_input_stream.read(reinterpret_cast<char *>(rtree_buffer),
|
||||
sizeof(RTreeNodeT) * tree_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
#ifndef OSRM_STORAGE_SERIALIZATION_HPP_
|
||||
#define OSRM_STORAGE_SERIALIZATION_HPP_
|
||||
|
||||
#include "contractor/query_edge.hpp"
|
||||
#include "extractor/extractor.hpp"
|
||||
#include "extractor/original_edge_data.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "storage/io.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/fingerprint.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/iostreams/seek.hpp>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace storage
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
|
||||
// To make function calls consistent, this function returns the fixed number of properties
|
||||
inline std::size_t readPropertiesCount() { return 1; }
|
||||
|
||||
struct HSGRHeader
|
||||
{
|
||||
std::uint32_t checksum;
|
||||
std::uint64_t number_of_nodes;
|
||||
std::uint64_t number_of_edges;
|
||||
};
|
||||
|
||||
// Reads the checksum, number of nodes and number of edges written in the header file of a `.hsgr`
|
||||
// file and returns them in a HSGRHeader struct
|
||||
inline HSGRHeader readHSGRHeader(io::FileReader &input_file)
|
||||
{
|
||||
const util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
|
||||
const auto fingerprint_loaded = input_file.ReadOne<util::FingerPrint>();
|
||||
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
|
||||
{
|
||||
util::Log(logWARNING) << ".hsgr was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
HSGRHeader header;
|
||||
input_file.ReadInto(header.checksum);
|
||||
input_file.ReadInto(header.number_of_nodes);
|
||||
input_file.ReadInto(header.number_of_edges);
|
||||
|
||||
// If we have edges, then we must have nodes.
|
||||
// However, there can be nodes with no edges (some test cases create this)
|
||||
BOOST_ASSERT_MSG(header.number_of_edges == 0 || header.number_of_nodes > 0,
|
||||
"edges exist, but there are no nodes");
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
// Reads the graph data of a `.hsgr` file into memory
|
||||
// Needs to be called after readHSGRHeader() to get the correct offset in the stream
|
||||
using NodeT = typename util::StaticGraph<contractor::QueryEdge::EdgeData>::NodeArrayEntry;
|
||||
using EdgeT = typename util::StaticGraph<contractor::QueryEdge::EdgeData>::EdgeArrayEntry;
|
||||
inline void readHSGR(io::FileReader &input_file,
|
||||
NodeT *node_buffer,
|
||||
const std::uint64_t number_of_nodes,
|
||||
EdgeT *edge_buffer,
|
||||
const std::uint64_t number_of_edges)
|
||||
{
|
||||
BOOST_ASSERT(node_buffer);
|
||||
BOOST_ASSERT(edge_buffer);
|
||||
input_file.ReadInto(node_buffer, number_of_nodes);
|
||||
input_file.ReadInto(edge_buffer, number_of_edges);
|
||||
}
|
||||
|
||||
// Loads datasource_indexes from .datasource_indexes into memory
|
||||
// Needs to be called after readElementCount() to get the correct offset in the stream
|
||||
inline void readDatasourceIndexes(io::FileReader &datasource_indexes_file,
|
||||
uint8_t *datasource_buffer,
|
||||
const std::uint64_t number_of_datasource_indexes)
|
||||
{
|
||||
BOOST_ASSERT(datasource_buffer);
|
||||
datasource_indexes_file.ReadInto(datasource_buffer, number_of_datasource_indexes);
|
||||
}
|
||||
|
||||
// Loads edge data from .edge files into memory which includes its
|
||||
// geometry, name ID, turn instruction, lane data ID, travel mode, entry class ID
|
||||
// Needs to be called after readElementCount() to get the correct offset in the stream
|
||||
inline void readEdges(io::FileReader &edges_input_file,
|
||||
GeometryID *geometry_list,
|
||||
NameID *name_id_list,
|
||||
extractor::guidance::TurnInstruction *turn_instruction_list,
|
||||
LaneDataID *lane_data_id_list,
|
||||
extractor::TravelMode *travel_mode_list,
|
||||
EntryClassID *entry_class_id_list,
|
||||
util::guidance::TurnBearing *pre_turn_bearing_list,
|
||||
util::guidance::TurnBearing *post_turn_bearing_list,
|
||||
const std::uint64_t number_of_edges)
|
||||
{
|
||||
BOOST_ASSERT(geometry_list);
|
||||
BOOST_ASSERT(name_id_list);
|
||||
BOOST_ASSERT(turn_instruction_list);
|
||||
BOOST_ASSERT(lane_data_id_list);
|
||||
BOOST_ASSERT(travel_mode_list);
|
||||
BOOST_ASSERT(entry_class_id_list);
|
||||
extractor::OriginalEdgeData current_edge_data;
|
||||
for (std::uint64_t i = 0; i < number_of_edges; ++i)
|
||||
{
|
||||
edges_input_file.ReadInto(current_edge_data);
|
||||
|
||||
geometry_list[i] = current_edge_data.via_geometry;
|
||||
name_id_list[i] = current_edge_data.name_id;
|
||||
turn_instruction_list[i] = current_edge_data.turn_instruction;
|
||||
lane_data_id_list[i] = current_edge_data.lane_data_id;
|
||||
travel_mode_list[i] = current_edge_data.travel_mode;
|
||||
entry_class_id_list[i] = current_edge_data.entry_classid;
|
||||
pre_turn_bearing_list[i] = current_edge_data.pre_turn_bearing;
|
||||
post_turn_bearing_list[i] = current_edge_data.post_turn_bearing;
|
||||
}
|
||||
}
|
||||
|
||||
// Loads coordinates and OSM node IDs from .nodes files into memory
|
||||
// Needs to be called after readElementCount() to get the correct offset in the stream
|
||||
template <typename OSMNodeIDVectorT>
|
||||
void readNodes(io::FileReader &nodes_file,
|
||||
util::Coordinate *coordinate_list,
|
||||
OSMNodeIDVectorT &osmnodeid_list,
|
||||
const std::uint64_t number_of_coordinates)
|
||||
{
|
||||
BOOST_ASSERT(coordinate_list);
|
||||
extractor::QueryNode current_node;
|
||||
for (std::uint64_t i = 0; i < number_of_coordinates; ++i)
|
||||
{
|
||||
nodes_file.ReadInto(current_node);
|
||||
coordinate_list[i] = util::Coordinate(current_node.lon, current_node.lat);
|
||||
osmnodeid_list.push_back(current_node.node_id);
|
||||
BOOST_ASSERT(coordinate_list[i].IsValid());
|
||||
}
|
||||
}
|
||||
|
||||
// Reads datasource names out of .datasource_names files and metadata such as
|
||||
// the length and offset of each name
|
||||
struct DatasourceNamesData
|
||||
{
|
||||
std::vector<char> names;
|
||||
std::vector<std::size_t> offsets;
|
||||
std::vector<std::size_t> lengths;
|
||||
};
|
||||
inline DatasourceNamesData readDatasourceNames(io::FileReader &datasource_names_file)
|
||||
{
|
||||
DatasourceNamesData datasource_names_data;
|
||||
std::vector<std::string> lines = datasource_names_file.ReadLines();
|
||||
for (const auto &name : lines)
|
||||
{
|
||||
datasource_names_data.offsets.push_back(datasource_names_data.names.size());
|
||||
datasource_names_data.lengths.push_back(name.size());
|
||||
std::copy(name.c_str(),
|
||||
name.c_str() + name.size(),
|
||||
std::back_inserter(datasource_names_data.names));
|
||||
}
|
||||
return datasource_names_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,11 +2,11 @@
|
||||
#define SHARED_DATA_TYPE_HPP
|
||||
|
||||
#include "util/exception.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -54,7 +54,7 @@ const constexpr char *block_id_to_name[] = {"NAME_OFFSETS",
|
||||
"LANE_DESCRIPTION_OFFSETS",
|
||||
"LANE_DESCRIPTION_MASKS"};
|
||||
|
||||
struct SharedDataLayout
|
||||
struct DataLayout
|
||||
{
|
||||
enum BlockID
|
||||
{
|
||||
@@ -98,21 +98,17 @@ struct SharedDataLayout
|
||||
NUM_BLOCKS
|
||||
};
|
||||
|
||||
std::array<uint64_t, NUM_BLOCKS> num_entries;
|
||||
std::array<uint64_t, NUM_BLOCKS> entry_size;
|
||||
std::array<std::uint64_t, NUM_BLOCKS> num_entries;
|
||||
std::array<std::size_t, NUM_BLOCKS> entry_size;
|
||||
std::array<std::size_t, NUM_BLOCKS> entry_align;
|
||||
|
||||
SharedDataLayout() : num_entries(), entry_size() {}
|
||||
DataLayout() : num_entries(), entry_size(), entry_align() {}
|
||||
|
||||
template <typename T> inline void SetBlockSize(BlockID bid, uint64_t entries)
|
||||
{
|
||||
num_entries[bid] = entries;
|
||||
entry_size[bid] = sizeof(T);
|
||||
}
|
||||
|
||||
inline uint64_t AlignBlockSize(uint64_t block_size) const
|
||||
{
|
||||
const uint64_t alignment = 4;
|
||||
return (block_size + (alignment - 1)) & ~(alignment - 1);
|
||||
entry_align[bid] = alignof(T);
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockSize(BlockID bid) const
|
||||
@@ -120,56 +116,77 @@ struct SharedDataLayout
|
||||
// special bit encoding
|
||||
if (bid == CORE_MARKER)
|
||||
{
|
||||
return AlignBlockSize((num_entries[bid] / 32 + 1) * entry_size[bid]);
|
||||
return (num_entries[bid] / 32 + 1) * entry_size[bid];
|
||||
}
|
||||
return AlignBlockSize(num_entries[bid] * entry_size[bid]);
|
||||
return num_entries[bid] * entry_size[bid];
|
||||
}
|
||||
|
||||
inline uint64_t GetSizeOfLayout() const
|
||||
{
|
||||
return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS * 2 * sizeof(CANARY);
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockOffset(BlockID bid) const
|
||||
{
|
||||
uint64_t result = sizeof(CANARY);
|
||||
for (auto i = 0; i < bid; i++)
|
||||
uint64_t result = 0;
|
||||
for (auto i = 0; i < NUM_BLOCKS; i++)
|
||||
{
|
||||
result += GetBlockSize((BlockID)i) + 2 * sizeof(CANARY);
|
||||
result += 2 * sizeof(CANARY) + GetBlockSize((BlockID)i) + entry_align[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, bool WRITE_CANARY = false>
|
||||
inline T *GetBlockPtr(char *shared_memory, BlockID bid)
|
||||
// \brief Fit aligned storage in buffer.
|
||||
// Interface Similar to [ptr.align] but omits space computation.
|
||||
// The method can be removed and changed directly to an std::align
|
||||
// function call after dropping gcc < 5 support.
|
||||
inline void *align(std::size_t align, std::size_t, void *&ptr) const noexcept
|
||||
{
|
||||
T *ptr = (T *)(shared_memory + GetBlockOffset(bid));
|
||||
const auto intptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
const auto aligned = (intptr - 1u + align) & -align;
|
||||
return ptr = reinterpret_cast<void *>(aligned);
|
||||
}
|
||||
|
||||
inline void *GetAlignedBlockPtr(void *ptr, BlockID bid) const
|
||||
{
|
||||
for (auto i = 0; i < bid; i++)
|
||||
{
|
||||
ptr = static_cast<char *>(ptr) + sizeof(CANARY);
|
||||
ptr = align(entry_align[i], entry_size[i], ptr);
|
||||
ptr = static_cast<char *>(ptr) + GetBlockSize((BlockID)i);
|
||||
ptr = static_cast<char *>(ptr) + sizeof(CANARY);
|
||||
}
|
||||
|
||||
ptr = static_cast<char *>(ptr) + sizeof(CANARY);
|
||||
ptr = align(entry_align[bid], entry_size[bid], ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename T, bool WRITE_CANARY = false>
|
||||
inline T *GetBlockPtr(char *shared_memory, BlockID bid) const
|
||||
{
|
||||
char *ptr = (char *)GetAlignedBlockPtr(shared_memory, bid);
|
||||
if (WRITE_CANARY)
|
||||
{
|
||||
char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
|
||||
char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
|
||||
char *start_canary_ptr = ptr - sizeof(CANARY);
|
||||
char *end_canary_ptr = ptr + GetBlockSize(bid);
|
||||
std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
|
||||
std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
|
||||
char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
|
||||
char *start_canary_ptr = ptr - sizeof(CANARY);
|
||||
char *end_canary_ptr = ptr + GetBlockSize(bid);
|
||||
bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
|
||||
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
if (!start_canary_alive)
|
||||
{
|
||||
throw util::exception(std::string("Start canary of block corrupted. (") +
|
||||
block_id_to_name[bid] + ")");
|
||||
throw util::exception("Start canary of block corrupted. (" +
|
||||
std::string(block_id_to_name[bid]) + ")" + SOURCE_REF);
|
||||
}
|
||||
if (!end_canary_alive)
|
||||
{
|
||||
throw util::exception(std::string("End canary of block corrupted. (") +
|
||||
block_id_to_name[bid] + ")");
|
||||
throw util::exception("End canary of block corrupted. (" +
|
||||
std::string(block_id_to_name[bid]) + ")" + SOURCE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
return (T *)ptr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -214,7 +231,7 @@ inline std::string regionToString(const SharedDataType region)
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(sizeof(block_id_to_name) / sizeof(*block_id_to_name) == SharedDataLayout::NUM_BLOCKS,
|
||||
static_assert(sizeof(block_id_to_name) / sizeof(*block_id_to_name) == DataLayout::NUM_BLOCKS,
|
||||
"Number of blocks needs to match the number of Block names.");
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user