Compare commits
154 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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)
|
||||
@@ -22,8 +26,15 @@
|
||||
- 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
|
||||
- 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
|
||||
|
||||
+129
-61
@@ -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,45 @@ 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}")
|
||||
|
||||
# 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)
|
||||
@@ -129,6 +138,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 +193,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 +209,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 +275,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 +322,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 +334,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 +416,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 +439,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 +482,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 +527,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 +543,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}
|
||||
@@ -618,9 +662,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 +675,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 +727,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) or [GeoJSON `Point`](http://geojson.org/geojson-spec.html#point) if it is only one coordinate (not wrapped by a GeoJSON feature)|
|
||||
|
||||
- `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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 | | | | |
|
||||
|
||||
@@ -72,16 +72,16 @@ Feature: Turn Lane Guidance
|
||||
Given the node map
|
||||
"""
|
||||
e
|
||||
a b c g
|
||||
d
|
||||
f
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
i h j
|
||||
a - - b.-.- - c-g
|
||||
| ' 'd
|
||||
| f
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
i - - h - - - j
|
||||
"""
|
||||
|
||||
And the ways
|
||||
|
||||
@@ -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 |
|
||||
@@ -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
|
||||
"""
|
||||
@@ -707,11 +724,11 @@ 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 |
|
||||
| waypoints | route | turns |
|
||||
| a,g | road,cross,cross | depart,turn left,arrive |
|
||||
| a,e | road,road,road | depart,continue straight,arrive |
|
||||
# We should discuss whether the next item should be collapsed to depart,turn right,arrive.
|
||||
| a,f | road,road,cross,cross | depart,continue slight right,turn right,arrive |
|
||||
| a,f | road,road,cross,cross | depart,continue straight,turn right,arrive |
|
||||
|
||||
Scenario: On-Off on Highway
|
||||
Given the node map
|
||||
@@ -738,12 +755,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 +772,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 +947,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 +1014,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 |
|
||||
|
||||
@@ -32,9 +32,9 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| 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
|
||||
@@ -63,9 +63,9 @@ Feature: Slipways and Dedicated Turn Lanes
|
||||
| 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,8 +119,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: Inner city expressway with on road
|
||||
Given the node map
|
||||
|
||||
@@ -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
|
||||
@@ -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,road | depart,turn left,arrive | g,e,f |
|
||||
| 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
|
||||
@@ -775,7 +775,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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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)};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
+149
-217
@@ -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"
|
||||
@@ -47,9 +42,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 +64,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,35 +112,35 @@ 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);
|
||||
m_check_sum =
|
||||
*data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::HSGR_CHECKSUM);
|
||||
util::SimpleLogger().Write() << "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))
|
||||
{
|
||||
@@ -158,325 +149,266 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
"Is any data loaded into shared memory?");
|
||||
}
|
||||
|
||||
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 +932,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,94 @@
|
||||
#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())
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::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);
|
||||
|
||||
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
|
||||
@@ -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,
|
||||
|
||||
@@ -233,7 +233,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),
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,6 +44,7 @@ struct ExtractionWay
|
||||
backward_speed = -1;
|
||||
duration = -1;
|
||||
roundabout = false;
|
||||
circular = false;
|
||||
is_startpoint = true;
|
||||
is_access_restricted = false;
|
||||
name.clear();
|
||||
@@ -50,6 +65,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,6 +95,7 @@ struct ExtractionWay
|
||||
std::string turn_lanes_forward;
|
||||
std::string turn_lanes_backward;
|
||||
bool roundabout;
|
||||
bool circular;
|
||||
bool is_access_restricted;
|
||||
bool is_startpoint;
|
||||
TravelMode forward_travel_mode : 4;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#ifndef OSRM_EXTRACTOR_COORDINATE_EXTRACTOR_HPP_
|
||||
#define OSRM_EXTRACTOR_COORDINATE_EXTRACTOR_HPP_
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
namespace osrm
|
||||
@@ -27,24 +29,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 +90,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 +134,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 +147,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 +241,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
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp" // EdgeID
|
||||
@@ -16,16 +17,37 @@ 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 IntersectionShapeData &lhs, const IntersectionShapeData &rhs) {
|
||||
return util::bearing::angleBetweenBearings(base_bearing, lhs.bearing) <
|
||||
util::bearing::angleBetweenBearings(base_bearing, rhs.bearing);
|
||||
};
|
||||
};
|
||||
|
||||
// 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
|
||||
@@ -49,14 +71,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,10 +96,24 @@ 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>
|
||||
using IntersectionShape = std::vector<IntersectionShapeData>;
|
||||
|
||||
struct IntersectionView final : std::vector<IntersectionViewData>
|
||||
{
|
||||
using Base = std::vector<IntersectionViewData>;
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return std::is_sorted(begin(), end(), std::mem_fn(&IntersectionViewData::CompareByAngle));
|
||||
};
|
||||
|
||||
Base::iterator findClosestTurn(double angle);
|
||||
Base::const_iterator findClosestTurn(double angle) const;
|
||||
};
|
||||
|
||||
struct Intersection final : std::vector<ConnectedRoad>
|
||||
{
|
||||
using Base = std::vector<ConnectedRoad>;
|
||||
|
||||
/*
|
||||
* find the turn whose angle offers the least angularDeviation to the specified angle
|
||||
* E.g. for turn angles [0,90,260] and a query of 180 we return the 260 degree turn (difference
|
||||
|
||||
@@ -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,11 +33,20 @@ 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;
|
||||
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
|
||||
*/
|
||||
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
|
||||
@@ -45,68 +54,61 @@ class IntersectionGenerator
|
||||
// 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;
|
||||
IntersectionView GetActualNextIntersection(const NodeID starting_node,
|
||||
const EdgeID via_edge,
|
||||
NodeID *resulting_from_node,
|
||||
EdgeID *resulting_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
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#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_*/
|
||||
@@ -21,9 +21,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
|
||||
@@ -90,7 +87,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 +116,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,11 +133,9 @@ 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,
|
||||
|
||||
@@ -65,7 +65,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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -165,6 +165,7 @@ 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();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#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"
|
||||
@@ -14,6 +15,7 @@
|
||||
#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 +23,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -34,7 +37,6 @@ namespace guidance
|
||||
|
||||
class TurnAnalysis
|
||||
{
|
||||
|
||||
public:
|
||||
TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
@@ -45,19 +47,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;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#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>
|
||||
@@ -22,13 +22,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
|
||||
|
||||
@@ -43,11 +43,12 @@ struct InternalExtractorEdge
|
||||
MIN_OSM_NODEID,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
false, // access restricted
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
guidance::TurnLaneType::empty,
|
||||
@@ -62,6 +63,7 @@ struct InternalExtractorEdge
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
@@ -75,6 +77,7 @@ struct InternalExtractorEdge
|
||||
forward,
|
||||
backward,
|
||||
roundabout,
|
||||
circular,
|
||||
access_restricted,
|
||||
startpoint,
|
||||
travel_mode,
|
||||
@@ -99,11 +102,12 @@ struct InternalExtractorEdge
|
||||
MIN_OSM_NODEID,
|
||||
0,
|
||||
WeightData(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
false, // access restricted
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
INVALID_LANE_DESCRIPTIONID,
|
||||
@@ -115,11 +119,12 @@ struct InternalExtractorEdge
|
||||
MAX_OSM_NODEID,
|
||||
SPECIAL_NODEID,
|
||||
WeightData(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
false, // access restricted
|
||||
true, // can be startpoint
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
false,
|
||||
INVALID_LANE_DESCRIPTIONID,
|
||||
|
||||
@@ -22,6 +22,7 @@ struct NodeBasedEdge
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
@@ -38,6 +39,7 @@ struct NodeBasedEdge
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool roundabout : 1;
|
||||
bool circular : 1;
|
||||
bool access_restricted : 1;
|
||||
bool startpoint : 1;
|
||||
bool is_split : 1;
|
||||
@@ -55,6 +57,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
@@ -70,8 +73,9 @@ 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), access_restricted(false),
|
||||
startpoint(true), is_split(false), travel_mode(false),
|
||||
lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -82,6 +86,7 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
@@ -89,9 +94,10 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
|
||||
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),
|
||||
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))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -119,6 +125,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
@@ -132,6 +139,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
forward,
|
||||
backward,
|
||||
roundabout,
|
||||
circular,
|
||||
access_restricted,
|
||||
startpoint,
|
||||
travel_mode,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+150
-195
@@ -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/fingerprint.hpp"
|
||||
#include "util/simple_logger.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
|
||||
{
|
||||
@@ -20,201 +20,156 @@ 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 std::string filename;
|
||||
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 &filename_, const FingerprintFlag flag)
|
||||
: filename(filename_.string())
|
||||
{
|
||||
input_stream.open(filename_, std::ios::binary);
|
||||
if (!input_stream)
|
||||
throw util::exception("Error opening " + filename + ":" + std::strerror(errno));
|
||||
|
||||
if (flag == VerifyFingerprint && !ReadAndCheckFingerprint())
|
||||
{
|
||||
throw util::exception("Fingerprint mismatch in " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 " + filename +
|
||||
": Unexpected end of file");
|
||||
}
|
||||
throw util::exception("Error reading from " + filename + ": " + std::strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
edges_input_stream.read((char *)&(current_edge_data), sizeof(extractor::OriginalEdgeData));
|
||||
|
||||
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(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)
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
// 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(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/simple_logger.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::SimpleLogger().Write(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
|
||||
@@ -4,9 +4,8 @@
|
||||
#include "util/exception.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -54,7 +53,7 @@ const constexpr char *block_id_to_name[] = {"NAME_OFFSETS",
|
||||
"LANE_DESCRIPTION_OFFSETS",
|
||||
"LANE_DESCRIPTION_MASKS"};
|
||||
|
||||
struct SharedDataLayout
|
||||
struct DataLayout
|
||||
{
|
||||
enum BlockID
|
||||
{
|
||||
@@ -98,21 +97,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,41 +115,62 @@ 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)
|
||||
@@ -169,7 +185,7 @@ struct SharedDataLayout
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
return (T *)ptr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -214,7 +230,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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef STORAGE_HPP
|
||||
#define STORAGE_HPP
|
||||
|
||||
#include "storage/shared_datatype.hpp"
|
||||
#include "storage/storage_config.hpp"
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@@ -52,6 +53,9 @@ class Storage
|
||||
|
||||
ReturnCode Run(int max_wait);
|
||||
|
||||
void PopulateLayout(DataLayout &layout);
|
||||
void PopulateData(const DataLayout &layout, char *memory_ptr);
|
||||
|
||||
private:
|
||||
StorageConfig config;
|
||||
};
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace osrm
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
namespace bearing
|
||||
{
|
||||
|
||||
inline std::string get(const double heading)
|
||||
{
|
||||
BOOST_ASSERT(heading >= 0);
|
||||
@@ -96,8 +96,40 @@ inline double reverseBearing(const double bearing)
|
||||
return bearing - 180.;
|
||||
return bearing + 180;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the angle between two bearings on a normal turn circle
|
||||
//
|
||||
// Bearings Angles
|
||||
//
|
||||
// 0 180
|
||||
// 315 45 225 135
|
||||
//
|
||||
// 270 x 90 270 x 90
|
||||
//
|
||||
// 225 135 315 45
|
||||
// 180 0
|
||||
//
|
||||
// A turn from north to north-east offerst bearing 0 and 45 has to be translated
|
||||
// into a turn of 135 degrees. The same holdes for 90 - 135 (east to south
|
||||
// east).
|
||||
// For north, the transformation works by angle = 540 (360 + 180) - exit_bearing
|
||||
// % 360;
|
||||
// All other cases are handled by first rotating both bearings to an
|
||||
// entry_bearing of 0.
|
||||
inline double angleBetweenBearings(const double entry_bearing, const double exit_bearing)
|
||||
{
|
||||
const double offset = 360 - entry_bearing;
|
||||
const double rotated_exit = [](double bearing, const double offset) {
|
||||
bearing += offset;
|
||||
return bearing > 360 ? bearing - 360 : bearing;
|
||||
}(exit_bearing, offset);
|
||||
|
||||
const auto angle = 540 - rotated_exit;
|
||||
return angle >= 360 ? angle - 360 : angle;
|
||||
}
|
||||
|
||||
} // namespace bearing
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
|
||||
#endif // BEARING_HPP
|
||||
|
||||
@@ -25,8 +25,8 @@ inline void print(const engine::guidance::RouteStep &step)
|
||||
{
|
||||
std::cout << static_cast<int>(step.maneuver.instruction.type) << " "
|
||||
<< static_cast<int>(step.maneuver.instruction.direction_modifier) << " "
|
||||
<< static_cast<int>(step.maneuver.waypoint_type) << " "
|
||||
<< step.maneuver.location << " "
|
||||
<< static_cast<int>(step.maneuver.waypoint_type) << " " << step.maneuver.location
|
||||
<< " "
|
||||
<< " Duration: " << step.duration << " Distance: " << step.distance
|
||||
<< " Geometry: " << step.geometry_begin << " " << step.geometry_end
|
||||
<< "\n\tIntersections: " << step.intersections.size() << " [";
|
||||
@@ -44,7 +44,8 @@ inline void print(const engine::guidance::RouteStep &step)
|
||||
std::cout << " " << (entry ? "true" : "false");
|
||||
std::cout << ")";
|
||||
}
|
||||
std::cout << "] name[" << step.name_id << "]: " << step.name << " Ref: " << step.ref << " Pronunciation: " << step.pronunciation;
|
||||
std::cout << "] name[" << step.name_id << "]: " << step.name << " Ref: " << step.ref
|
||||
<< " Pronunciation: " << step.pronunciation;
|
||||
}
|
||||
|
||||
inline void print(const std::vector<engine::guidance::RouteStep> &steps)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "extractor/node_based_edge.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "storage/io.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/fingerprint.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
@@ -20,6 +21,7 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
@@ -32,25 +34,14 @@ namespace util
|
||||
* The since the restrictions reference nodes using their external node id,
|
||||
* we need to renumber it to the new internal id.
|
||||
*/
|
||||
unsigned loadRestrictionsFromFile(std::istream &input_stream,
|
||||
std::vector<extractor::TurnRestriction> &restriction_list)
|
||||
inline unsigned loadRestrictionsFromFile(storage::io::FileReader &file_reader,
|
||||
std::vector<extractor::TurnRestriction> &restriction_list)
|
||||
{
|
||||
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
|
||||
FingerPrint fingerprint_loaded;
|
||||
unsigned number_of_usable_restrictions = 0;
|
||||
input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
|
||||
if (!fingerprint_loaded.TestContractor(fingerprint_valid))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
input_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
|
||||
unsigned number_of_usable_restrictions = file_reader.ReadElementCount32();
|
||||
restriction_list.resize(number_of_usable_restrictions);
|
||||
if (number_of_usable_restrictions > 0)
|
||||
{
|
||||
input_stream.read((char *)restriction_list.data(),
|
||||
number_of_usable_restrictions * sizeof(extractor::TurnRestriction));
|
||||
file_reader.ReadInto(restriction_list.data(), number_of_usable_restrictions);
|
||||
}
|
||||
|
||||
return number_of_usable_restrictions;
|
||||
@@ -58,64 +49,59 @@ unsigned loadRestrictionsFromFile(std::istream &input_stream,
|
||||
|
||||
/**
|
||||
* Reads the beginning of an .osrm file and produces:
|
||||
* - list of barrier nodes
|
||||
* - list of traffic lights
|
||||
* - barrier nodes
|
||||
* - traffic lights
|
||||
* - nodes indexed by their internal (non-osm) id
|
||||
*/
|
||||
NodeID loadNodesFromFile(std::istream &input_stream,
|
||||
std::vector<NodeID> &barrier_node_list,
|
||||
std::vector<NodeID> &traffic_light_node_list,
|
||||
template <typename BarrierOutIter, typename TrafficSignalsOutIter>
|
||||
NodeID loadNodesFromFile(storage::io::FileReader &file_reader,
|
||||
BarrierOutIter barriers,
|
||||
TrafficSignalsOutIter traffic_signals,
|
||||
std::vector<extractor::QueryNode> &node_array)
|
||||
{
|
||||
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
|
||||
FingerPrint fingerprint_loaded;
|
||||
input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
|
||||
NodeID number_of_nodes = file_reader.ReadElementCount32();
|
||||
SimpleLogger().Write() << "Importing number_of_nodes new = " << number_of_nodes << " nodes ";
|
||||
|
||||
if (!fingerprint_loaded.TestContractor(fingerprint_valid))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
NodeID n;
|
||||
input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
|
||||
SimpleLogger().Write() << "Importing n = " << n << " nodes ";
|
||||
node_array.resize(number_of_nodes);
|
||||
|
||||
extractor::ExternalMemoryNode current_node;
|
||||
for (NodeID i = 0; i < n; ++i)
|
||||
for (NodeID i = 0; i < number_of_nodes; ++i)
|
||||
{
|
||||
input_stream.read(reinterpret_cast<char *>(¤t_node),
|
||||
sizeof(extractor::ExternalMemoryNode));
|
||||
node_array.emplace_back(current_node.lon, current_node.lat, current_node.node_id);
|
||||
file_reader.ReadInto(¤t_node, 1);
|
||||
|
||||
node_array[i].lon = current_node.lon;
|
||||
node_array[i].lat = current_node.lat;
|
||||
node_array[i].node_id = current_node.node_id;
|
||||
|
||||
if (current_node.barrier)
|
||||
{
|
||||
barrier_node_list.emplace_back(i);
|
||||
*barriers = i;
|
||||
++barriers;
|
||||
}
|
||||
|
||||
if (current_node.traffic_lights)
|
||||
{
|
||||
traffic_light_node_list.emplace_back(i);
|
||||
*traffic_signals = i;
|
||||
++traffic_signals;
|
||||
}
|
||||
}
|
||||
|
||||
// tighten vector sizes
|
||||
barrier_node_list.shrink_to_fit();
|
||||
traffic_light_node_list.shrink_to_fit();
|
||||
|
||||
return n;
|
||||
return number_of_nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a .osrm file and produces the edges.
|
||||
*/
|
||||
NodeID loadEdgesFromFile(std::istream &input_stream,
|
||||
std::vector<extractor::NodeBasedEdge> &edge_list)
|
||||
inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
|
||||
std::vector<extractor::NodeBasedEdge> &edge_list)
|
||||
{
|
||||
EdgeID m;
|
||||
input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
|
||||
edge_list.resize(m);
|
||||
SimpleLogger().Write() << " and " << m << " edges ";
|
||||
EdgeID number_of_edges = file_reader.ReadElementCount32();
|
||||
BOOST_ASSERT(sizeof(EdgeID) == sizeof(number_of_edges));
|
||||
|
||||
input_stream.read((char *)edge_list.data(), m * sizeof(extractor::NodeBasedEdge));
|
||||
edge_list.resize(number_of_edges);
|
||||
SimpleLogger().Write() << " and " << number_of_edges << " edges ";
|
||||
|
||||
file_reader.ReadInto(edge_list.data(), number_of_edges);
|
||||
|
||||
BOOST_ASSERT(edge_list.size() > 0);
|
||||
|
||||
@@ -145,7 +131,7 @@ NodeID loadEdgesFromFile(std::istream &input_stream,
|
||||
|
||||
SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
|
||||
|
||||
return m;
|
||||
return number_of_edges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace guidance
|
||||
class BearingClass
|
||||
{
|
||||
public:
|
||||
BearingClass();
|
||||
|
||||
// Add a bearing to the set
|
||||
void add(const DiscreteBearing bearing);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <bitset>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
/* A set of tools required for guidance in both pre and post-processing */
|
||||
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
@@ -50,11 +51,11 @@ inline extractor::guidance::DirectionModifier::Enum getTurnDirection(const doubl
|
||||
return extractor::guidance::DirectionModifier::SharpRight;
|
||||
if (angle >= 60 && angle < 140)
|
||||
return extractor::guidance::DirectionModifier::Right;
|
||||
if (angle >= 140 && angle < 170)
|
||||
if (angle >= 140 && angle < 160)
|
||||
return extractor::guidance::DirectionModifier::SlightRight;
|
||||
if (angle >= 165 && angle <= 195)
|
||||
if (angle >= 160 && angle <= 200)
|
||||
return extractor::guidance::DirectionModifier::Straight;
|
||||
if (angle > 190 && angle <= 220)
|
||||
if (angle > 200 && angle <= 220)
|
||||
return extractor::guidance::DirectionModifier::SlightLeft;
|
||||
if (angle > 220 && angle <= 300)
|
||||
return extractor::guidance::DirectionModifier::Left;
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace util
|
||||
namespace guidance
|
||||
{
|
||||
class LaneTuple;
|
||||
class LaneTupleIdPair;
|
||||
} // namespace guidance
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
@@ -27,6 +28,11 @@ template <> struct hash<::osrm::util::guidance::LaneTuple>
|
||||
{
|
||||
inline std::size_t operator()(const ::osrm::util::guidance::LaneTuple &bearing_class) const;
|
||||
};
|
||||
template <> struct hash<::osrm::util::guidance::LaneTupleIdPair>
|
||||
{
|
||||
inline std::size_t
|
||||
operator()(const ::osrm::util::guidance::LaneTupleIdPair &bearing_class) const;
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace osrm
|
||||
@@ -73,7 +79,23 @@ class LaneTuple
|
||||
}
|
||||
};
|
||||
|
||||
using LaneTupleIdPair = std::pair<util::guidance::LaneTuple, LaneDescriptionID>;
|
||||
class LaneTupleIdPair
|
||||
{
|
||||
public:
|
||||
util::guidance::LaneTuple first;
|
||||
LaneDescriptionID second;
|
||||
|
||||
bool operator==(const LaneTupleIdPair &other) const;
|
||||
|
||||
friend std::size_t hash_value(const LaneTupleIdPair &pair)
|
||||
{
|
||||
std::size_t seed{0};
|
||||
boost::hash_combine(seed, pair.first);
|
||||
boost::hash_combine(seed, pair.second);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "osrm/coordinate.hpp"
|
||||
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
|
||||
namespace osrm
|
||||
@@ -10,8 +11,64 @@ namespace osrm
|
||||
namespace util
|
||||
{
|
||||
|
||||
// Transform x and y to Hilbert SFC linear coordinate
|
||||
// using N most significant bits of x and y.
|
||||
// References:
|
||||
// [1] Arndt, Jörg. Matters Computational Ideas, Algorithms, Source Code, 2010. 1.31.1 The Hilbert
|
||||
// curve p. 86
|
||||
// [2] FSM implementation from http://www.hackersdelight.org/hdcodetxt/hilbert/hil_s_from_xy.c.txt
|
||||
// The method is to employ the following state transition table:
|
||||
// ----------------------------------------------------------
|
||||
// If the current And the next bits then append and enter
|
||||
// state is of x and y are to result state
|
||||
// ----------------------------------------------------------
|
||||
// A (0, 0) 00 B
|
||||
// A (0, 1) 01 A
|
||||
// A (1, 0) 11 D
|
||||
// A (1, 1) 10 A
|
||||
// B (0, 0) 00 A
|
||||
// B (0, 1) 11 C
|
||||
// B (1, 0) 01 B
|
||||
// B (1, 1) 10 B
|
||||
// C (0, 0) 10 D
|
||||
// C (0, 1) 11 B
|
||||
// C (1, 0) 01 C
|
||||
// C (1, 1) 00 D
|
||||
// D (0, 0) 10 C
|
||||
// D (0, 1) 01 D
|
||||
// D (1, 0) 11 A
|
||||
// D (1, 1) 00 C
|
||||
template <int N = 32, typename T = std::uint32_t, typename R = std::uint64_t>
|
||||
inline R HilbertToLinear(T x, T y)
|
||||
{
|
||||
static_assert(N <= sizeof(T) * CHAR_BIT, "input type is smaller than N");
|
||||
static_assert(2 * N <= sizeof(R) * CHAR_BIT, "output type is smaller than 2N");
|
||||
|
||||
R result = 0;
|
||||
unsigned state = 0;
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
const unsigned xi = (x >> (sizeof(T) * CHAR_BIT - 1)) & 1;
|
||||
const unsigned yi = (y >> (sizeof(T) * CHAR_BIT - 1)) & 1;
|
||||
x <<= 1;
|
||||
y <<= 1;
|
||||
|
||||
const unsigned row = 4 * state | 2 * xi | yi;
|
||||
result = (result << 2) | ((0x361E9CB4 >> 2 * row) & 3);
|
||||
state = (0x8FE65831 >> 2 * row) & 3;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Computes a 64 bit value that corresponds to the hilbert space filling curve
|
||||
std::uint64_t hilbertCode(const Coordinate coordinate);
|
||||
inline std::uint64_t GetHilbertCode(const Coordinate &coordinate)
|
||||
{
|
||||
const std::uint32_t x = static_cast<std::int32_t>(coordinate.lon) +
|
||||
static_cast<std::int32_t>(180 * COORDINATE_PRECISION);
|
||||
const std::uint32_t y = static_cast<std::int32_t>(coordinate.lat) +
|
||||
static_cast<std::int32_t>(90 * COORDINATE_PRECISION);
|
||||
return HilbertToLinear(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-82
@@ -14,6 +14,7 @@
|
||||
#include <stxxl/vector>
|
||||
#include <vector>
|
||||
|
||||
#include "storage/io.hpp"
|
||||
#include "util/fingerprint.hpp"
|
||||
|
||||
namespace osrm
|
||||
@@ -28,31 +29,6 @@ inline bool writeFingerprint(std::ostream &stream)
|
||||
return static_cast<bool>(stream);
|
||||
}
|
||||
|
||||
inline bool readAndCheckFingerprint(std::istream &stream)
|
||||
{
|
||||
FingerPrint fingerprint;
|
||||
const auto valid = FingerPrint::GetValid();
|
||||
stream.read(reinterpret_cast<char *>(&fingerprint), sizeof(fingerprint));
|
||||
// compare the compilation state stored in the fingerprint
|
||||
return static_cast<bool>(stream) && valid.IsMagicNumberOK(fingerprint) &&
|
||||
valid.TestContractor(fingerprint) && valid.TestGraphUtil(fingerprint) &&
|
||||
valid.TestRTree(fingerprint) && valid.TestQueryObjects(fingerprint);
|
||||
}
|
||||
|
||||
template <typename simple_type>
|
||||
bool serializeVector(const std::string &filename, const std::vector<simple_type> &data)
|
||||
{
|
||||
std::ofstream stream(filename, std::ios::binary);
|
||||
|
||||
writeFingerprint(stream);
|
||||
|
||||
std::uint64_t count = data.size();
|
||||
stream.write(reinterpret_cast<const char *>(&count), sizeof(count));
|
||||
if (!data.empty())
|
||||
stream.write(reinterpret_cast<const char *>(&data[0]), sizeof(simple_type) * count);
|
||||
return static_cast<bool>(stream);
|
||||
}
|
||||
|
||||
template <typename simple_type>
|
||||
bool serializeVector(std::ostream &stream, const std::vector<simple_type> &data)
|
||||
{
|
||||
@@ -64,30 +40,13 @@ bool serializeVector(std::ostream &stream, const std::vector<simple_type> &data)
|
||||
}
|
||||
|
||||
template <typename simple_type>
|
||||
bool deserializeVector(const std::string &filename, std::vector<simple_type> &data)
|
||||
bool serializeVector(const std::string &filename, const std::vector<simple_type> &data)
|
||||
{
|
||||
std::ifstream stream(filename, std::ios::binary);
|
||||
std::ofstream stream(filename, std::ios::binary);
|
||||
|
||||
if (!readAndCheckFingerprint(stream))
|
||||
return false;
|
||||
writeFingerprint(stream);
|
||||
|
||||
std::uint64_t count = 0;
|
||||
stream.read(reinterpret_cast<char *>(&count), sizeof(count));
|
||||
data.resize(count);
|
||||
if (count)
|
||||
stream.read(reinterpret_cast<char *>(&data[0]), sizeof(simple_type) * count);
|
||||
return static_cast<bool>(stream);
|
||||
}
|
||||
|
||||
template <typename simple_type>
|
||||
bool deserializeVector(std::istream &stream, std::vector<simple_type> &data)
|
||||
{
|
||||
std::uint64_t count = 0;
|
||||
stream.read(reinterpret_cast<char *>(&count), sizeof(count));
|
||||
data.resize(count);
|
||||
if (count)
|
||||
stream.read(reinterpret_cast<char *>(&data[0]), sizeof(simple_type) * count);
|
||||
return static_cast<bool>(stream);
|
||||
return serializeVector(stream, data);
|
||||
}
|
||||
|
||||
// serializes a vector of vectors into an adjacency array (creates a copy of the data internally)
|
||||
@@ -149,23 +108,20 @@ bool serializeVector(std::ofstream &out_stream, const stxxl::vector<simple_type>
|
||||
}
|
||||
|
||||
template <typename simple_type>
|
||||
bool deserializeAdjacencyArray(const std::string &filename,
|
||||
void deserializeAdjacencyArray(const std::string &filename,
|
||||
std::vector<std::uint32_t> &offsets,
|
||||
std::vector<simple_type> &data)
|
||||
{
|
||||
std::ifstream in_stream(filename, std::ios::binary);
|
||||
storage::io::FileReader file(filename, storage::io::FileReader::HasNoFingerprint);
|
||||
|
||||
if (!deserializeVector(in_stream, offsets))
|
||||
return false;
|
||||
|
||||
if (!deserializeVector(in_stream, data))
|
||||
return false;
|
||||
file.DeserializeVector(offsets);
|
||||
file.DeserializeVector(data);
|
||||
|
||||
// offsets have to match up with the size of the data
|
||||
if (offsets.empty() || (offsets.back() != boost::numeric_cast<std::uint32_t>(data.size())))
|
||||
return false;
|
||||
|
||||
return static_cast<bool>(in_stream);
|
||||
throw util::exception("Error in " + filename + (offsets.empty()
|
||||
? "Offsets are empty"
|
||||
: "Offset and data size do not match"));
|
||||
}
|
||||
|
||||
inline bool serializeFlags(const boost::filesystem::path &path, const std::vector<bool> &flags)
|
||||
@@ -196,32 +152,6 @@ inline bool serializeFlags(const boost::filesystem::path &path, const std::vecto
|
||||
return static_cast<bool>(flag_stream);
|
||||
}
|
||||
|
||||
inline bool deserializeFlags(const boost::filesystem::path &path, std::vector<bool> &flags)
|
||||
{
|
||||
SimpleLogger().Write() << "Reading flags from " << path;
|
||||
std::ifstream flag_stream(path.string(), std::ios::binary);
|
||||
|
||||
if (!readAndCheckFingerprint(flag_stream))
|
||||
return false;
|
||||
|
||||
std::uint32_t number_of_bits;
|
||||
flag_stream.read(reinterpret_cast<char *>(&number_of_bits), sizeof(number_of_bits));
|
||||
flags.resize(number_of_bits);
|
||||
// putting bits in ints
|
||||
std::uint32_t chunks = (number_of_bits + 31) / 32;
|
||||
std::size_t bit_position = 0;
|
||||
std::uint32_t chunk;
|
||||
for (std::size_t chunk_id = 0; chunk_id < chunks; ++chunk_id)
|
||||
{
|
||||
flag_stream.read(reinterpret_cast<char *>(&chunk), sizeof(chunk));
|
||||
std::bitset<32> chunk_bits(chunk);
|
||||
for (std::size_t bit = 0; bit < 32 && bit_position < number_of_bits; ++bit, ++bit_position)
|
||||
flags[bit_position] = chunk_bits[bit];
|
||||
}
|
||||
SimpleLogger().Write() << "Read " << number_of_bits << " bits in " << chunks
|
||||
<< " Chunks from disk.";
|
||||
return static_cast<bool>(flag_stream);
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef ISATTY_HPP
|
||||
#define ISATTY_HPP
|
||||
|
||||
// For isatty()
|
||||
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#define isatty _isatty
|
||||
#define fileno _fileno
|
||||
#else
|
||||
#error Unknown platform - isatty implementation required
|
||||
#endif // win32
|
||||
#endif // unix
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
// Returns true if stdout is a tty, false otherwise
|
||||
// Useful for when you want to do something different when
|
||||
// output is redirected to a logfile
|
||||
inline bool IsStdoutATTY() { return isatty(fileno(stdout)); }
|
||||
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
|
||||
#endif
|
||||
@@ -18,7 +18,7 @@ class NameTable
|
||||
{
|
||||
private:
|
||||
// FIXME should this use shared memory
|
||||
RangeTable<16, false> m_name_table;
|
||||
util::RangeTable<16, false> m_name_table;
|
||||
ShM<char, false>::vector m_names_char_list;
|
||||
|
||||
public:
|
||||
|
||||
@@ -20,7 +20,7 @@ struct NodeBasedEdgeData
|
||||
NodeBasedEdgeData()
|
||||
: distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
|
||||
name_id(std::numeric_limits<unsigned>::max()), access_restricted(false), reversed(false),
|
||||
roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE),
|
||||
roundabout(false), circular(false), travel_mode(TRAVEL_MODE_INACCESSIBLE),
|
||||
lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
{
|
||||
}
|
||||
@@ -31,12 +31,14 @@ struct NodeBasedEdgeData
|
||||
bool access_restricted,
|
||||
bool reversed,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
extractor::TravelMode travel_mode,
|
||||
const LaneDescriptionID lane_description_id)
|
||||
: distance(distance), edge_id(edge_id), name_id(name_id),
|
||||
access_restricted(access_restricted), reversed(reversed), roundabout(roundabout),
|
||||
startpoint(startpoint), travel_mode(travel_mode), lane_description_id(lane_description_id)
|
||||
circular(circular), startpoint(startpoint), travel_mode(travel_mode),
|
||||
lane_description_id(lane_description_id)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -46,6 +48,7 @@ struct NodeBasedEdgeData
|
||||
bool access_restricted : 1;
|
||||
bool reversed : 1;
|
||||
bool roundabout : 1;
|
||||
bool circular : 1;
|
||||
bool startpoint : 1;
|
||||
extractor::TravelMode travel_mode : 4;
|
||||
LaneDescriptionID lane_description_id;
|
||||
@@ -54,7 +57,8 @@ struct NodeBasedEdgeData
|
||||
bool IsCompatibleTo(const NodeBasedEdgeData &other) const
|
||||
{
|
||||
return (reversed == other.reversed) && (roundabout == other.roundabout) &&
|
||||
(startpoint == other.startpoint) && (access_restricted == other.access_restricted) &&
|
||||
(circular == other.circular) && (startpoint == other.startpoint) &&
|
||||
(access_restricted == other.access_restricted) &&
|
||||
(travel_mode == other.travel_mode) &&
|
||||
(road_classification == other.road_classification);
|
||||
}
|
||||
@@ -82,6 +86,7 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
|
||||
BOOST_ASSERT(output_edge.data.distance > 0);
|
||||
|
||||
output_edge.data.roundabout = input_edge.roundabout;
|
||||
output_edge.data.circular = input_edge.circular;
|
||||
output_edge.data.name_id = input_edge.name_id;
|
||||
output_edge.data.access_restricted = input_edge.access_restricted;
|
||||
output_edge.data.travel_mode = input_edge.travel_mode;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
|
||||
#include "util/isatty.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace util
|
||||
@@ -71,6 +73,12 @@ class Percent
|
||||
{
|
||||
std::cout << ".";
|
||||
}
|
||||
|
||||
// When not on a TTY, print newlines after each progress indicator so
|
||||
// so that progress is visible to line-buffered logging systems
|
||||
if (!IsStdoutATTY())
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef RANGE_TABLE_HPP
|
||||
#define RANGE_TABLE_HPP
|
||||
|
||||
#include "storage/io.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/shared_memory_vector_wrapper.hpp"
|
||||
|
||||
@@ -138,6 +139,21 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
|
||||
sum_lengths = lengths_prefix_sum;
|
||||
}
|
||||
|
||||
void ReadARangeTable(osrm::storage::io::FileReader &filereader)
|
||||
{
|
||||
unsigned number_of_blocks = filereader.ReadElementCount32();
|
||||
// read total length
|
||||
filereader.ReadInto(&sum_lengths, 1);
|
||||
|
||||
block_offsets.resize(number_of_blocks);
|
||||
diff_blocks.resize(number_of_blocks);
|
||||
|
||||
// read block offsets
|
||||
filereader.ReadInto(block_offsets.data(), number_of_blocks);
|
||||
// read blocks
|
||||
filereader.ReadInto(diff_blocks.data(), number_of_blocks);
|
||||
}
|
||||
|
||||
inline RangeT GetRange(const unsigned id) const
|
||||
{
|
||||
BOOST_ASSERT(id < block_offsets.size() + diff_blocks.size() * BLOCK_SIZE);
|
||||
|
||||
@@ -198,7 +198,7 @@ class StaticRTree
|
||||
COORDINATE_PRECISION *
|
||||
web_mercator::latToY(toFloating(current_centroid.lat)))};
|
||||
|
||||
current_wrapper.m_hilbert_value = hilbertCode(current_centroid);
|
||||
current_wrapper.m_hilbert_value = GetHilbertCode(current_centroid);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -346,21 +346,13 @@ class StaticRTree
|
||||
const CoordinateListT &coordinate_list)
|
||||
: m_coordinate_list(coordinate_list)
|
||||
{
|
||||
// open tree node file and load into RAM.
|
||||
if (!boost::filesystem::exists(node_file))
|
||||
{
|
||||
throw exception("ram index file does not exist");
|
||||
}
|
||||
if (boost::filesystem::file_size(node_file) == 0)
|
||||
{
|
||||
throw exception("ram index file is empty");
|
||||
}
|
||||
boost::filesystem::ifstream tree_node_file(node_file, std::ios::binary);
|
||||
storage::io::FileReader tree_node_file(node_file,
|
||||
storage::io::FileReader::HasNoFingerprint);
|
||||
|
||||
const auto tree_size = storage::io::readElementCount(tree_node_file);
|
||||
const auto tree_size = tree_node_file.ReadElementCount64();
|
||||
|
||||
m_search_tree.resize(tree_size);
|
||||
storage::io::readRamIndex(tree_node_file, &m_search_tree[0], tree_size);
|
||||
tree_node_file.ReadInto(&m_search_tree[0], tree_size);
|
||||
|
||||
MapLeafNodesFile(leaf_file);
|
||||
}
|
||||
|
||||
+9
-1
@@ -17,11 +17,18 @@
|
||||
"bin": {
|
||||
"cucumber": "./node_modules/cucumber/bin/cucumber.js"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
"babelify",
|
||||
"brfs"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint -c ./.eslintrc features/step_definitions/ features/support/",
|
||||
"test": "npm run lint && ./node_modules/cucumber/bin/cucumber.js features/ -p verify",
|
||||
"clean-test": "rm -rf test/cache",
|
||||
"cucumber": "./node_modules/cucumber/bin/cucumber.js"
|
||||
"cucumber": "./node_modules/cucumber/bin/cucumber.js",
|
||||
"build-api-docs": "./scripts/build_api_docs.sh"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -37,6 +44,7 @@
|
||||
"node": ">=4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"docbox": "^1.0.2",
|
||||
"eslint": "^2.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,9 +221,12 @@ function way_function (way, result)
|
||||
end
|
||||
|
||||
-- roundabout handling
|
||||
if junction and "roundabout" == junction then
|
||||
if junction and ("roundabout" == junction) then
|
||||
result.roundabout = true
|
||||
end
|
||||
if junction and ("circular" == junction) then
|
||||
result.circular = true;
|
||||
end
|
||||
|
||||
-- speed
|
||||
local bridge_speed = bridge_speeds[bridge]
|
||||
@@ -281,7 +284,7 @@ function way_function (way, result)
|
||||
else
|
||||
-- biking not allowed, maybe we can push our bike?
|
||||
-- essentially requires pedestrian profiling, for example foot=no mean we can't push a bike
|
||||
if foot ~= 'no' and junction ~= "roundabout" then
|
||||
if foot ~= 'no' and (junction ~= "roundabout" and junction ~= "circular") then
|
||||
if pedestrian_speeds[highway] then
|
||||
-- pedestrian-only ways and areas
|
||||
result.forward_speed = pedestrian_speeds[highway]
|
||||
@@ -313,7 +316,7 @@ function way_function (way, result)
|
||||
|
||||
-- direction
|
||||
local impliedOneway = false
|
||||
if junction == "roundabout" or highway == "motorway" then
|
||||
if junction == "roundabout" or junction == "circular" or highway == "motorway" then
|
||||
impliedOneway = true
|
||||
end
|
||||
|
||||
@@ -353,7 +356,7 @@ function way_function (way, result)
|
||||
|
||||
-- pushing bikes
|
||||
if bicycle_speeds[highway] or pedestrian_speeds[highway] then
|
||||
if foot ~= "no" and junction ~= "roundabout" then
|
||||
if foot ~= "no" and junction ~= "roundabout" and junction ~= "circular" then
|
||||
if result.backward_mode == mode.inaccessible then
|
||||
result.backward_speed = walking_speed
|
||||
result.backward_mode = mode.pushing_bike
|
||||
|
||||
+402
-223
@@ -3,48 +3,100 @@ local find_access_tag = require("lib/access").find_access_tag
|
||||
local get_destination = require("lib/destination").get_destination
|
||||
local set_classification = require("lib/guidance").set_classification
|
||||
local get_turn_lanes = require("lib/guidance").get_turn_lanes
|
||||
local Set = require('lib/set')
|
||||
local Sequence = require('lib/sequence')
|
||||
|
||||
-- Begin of globals
|
||||
barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["checkpoint"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["lift_gate"] = true, ["no"] = true, ["entrance"] = true }
|
||||
access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true, ["destination"] = true }
|
||||
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["emergency"] = true, ["psv"] = true, ["delivery"] = true }
|
||||
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
|
||||
access_tags_hierarchy = { "motorcar", "motor_vehicle", "vehicle", "access" }
|
||||
service_tag_restricted = { ["parking_aisle"] = true, ["parking"] = true }
|
||||
service_tag_forbidden = { ["emergency_access"] = true }
|
||||
restrictions = { "motorcar", "motor_vehicle", "vehicle" }
|
||||
barrier_whitelist = Set {
|
||||
'cattle_grid',
|
||||
'border_control',
|
||||
'checkpoint',
|
||||
'toll_booth',
|
||||
'sally_port',
|
||||
'gate',
|
||||
'lift_gate',
|
||||
'no',
|
||||
'entrance'
|
||||
}
|
||||
|
||||
access_tag_whitelist = Set {
|
||||
'yes',
|
||||
'motorcar',
|
||||
'motor_vehicle',
|
||||
'vehicle',
|
||||
'permissive',
|
||||
'designated',
|
||||
'destination'
|
||||
}
|
||||
|
||||
access_tag_blacklist = Set {
|
||||
'no',
|
||||
'private',
|
||||
'agricultural',
|
||||
'forestry',
|
||||
'emergency',
|
||||
'psv',
|
||||
'delivery'
|
||||
}
|
||||
|
||||
access_tag_restricted = Set {
|
||||
'destination',
|
||||
'delivery'
|
||||
}
|
||||
|
||||
access_tags_hierarchy = Sequence {
|
||||
'motorcar',
|
||||
'motor_vehicle',
|
||||
'vehicle',
|
||||
'access'
|
||||
}
|
||||
|
||||
service_tag_restricted = Set {
|
||||
'parking_aisle',
|
||||
'parking'
|
||||
}
|
||||
|
||||
service_tag_forbidden = Set {
|
||||
'emergency_access'
|
||||
}
|
||||
|
||||
restrictions = Sequence {
|
||||
'motorcar', "motor_vehicle", "vehicle" }
|
||||
|
||||
-- A list of suffixes to suppress in name change instructions
|
||||
suffix_list = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "North", "South", "West", "East" }
|
||||
-- Note: a Set does not work here because it's read from C++
|
||||
suffix_list = {
|
||||
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East'
|
||||
}
|
||||
|
||||
speed_profile = {
|
||||
["motorway"] = 90,
|
||||
["motorway_link"] = 45,
|
||||
["trunk"] = 85,
|
||||
["trunk_link"] = 40,
|
||||
["primary"] = 65,
|
||||
["primary_link"] = 30,
|
||||
["secondary"] = 55,
|
||||
["secondary_link"] = 25,
|
||||
["tertiary"] = 40,
|
||||
["tertiary_link"] = 20,
|
||||
["unclassified"] = 25,
|
||||
["residential"] = 25,
|
||||
["living_street"] = 10,
|
||||
["service"] = 15,
|
||||
-- ["track"] = 5,
|
||||
["ferry"] = 5,
|
||||
["movable"] = 5,
|
||||
["shuttle_train"] = 10,
|
||||
["default"] = 10
|
||||
motorway = 90,
|
||||
motorway_link = 45,
|
||||
trunk = 85,
|
||||
trunk_link = 40,
|
||||
primary = 65,
|
||||
primary_link = 30,
|
||||
secondary = 55,
|
||||
secondary_link = 25,
|
||||
tertiary = 40,
|
||||
tertiary_link = 20,
|
||||
unclassified = 25,
|
||||
residential = 25,
|
||||
living_street = 10,
|
||||
service = 15,
|
||||
--track = 5,
|
||||
ferry = 5,
|
||||
movable = 5,
|
||||
shuttle_train = 10,
|
||||
default = 10
|
||||
}
|
||||
|
||||
-- service speeds
|
||||
service_speeds = {
|
||||
["alley"] = 5,
|
||||
["parking"] = 5,
|
||||
["parking_aisle"] = 5,
|
||||
["driveway"] = 5,
|
||||
alley = 5,
|
||||
parking = 5,
|
||||
parking_aisle = 5,
|
||||
driveway = 5,
|
||||
["drive-through"] = 5
|
||||
}
|
||||
|
||||
@@ -53,67 +105,67 @@ service_speeds = {
|
||||
|
||||
-- max speed for surfaces
|
||||
surface_speeds = {
|
||||
["asphalt"] = nil, -- nil mean no limit. removing the line has the same effect
|
||||
["concrete"] = nil,
|
||||
asphalt = nil, -- nil mean no limit. removing the line has the same effect
|
||||
concrete = nil,
|
||||
["concrete:plates"] = nil,
|
||||
["concrete:lanes"] = nil,
|
||||
["paved"] = nil,
|
||||
paved = nil,
|
||||
|
||||
["cement"] = 80,
|
||||
["compacted"] = 80,
|
||||
["fine_gravel"] = 80,
|
||||
cement = 80,
|
||||
compacted = 80,
|
||||
fine_gravel = 80,
|
||||
|
||||
["paving_stones"] = 60,
|
||||
["metal"] = 60,
|
||||
["bricks"] = 60,
|
||||
paving_stones = 60,
|
||||
metal = 60,
|
||||
bricks = 60,
|
||||
|
||||
["grass"] = 40,
|
||||
["wood"] = 40,
|
||||
["sett"] = 40,
|
||||
["grass_paver"] = 40,
|
||||
["gravel"] = 40,
|
||||
["unpaved"] = 40,
|
||||
["ground"] = 40,
|
||||
["dirt"] = 40,
|
||||
["pebblestone"] = 40,
|
||||
["tartan"] = 40,
|
||||
grass = 40,
|
||||
wood = 40,
|
||||
sett = 40,
|
||||
grass_paver = 40,
|
||||
gravel = 40,
|
||||
unpaved = 40,
|
||||
ground = 40,
|
||||
dirt = 40,
|
||||
pebblestone = 40,
|
||||
tartan = 40,
|
||||
|
||||
["cobblestone"] = 30,
|
||||
["clay"] = 30,
|
||||
cobblestone = 30,
|
||||
clay = 30,
|
||||
|
||||
["earth"] = 20,
|
||||
["stone"] = 20,
|
||||
["rocky"] = 20,
|
||||
["sand"] = 20,
|
||||
earth = 20,
|
||||
stone = 20,
|
||||
rocky = 20,
|
||||
sand = 20,
|
||||
|
||||
["mud"] = 10
|
||||
mud = 10
|
||||
}
|
||||
|
||||
-- max speed for tracktypes
|
||||
tracktype_speeds = {
|
||||
["grade1"] = 60,
|
||||
["grade2"] = 40,
|
||||
["grade3"] = 30,
|
||||
["grade4"] = 25,
|
||||
["grade5"] = 20
|
||||
grade1 = 60,
|
||||
grade2 = 40,
|
||||
grade3 = 30,
|
||||
grade4 = 25,
|
||||
grade5 = 20
|
||||
}
|
||||
|
||||
-- max speed for smoothnesses
|
||||
smoothness_speeds = {
|
||||
["intermediate"] = 80,
|
||||
["bad"] = 40,
|
||||
["very_bad"] = 20,
|
||||
["horrible"] = 10,
|
||||
["very_horrible"] = 5,
|
||||
["impassable"] = 0
|
||||
intermediate = 80,
|
||||
bad = 40,
|
||||
very_bad = 20,
|
||||
horrible = 10,
|
||||
very_horrible = 5,
|
||||
impassable = 0
|
||||
}
|
||||
|
||||
-- http://wiki.openstreetmap.org/wiki/Speed_limits
|
||||
maxspeed_table_default = {
|
||||
["urban"] = 50,
|
||||
["rural"] = 90,
|
||||
["trunk"] = 110,
|
||||
["motorway"] = 130
|
||||
urban = 50,
|
||||
rural = 90,
|
||||
trunk = 110,
|
||||
motorway = 130
|
||||
}
|
||||
|
||||
-- List only exceptions
|
||||
@@ -209,13 +261,13 @@ end
|
||||
function node_function (node, result)
|
||||
-- parse access and barrier tags
|
||||
local access = find_access_tag(node, access_tags_hierarchy)
|
||||
if access and access ~= "" then
|
||||
if access then
|
||||
if access_tag_blacklist[access] then
|
||||
result.barrier = true
|
||||
end
|
||||
else
|
||||
local barrier = node:get_value_by_key("barrier")
|
||||
if barrier and "" ~= barrier then
|
||||
if barrier then
|
||||
-- make an exception for rising bollard barriers
|
||||
local bollard = node:get_value_by_key("bollard")
|
||||
local rising_bollard = bollard and "rising" == bollard
|
||||
@@ -228,35 +280,27 @@ function node_function (node, result)
|
||||
|
||||
-- check if node is a traffic light
|
||||
local tag = node:get_value_by_key("highway")
|
||||
if tag and "traffic_signals" == tag then
|
||||
if "traffic_signals" == tag then
|
||||
result.traffic_lights = true
|
||||
end
|
||||
end
|
||||
|
||||
function way_function (way, result)
|
||||
local highway = way:get_value_by_key("highway")
|
||||
local route = way:get_value_by_key("route")
|
||||
local bridge = way:get_value_by_key("bridge")
|
||||
-- abort early if this way is obviouslt not routable
|
||||
function initial_routability_check(way,result,data)
|
||||
data.speed_type = way:get_value_by_key('highway')
|
||||
|
||||
if not ((highway and highway ~= "") or (route and route ~= "") or (bridge and bridge ~= "")) then
|
||||
return
|
||||
end
|
||||
|
||||
-- default to driving mode, may get overwritten below
|
||||
result.forward_mode = mode.driving
|
||||
result.backward_mode = mode.driving
|
||||
|
||||
-- we dont route over areas
|
||||
local area = way:get_value_by_key("area")
|
||||
if ignore_areas and area and "yes" == area then
|
||||
return
|
||||
end
|
||||
return data.speed_type ~= nil or
|
||||
way:get_value_by_key('route') ~= nil or
|
||||
way:get_value_by_key('bridge') ~= nil
|
||||
end
|
||||
|
||||
-- handle high occupancy vehicle tags
|
||||
function handle_hov(way,result)
|
||||
-- respect user-preference for HOV-only ways
|
||||
if ignore_hov_ways then
|
||||
local hov = way:get_value_by_key("hov")
|
||||
if hov and "designated" == hov then
|
||||
return
|
||||
if "designated" == hov then
|
||||
return false
|
||||
end
|
||||
|
||||
-- also respect user-preference for HOV-only ways when all lanes are HOV-designated
|
||||
@@ -277,18 +321,18 @@ function way_function (way, result)
|
||||
local hov_lanes_forward = way:get_value_by_key("hov:lanes:forward")
|
||||
local hov_lanes_backward = way:get_value_by_key("hov:lanes:backward")
|
||||
|
||||
local hov_all_designated = hov_lanes and hov_lanes ~= ""
|
||||
and has_all_designated_hov_lanes(hov_lanes)
|
||||
local hov_all_designated = hov_lanes and
|
||||
has_all_designated_hov_lanes(hov_lanes)
|
||||
|
||||
local hov_all_designated_forward = hov_lanes_forward and hov_lanes_forward ~= ""
|
||||
and has_all_designated_hov_lanes(hov_lanes_forward)
|
||||
local hov_all_designated_forward = hov_lanes_forward and
|
||||
has_all_designated_hov_lanes(hov_lanes_forward)
|
||||
|
||||
local hov_all_designated_backward = hov_lanes_backward and hov_lanes_backward ~= ""
|
||||
and has_all_designated_hov_lanes(hov_lanes_backward)
|
||||
local hov_all_designated_backward = hov_lanes_backward and
|
||||
has_all_designated_hov_lanes(hov_lanes_backward)
|
||||
|
||||
-- forward/backward lane depend on a way's direction
|
||||
local oneway = way:get_value_by_key("oneway")
|
||||
local reverse = oneway and oneway == "-1"
|
||||
local reverse = oneway == "-1"
|
||||
|
||||
if hov_all_designated or hov_all_designated_forward then
|
||||
if reverse then
|
||||
@@ -306,72 +350,97 @@ function way_function (way, result)
|
||||
end
|
||||
end
|
||||
|
||||
end -- hov handling
|
||||
end
|
||||
end
|
||||
|
||||
-- handle various that can block access
|
||||
function is_way_blocked(way,result)
|
||||
-- we dont route over areas
|
||||
local area = way:get_value_by_key("area")
|
||||
if ignore_areas and "yes" == area then
|
||||
return false
|
||||
end
|
||||
|
||||
-- respect user-preference for toll=yes ways
|
||||
local toll = way:get_value_by_key("toll")
|
||||
if ignore_toll_ways and toll and "yes" == toll then
|
||||
return
|
||||
if ignore_toll_ways and "yes" == toll then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Reversible oneways change direction with low frequency (think twice a day):
|
||||
-- do not route over these at all at the moment because of time dependence.
|
||||
-- Note: alternating (high frequency) oneways are handled below with penalty.
|
||||
local oneway = way:get_value_by_key("oneway")
|
||||
if oneway and "reversible" == oneway then
|
||||
return
|
||||
if "reversible" == oneway then
|
||||
return false
|
||||
end
|
||||
|
||||
local impassable = way:get_value_by_key("impassable")
|
||||
if impassable and "yes" == impassable then
|
||||
return
|
||||
if "yes" == impassable then
|
||||
return false
|
||||
end
|
||||
|
||||
local status = way:get_value_by_key("status")
|
||||
if status and "impassable" == status then
|
||||
return
|
||||
if "impassable" == status then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if we are allowed to access the way
|
||||
local access = find_access_tag(way, access_tags_hierarchy)
|
||||
if access_tag_blacklist[access] then
|
||||
return
|
||||
-- set default mode
|
||||
function set_default_mode(way,result)
|
||||
result.forward_mode = mode.driving
|
||||
result.backward_mode = mode.driving
|
||||
end
|
||||
|
||||
-- check accessibility by traversing our acces tag hierarchy
|
||||
function handle_access(way,result,data)
|
||||
data.access = find_access_tag(way, access_tags_hierarchy)
|
||||
if access_tag_blacklist[data.access] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- handling ferries and piers
|
||||
local route_speed = speed_profile[route]
|
||||
if (route_speed and route_speed > 0) then
|
||||
highway = route
|
||||
local duration = way:get_value_by_key("duration")
|
||||
if duration and durationIsValid(duration) then
|
||||
result.duration = max( parseDuration(duration), 1 )
|
||||
-- handling ferries and piers
|
||||
function handle_ferries(way,result)
|
||||
local route = way:get_value_by_key("route")
|
||||
if route then
|
||||
local route_speed = speed_profile[route]
|
||||
if route_speed and route_speed > 0 then
|
||||
local duration = way:get_value_by_key("duration")
|
||||
if duration and durationIsValid(duration) then
|
||||
result.duration = max( parseDuration(duration), 1 )
|
||||
end
|
||||
result.forward_mode = mode.ferry
|
||||
result.backward_mode = mode.ferry
|
||||
result.forward_speed = route_speed
|
||||
result.backward_speed = route_speed
|
||||
end
|
||||
result.forward_mode = mode.ferry
|
||||
result.backward_mode = mode.ferry
|
||||
result.forward_speed = route_speed
|
||||
result.backward_speed = route_speed
|
||||
end
|
||||
end
|
||||
|
||||
-- handling movable bridges
|
||||
local bridge_speed = speed_profile[bridge]
|
||||
local capacity_car = way:get_value_by_key("capacity:car")
|
||||
if (bridge_speed and bridge_speed > 0) and (capacity_car ~= 0) then
|
||||
highway = bridge
|
||||
local duration = way:get_value_by_key("duration")
|
||||
if duration and durationIsValid(duration) then
|
||||
result.duration = max( parseDuration(duration), 1 )
|
||||
-- handling movable bridges
|
||||
function handle_movables(way,result)
|
||||
local bridge = way:get_value_by_key("bridge")
|
||||
if bridge then
|
||||
local bridge_speed = speed_profile[bridge]
|
||||
if bridge_speed and bridge_speed > 0 then
|
||||
local capacity_car = way:get_value_by_key("capacity:car")
|
||||
if capacity_car ~= 0 then
|
||||
local duration = way:get_value_by_key("duration")
|
||||
if duration and durationIsValid(duration) then
|
||||
result.duration = max( parseDuration(duration), 1 )
|
||||
end
|
||||
result.forward_speed = bridge_speed
|
||||
result.backward_speed = bridge_speed
|
||||
end
|
||||
end
|
||||
result.forward_speed = bridge_speed
|
||||
result.backward_speed = bridge_speed
|
||||
end
|
||||
|
||||
-- leave early if this way is not accessible
|
||||
if "" == highway then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- handle speed (excluding maxspeed)
|
||||
function handle_speed(way,result,data)
|
||||
if result.forward_speed == -1 then
|
||||
local highway_speed = speed_profile[highway]
|
||||
local highway_speed = speed_profile[way:get_value_by_key("highway")]
|
||||
local max_speed = parse_maxspeed( way:get_value_by_key("maxspeed") )
|
||||
-- Set the avg speed on the way if it is accessible by road class
|
||||
if highway_speed then
|
||||
@@ -385,7 +454,7 @@ function way_function (way, result)
|
||||
end
|
||||
else
|
||||
-- Set the avg speed on ways that are marked accessible
|
||||
if access_tag_whitelist[access] then
|
||||
if access_tag_whitelist[data.access] then
|
||||
result.forward_speed = speed_profile["default"]
|
||||
result.backward_speed = speed_profile["default"]
|
||||
end
|
||||
@@ -398,18 +467,28 @@ function way_function (way, result)
|
||||
end
|
||||
|
||||
if -1 == result.forward_speed and -1 == result.backward_speed then
|
||||
return
|
||||
return false
|
||||
end
|
||||
|
||||
if handle_side_roads(way,result) == false then return false end
|
||||
if handle_surface(way,result) == false then return false end
|
||||
if handle_maxspeed(way,result) == false then return false end
|
||||
if handle_speed_scaling(way,result) == false then return false end
|
||||
if handle_alternating_speed(way,result) == false then return false end
|
||||
end
|
||||
|
||||
-- reduce speed on special side roads
|
||||
-- reduce speed on special side roads
|
||||
function handle_side_roads(way,result)
|
||||
local sideway = way:get_value_by_key("side_road")
|
||||
if "yes" == sideway or
|
||||
"rotary" == sideway then
|
||||
result.forward_speed = result.forward_speed * side_road_speed_multiplier
|
||||
result.backward_speed = result.backward_speed * side_road_speed_multiplier
|
||||
end
|
||||
end
|
||||
|
||||
-- reduce speed on bad surfaces
|
||||
-- reduce speed on bad surfaces
|
||||
function handle_surface(way,result)
|
||||
local surface = way:get_value_by_key("surface")
|
||||
local tracktype = way:get_value_by_key("tracktype")
|
||||
local smoothness = way:get_value_by_key("smoothness")
|
||||
@@ -426,65 +505,77 @@ function way_function (way, result)
|
||||
result.forward_speed = math.min(smoothness_speeds[smoothness], result.forward_speed)
|
||||
result.backward_speed = math.min(smoothness_speeds[smoothness], result.backward_speed)
|
||||
end
|
||||
end
|
||||
|
||||
-- set the road classification based on guidance globals configuration
|
||||
set_classification(highway,result,way)
|
||||
|
||||
-- handles name, including ref and pronunciation
|
||||
function handle_names(way,result)
|
||||
-- parse the remaining tags
|
||||
local name = way:get_value_by_key("name")
|
||||
local pronunciation = way:get_value_by_key("name:pronunciation")
|
||||
local ref = way:get_value_by_key("ref")
|
||||
local junction = way:get_value_by_key("junction")
|
||||
-- local barrier = way:get_value_by_key("barrier", "")
|
||||
-- local cycleway = way:get_value_by_key("cycleway", "")
|
||||
local service = way:get_value_by_key("service")
|
||||
|
||||
-- Set the name that will be used for instructions
|
||||
local has_ref = ref and "" ~= ref
|
||||
local has_name = name and "" ~= name
|
||||
local has_pronunciation = pronunciation and "" ~= pronunciation
|
||||
|
||||
if has_name then
|
||||
if name then
|
||||
result.name = name
|
||||
end
|
||||
|
||||
if has_ref then
|
||||
if ref then
|
||||
result.ref = canonicalizeStringList(ref, ";")
|
||||
end
|
||||
|
||||
if has_pronunciation then
|
||||
if pronunciation then
|
||||
result.pronunciation = pronunciation
|
||||
end
|
||||
end
|
||||
|
||||
local turn_lanes = ""
|
||||
local turn_lanes_forward = ""
|
||||
local turn_lanes_backward = ""
|
||||
-- handle turn lanes
|
||||
function handle_turn_lanes(way,result)
|
||||
local turn_lanes = ''
|
||||
local turn_lanes_forward = ''
|
||||
local turn_lanes_backward = ''
|
||||
|
||||
turn_lanes, turn_lanes_forward, turn_lanes_backward = get_turn_lanes(way)
|
||||
if turn_lanes and turn_lanes ~= "" then
|
||||
if turn_lanes and turn_lanes ~= '' then
|
||||
result.turn_lanes_forward = turn_lanes;
|
||||
result.turn_lanes_backward = turn_lanes;
|
||||
else
|
||||
if turn_lanes_forward and turn_lanes_forward ~= "" then
|
||||
result.turn_lanes_forward = turn_lanes_forward;
|
||||
if turn_lanes_forward and turn_lanes_forward ~= '' then
|
||||
result.turn_lanes_forward = turn_lanes_forward;
|
||||
end
|
||||
|
||||
if turn_lanes_backward and turn_lanes_backward ~= "" then
|
||||
result.turn_lanes_backward = turn_lanes_backward;
|
||||
if turn_lanes_backward and turn_lanes_backward ~= '' then
|
||||
result.turn_lanes_backward = turn_lanes_backward;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- junctions
|
||||
function handle_roundabouts(way,result)
|
||||
local junction = way:get_value_by_key("junction");
|
||||
|
||||
if junction and "roundabout" == junction then
|
||||
if junction == "roundabout" then
|
||||
result.roundabout = true
|
||||
end
|
||||
|
||||
-- Set access restriction flag if access is allowed under certain restrictions only
|
||||
if access ~= "" and access_tag_restricted[access] then
|
||||
-- See Issue 3361: roundabout-shaped not following roundabout rules.
|
||||
-- This will get us "At Strausberger Platz do Maneuver X" instead of multiple quick turns.
|
||||
-- In a new API version we can think of having a separate type passing it through to the user.
|
||||
if junction == "circular" then
|
||||
result.circular = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Set access restriction flag if access is allowed under certain restrictions only
|
||||
function handle_restricted(way,result,data)
|
||||
if data.access and access_tag_restricted[data.access] then
|
||||
result.is_access_restricted = true
|
||||
end
|
||||
end
|
||||
|
||||
if service and service ~= "" then
|
||||
-- service roads
|
||||
function handle_service(way,result)
|
||||
local service = way:get_value_by_key("service")
|
||||
if service then
|
||||
-- Set access restriction flag if service is allowed under certain restrictions only
|
||||
if service_tag_restricted[service] then
|
||||
result.is_access_restricted = true
|
||||
@@ -494,11 +585,57 @@ function way_function (way, result)
|
||||
if service_tag_forbidden[service] then
|
||||
result.forward_mode = mode.inaccessible
|
||||
result.backward_mode = mode.inaccessible
|
||||
return
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- scale speeds to get better average driving times
|
||||
function handle_speed_scaling(way,result)
|
||||
local width = math.huge
|
||||
local lanes = math.huge
|
||||
if result.forward_speed > 0 or result.backward_speed > 0 then
|
||||
local width_string = way:get_value_by_key("width")
|
||||
if width_string and tonumber(width_string:match("%d*")) then
|
||||
width = tonumber(width_string:match("%d*"))
|
||||
end
|
||||
|
||||
local lanes_string = way:get_value_by_key("lanes")
|
||||
if lanes_string and tonumber(lanes_string:match("%d*")) then
|
||||
lanes = tonumber(lanes_string:match("%d*"))
|
||||
end
|
||||
end
|
||||
|
||||
-- Set direction according to tags on way
|
||||
local is_bidirectional = result.forward_mode ~= mode.inaccessible and
|
||||
result.backward_mode ~= mode.inaccessible
|
||||
|
||||
local service = way:get_value_by_key("service")
|
||||
if result.forward_speed > 0 then
|
||||
local scaled_speed = result.forward_speed * speed_reduction
|
||||
local penalized_speed = math.huge
|
||||
if service and service_speeds[service] then
|
||||
penalized_speed = service_speeds[service]
|
||||
elseif width <= 3 or (lanes <= 1 and is_bidirectional) then
|
||||
penalized_speed = result.forward_speed / 2
|
||||
end
|
||||
result.forward_speed = math.min(penalized_speed, scaled_speed)
|
||||
end
|
||||
|
||||
if result.backward_speed > 0 then
|
||||
local scaled_speed = result.backward_speed * speed_reduction
|
||||
local penalized_speed = math.huge
|
||||
if service and service_speeds[service]then
|
||||
penalized_speed = service_speeds[service]
|
||||
elseif width <= 3 or (lanes <= 1 and is_bidirectional) then
|
||||
penalized_speed = result.backward_speed / 2
|
||||
end
|
||||
result.backward_speed = math.min(penalized_speed, scaled_speed)
|
||||
end
|
||||
end
|
||||
|
||||
-- oneways
|
||||
function handle_oneway(way,result)
|
||||
local oneway = way:get_value_by_key("oneway")
|
||||
if obey_oneway then
|
||||
if oneway == "-1" then
|
||||
result.forward_mode = mode.inaccessible
|
||||
@@ -507,10 +644,11 @@ function way_function (way, result)
|
||||
local destination = get_destination(way, is_forward)
|
||||
result.destinations = canonicalizeStringList(destination, ",")
|
||||
elseif oneway == "yes" or
|
||||
oneway == "1" or
|
||||
oneway == "true" or
|
||||
junction == "roundabout" or
|
||||
(highway == "motorway" and oneway ~= "no") then
|
||||
oneway == "1" or
|
||||
oneway == "true" or
|
||||
way:get_value_by_key("junction") == "roundabout" or
|
||||
way:get_value_by_key("junction") == "circular" or
|
||||
(way:get_value_by_key("highway") == "motorway" and oneway ~= "no") then
|
||||
|
||||
result.backward_mode = mode.inaccessible
|
||||
|
||||
@@ -519,13 +657,17 @@ function way_function (way, result)
|
||||
result.destinations = canonicalizeStringList(destination, ",")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- maxspeed and advisory maxspeed
|
||||
function handle_maxspeed(way,result)
|
||||
-- Override speed settings if explicit forward/backward maxspeeds are given
|
||||
local maxspeed_forward = parse_maxspeed(way:get_value_by_key("maxspeed:forward"))
|
||||
local maxspeed_backward = parse_maxspeed(way:get_value_by_key("maxspeed:backward"))
|
||||
if maxspeed_forward and maxspeed_forward > 0 then
|
||||
if mode.inaccessible ~= result.forward_mode and mode.inaccessible ~= result.backward_mode then
|
||||
result.backward_speed = result.forward_speed
|
||||
if mode.inaccessible ~= result.forward_mode and
|
||||
mode.inaccessible ~= result.backward_mode then
|
||||
result.backward_speed = result.forward_speed
|
||||
end
|
||||
result.forward_speed = maxspeed_forward
|
||||
end
|
||||
@@ -555,49 +697,12 @@ function way_function (way, result)
|
||||
if advisory_backward and advisory_backward > 0 then
|
||||
result.backward_speed = advisory_backward
|
||||
end
|
||||
end
|
||||
|
||||
local width = math.huge
|
||||
local lanes = math.huge
|
||||
if result.forward_speed > 0 or result.backward_speed > 0 then
|
||||
local width_string = way:get_value_by_key("width")
|
||||
if width_string and tonumber(width_string:match("%d*")) then
|
||||
width = tonumber(width_string:match("%d*"))
|
||||
end
|
||||
|
||||
local lanes_string = way:get_value_by_key("lanes")
|
||||
if lanes_string and tonumber(lanes_string:match("%d*")) then
|
||||
lanes = tonumber(lanes_string:match("%d*"))
|
||||
end
|
||||
end
|
||||
|
||||
local is_bidirectional = result.forward_mode ~= mode.inaccessible and result.backward_mode ~= mode.inaccessible
|
||||
|
||||
-- scale speeds to get better avg driving times
|
||||
if result.forward_speed > 0 then
|
||||
local scaled_speed = result.forward_speed * speed_reduction
|
||||
local penalized_speed = math.huge
|
||||
if service and service ~= "" and service_speeds[service] then
|
||||
penalized_speed = service_speeds[service]
|
||||
elseif width <= 3 or (lanes <= 1 and is_bidirectional) then
|
||||
penalized_speed = result.forward_speed / 2
|
||||
end
|
||||
result.forward_speed = math.min(penalized_speed, scaled_speed)
|
||||
end
|
||||
|
||||
if result.backward_speed > 0 then
|
||||
local scaled_speed = result.backward_speed * speed_reduction
|
||||
local penalized_speed = math.huge
|
||||
if service and service ~= "" and service_speeds[service]then
|
||||
penalized_speed = service_speeds[service]
|
||||
elseif width <= 3 or (lanes <= 1 and is_bidirectional) then
|
||||
penalized_speed = result.backward_speed / 2
|
||||
end
|
||||
result.backward_speed = math.min(penalized_speed, scaled_speed)
|
||||
end
|
||||
|
||||
-- Handle high frequency reversible oneways (think traffic signal controlled, changing direction every 15 minutes).
|
||||
-- Scaling speed to take average waiting time into account plus some more for start / stop.
|
||||
if oneway and "alternating" == oneway then
|
||||
-- Handle high frequency reversible oneways (think traffic signal controlled, changing direction every 15 minutes).
|
||||
-- Scaling speed to take average waiting time into account plus some more for start / stop.
|
||||
function handle_alternating_speed(way,result)
|
||||
if "alternating" == way:get_value_by_key('oneway') then
|
||||
local scaling_factor = 0.4
|
||||
if result.forward_speed ~= math.huge then
|
||||
result.forward_speed = result.forward_speed * scaling_factor
|
||||
@@ -606,9 +711,83 @@ function way_function (way, result)
|
||||
result.backward_speed = result.backward_speed * scaling_factor
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- determine if this way can be used as a start/end point for routing
|
||||
function handle_startpoint(way,result)
|
||||
-- only allow this road as start point if it not a ferry
|
||||
result.is_startpoint = result.forward_mode == mode.driving or result.backward_mode == mode.driving
|
||||
result.is_startpoint = result.forward_mode == mode.driving or
|
||||
result.backward_mode == mode.driving
|
||||
end
|
||||
|
||||
-- set the road classification based on guidance globals configuration
|
||||
function handle_classification(way,result)
|
||||
set_classification(way:get_value_by_key("highway"),result,way)
|
||||
end
|
||||
|
||||
-- main entry point for processsing a way
|
||||
function way_function(way, result)
|
||||
-- intermediate values used during processing
|
||||
local data = {}
|
||||
|
||||
-- to optimize processing, we should try to abort as soon as
|
||||
-- possible if the way is not routable, to avoid doing
|
||||
-- unnecessary work. this implies we should check things that
|
||||
-- commonly forbids access early, and handle complicated edge
|
||||
-- cases later.
|
||||
|
||||
-- perform an quick initial check and abort if way is obviously
|
||||
-- not routable, e.g. because it does not have any of the key
|
||||
-- tags indicating routability
|
||||
if initial_routability_check(way,result,data) == false then return end
|
||||
|
||||
-- set the default mode for this profile. if can be changed later
|
||||
-- in case it turns we're e.g. on a ferry
|
||||
if set_default_mode(way,result) == false then return end
|
||||
|
||||
-- check various tags that could indicate that the way is not
|
||||
-- routable. this includes things like status=impassable,
|
||||
-- toll=yes and oneway=reversible
|
||||
if is_way_blocked(way,result) == false then return end
|
||||
|
||||
-- determine access status by checking our hierarchy of
|
||||
-- access tags, e.g: motorcar, motor_vehicle, vehicle
|
||||
if handle_access(way,result,data) == false then return end
|
||||
|
||||
-- check high occupancy vehicle restrictions
|
||||
if handle_hov(way,result) == false then return end
|
||||
|
||||
-- check whether we're using a special transport mode
|
||||
if handle_ferries(way,result) == false then return end
|
||||
if handle_movables(way,result) == false then return end
|
||||
|
||||
-- handle service road restrictions
|
||||
if handle_service(way,result) == false then return end
|
||||
|
||||
-- check whether forward/backward directons are routable
|
||||
if handle_oneway(way,result) == false then return end
|
||||
|
||||
-- compute speed taking into account way type, maxspeed tags, etc.
|
||||
if handle_speed(way,result,data) == false then return end
|
||||
|
||||
-- handle turn lanes and road classification, used for guidance
|
||||
if handle_turn_lanes(way,result) == false then return end
|
||||
if handle_classification(way,result) == false then return end
|
||||
|
||||
-- handle various other flags
|
||||
if handle_roundabouts(way,result) == false then return end
|
||||
if handle_startpoint(way,result) == false then return end
|
||||
if handle_restricted(way,result,data) == false then return end
|
||||
|
||||
-- handle roundabout flags
|
||||
if handle_roundabouts(way,result) == false then return end
|
||||
|
||||
-- check if this way can be routed through, but not used as
|
||||
-- origin or destination
|
||||
if handle_restricted(way,result,data) == false then return end
|
||||
|
||||
-- set name, ref and pronunciation
|
||||
if handle_names(way,result) == false then return end
|
||||
end
|
||||
|
||||
function turn_function (angle)
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
-- Enable calling our lua profile code directly from the lua command line,
|
||||
-- which makes it easier to debug.
|
||||
-- We simulate the normal C++ environment by defining the required globals and functions.
|
||||
|
||||
-- Usage:
|
||||
-- > cd profiles
|
||||
-- > lua5.1 debug.lua
|
||||
|
||||
|
||||
-- for more convenient printing of tables
|
||||
local pprint = require('lib/pprint')
|
||||
|
||||
-- globals that are normally set from C++
|
||||
|
||||
-- profiles code modifies this table
|
||||
properties = {}
|
||||
|
||||
-- should match values defined in include/extractor/guidance/road_classification.hpp
|
||||
road_priority_class = {
|
||||
motorway = 0,
|
||||
trunk = 2,
|
||||
primary = 4,
|
||||
secondary = 6,
|
||||
tertiary = 8,
|
||||
main_residential = 10,
|
||||
side_residential = 11,
|
||||
link_road = 14,
|
||||
bike_path = 16,
|
||||
foot_path = 18,
|
||||
connectivity = 31,
|
||||
}
|
||||
|
||||
-- should match values defined in include/extractor/travel_mode.hpp
|
||||
mode = {
|
||||
inaccessible = 0,
|
||||
driving = 1,
|
||||
cycling = 2,
|
||||
walking = 3,
|
||||
ferry = 4,
|
||||
train = 5,
|
||||
pushing_bike = 6,
|
||||
}
|
||||
|
||||
-- input tags, normally extracted from OSM data
|
||||
local way = {
|
||||
highway = 'motorway',
|
||||
name = 'Main Street',
|
||||
--width = '3',
|
||||
--maxspeed = '30',
|
||||
--['maxspeed:advisory'] = '25',
|
||||
--oneway = '-1',
|
||||
--service = 'alley',
|
||||
--['oneway:bicycle'] = 'yes',
|
||||
--junction = 'roundabout',
|
||||
--['name:pronunciation'] = 'fuerloong',
|
||||
--route = 'ferry',
|
||||
--duration = '00:01:00',
|
||||
--hov = 'designated',
|
||||
--access = 'no'
|
||||
--destination = 'Berlin',
|
||||
["destination:ref"] = 'Nuremberg',
|
||||
--["destination:ref:forward"] = 'Hamburg;Dresden',
|
||||
}
|
||||
-- tag function normally provided via C++
|
||||
function way:get_value_by_key(k)
|
||||
return self[k]
|
||||
end
|
||||
|
||||
-- Mock C++ helper functions which are called from LUA.
|
||||
-- FIXME
|
||||
-- Debugging LUA code that uses these will not work correctly
|
||||
-- unless we reimplement themethods in LUA.
|
||||
|
||||
function durationIsValid(str)
|
||||
return true
|
||||
end
|
||||
|
||||
function parseDuration(str)
|
||||
return 1
|
||||
end
|
||||
|
||||
function canonicalizeStringList(str)
|
||||
return str
|
||||
end
|
||||
|
||||
-- start state of result table, normally set form C++
|
||||
local result = {
|
||||
road_classification = {},
|
||||
forward_speed = -1,
|
||||
backward_speed = -1,
|
||||
}
|
||||
|
||||
-- the profile we want to debug
|
||||
require("car")
|
||||
|
||||
-- call the way function
|
||||
way_function(way,result)
|
||||
|
||||
-- and print the output
|
||||
pprint(way)
|
||||
print("=>")
|
||||
pprint(result)
|
||||
+4
-1
@@ -156,10 +156,13 @@ function way_function (way, result)
|
||||
result.ref = ref
|
||||
end
|
||||
|
||||
-- roundabouts
|
||||
-- roundabouts
|
||||
if "roundabout" == junction then
|
||||
result.roundabout = true
|
||||
end
|
||||
if "circular" == junction then
|
||||
result.circular = true
|
||||
end
|
||||
|
||||
-- speed
|
||||
if route_speeds[route] then
|
||||
|
||||
@@ -5,11 +5,11 @@ local Access = {}
|
||||
function Access.find_access_tag(source,access_tags_hierarchy)
|
||||
for i,v in ipairs(access_tags_hierarchy) do
|
||||
local tag = source:get_value_by_key(v)
|
||||
if tag and tag ~= '' then
|
||||
if tag then
|
||||
return tag
|
||||
end
|
||||
end
|
||||
return ""
|
||||
return nil
|
||||
end
|
||||
|
||||
return Access
|
||||
|
||||
@@ -1,53 +1,28 @@
|
||||
local Destination = {}
|
||||
|
||||
function Destination.get_directional_tag(way, is_forward, tag)
|
||||
local v
|
||||
if is_forward then
|
||||
v = way:get_value_by_key(tag .. ':forward') or way:get_value_by_key(tag)
|
||||
else
|
||||
v = way:get_value_by_key(tag .. ':backward') or way:get_value_by_key(tag)
|
||||
end
|
||||
if v then
|
||||
return v.gsub(v, ';', ', ')
|
||||
end
|
||||
end
|
||||
|
||||
-- Assemble destination as: "A59: Düsseldorf, Köln"
|
||||
-- destination:ref ^ ^ destination
|
||||
|
||||
function Destination.get_destination(way, is_forward)
|
||||
local destination = way:get_value_by_key("destination")
|
||||
local destination_forward = way:get_value_by_key("destination:forward")
|
||||
local destination_backward = way:get_value_by_key("destination:backward")
|
||||
local destination_ref = way:get_value_by_key("destination:ref")
|
||||
local destination_ref_forward = way:get_value_by_key("destination:ref:forward")
|
||||
local destination_ref_backward = way:get_value_by_key("destination:ref:backward")
|
||||
|
||||
-- Assemble destination as: "A59: Düsseldorf, Köln"
|
||||
-- destination:ref ^ ^ destination
|
||||
|
||||
local rv = ""
|
||||
|
||||
if destination_ref then
|
||||
if is_forward == true and destination_ref == "" then
|
||||
if destination_ref_forward then
|
||||
destination_ref = destination_ref_forward
|
||||
end
|
||||
elseif is_forward == false then
|
||||
if destination_ref_backward then
|
||||
destination_ref = destination_ref_backward
|
||||
end
|
||||
end
|
||||
|
||||
rv = rv .. string.gsub(destination_ref, ";", ", ")
|
||||
ref = Destination.get_directional_tag(way, is_forward, 'destination:ref')
|
||||
dest = Destination.get_directional_tag(way, is_forward, 'destination')
|
||||
if ref and dest then
|
||||
return ref .. ': ' .. dest
|
||||
else
|
||||
return ref or dest or ''
|
||||
end
|
||||
|
||||
if destination then
|
||||
if is_forward == true and destination == "" then
|
||||
if destination_forward then
|
||||
destination = destination_forward
|
||||
end
|
||||
elseif is_forward == false then
|
||||
if destination_backward then
|
||||
destination = destination_backward
|
||||
end
|
||||
end
|
||||
|
||||
if destination ~= "" then
|
||||
if rv ~= "" then
|
||||
rv = rv .. ": "
|
||||
end
|
||||
|
||||
rv = rv .. string.gsub(destination, ";", ", ")
|
||||
end
|
||||
end
|
||||
|
||||
return rv
|
||||
end
|
||||
|
||||
return Destination
|
||||
@@ -61,7 +61,7 @@ function Guidance.set_classification (highway, result, input_way)
|
||||
end
|
||||
|
||||
local lane_count = input_way:get_value_by_key("lanes")
|
||||
if lane_count and lane_count ~= "" then
|
||||
if lane_count then
|
||||
local lc = tonumber(lane_count)
|
||||
if lc ~= nil then
|
||||
result.road_classification.num_lanes = lc
|
||||
@@ -69,14 +69,14 @@ function Guidance.set_classification (highway, result, input_way)
|
||||
else
|
||||
local total_count = 0
|
||||
local forward_count = input_way:get_value_by_key("lanes:forward")
|
||||
if forward_count and forward_count ~= "" then
|
||||
if forward_count then
|
||||
local fc = tonumber(forward_count)
|
||||
if fc ~= nil then
|
||||
total_count = fc
|
||||
end
|
||||
end
|
||||
local backward_count = input_way:get_value_by_key("lanes:backward")
|
||||
if backward_count and backward_count ~= "" then
|
||||
if backward_count then
|
||||
local bc = tonumber(backward_count)
|
||||
if bc ~= nil then
|
||||
total_count = total_count + bc
|
||||
@@ -96,19 +96,19 @@ local function get_psv_counts(way)
|
||||
|
||||
local fw = 0;
|
||||
local bw = 0;
|
||||
if psv and psv ~= "" then
|
||||
if psv then
|
||||
fw = tonumber(psv)
|
||||
if( fw == nil ) then
|
||||
fw = 0
|
||||
end
|
||||
end
|
||||
if psv_forward and psv_forward ~= "" then
|
||||
if psv_forward then
|
||||
fw = tonumber(psv_forward)
|
||||
if( fw == nil ) then
|
||||
fw = 0
|
||||
end
|
||||
end
|
||||
if psv_backward and psv_backward ~= "" then
|
||||
if psv_backward then
|
||||
bw = tonumber(psv_backward);
|
||||
if( bw == nil ) then
|
||||
bw = 0
|
||||
@@ -119,8 +119,8 @@ end
|
||||
|
||||
-- trims lane string with regard to supported lanes
|
||||
local function process_lanes(turn_lane,vehicle_lane,first_count,second_count)
|
||||
if turn_lane and turn_lane ~= "" then
|
||||
if vehicle_lane and vehicle_lane ~= "" then
|
||||
if turn_lane then
|
||||
if vehicle_lane then
|
||||
turn_lane = applyAccessTokens(turn_lane,vehicle_lane)
|
||||
elseif first_count ~= 0 or second_count ~= 0 then
|
||||
turn_lane = trimLaneString(turn_lane, first_count, second_count)
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
-- Easy way to print data structes
|
||||
-- From https://github.com/jagt/pprint.lua, file is license as pubic domain
|
||||
|
||||
local pprint = { VERSION = '0.1' }
|
||||
|
||||
pprint.defaults = {
|
||||
-- type display trigger, hide not useful datatypes by default
|
||||
-- custom types are treated as table
|
||||
show_nil = true,
|
||||
show_boolean = true,
|
||||
show_number = true,
|
||||
show_string = true,
|
||||
show_table = true,
|
||||
show_function = false,
|
||||
show_thread = false,
|
||||
show_userdata = false,
|
||||
-- additional display trigger
|
||||
show_metatable = false, -- show metatable
|
||||
show_all = false, -- override other show settings and show everything
|
||||
use_tostring = false, -- use __tostring to print table if available
|
||||
filter_function = nil, -- called like callback(value[,key, parent]), return truty value to hide
|
||||
object_cache = 'local', -- cache blob and table to give it a id, 'local' cache per print, 'global' cache
|
||||
-- per process, falsy value to disable (might cause infinite loop)
|
||||
-- format settings
|
||||
indent_size = 2, -- indent for each nested table level
|
||||
level_width = 80, -- max width per indent level
|
||||
wrap_string = true, -- wrap string when it's longer than level_width
|
||||
wrap_array = false, -- wrap every array elements
|
||||
sort_keys = true, -- sort table keys
|
||||
}
|
||||
|
||||
local TYPES = {
|
||||
['nil'] = 1, ['boolean'] = 2, ['number'] = 3, ['string'] = 4,
|
||||
['table'] = 5, ['function'] = 6, ['thread'] = 7, ['userdata'] = 8
|
||||
}
|
||||
|
||||
-- seems this is the only way to escape these, as lua don't know how to map char '\a' to 'a'
|
||||
local ESCAPE_MAP = {
|
||||
['\a'] = '\\a', ['\b'] = '\\b', ['\f'] = '\\f', ['\n'] = '\\n', ['\r'] = '\\r',
|
||||
['\t'] = '\\t', ['\v'] = '\\v', ['\\'] = '\\\\',
|
||||
}
|
||||
|
||||
-- generic utilities
|
||||
local function escape(s)
|
||||
s = s:gsub('([%c\\])', ESCAPE_MAP)
|
||||
local dq = s:find('"')
|
||||
local sq = s:find("'")
|
||||
if dq and sq then
|
||||
return s:gsub('"', '\\"'), '"'
|
||||
elseif sq then
|
||||
return s, '"'
|
||||
else
|
||||
return s, "'"
|
||||
end
|
||||
end
|
||||
|
||||
local function is_plain_key(key)
|
||||
return type(key) == 'string' and key:match('^[%a_][%a%d_]*$')
|
||||
end
|
||||
|
||||
local CACHE_TYPES = {
|
||||
['table'] = true, ['function'] = true, ['thread'] = true, ['userdata'] = true
|
||||
}
|
||||
|
||||
-- cache would be populated to be like:
|
||||
-- {
|
||||
-- function = { `fun1` = 1, _cnt = 1 }, -- object id
|
||||
-- table = { `table1` = 1, `table2` = 2, _cnt = 2 },
|
||||
-- visited_tables = { `table1` = 7, `table2` = 8 }, -- visit count
|
||||
-- }
|
||||
-- use weakrefs to avoid accidentall adding refcount
|
||||
local function cache_apperance(obj, cache, option)
|
||||
if not cache.visited_tables then
|
||||
cache.visited_tables = setmetatable({}, {__mode = 'k'})
|
||||
end
|
||||
local t = type(obj)
|
||||
|
||||
-- TODO can't test filter_function here as we don't have the ix and key,
|
||||
-- might cause different results?
|
||||
-- respect show_xxx and filter_function to be consistent with print results
|
||||
if (not TYPES[t] and not option.show_table)
|
||||
or (TYPES[t] and not option['show_'..t]) then
|
||||
return
|
||||
end
|
||||
|
||||
if CACHE_TYPES[t] or TYPES[t] == nil then
|
||||
if not cache[t] then
|
||||
cache[t] = setmetatable({}, {__mode = 'k'})
|
||||
cache[t]._cnt = 0
|
||||
end
|
||||
if not cache[t][obj] then
|
||||
cache[t]._cnt = cache[t]._cnt + 1
|
||||
cache[t][obj] = cache[t]._cnt
|
||||
end
|
||||
end
|
||||
if t == 'table' or TYPES[t] == nil then
|
||||
if cache.visited_tables[obj] == false then
|
||||
-- already printed, no need to mark this and its children anymore
|
||||
return
|
||||
elseif cache.visited_tables[obj] == nil then
|
||||
cache.visited_tables[obj] = 1
|
||||
else
|
||||
-- visited already, increment and continue
|
||||
cache.visited_tables[obj] = cache.visited_tables[obj] + 1
|
||||
return
|
||||
end
|
||||
for k, v in pairs(obj) do
|
||||
cache_apperance(k, cache, option)
|
||||
cache_apperance(v, cache, option)
|
||||
end
|
||||
local mt = getmetatable(obj)
|
||||
if mt and option.show_metatable then
|
||||
cache_apperance(mt, cache, option)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- makes 'foo2' < 'foo100000'. string.sub makes substring anyway, no need to use index based method
|
||||
local function str_natural_cmp(lhs, rhs)
|
||||
while #lhs > 0 and #rhs > 0 do
|
||||
local lmid, lend = lhs:find('%d+')
|
||||
local rmid, rend = rhs:find('%d+')
|
||||
if not (lmid and rmid) then return lhs < rhs end
|
||||
|
||||
local lsub = lhs:sub(1, lmid-1)
|
||||
local rsub = rhs:sub(1, rmid-1)
|
||||
if lsub ~= rsub then
|
||||
return lsub < rsub
|
||||
end
|
||||
|
||||
local lnum = tonumber(lhs:sub(lmid, lend))
|
||||
local rnum = tonumber(rhs:sub(rmid, rend))
|
||||
if lnum ~= rnum then
|
||||
return lnum < rnum
|
||||
end
|
||||
|
||||
lhs = lhs:sub(lend+1)
|
||||
rhs = rhs:sub(rend+1)
|
||||
end
|
||||
return lhs < rhs
|
||||
end
|
||||
|
||||
local function cmp(lhs, rhs)
|
||||
local tleft = type(lhs)
|
||||
local tright = type(rhs)
|
||||
if tleft == 'number' and tright == 'number' then return lhs < rhs end
|
||||
if tleft == 'string' and tright == 'string' then return str_natural_cmp(lhs, rhs) end
|
||||
if tleft == tright then return str_natural_cmp(tostring(lhs), tostring(rhs)) end
|
||||
|
||||
-- allow custom types
|
||||
local oleft = TYPES[tleft] or 9
|
||||
local oright = TYPES[tright] or 9
|
||||
return oleft < oright
|
||||
end
|
||||
|
||||
-- setup option with default
|
||||
local function make_option(option)
|
||||
if option == nil then
|
||||
option = {}
|
||||
end
|
||||
for k, v in pairs(pprint.defaults) do
|
||||
if option[k] == nil then
|
||||
option[k] = v
|
||||
end
|
||||
if option.show_all then
|
||||
for t, _ in pairs(TYPES) do
|
||||
option['show_'..t] = true
|
||||
end
|
||||
option.show_metatable = true
|
||||
end
|
||||
end
|
||||
return option
|
||||
end
|
||||
|
||||
-- override defaults and take effects for all following calls
|
||||
function pprint.setup(option)
|
||||
pprint.defaults = make_option(option)
|
||||
end
|
||||
|
||||
-- format lua object into a string
|
||||
function pprint.pformat(obj, option, printer)
|
||||
option = make_option(option)
|
||||
local buf = {}
|
||||
local function default_printer(s)
|
||||
table.insert(buf, s)
|
||||
end
|
||||
printer = printer or default_printer
|
||||
|
||||
local cache
|
||||
if option.object_cache == 'global' then
|
||||
-- steal the cache into a local var so it's not visible from _G or anywhere
|
||||
-- still can't avoid user explicitly referentce pprint._cache but it shouldn't happen anyway
|
||||
cache = pprint._cache or {}
|
||||
pprint._cache = nil
|
||||
elseif option.object_cache == 'local' then
|
||||
cache = {}
|
||||
end
|
||||
|
||||
local last = '' -- used for look back and remove trailing comma
|
||||
local status = {
|
||||
indent = '', -- current indent
|
||||
len = 0, -- current line length
|
||||
}
|
||||
|
||||
local wrapped_printer = function(s)
|
||||
printer(last)
|
||||
last = s
|
||||
end
|
||||
|
||||
local function _indent(d)
|
||||
status.indent = string.rep(' ', d + #(status.indent))
|
||||
end
|
||||
|
||||
local function _n(d)
|
||||
wrapped_printer('\n')
|
||||
wrapped_printer(status.indent)
|
||||
if d then
|
||||
_indent(d)
|
||||
end
|
||||
status.len = 0
|
||||
return true -- used to close bracket correctly
|
||||
end
|
||||
|
||||
local function _p(s, nowrap)
|
||||
status.len = status.len + #s
|
||||
if not nowrap and status.len > option.level_width then
|
||||
_n()
|
||||
wrapped_printer(s)
|
||||
status.len = #s
|
||||
else
|
||||
wrapped_printer(s)
|
||||
end
|
||||
end
|
||||
|
||||
local formatter = {}
|
||||
local function format(v)
|
||||
local f = formatter[type(v)]
|
||||
f = f or formatter.table -- allow patched type()
|
||||
if option.filter_function and option.filter_function(v, nil, nil) then
|
||||
return ''
|
||||
else
|
||||
return f(v)
|
||||
end
|
||||
end
|
||||
|
||||
local function tostring_formatter(v)
|
||||
return tostring(v)
|
||||
end
|
||||
|
||||
local function number_formatter(n)
|
||||
return n == math.huge and '[[math.huge]]' or tostring(n)
|
||||
end
|
||||
|
||||
local function nop_formatter(v)
|
||||
return ''
|
||||
end
|
||||
|
||||
local function make_fixed_formatter(t, has_cache)
|
||||
if has_cache then
|
||||
return function (v)
|
||||
return string.format('[[%s %d]]', t, cache[t][v])
|
||||
end
|
||||
else
|
||||
return function (v)
|
||||
return '[['..t..']]'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function string_formatter(s, force_long_quote)
|
||||
local s, quote = escape(s)
|
||||
local quote_len = force_long_quote and 4 or 2
|
||||
if quote_len + #s + status.len > option.level_width then
|
||||
_n()
|
||||
-- only wrap string when is longer than level_width
|
||||
if option.wrap_string and #s + quote_len > option.level_width then
|
||||
-- keep the quotes together
|
||||
_p('[[')
|
||||
while #s + status.len >= option.level_width do
|
||||
local seg = option.level_width - status.len
|
||||
_p(string.sub(s, 1, seg), true)
|
||||
_n()
|
||||
s = string.sub(s, seg+1)
|
||||
end
|
||||
_p(s) -- print the remaining parts
|
||||
return ']]'
|
||||
end
|
||||
end
|
||||
|
||||
return force_long_quote and '[['..s..']]' or quote..s..quote
|
||||
end
|
||||
|
||||
local function table_formatter(t)
|
||||
if option.use_tostring then
|
||||
local mt = getmetatable(t)
|
||||
if mt and mt.__tostring then
|
||||
return string_formatter(tostring(t), true)
|
||||
end
|
||||
end
|
||||
|
||||
local print_header_ix = nil
|
||||
local ttype = type(t)
|
||||
if option.object_cache then
|
||||
local cache_state = cache.visited_tables[t]
|
||||
local tix = cache[ttype][t]
|
||||
-- FIXME should really handle `cache_state == nil`
|
||||
-- as user might add things through filter_function
|
||||
if cache_state == false then
|
||||
-- already printed, just print the the number
|
||||
return string_formatter(string.format('%s %d', ttype, tix), true)
|
||||
elseif cache_state > 1 then
|
||||
-- appeared more than once, print table header with number
|
||||
print_header_ix = tix
|
||||
cache.visited_tables[t] = false
|
||||
else
|
||||
-- appeared exactly once, print like a normal table
|
||||
end
|
||||
end
|
||||
|
||||
local tlen = #t
|
||||
local wrapped = false
|
||||
_p('{')
|
||||
_indent(option.indent_size)
|
||||
_p(string.rep(' ', option.indent_size - 1))
|
||||
if print_header_ix then
|
||||
_p(string.format('--[[%s %d]] ', ttype, print_header_ix))
|
||||
end
|
||||
for ix = 1,tlen do
|
||||
local v = t[ix]
|
||||
if formatter[type(v)] == nop_formatter or
|
||||
(option.filter_function and option.filter_function(v, ix, t)) then
|
||||
-- pass
|
||||
else
|
||||
if option.wrap_array then
|
||||
wrapped = _n()
|
||||
end
|
||||
_p(format(v)..', ')
|
||||
end
|
||||
end
|
||||
|
||||
-- hashmap part of the table, in contrast to array part
|
||||
local function is_hash_key(k)
|
||||
local numkey = tonumber(k)
|
||||
if numkey ~= k or numkey > tlen then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function print_kv(k, v, t)
|
||||
-- can't use option.show_x as obj may contain custom type
|
||||
if formatter[type(v)] == nop_formatter or
|
||||
formatter[type(k)] == nop_formatter or
|
||||
(option.filter_function and option.filter_function(v, k, t)) then
|
||||
return
|
||||
end
|
||||
wrapped = _n()
|
||||
if is_plain_key(k) then
|
||||
_p(k, true)
|
||||
else
|
||||
_p('[')
|
||||
-- [[]] type string in key is illegal, needs to add spaces inbetween
|
||||
local k = format(k)
|
||||
if string.match(k, '%[%[') then
|
||||
_p(' '..k..' ', true)
|
||||
else
|
||||
_p(k, true)
|
||||
end
|
||||
_p(']')
|
||||
end
|
||||
_p(' = ', true)
|
||||
_p(format(v), true)
|
||||
_p(',', true)
|
||||
end
|
||||
|
||||
if option.sort_keys then
|
||||
local keys = {}
|
||||
for k, _ in pairs(t) do
|
||||
if is_hash_key(k) then
|
||||
table.insert(keys, k)
|
||||
end
|
||||
end
|
||||
table.sort(keys, cmp)
|
||||
for _, k in ipairs(keys) do
|
||||
print_kv(k, t[k], t)
|
||||
end
|
||||
else
|
||||
for k, v in pairs(t) do
|
||||
if is_hash_key(k) then
|
||||
print_kv(k, v, t)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if option.show_metatable then
|
||||
local mt = getmetatable(t)
|
||||
if mt then
|
||||
print_kv('__metatable', mt, t)
|
||||
end
|
||||
end
|
||||
|
||||
_indent(-option.indent_size)
|
||||
-- make { } into {}
|
||||
last = string.gsub(last, '^ +$', '')
|
||||
-- peek last to remove trailing comma
|
||||
last = string.gsub(last, ',%s*$', ' ')
|
||||
if wrapped then
|
||||
_n()
|
||||
end
|
||||
_p('}')
|
||||
|
||||
return ''
|
||||
end
|
||||
|
||||
-- set formatters
|
||||
formatter['nil'] = option.show_nil and tostring_formatter or nop_formatter
|
||||
formatter['boolean'] = option.show_boolean and tostring_formatter or nop_formatter
|
||||
formatter['number'] = option.show_number and number_formatter or nop_formatter -- need to handle math.huge
|
||||
formatter['function'] = option.show_function and make_fixed_formatter('function', option.object_cache) or nop_formatter
|
||||
formatter['thread'] = option.show_thread and make_fixed_formatter('thread', option.object_cache) or nop_formatter
|
||||
formatter['userdata'] = option.show_userdata and make_fixed_formatter('userdata', option.object_cache) or nop_formatter
|
||||
formatter['string'] = option.show_string and string_formatter or nop_formatter
|
||||
formatter['table'] = option.show_table and table_formatter or nop_formatter
|
||||
|
||||
if option.object_cache then
|
||||
-- needs to visit the table before start printing
|
||||
cache_apperance(obj, cache, option)
|
||||
end
|
||||
|
||||
_p(format(obj))
|
||||
printer(last) -- close the buffered one
|
||||
|
||||
-- put cache back if global
|
||||
if option.object_cache == 'global' then
|
||||
pprint._cache = cache
|
||||
end
|
||||
|
||||
return table.concat(buf)
|
||||
end
|
||||
|
||||
-- pprint all the arguments
|
||||
function pprint.pprint( ... )
|
||||
local args = {...}
|
||||
-- select will get an accurate count of array len, counting trailing nils
|
||||
local len = select('#', ...)
|
||||
for ix = 1,len do
|
||||
pprint.pformat(args[ix], nil, io.write)
|
||||
io.write('\n')
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(pprint, {
|
||||
__call = function (_, ...)
|
||||
pprint.pprint(...)
|
||||
end
|
||||
})
|
||||
|
||||
return pprint
|
||||
@@ -0,0 +1,10 @@
|
||||
-- Sequence of items
|
||||
-- Ordered, but have to loop through items to check for inclusion.
|
||||
-- Currently the same as a table.
|
||||
|
||||
|
||||
function Sequence(source)
|
||||
return source
|
||||
end
|
||||
|
||||
return Sequence
|
||||
@@ -0,0 +1,23 @@
|
||||
-- Set of items
|
||||
-- Fast check for inclusion, but unordered.
|
||||
--
|
||||
-- Instead of having to do:
|
||||
-- whitelist = { 'apple'=true, 'cherries'=true, 'melons'=true }
|
||||
--
|
||||
-- you can do:
|
||||
-- whitelist = Set { 'apple', 'cherries', 'melons' }
|
||||
--
|
||||
-- and then use it as:
|
||||
-- print( whitelist['cherries'] ) => true
|
||||
|
||||
function Set(source)
|
||||
set = {}
|
||||
if source then
|
||||
for i,v in ipairs(source) do
|
||||
set[v] = true
|
||||
end
|
||||
end
|
||||
return set
|
||||
end
|
||||
|
||||
return Set
|
||||
@@ -0,0 +1,97 @@
|
||||
-- Enable calling our lua profile code directly from the lua command line,
|
||||
-- which makes it easier to debug.
|
||||
-- We simulate the normal C++ environment by defining the required globals and functions.
|
||||
|
||||
-- Usage:
|
||||
-- > cd profiles
|
||||
-- > lua5.1 debug.lua
|
||||
|
||||
|
||||
-- for more convenient printing of tables
|
||||
local pprint = require('lib/pprint')
|
||||
|
||||
-- globals that are normally set from C++
|
||||
|
||||
-- profiles code modifies this table
|
||||
properties = {}
|
||||
|
||||
-- should match values defined in include/extractor/guidance/road_classification.hpp
|
||||
road_priority_class = {
|
||||
motorway = 0,
|
||||
trunk = 2,
|
||||
primary = 4,
|
||||
secondary = 6,
|
||||
tertiary = 8,
|
||||
main_residential = 10,
|
||||
side_residential = 11,
|
||||
link_road = 14,
|
||||
bike_path = 16,
|
||||
foot_path = 18,
|
||||
connectivity = 31,
|
||||
}
|
||||
|
||||
-- should match values defined in include/extractor/travel_mode.hpp
|
||||
mode = {
|
||||
inaccessible = 0,
|
||||
driving = 1,
|
||||
cycling = 2,
|
||||
walking = 3,
|
||||
ferry = 4,
|
||||
train = 5,
|
||||
pushing_bike = 6,
|
||||
}
|
||||
|
||||
-- input tags, normally extracted from OSM data
|
||||
local way = {
|
||||
highway = 'primary',
|
||||
name = 'Main Street',
|
||||
--width = '3',
|
||||
--maxspeed = '30',
|
||||
--['maxspeed:advisory'] = '25',
|
||||
--oneway = '-1',
|
||||
--service = 'alley',
|
||||
--['oneway:bicycle'] = 'yes',
|
||||
--junction = 'roundabout',
|
||||
--['name:pronunciation'] = 'fuerloong',
|
||||
--route = 'ferry',
|
||||
--duration = '00:01:00',
|
||||
--hov = 'designated',
|
||||
--access = 'no'
|
||||
}
|
||||
-- tag function normally provided via C++
|
||||
function way:get_value_by_key(k)
|
||||
return self[k]
|
||||
end
|
||||
|
||||
-- Mock C++ helper functions which are called from LUA.
|
||||
-- FIXME
|
||||
-- Debugging LUA code that uses these will not work correctly
|
||||
-- unless we reimplement themethods in LUA.
|
||||
|
||||
function durationIsValid(str)
|
||||
return true
|
||||
end
|
||||
|
||||
function parseDuration(str)
|
||||
return 1
|
||||
end
|
||||
|
||||
function canonicalizeStringList(str)
|
||||
return str
|
||||
end
|
||||
|
||||
-- start state of result table, normally set form C++
|
||||
local result = {
|
||||
road_classification = {},
|
||||
forward_speed = -1,
|
||||
backward_speed = -1,
|
||||
}
|
||||
|
||||
-- the profile we want to debug
|
||||
require("car")
|
||||
|
||||
-- call the way function
|
||||
for i=0,10000,1
|
||||
do
|
||||
way_function(way,result)
|
||||
end
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -u
|
||||
|
||||
if [ ! -f docs/http.md ] ; then
|
||||
echo "This script should be run from the repository root directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that the required tools are in the PATH somewhere.
|
||||
# If executed via `npm run build-api-docs`, then node_modules/.bin is in the PATH
|
||||
# and these tools should be found
|
||||
babel -V >/dev/null 2>&1 || { echo >&2 "Can't find babel. Add node_modules/.bin to your path, or run via \"npm run\""; exit 1; }
|
||||
browserify --help >/dev/null 2>&1 || { echo >&2 "Can't find browserify. Add node_modules/.bin to your path, or run via \"npm run\""; exit 1; }
|
||||
uglifyjs -V >/dev/null 2>&1 || { echo >&2 "Can't find uglifyjs. Add node_modules/.bin to your path, or run via \"npm run\""; exit 1; }
|
||||
|
||||
# Clean up previous version
|
||||
rm -rf build/docs
|
||||
|
||||
# Make temp dir to hold docbox template
|
||||
mkdir -p build/docs/tmp/src
|
||||
|
||||
# Copy docbox template scripts into temp dir
|
||||
cp -r node_modules/docbox/src/* build/docs/tmp/src
|
||||
cp -r node_modules/docbox/css build/docs/
|
||||
|
||||
# Copy our images/templates into the temp docs dir
|
||||
cp -r docs/images build/docs
|
||||
cp docs/src/index.html build/docs/tmp
|
||||
cp docs/src/* build/docs/tmp/src/custom
|
||||
mkdir -p build/docs/tmp/content
|
||||
cp docs/*.md build/docs/tmp/content
|
||||
|
||||
# Now, run the scripts to generate the actual final product
|
||||
pushd build/docs/tmp
|
||||
NODE_ENV=production browserify src/index.js | uglifyjs -c -m > ../bundle.js
|
||||
babel src --out-dir lib
|
||||
node lib/render.js ../index.html
|
||||
popd
|
||||
|
||||
# Cleanup
|
||||
rm -rf build/docs/tmp
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict'
|
||||
|
||||
var crypto = require('crypto');
|
||||
var fs = require('fs');
|
||||
|
||||
var idx = process.argv.indexOf('-c');
|
||||
if (idx > -1) {
|
||||
var validate_file = process.argv[idx+1];
|
||||
if (!process.argv[idx+1]) {
|
||||
console.error('Please pass arg to -c with a path to the data.md5sum file used to validate');
|
||||
process.exit(1);
|
||||
}
|
||||
validate(validate_file);
|
||||
} else {
|
||||
// we are generating checksums for all filenames passed
|
||||
var args = process.argv.slice(2);
|
||||
if (args.length > 0) {
|
||||
generate(args);
|
||||
} else {
|
||||
console.error('Please pass either a list of files to generate an md5sum for or validate with "-c data.md5sum"');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function md5FileSync (filename) {
|
||||
var BUFFER_SIZE = 8192;
|
||||
var fd = fs.openSync(filename, 'r');
|
||||
var hash = crypto.createHash('md5');
|
||||
var buffer = new Buffer(BUFFER_SIZE);
|
||||
|
||||
try {
|
||||
var bytesRead;
|
||||
|
||||
do {
|
||||
bytesRead = fs.readSync(fd, buffer, 0, BUFFER_SIZE);
|
||||
hash.update(buffer.slice(0, bytesRead));
|
||||
} while (bytesRead === BUFFER_SIZE)
|
||||
} finally {
|
||||
fs.closeSync(fd);
|
||||
}
|
||||
|
||||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
function generate(files) {
|
||||
files.forEach(function(filename) {
|
||||
var md5_actual = md5FileSync(filename);
|
||||
console.log(md5_actual,'',filename);
|
||||
})
|
||||
}
|
||||
|
||||
function validate(validate_file) {
|
||||
|
||||
var sums = {};
|
||||
var lines = fs.readFileSync(validate_file).
|
||||
toString().
|
||||
split('\n').
|
||||
filter(function(line) {
|
||||
return line !== "";
|
||||
});
|
||||
|
||||
var error = 0;
|
||||
|
||||
lines.forEach(function(line) {
|
||||
var parts = line.split(' ');
|
||||
var filename = parts[1];
|
||||
var md5 = parts[0];
|
||||
sums[filename] = md5;
|
||||
var md5_actual = md5FileSync(filename);
|
||||
if (md5_actual !== md5) {
|
||||
error++;
|
||||
console.error(filename + ': FAILED')
|
||||
} else {
|
||||
console.log(filename + ': OK');
|
||||
}
|
||||
})
|
||||
|
||||
if (error > 0) {
|
||||
console.error('ms5sum.js WARNING: 1 computed checksum did NOT match');
|
||||
console.error('\nExpected:')
|
||||
lines.forEach(function(line) {
|
||||
var parts = line.split(' ');
|
||||
var filename = parts[1];
|
||||
var md5 = parts[0];
|
||||
console.log(md5 + ' ' + filename);
|
||||
})
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user