Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5167d4ade | |||
| 1548803a77 | |||
| 2b2906f97a | |||
| ca464fcd5d | |||
| e9b7b68427 | |||
| 6b8ae24df6 | |||
| 65385b55e9 | |||
| f20dda55c0 | |||
| ff7f8557e3 | |||
| eff1d4e622 | |||
| f82908d509 | |||
| b3b6e16940 | |||
| f9fb0b84a8 | |||
| 83acb46390 | |||
| f36b3fb4bc | |||
| e7be271c43 | |||
| 790b574114 | |||
| b3f59ab92c | |||
| f2333eb31a | |||
| a862e5fb3a | |||
| 2715e5758b | |||
| 454487dd41 | |||
| 2ed4f6eb0c | |||
| d7bcafcb59 | |||
| c37a8ddd83 | |||
| fc3f96abcb | |||
| c37ea441fc | |||
| fa1a4e8bf6 | |||
| 2532d56b85 | |||
| 00fd869224 | |||
| 5661726e2e | |||
| cfa5d7e172 | |||
| fd7791a0e2 | |||
| e32b8bae00 | |||
| 966139cde9 | |||
| ee19383f4d | |||
| 172a8bdcdb | |||
| 543048efcc | |||
| 67c85ffa4c | |||
| c065335882 | |||
| f6313fcbfb | |||
| 6a3ea876b5 | |||
| 64ad308e9d | |||
| 94169a20de | |||
| 5ca38eee3a | |||
| f4f65f62ee | |||
| f89ada7f61 | |||
| ff3b398e23 | |||
| 84cb7865ab | |||
| 75bdf114be | |||
| c2fd64d3cc | |||
| 580c5e39ae | |||
| 8da6281dcd | |||
| f79bcc6b8d | |||
| f2b63ba0aa | |||
| a253111cbe | |||
| a5776288f6 | |||
| dbcf4cab16 | |||
| 4ea3f33376 | |||
| e4cdfb50cd |
+27
-22
@@ -68,7 +68,7 @@ matrix:
|
|||||||
addons: &gcc6
|
addons: &gcc6
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' ENABLE_COVERAGE=ON CUCUMBER_TIMEOUT=20000
|
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' ENABLE_COVERAGE=ON CUCUMBER_TIMEOUT=20000
|
||||||
after_success:
|
after_success:
|
||||||
- bash <(curl -s https://codecov.io/bash)
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
@@ -78,15 +78,15 @@ matrix:
|
|||||||
addons: &gcc6
|
addons: &gcc6
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' TARGET_ARCH='x86_64-asan' ENABLE_SANITIZER=ON CUCUMBER_TIMEOUT=20000
|
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' TARGET_ARCH='x86_64-asan' ENABLE_SANITIZER=ON CUCUMBER_TIMEOUT=20000 LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/scripts/travis/leaksanitizer.conf"
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: "clang-4.0-debug"
|
compiler: "clang-4.0-debug"
|
||||||
addons: &clang40
|
addons: &clang40
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['libstdc++-5-dev', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
packages: ['libstdc++-4.9-dev', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' CUCUMBER_TIMEOUT=60000
|
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' CUCUMBER_TIMEOUT=60000
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
@@ -94,8 +94,8 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['libstdc++-5-dev']
|
packages: ['libstdc++-4.9-dev']
|
||||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_SANITIZER=ON
|
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_SANITIZER=ON LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/scripts/travis/leaksanitizer.conf"
|
||||||
|
|
||||||
# Release Builds
|
# Release Builds
|
||||||
- os: linux
|
- os: linux
|
||||||
@@ -103,7 +103,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['libstdc++-5-dev']
|
packages: ['libstdc++-4.9-dev']
|
||||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON RUN_CLANG_FORMAT=ON ENABLE_LTO=ON
|
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON RUN_CLANG_FORMAT=ON ENABLE_LTO=ON
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
@@ -111,7 +111,7 @@ matrix:
|
|||||||
addons: &gcc6
|
addons: &gcc6
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release'
|
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
@@ -125,7 +125,7 @@ matrix:
|
|||||||
addons: &gcc6
|
addons: &gcc6
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' ENABLE_STXXL=On
|
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' ENABLE_STXXL=On
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
@@ -133,7 +133,7 @@ matrix:
|
|||||||
addons: &gcc49
|
addons: &gcc49
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['g++-4.9', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev', 'ccache']
|
packages: ['g++-4.9', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev', 'ccache']
|
||||||
env: CCOMPILER='gcc-4.9' CXXCOMPILER='g++-4.9' BUILD_TYPE='Release'
|
env: CCOMPILER='gcc-4.9' CXXCOMPILER='g++-4.9' BUILD_TYPE='Release'
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
@@ -158,7 +158,7 @@ matrix:
|
|||||||
#- addons: &clang40
|
#- addons: &clang40
|
||||||
#- apt:
|
#- apt:
|
||||||
#- sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test']
|
#- sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test']
|
||||||
#- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
#- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||||
#- env: CCOMPILER='clang-4.0' CXXCOMPILER='clang++-4.0' BUILD_TYPE='Release'
|
#- env: CCOMPILER='clang-4.0' CXXCOMPILER='clang++-4.0' BUILD_TYPE='Release'
|
||||||
|
|
||||||
# Shared Library
|
# Shared Library
|
||||||
@@ -167,7 +167,7 @@ matrix:
|
|||||||
addons: &gcc6
|
addons: &gcc6
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||||
|
|
||||||
# Disabled because CI slowness
|
# Disabled because CI slowness
|
||||||
@@ -176,7 +176,7 @@ matrix:
|
|||||||
#- addons: &clang40
|
#- addons: &clang40
|
||||||
#- apt:
|
#- apt:
|
||||||
#- sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test']
|
#- sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test']
|
||||||
#- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
#- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev']
|
||||||
#- env: CCOMPILER='clang-4.0' CXXCOMPILER='clang++-4.0' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
#- env: CCOMPILER='clang-4.0' CXXCOMPILER='clang++-4.0' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||||
|
|
||||||
# Node build jobs. These skip running the tests.
|
# Node build jobs. These skip running the tests.
|
||||||
@@ -186,7 +186,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['libstdc++-5-dev']
|
packages: ['libstdc++-4.9-dev']
|
||||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3
|
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3
|
||||||
install:
|
install:
|
||||||
- pushd ${OSRM_BUILD_DIR}
|
- pushd ${OSRM_BUILD_DIR}
|
||||||
@@ -195,7 +195,8 @@ matrix:
|
|||||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||||
-DENABLE_CCACHE=ON \
|
-DENABLE_CCACHE=ON \
|
||||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
|
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||||
|
-DENABLE_GLIBC_WORKAROUND=ON
|
||||||
- make --jobs=${JOBS}
|
- make --jobs=${JOBS}
|
||||||
- popd
|
- popd
|
||||||
script:
|
script:
|
||||||
@@ -209,7 +210,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['libstdc++-5-dev']
|
packages: ['libstdc++-4.9-dev']
|
||||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3
|
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3
|
||||||
install:
|
install:
|
||||||
- pushd ${OSRM_BUILD_DIR}
|
- pushd ${OSRM_BUILD_DIR}
|
||||||
@@ -218,7 +219,8 @@ matrix:
|
|||||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||||
-DENABLE_CCACHE=ON \
|
-DENABLE_CCACHE=ON \
|
||||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
|
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||||
|
-DENABLE_GLIBC_WORKAROUND=ON
|
||||||
- make --jobs=${JOBS}
|
- make --jobs=${JOBS}
|
||||||
- popd
|
- popd
|
||||||
script:
|
script:
|
||||||
@@ -232,7 +234,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['libstdc++-5-dev']
|
packages: ['libstdc++-4.9-dev']
|
||||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="6"
|
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="6"
|
||||||
install:
|
install:
|
||||||
- pushd ${OSRM_BUILD_DIR}
|
- pushd ${OSRM_BUILD_DIR}
|
||||||
@@ -241,7 +243,8 @@ matrix:
|
|||||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||||
-DENABLE_CCACHE=ON \
|
-DENABLE_CCACHE=ON \
|
||||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
|
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||||
|
-DENABLE_GLIBC_WORKAROUND=ON
|
||||||
- make --jobs=${JOBS}
|
- make --jobs=${JOBS}
|
||||||
- popd
|
- popd
|
||||||
script:
|
script:
|
||||||
@@ -255,7 +258,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: ['libstdc++-5-dev']
|
packages: ['libstdc++-4.9-dev']
|
||||||
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="6"
|
env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="6"
|
||||||
install:
|
install:
|
||||||
- pushd ${OSRM_BUILD_DIR}
|
- pushd ${OSRM_BUILD_DIR}
|
||||||
@@ -264,7 +267,8 @@ matrix:
|
|||||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||||
-DENABLE_CCACHE=ON \
|
-DENABLE_CCACHE=ON \
|
||||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
|
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||||
|
-DENABLE_GLIBC_WORKAROUND=ON
|
||||||
- make --jobs=${JOBS}
|
- make --jobs=${JOBS}
|
||||||
- popd
|
- popd
|
||||||
script:
|
script:
|
||||||
@@ -338,7 +342,8 @@ install:
|
|||||||
-DENABLE_STXXL=${ENABLE_STXXL:-OFF} \
|
-DENABLE_STXXL=${ENABLE_STXXL:-OFF} \
|
||||||
-DBUILD_TOOLS=ON \
|
-DBUILD_TOOLS=ON \
|
||||||
-DENABLE_CCACHE=ON \
|
-DENABLE_CCACHE=ON \
|
||||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR}
|
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||||
|
-DENABLE_GLIBC_WORKAROUND=${ENABLE_GLIBC_WORKAROUND:-OFF}
|
||||||
- echo "travis_fold:start:MAKE"
|
- echo "travis_fold:start:MAKE"
|
||||||
- make --jobs=${JOBS}
|
- make --jobs=${JOBS}
|
||||||
- make tests --jobs=${JOBS}
|
- make tests --jobs=${JOBS}
|
||||||
|
|||||||
@@ -1,4 +1,15 @@
|
|||||||
# UNRELEASED
|
# UNRELEASED
|
||||||
|
- Profile:
|
||||||
|
- New function to support relations: `process_relation`. Read more in profiles documentation.
|
||||||
|
- Support of `distance` weight in foot and bicycle profiles
|
||||||
|
- Infrastructure:
|
||||||
|
- Lua 5.1 support is removed due to lack of support in sol2 https://github.com/ThePhD/sol2/issues/302
|
||||||
|
- Node.js Bindings:
|
||||||
|
- Exposes `use_threads_number=Number` parameter of `EngineConfig` to limit a number of threads in a TBB internal pool
|
||||||
|
- Internals
|
||||||
|
- MLD uses a unidirectional Dijkstra for 1-to-N and N-to-1 matrices
|
||||||
|
|
||||||
|
# 5.12.0
|
||||||
- Guidance
|
- Guidance
|
||||||
- now announcing turning onto oneways at the end of a road (e.g. onto dual carriageways)
|
- now announcing turning onto oneways at the end of a road (e.g. onto dual carriageways)
|
||||||
- Adds new instruction types at the exit of roundabouts and rotaries `exit roundabout` and `exit rotary`.
|
- Adds new instruction types at the exit of roundabouts and rotaries `exit roundabout` and `exit rotary`.
|
||||||
|
|||||||
+13
-27
@@ -31,12 +31,13 @@ option(ENABLE_LTO "Use LTO if available" OFF)
|
|||||||
option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF)
|
option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF)
|
||||||
option(ENABLE_GOLD_LINKER "Use GNU gold linker if available" ON)
|
option(ENABLE_GOLD_LINKER "Use GNU gold linker if available" ON)
|
||||||
option(ENABLE_NODE_BINDINGS "Build NodeJs bindings" OFF)
|
option(ENABLE_NODE_BINDINGS "Build NodeJs bindings" OFF)
|
||||||
|
option(ENABLE_GLIBC_WORKAROUND "Workaround GLIBC symbol exports" OFF)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
if(ENABLE_MASON)
|
if(ENABLE_MASON)
|
||||||
# versions in use
|
# versions in use
|
||||||
set(MASON_BOOST_VERSION "1.63.0")
|
set(MASON_BOOST_VERSION "1.65.1")
|
||||||
set(MASON_STXXL_VERSION "1.4.1-1")
|
set(MASON_STXXL_VERSION "1.4.1-1")
|
||||||
set(MASON_EXPAT_VERSION "2.2.0")
|
set(MASON_EXPAT_VERSION "2.2.0")
|
||||||
set(MASON_LUA_VERSION "5.2.4")
|
set(MASON_LUA_VERSION "5.2.4")
|
||||||
@@ -60,7 +61,7 @@ if (POLICY CMP0048)
|
|||||||
endif()
|
endif()
|
||||||
project(OSRM C CXX)
|
project(OSRM C CXX)
|
||||||
set(OSRM_VERSION_MAJOR 5)
|
set(OSRM_VERSION_MAJOR 5)
|
||||||
set(OSRM_VERSION_MINOR 12)
|
set(OSRM_VERSION_MINOR 13)
|
||||||
set(OSRM_VERSION_PATCH 0)
|
set(OSRM_VERSION_PATCH 0)
|
||||||
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
|
||||||
|
|
||||||
@@ -379,8 +380,8 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
|||||||
|
|
||||||
# Activate C++1y
|
# Activate C++1y
|
||||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
|
||||||
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++1y")
|
set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++14")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Configuring other platform dependencies
|
# Configuring other platform dependencies
|
||||||
@@ -517,29 +518,10 @@ else()
|
|||||||
find_package(BZip2 REQUIRED)
|
find_package(BZip2 REQUIRED)
|
||||||
add_dependency_includes(${BZIP2_INCLUDE_DIR})
|
add_dependency_includes(${BZIP2_INCLUDE_DIR})
|
||||||
|
|
||||||
FIND_PACKAGE(Lua 5.2 EXACT)
|
find_package(Lua 5.2 REQUIRED)
|
||||||
IF (LUA_FOUND)
|
if (LUA_FOUND)
|
||||||
MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}")
|
message(STATUS "Using Lua ${LUA_VERSION_STRING}")
|
||||||
ELSE()
|
endif()
|
||||||
FIND_PACKAGE(Lua 5.1 EXACT)
|
|
||||||
IF (LUA_FOUND)
|
|
||||||
MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}")
|
|
||||||
ELSE()
|
|
||||||
# Now fall back to a lua verison without exact
|
|
||||||
# in case this cmake version also forces patch versions
|
|
||||||
FIND_PACKAGE(Lua 5.2)
|
|
||||||
IF (LUA_FOUND)
|
|
||||||
MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}")
|
|
||||||
ELSE()
|
|
||||||
FIND_PACKAGE(Lua 5.1)
|
|
||||||
IF (LUA_FOUND)
|
|
||||||
MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}")
|
|
||||||
ELSE()
|
|
||||||
MESSAGE(FATAL_ERROR "Lua 5.1 or 5.2 was not found.")
|
|
||||||
ENDIF()
|
|
||||||
ENDIF()
|
|
||||||
ENDIF()
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
set(USED_LUA_LIBRARIES ${LUA_LIBRARIES})
|
set(USED_LUA_LIBRARIES ${LUA_LIBRARIES})
|
||||||
add_dependency_includes(${LUA_INCLUDE_DIR})
|
add_dependency_includes(${LUA_INCLUDE_DIR})
|
||||||
@@ -829,6 +811,10 @@ add_custom_target(uninstall
|
|||||||
add_subdirectory(unit_tests)
|
add_subdirectory(unit_tests)
|
||||||
add_subdirectory(src/benchmarks)
|
add_subdirectory(src/benchmarks)
|
||||||
|
|
||||||
|
if (ENABLE_GLIBC_WORKAROUND)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLIBC_WORKAROUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
if (ENABLE_NODE_BINDINGS)
|
if (ENABLE_NODE_BINDINGS)
|
||||||
add_subdirectory(src/nodejs)
|
add_subdirectory(src/nodejs)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -157,7 +157,9 @@ which will check and use pre-built binaries if they're available for this releas
|
|||||||
|
|
||||||
to always force building the Node.js bindings from source.
|
to always force building the Node.js bindings from source.
|
||||||
|
|
||||||
For usage details have a look [these API docs](docs/nodejs/api.md).
|
For usage details have a look [these API docs](docs/nodejs/api.md).
|
||||||
|
|
||||||
|
An exemplary implementation by a 3rd party with Docker and Node.js can be found [here](https://github.com/door2door-io/osrm-express-server-demo).
|
||||||
|
|
||||||
|
|
||||||
## References in publications
|
## References in publications
|
||||||
|
|||||||
+8
-5
@@ -7,19 +7,22 @@ ECHO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||||||
SET PROJECT_DIR=%CD%
|
SET PROJECT_DIR=%CD%
|
||||||
ECHO PROJECT_DIR^: %PROJECT_DIR%
|
ECHO PROJECT_DIR^: %PROJECT_DIR%
|
||||||
ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS%
|
ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS%
|
||||||
|
|
||||||
|
|
||||||
|
:: Check CMake version
|
||||||
|
SET CMAKE_VERSION=3.9.2
|
||||||
|
SET PATH=%PROJECT_DIR%\cmake-%CMAKE_VERSION%-win32-x86\bin;%PATH%
|
||||||
ECHO cmake^: && cmake --version
|
ECHO cmake^: && cmake --version
|
||||||
IF %ERRORLEVEL% NEQ 0 ECHO CMAKE not found && GOTO CMAKE_NOT_OK
|
IF %ERRORLEVEL% NEQ 0 ECHO CMAKE not found && GOTO CMAKE_NOT_OK
|
||||||
|
|
||||||
cmake --version | findstr /C:"3.7.1" && GOTO CMAKE_OK
|
cmake --version | findstr /C:%CMAKE_VERSION% && GOTO CMAKE_OK
|
||||||
|
|
||||||
:CMAKE_NOT_OK
|
:CMAKE_NOT_OK
|
||||||
SET CMAKE_VERSION=3.7.1
|
|
||||||
ECHO CMAKE NOT OK - downloading new CMake %CMAKE_VERSION%
|
ECHO CMAKE NOT OK - downloading new CMake %CMAKE_VERSION%
|
||||||
IF NOT EXIST cm.zip powershell Invoke-WebRequest https://cmake.org/files/v3.7/cmake-%CMAKE_VERSION%-win32-x86.zip -OutFile $env:PROJECT_DIR\cm.zip
|
powershell Invoke-WebRequest https://cmake.org/files/v3.9/cmake-%CMAKE_VERSION%-win32-x86.zip -OutFile $env:PROJECT_DIR\cm.zip
|
||||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||||
IF NOT EXIST cmake-%CMAKE_VERSION%-win32-x86 7z -y x cm.zip | %windir%\system32\FIND "ing archive"
|
IF NOT EXIST cmake-%CMAKE_VERSION%-win32-x86 7z -y x cm.zip | %windir%\system32\FIND "ing archive"
|
||||||
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
|
||||||
SET PATH=%PROJECT_DIR%\cmake-%CMAKE_VERSION%-win32-x86\bin;%PATH%
|
|
||||||
|
|
||||||
:CMAKE_OK
|
:CMAKE_OK
|
||||||
ECHO CMAKE_OK
|
ECHO CMAKE_OK
|
||||||
@@ -37,7 +40,7 @@ ECHO msbuild version
|
|||||||
msbuild /version
|
msbuild /version
|
||||||
|
|
||||||
:: HARDCODE "x64" as it is uppercase on AppVeyor and download from S3 is case sensitive
|
:: HARDCODE "x64" as it is uppercase on AppVeyor and download from S3 is case sensitive
|
||||||
SET DEPSPKG=osrm-deps-win-x64-14.0.7z
|
SET DEPSPKG=osrm-deps-win-x64-14.0-2017.09.7z
|
||||||
|
|
||||||
:: local development
|
:: local development
|
||||||
ECHO.
|
ECHO.
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
# This is because, the lua location is not standardized and may exist in
|
# This is because, the lua location is not standardized and may exist in
|
||||||
# locations other than lua/
|
# locations other than lua/
|
||||||
|
|
||||||
|
include(FindPkgConfig)
|
||||||
|
|
||||||
unset(_lua_include_subdirs)
|
unset(_lua_include_subdirs)
|
||||||
unset(_lua_library_names)
|
unset(_lua_library_names)
|
||||||
unset(_lua_append_versions)
|
unset(_lua_append_versions)
|
||||||
@@ -81,6 +83,7 @@ function(_lua_set_version_vars)
|
|||||||
lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
|
lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
|
||||||
lua.${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
|
lua.${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
|
||||||
)
|
)
|
||||||
|
pkg_check_modules(LUA QUIET "lua${ver}")
|
||||||
endforeach ()
|
endforeach ()
|
||||||
|
|
||||||
set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
|
set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
|
||||||
|
|||||||
+3
-3
@@ -7,7 +7,7 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
|||||||
echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||||
apk update && \
|
apk update && \
|
||||||
apk upgrade && \
|
apk upgrade && \
|
||||||
apk add git cmake wget make libc-dev gcc g++ bzip2-dev boost-dev zlib-dev expat-dev lua5.1-dev libtbb@testing libtbb-dev@testing && \
|
apk add git cmake wget make libc-dev gcc g++ bzip2-dev boost-dev zlib-dev expat-dev lua5.2-dev libtbb@testing libtbb-dev@testing && \
|
||||||
\
|
\
|
||||||
echo "Building libstxxl" && \
|
echo "Building libstxxl" && \
|
||||||
cd /opt && \
|
cd /opt && \
|
||||||
@@ -46,8 +46,8 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
|||||||
rm /usr/local/lib/libstxxl* && \
|
rm /usr/local/lib/libstxxl* && \
|
||||||
cd /opt && \
|
cd /opt && \
|
||||||
apk del boost-dev && \
|
apk del boost-dev && \
|
||||||
apk del g++ cmake libc-dev expat-dev zlib-dev bzip2-dev lua5.1-dev git make gcc && \
|
apk del g++ cmake libc-dev expat-dev zlib-dev bzip2-dev lua5.2-dev git make gcc && \
|
||||||
apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.1 expat && \
|
apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.2 expat && \
|
||||||
rm -rf /src /opt/stxxl /usr/local/bin/stxxl_tool /usr/local/lib/libosrm*
|
rm -rf /src /opt/stxxl /usr/local/bin/stxxl_tool /usr/local/lib/libosrm*
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|||||||
+60
-8
@@ -47,7 +47,7 @@ Profiles can also define a `process_segment` function to handle differences in s
|
|||||||
|
|
||||||
At the end of the file, a table if returned with references to the setup and processing functions the profile has defined.
|
At the end of the file, a table if returned with references to the setup and processing functions the profile has defined.
|
||||||
|
|
||||||
## Understanding speed, weight and rate
|
## Understanding speed, weight and rate
|
||||||
When computing a route from A to B there can be different measure of what is the best route. That's why there's a need for different profiles.
|
When computing a route from A to B there can be different measure of what is the best route. That's why there's a need for different profiles.
|
||||||
|
|
||||||
Because speeds very on different types of roads, the shortest and the fastest route are typically different. But there are many other possible preferences. For example a user might prefer a bicycle route that follow parks or other green areas, even though both duration and distance are a bit longer.
|
Because speeds very on different types of roads, the shortest and the fastest route are typically different. But there are many other possible preferences. For example a user might prefer a bicycle route that follow parks or other green areas, even though both duration and distance are a bit longer.
|
||||||
@@ -91,7 +91,7 @@ The `setup` function is called once when the profile is loaded and must return a
|
|||||||
|
|
||||||
Note that processing of data is parallelized and several unconnected LUA interpreters will be running at the same time. The `setup` function will be called once for each. Each LUA iinterpreter will have it's own set of globals.
|
Note that processing of data is parallelized and several unconnected LUA interpreters will be running at the same time. The `setup` function will be called once for each. Each LUA iinterpreter will have it's own set of globals.
|
||||||
|
|
||||||
The following global properties can be set under `properties` in the hash you return in the `setup` function:
|
The following global properties can be set under `properties` in the hash you return in the `setup` function:
|
||||||
|
|
||||||
Attribute | Type | Notes
|
Attribute | Type | Notes
|
||||||
-------------------------------------|----------|----------------------------------------------------------------------------
|
-------------------------------------|----------|----------------------------------------------------------------------------
|
||||||
@@ -114,7 +114,7 @@ classes | Sequence | Determines the allowed
|
|||||||
restrictions | Sequence | Determines which turn restrictions will be used for this profile.
|
restrictions | Sequence | Determines which turn restrictions will be used for this profile.
|
||||||
suffix_list | Set | List of name suffixes needed for determining if "Highway 101 NW" the same road as "Highway 101 ES".
|
suffix_list | Set | List of name suffixes needed for determining if "Highway 101 NW" the same road as "Highway 101 ES".
|
||||||
|
|
||||||
### process_node(profile, node, result)
|
### process_node(profile, node, result, relations)
|
||||||
Process an OSM node to determine whether this node is a barrier or can be passed and whether passing it incurs a delay.
|
Process an OSM node to determine whether this node is a barrier or can be passed and whether passing it incurs a delay.
|
||||||
|
|
||||||
Argument | Description
|
Argument | Description
|
||||||
@@ -122,6 +122,7 @@ Argument | Description
|
|||||||
profile | The configuration table you returned in `setup`.
|
profile | The configuration table you returned in `setup`.
|
||||||
node | The input node to process (read-only).
|
node | The input node to process (read-only).
|
||||||
result | The output that you will modify.
|
result | The output that you will modify.
|
||||||
|
relations| The list of relation attributes passed from `process_relation` function for this node.
|
||||||
|
|
||||||
The following attributes can be set on `result`:
|
The following attributes can be set on `result`:
|
||||||
|
|
||||||
@@ -130,7 +131,7 @@ Attribute | Type | Notes
|
|||||||
barrier | Boolean | Is it an impassable barrier?
|
barrier | Boolean | Is it an impassable barrier?
|
||||||
traffic_lights | Boolean | Is it a traffic light (incurs delay in `process_turn`)?
|
traffic_lights | Boolean | Is it a traffic light (incurs delay in `process_turn`)?
|
||||||
|
|
||||||
## process_way(profile, way, result)
|
### process_way(profile, way, result, relations)
|
||||||
Given an OpenStreetMap way, the `process_way` function will either return nothing (meaning we are not going to route over this way at all), or it will set up a result hash.
|
Given an OpenStreetMap way, the `process_way` function will either return nothing (meaning we are not going to route over this way at all), or it will set up a result hash.
|
||||||
|
|
||||||
Argument | Description
|
Argument | Description
|
||||||
@@ -138,6 +139,7 @@ Argument | Description
|
|||||||
profile | The configuration table you returned in `setup`.
|
profile | The configuration table you returned in `setup`.
|
||||||
node | The input way to process (read-only).
|
node | The input way to process (read-only).
|
||||||
result | The output that you will modify.
|
result | The output that you will modify.
|
||||||
|
relations| The list of relation attributes passed from `process_relation` function for this way.
|
||||||
|
|
||||||
Importantly it will set `result.forward_mode` and `result.backward_mode` to indicate the travel mode in each direction, as well as set `result.forward_speed` and `result.backward_speed` to integer values representing the speed for traversing the way.
|
Importantly it will set `result.forward_mode` and `result.backward_mode` to indicate the travel mode in each direction, as well as set `result.forward_speed` and `result.backward_speed` to integer values representing the speed for traversing the way.
|
||||||
|
|
||||||
@@ -177,10 +179,60 @@ road_classification.road_priority_class | Enum | Guidance: order in priority
|
|||||||
road_classification.may_be_ignored | Boolean | Guidance: way is non-highway
|
road_classification.may_be_ignored | Boolean | Guidance: way is non-highway
|
||||||
road_classification.num_lanes | Unsigned | Guidance: total number of lanes in way
|
road_classification.num_lanes | Unsigned | Guidance: total number of lanes in way
|
||||||
|
|
||||||
### process_segment(profile, segment)
|
### process_relation(profile, relation, result)
|
||||||
The `process_segment` function is called for every segment of OSM ways. A segment is a straight line between two OSM nodes.
|
|
||||||
|
|
||||||
On OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However many ways are long. For example, many ways pass hills without any change in tags.
|
Supported since API **version 3**.
|
||||||
|
|
||||||
|
Given an OpenStreetMap relation, the `process_relation` function should setup values into result structure.
|
||||||
|
|
||||||
|
Argument | Description
|
||||||
|
---------|-------------------------------------------------------
|
||||||
|
profile | The configuration table you returned in `setup`.
|
||||||
|
node | The input relation to process (read-only).
|
||||||
|
result | The output that you will modify.
|
||||||
|
|
||||||
|
Relation process work flow consist of next steps:
|
||||||
|
1. Calls `process_relation` function for each relation. It should fill a `result` structure
|
||||||
|
2. After that each data will be passed for each member of processed relation into `process_node` and `process_way` functions
|
||||||
|
|
||||||
|
The following attributes can be set on that result in `process_relation`:
|
||||||
|
|
||||||
|
Attribute | Type | Notes
|
||||||
|
----------------------------------------|----------|--------------------------------------------------------------------------
|
||||||
|
is_restriction | Boolean | Flag to determine if relation is a turn restriction
|
||||||
|
|
||||||
|
Example processing code:
|
||||||
|
```lua
|
||||||
|
|
||||||
|
function process_way(profile, way, result, relations)
|
||||||
|
for _, r in ipairs(relations) do
|
||||||
|
for k, v in pairs(r) do
|
||||||
|
print('data_' .. k .. '_value_' .. v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print ('process_way ' .. way:id() .. ' ' .. result.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_relation(profile, relation, result)
|
||||||
|
local t = relation:get_value_by_key("type")
|
||||||
|
if t == "route" then
|
||||||
|
for _, m in ipairs(relation:members()) do
|
||||||
|
if m:role == "north" then
|
||||||
|
result[m]['direction'] = 'north'
|
||||||
|
print('direction_north')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print('route_relation')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### process_segment(profile, segment)
|
||||||
|
The `process_segment` function is called for every segment of OSM ways. A segment is a straight line between two OSM nodes.
|
||||||
|
|
||||||
|
On OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However many ways are long. For example, many ways pass hills without any change in tags.
|
||||||
|
|
||||||
Processing each segment of an OSM way makes it possible to have different speeds on different parts of a way based on external data like data about elevation, pollution, noise or scenic value and adjust weight and duration of the segment.
|
Processing each segment of an OSM way makes it possible to have different speeds on different parts of a way based on external data like data about elevation, pollution, noise or scenic value and adjust weight and duration of the segment.
|
||||||
|
|
||||||
@@ -265,7 +317,7 @@ Example:
|
|||||||
function process_segment (profile, segment)
|
function process_segment (profile, segment)
|
||||||
local sourceData = raster:query(profile.raster_source, segment.source.lon, segment.source.lat)
|
local sourceData = raster:query(profile.raster_source, segment.source.lon, segment.source.lat)
|
||||||
local targetData = raster:query(profile.raster_source, segment.target.lon, segment.target.lat)
|
local targetData = raster:query(profile.raster_source, segment.target.lon, segment.target.lat)
|
||||||
|
|
||||||
local invalid = sourceData.invalid_data()
|
local invalid = sourceData.invalid_data()
|
||||||
if sourceData.datum ~= invalid and targetData.datum ~= invalid then
|
if sourceData.datum ~= invalid and targetData.datum ~= invalid then
|
||||||
-- use values to adjust weight and duration
|
-- use values to adjust weight and duration
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
@routing @bicycle
|
||||||
|
Feature: Bike - Use distance weight
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a grid size of 200 meters
|
||||||
|
|
||||||
|
Scenario: Bike - Check distance weight
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
local functions = require('bicycle')
|
||||||
|
functions.setup_testbot = functions.setup
|
||||||
|
|
||||||
|
functions.setup = function()
|
||||||
|
local profile = functions.setup_testbot()
|
||||||
|
profile.properties.weight_name = 'distance'
|
||||||
|
return profile
|
||||||
|
end
|
||||||
|
|
||||||
|
return functions
|
||||||
|
"""
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a-b-c
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway |
|
||||||
|
| abc | residential |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | weight | time | distance |
|
||||||
|
| a | b | abc,abc | 200 | 48s | 200m +-1 |
|
||||||
|
| a | c | abc,abc | 400 | 96s | 400m +-1 |
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
@routing @foot
|
||||||
|
Feature: Foot - Use distance weight
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a grid size of 200 meters
|
||||||
|
|
||||||
|
Scenario: Foot - Check distance weight
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
local functions = require('foot')
|
||||||
|
functions.setup_testbot = functions.setup
|
||||||
|
|
||||||
|
functions.setup = function()
|
||||||
|
local profile = functions.setup_testbot()
|
||||||
|
profile.properties.weight_name = 'distance'
|
||||||
|
return profile
|
||||||
|
end
|
||||||
|
|
||||||
|
return functions
|
||||||
|
"""
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a-b-c
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway |
|
||||||
|
| abc | residential |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | weight | time | distance |
|
||||||
|
| a | b | abc,abc | 200 | 144s | 200m +-1 |
|
||||||
|
| a | c | abc,abc | 400 | 288s | 400m +-1 |
|
||||||
@@ -280,6 +280,35 @@ Feature: Simple Turns
|
|||||||
| a,d | road,road | depart,arrive |
|
| a,d | road,road | depart,arrive |
|
||||||
| e,a | road,road | depart,arrive |
|
| e,a | road,road | depart,arrive |
|
||||||
|
|
||||||
|
Scenario: Splitting Road with many lanes; same as above makes sure len(turn:lanes) work as expected
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
f - - - - - - - - - - - - - - - - - - - - e
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'
|
||||||
|
a - - - - - b
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'
|
||||||
|
'
|
||||||
|
c - - - - - - - - - - - - - - - - - - - - d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | name | turn:lanes | oneway |
|
||||||
|
| ab | primary | road | left\|left\|right\|right | no |
|
||||||
|
| bcd | primary | road | through\|through | yes |
|
||||||
|
| efb | primary | road | through\|through | yes |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,d | road,road | depart,arrive |
|
||||||
|
| e,a | road,road | depart,arrive |
|
||||||
|
|
||||||
@todo
|
@todo
|
||||||
# currently the intersections don't match up do to the `merging` process.
|
# currently the intersections don't match up do to the `merging` process.
|
||||||
# The intermediate intersection is technically no-turn at all, since the road continues.
|
# The intermediate intersection is technically no-turn at all, since the road continues.
|
||||||
|
|||||||
@@ -1349,3 +1349,24 @@ Feature: Simple Turns
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns |
|
| waypoints | route | turns |
|
||||||
| a,d | ab,dc,dc | depart,turn left,arrive |
|
| a,d | ab,dc,dc | depart,turn left,arrive |
|
||||||
|
|
||||||
|
|
||||||
|
# https://www.openstreetmap.org/node/1332083066
|
||||||
|
Scenario: Turns ordering must respect initial bearings
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a . be .
|
||||||
|
\ c.
|
||||||
|
d/ .f . g
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | oneway |
|
||||||
|
| ab | primary | yes |
|
||||||
|
| bcd | primary | yes |
|
||||||
|
| befg | primary | yes |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,d | ab,bcd,bcd | depart,fork slight right,arrive |
|
||||||
|
| a,g | ab,befg,befg | depart,fork slight left,arrive |
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
@extract
|
||||||
|
Feature: osrm-extract must be silent with NONE
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ab |
|
||||||
|
And the data has been saved to disk
|
||||||
|
|
||||||
|
Scenario: osrm-extract - Passing base file with verbosity NONE
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
functions = require('testbot')
|
||||||
|
|
||||||
|
function way_function(profile, way, result)
|
||||||
|
result.forward_mode = mode.driving
|
||||||
|
result.forward_speed = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
functions.process_way = way_function
|
||||||
|
return functions
|
||||||
|
"""
|
||||||
|
When I run "osrm-extract --profile {profile_file} {osm_file} --verbosity NONE"
|
||||||
|
Then it should exit successfully
|
||||||
|
And stdout should not contain "[info]"
|
||||||
|
And stdout should not contain "[error]"
|
||||||
|
And stdout should not contain "10%"
|
||||||
|
And stderr should be empty
|
||||||
@@ -24,7 +24,7 @@ Feature: Invalid profile API versions
|
|||||||
Scenario: Profile API version too high
|
Scenario: Profile API version too high
|
||||||
Given the profile file
|
Given the profile file
|
||||||
"""
|
"""
|
||||||
api_version = 3
|
api_version = 4
|
||||||
"""
|
"""
|
||||||
And the node map
|
And the node map
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
Feature: Profile API version 3
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a grid size of 100 meters
|
||||||
|
|
||||||
|
Scenario: Basic profile function calls and property values
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
api_version = 3
|
||||||
|
|
||||||
|
Set = require('lib/set')
|
||||||
|
Sequence = require('lib/sequence')
|
||||||
|
Handlers = require("lib/way_handlers")
|
||||||
|
find_access_tag = require("lib/access").find_access_tag
|
||||||
|
limit = require("lib/maxspeed").limit
|
||||||
|
|
||||||
|
|
||||||
|
function setup()
|
||||||
|
return {
|
||||||
|
properties = {
|
||||||
|
max_speed_for_map_matching = 180/3.6,
|
||||||
|
use_turn_restrictions = true,
|
||||||
|
continue_straight_at_waypoint = true,
|
||||||
|
weight_name = 'test_version2',
|
||||||
|
weight_precision = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_node(profile, node, result, relations)
|
||||||
|
print ('process_node ' .. node:id())
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_way(profile, way, result, relations)
|
||||||
|
result.name = way:get_value_by_key('name')
|
||||||
|
result.weight = 10
|
||||||
|
result.forward_mode = mode.driving
|
||||||
|
result.backward_mode = mode.driving
|
||||||
|
result.forward_speed = 36
|
||||||
|
result.backward_speed = 36
|
||||||
|
|
||||||
|
for _, r in ipairs(relations) do
|
||||||
|
for k, v in pairs(r) do
|
||||||
|
print('data_' .. k .. '_value_' .. v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print ('process_way ' .. way:id() .. ' ' .. result.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_relation(profile, relation, result)
|
||||||
|
local t = relation:get_value_by_key("type")
|
||||||
|
if t == "route" then
|
||||||
|
for _, m in ipairs(relation:members()) do
|
||||||
|
if m:role() == "north" then
|
||||||
|
result[m]['direction'] = 'north'
|
||||||
|
print('direction_north')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print('route_relation')
|
||||||
|
end
|
||||||
|
|
||||||
|
print ('process_relation ' .. relation:id())
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_turn (profile, turn)
|
||||||
|
print('process_turn', turn.angle, turn.turn_type, turn.direction_modifier, turn.has_traffic_light)
|
||||||
|
turn.weight = turn.angle == 0 and 0 or 4.2
|
||||||
|
turn.duration = turn.weight
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_segment (profile, segment)
|
||||||
|
print ('process_segment ' .. segment.source.lon .. ' ' .. segment.source.lat)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
setup = setup,
|
||||||
|
process_node = process_node,
|
||||||
|
process_way = process_way,
|
||||||
|
process_relation = process_relation,
|
||||||
|
process_segment = process_segment,
|
||||||
|
process_turn = process_turn
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And the node map
|
||||||
|
"""
|
||||||
|
a
|
||||||
|
bcd
|
||||||
|
e
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ac |
|
||||||
|
| cb |
|
||||||
|
| cd |
|
||||||
|
| ce |
|
||||||
|
|
||||||
|
And the relations
|
||||||
|
| type | way:north | route |
|
||||||
|
| route | ac | road |
|
||||||
|
|
||||||
|
And the data has been saved to disk
|
||||||
|
|
||||||
|
When I run "osrm-extract --profile {profile_file} {osm_file}"
|
||||||
|
Then it should exit successfully
|
||||||
|
And stdout should contain "process_relation"
|
||||||
|
And stdout should contain "route_relation"
|
||||||
|
And stdout should contain "direction_north"
|
||||||
|
And stdout should contain "data_direction_value_north"
|
||||||
|
And stdout should contain "process_node"
|
||||||
|
And stdout should contain "process_way"
|
||||||
|
And stdout should contain "process_turn"
|
||||||
|
And stdout should contain "process_segment"
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | time |
|
||||||
|
| a | b | ac,cb,cb | 19.2s |
|
||||||
|
| a | d | ac,cd,cd | 19.2s |
|
||||||
|
| a | e | ac,ce | 20s |
|
||||||
@@ -11,7 +11,7 @@ module.exports = function () {
|
|||||||
var waypoints = [],
|
var waypoints = [],
|
||||||
columnHeaders = tableRows[0].slice(1),
|
columnHeaders = tableRows[0].slice(1),
|
||||||
rowHeaders = tableRows.map((h) => h[0]).slice(1),
|
rowHeaders = tableRows.map((h) => h[0]).slice(1),
|
||||||
symmetric = columnHeaders.every((ele, i) => ele === rowHeaders[i]);
|
symmetric = columnHeaders.length == rowHeaders.length && columnHeaders.every((ele, i) => ele === rowHeaders[i]);
|
||||||
|
|
||||||
if (symmetric) {
|
if (symmetric) {
|
||||||
columnHeaders.forEach((nodeName) => {
|
columnHeaders.forEach((nodeName) => {
|
||||||
|
|||||||
@@ -41,6 +41,17 @@ Feature: Basic Distance Matrix
|
|||||||
| c | 30 | 20 | 0 | 30 |
|
| c | 30 | 20 | 0 | 30 |
|
||||||
| d | 60 | 50 | 30 | 0 |
|
| d | 60 | 50 | 30 | 0 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 10 | 30 | 60 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 10 |
|
||||||
|
| c | 30 |
|
||||||
|
| d | 60 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time matrix with fuzzy match
|
Scenario: Testbot - Travel time matrix with fuzzy match
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -132,6 +143,13 @@ Feature: Basic Distance Matrix
|
|||||||
| | a | b | e | f |
|
| | a | b | e | f |
|
||||||
| a | 0 | 10 | 20 | 30 |
|
| a | 0 | 10 | 20 | 30 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 10 |
|
||||||
|
| e | 20 |
|
||||||
|
| f | 30 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel time 3x2 matrix
|
Scenario: Testbot - Travel time 3x2 matrix
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@@ -308,3 +326,52 @@ Feature: Basic Distance Matrix
|
|||||||
| 6 | 7 | 6 | 10 | 9 | 1 | 0 | 3.9 | 2.9 |
|
| 6 | 7 | 6 | 10 | 9 | 1 | 0 | 3.9 | 2.9 |
|
||||||
| 7 | 3.1 | 2.1 | 6.1 | 5.1 | 9.1 | 8.1 | 0 | 11 |
|
| 7 | 3.1 | 2.1 | 6.1 | 5.1 | 9.1 | 8.1 | 0 | 11 |
|
||||||
| 8 | 4.1 | 3.1 | 7.1 | 6.1 | 10.1 | 9.1 | 1 | 0 |
|
| 8 | 4.1 | 3.1 | 7.1 | 6.1 | 10.1 | 9.1 | 1 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix with ties
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
local functions = require('testbot')
|
||||||
|
functions.process_segment = function(profile, segment)
|
||||||
|
segment.weight = 1
|
||||||
|
segment.duration = 1
|
||||||
|
end
|
||||||
|
functions.process_turn = function(profile, turn)
|
||||||
|
if turn.angle >= 0 then
|
||||||
|
turn.duration = 16
|
||||||
|
else
|
||||||
|
turn.duration = 4
|
||||||
|
end
|
||||||
|
turn.weight = 0
|
||||||
|
end
|
||||||
|
return functions
|
||||||
|
"""
|
||||||
|
And the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ab |
|
||||||
|
| ac |
|
||||||
|
| bd |
|
||||||
|
| dc |
|
||||||
|
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | distance | time | weight |
|
||||||
|
| a | c | ac,ac | 200m | 5s | 5 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 1 | 5 | 10 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 1 |
|
||||||
|
| c | 15 |
|
||||||
|
| d | 10 |
|
||||||
|
|||||||
@@ -159,14 +159,16 @@ class CellCustomizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EdgeWeight to_weight = weight + subcell_weight;
|
const EdgeWeight to_weight = weight + subcell_weight;
|
||||||
|
const EdgeDuration to_duration = duration + *subcell_duration;
|
||||||
if (!heap.WasInserted(to))
|
if (!heap.WasInserted(to))
|
||||||
{
|
{
|
||||||
heap.Insert(to, to_weight, {true, duration + *subcell_duration});
|
heap.Insert(to, to_weight, {true, to_duration});
|
||||||
}
|
}
|
||||||
else if (to_weight < heap.GetKey(to))
|
else if (std::tie(to_weight, to_duration) <
|
||||||
|
std::tie(heap.GetKey(to), heap.GetData(to).duration))
|
||||||
{
|
{
|
||||||
heap.DecreaseKey(to, to_weight);
|
heap.DecreaseKey(to, to_weight);
|
||||||
heap.GetData(to) = {true, duration + *subcell_duration};
|
heap.GetData(to) = {true, to_duration};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,14 +193,16 @@ class CellCustomizer
|
|||||||
partition.GetCell(level - 1, node) != partition.GetCell(level - 1, to)))
|
partition.GetCell(level - 1, node) != partition.GetCell(level - 1, to)))
|
||||||
{
|
{
|
||||||
const EdgeWeight to_weight = weight + data.weight;
|
const EdgeWeight to_weight = weight + data.weight;
|
||||||
|
const EdgeDuration to_duration = duration + data.duration;
|
||||||
if (!heap.WasInserted(to))
|
if (!heap.WasInserted(to))
|
||||||
{
|
{
|
||||||
heap.Insert(to, to_weight, {false, duration + data.duration});
|
heap.Insert(to, to_weight, {false, duration + data.duration});
|
||||||
}
|
}
|
||||||
else if (to_weight < heap.GetKey(to))
|
else if (std::tie(to_weight, to_duration) <
|
||||||
|
std::tie(heap.GetKey(to), heap.GetData(to).duration))
|
||||||
{
|
{
|
||||||
heap.DecreaseKey(to, to_weight);
|
heap.DecreaseKey(to, to_weight);
|
||||||
heap.GetData(to) = {false, duration + data.duration};
|
heap.GetData(to) = {false, to_duration};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include "util/fingerprint.hpp"
|
#include "util/fingerprint.hpp"
|
||||||
#include "util/json_container.hpp"
|
#include "util/json_container.hpp"
|
||||||
|
|
||||||
|
#include <tbb/task_scheduler_init.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -53,7 +55,8 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Engine(const EngineConfig &config)
|
explicit Engine(const EngineConfig &config)
|
||||||
: route_plugin(config.max_locations_viaroute, config.max_alternatives), //
|
: task_scheduler(config.use_threads_number),
|
||||||
|
route_plugin(config.max_locations_viaroute, config.max_alternatives), //
|
||||||
table_plugin(config.max_locations_distance_table), //
|
table_plugin(config.max_locations_distance_table), //
|
||||||
nearest_plugin(config.max_results_nearest), //
|
nearest_plugin(config.max_results_nearest), //
|
||||||
trip_plugin(config.max_locations_trip), //
|
trip_plugin(config.max_locations_trip), //
|
||||||
@@ -125,6 +128,7 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
|||||||
}
|
}
|
||||||
std::unique_ptr<DataFacadeProvider<Algorithm>> facade_provider;
|
std::unique_ptr<DataFacadeProvider<Algorithm>> facade_provider;
|
||||||
mutable SearchEngineData<Algorithm> heaps;
|
mutable SearchEngineData<Algorithm> heaps;
|
||||||
|
tbb::task_scheduler_init task_scheduler;
|
||||||
|
|
||||||
const plugins::ViaRoutePlugin route_plugin;
|
const plugins::ViaRoutePlugin route_plugin;
|
||||||
const plugins::TablePlugin table_plugin;
|
const plugins::TablePlugin table_plugin;
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ struct EngineConfig final
|
|||||||
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
||||||
bool use_shared_memory = true;
|
bool use_shared_memory = true;
|
||||||
Algorithm algorithm = Algorithm::CH;
|
Algorithm algorithm = Algorithm::CH;
|
||||||
|
int use_threads_number = 1;
|
||||||
|
std::string verbosity;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class RoutingAlgorithmsInterface
|
|||||||
virtual InternalRouteResult
|
virtual InternalRouteResult
|
||||||
DirectShortestPathSearch(const PhantomNodes &phantom_node_pair) const = 0;
|
DirectShortestPathSearch(const PhantomNodes &phantom_node_pair) const = 0;
|
||||||
|
|
||||||
virtual std::vector<EdgeWeight>
|
virtual std::vector<EdgeDuration>
|
||||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices) const = 0;
|
const std::vector<std::size_t> &target_indices) const = 0;
|
||||||
@@ -81,7 +81,7 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
|||||||
InternalRouteResult
|
InternalRouteResult
|
||||||
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override;
|
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override;
|
||||||
|
|
||||||
std::vector<EdgeWeight>
|
std::vector<EdgeDuration>
|
||||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices) const final override;
|
const std::vector<std::size_t> &target_indices) const final override;
|
||||||
@@ -166,16 +166,6 @@ RoutingAlgorithms<Algorithm>::DirectShortestPathSearch(const PhantomNodes &phant
|
|||||||
return routing_algorithms::directShortestPathSearch(heaps, *facade, phantom_nodes);
|
return routing_algorithms::directShortestPathSearch(heaps, *facade, phantom_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
|
||||||
std::vector<EdgeWeight>
|
|
||||||
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
|
||||||
const std::vector<std::size_t> &source_indices,
|
|
||||||
const std::vector<std::size_t> &target_indices) const
|
|
||||||
{
|
|
||||||
return routing_algorithms::manyToManySearch(
|
|
||||||
heaps, *facade, phantom_nodes, source_indices, target_indices);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
inline routing_algorithms::SubMatchingList RoutingAlgorithms<Algorithm>::MapMatching(
|
inline routing_algorithms::SubMatchingList RoutingAlgorithms<Algorithm>::MapMatching(
|
||||||
const routing_algorithms::CandidateLists &candidates_list,
|
const routing_algorithms::CandidateLists &candidates_list,
|
||||||
@@ -211,7 +201,7 @@ InternalManyRoutesResult inline RoutingAlgorithms<
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline std::vector<EdgeWeight>
|
inline std::vector<EdgeDuration>
|
||||||
RoutingAlgorithms<routing_algorithms::corech::Algorithm>::ManyToManySearch(
|
RoutingAlgorithms<routing_algorithms::corech::Algorithm>::ManyToManySearch(
|
||||||
const std::vector<PhantomNode> &,
|
const std::vector<PhantomNode> &,
|
||||||
const std::vector<std::size_t> &,
|
const std::vector<std::size_t> &,
|
||||||
|
|||||||
@@ -17,11 +17,23 @@ namespace routing_algorithms
|
|||||||
{
|
{
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
std::vector<EdgeWeight> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
std::vector<std::size_t> source_indices,
|
||||||
const std::vector<std::size_t> &target_indices);
|
std::vector<std::size_t> target_indices);
|
||||||
|
|
||||||
|
namespace mld
|
||||||
|
{
|
||||||
|
|
||||||
|
template <bool DIRECTION>
|
||||||
|
std::vector<EdgeDuration> oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
|
const DataFacade<Algorithm> &facade,
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
std::size_t phantom_index,
|
||||||
|
std::vector<std::size_t> phantom_indices);
|
||||||
|
|
||||||
|
} // mld
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|||||||
@@ -132,44 +132,16 @@ retrievePackedPathFromHeap(const SearchEngineData<Algorithm>::QueryHeap &forward
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <bool DIRECTION, typename Algorithm, typename... Args>
|
template <bool DIRECTION, typename Algorithm, typename... Args>
|
||||||
void routingStep(const DataFacade<Algorithm> &facade,
|
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
const NodeID node,
|
||||||
NodeID &middle_node,
|
const EdgeWeight weight,
|
||||||
EdgeWeight &path_upper_bound,
|
Args... args)
|
||||||
const bool force_loop_forward,
|
|
||||||
const bool force_loop_reverse,
|
|
||||||
Args... args)
|
|
||||||
{
|
{
|
||||||
const auto &partition = facade.GetMultiLevelPartition();
|
const auto &partition = facade.GetMultiLevelPartition();
|
||||||
const auto &cells = facade.GetCellStorage();
|
const auto &cells = facade.GetCellStorage();
|
||||||
const auto &metric = facade.GetCellMetric();
|
const auto &metric = facade.GetCellMetric();
|
||||||
|
|
||||||
const auto node = forward_heap.DeleteMin();
|
|
||||||
const auto weight = forward_heap.GetKey(node);
|
|
||||||
|
|
||||||
BOOST_ASSERT(!facade.ExcludeNode(node));
|
|
||||||
|
|
||||||
// Upper bound for the path source -> target with
|
|
||||||
// weight(source -> node) = weight weight(to -> target) ≤ reverse_weight
|
|
||||||
// is weight + reverse_weight
|
|
||||||
// More tighter upper bound requires additional condition reverse_heap.WasRemoved(to)
|
|
||||||
// with weight(to -> target) = reverse_weight and all weights ≥ 0
|
|
||||||
if (reverse_heap.WasInserted(node))
|
|
||||||
{
|
|
||||||
auto reverse_weight = reverse_heap.GetKey(node);
|
|
||||||
auto path_weight = weight + reverse_weight;
|
|
||||||
|
|
||||||
// if loops are forced, they are so at the source
|
|
||||||
if (!(force_loop_forward && forward_heap.GetData(node).parent == node) &&
|
|
||||||
!(force_loop_reverse && reverse_heap.GetData(node).parent == node) &&
|
|
||||||
(path_weight >= 0) && (path_weight < path_upper_bound))
|
|
||||||
{
|
|
||||||
middle_node = node;
|
|
||||||
path_upper_bound = path_weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto level = getNodeQueryLevel(partition, node, args...);
|
const auto level = getNodeQueryLevel(partition, node, args...);
|
||||||
|
|
||||||
if (level >= 1 && !forward_heap.GetData(node).from_clique_arc)
|
if (level >= 1 && !forward_heap.GetData(node).from_clique_arc)
|
||||||
@@ -258,6 +230,45 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool DIRECTION, typename Algorithm, typename... Args>
|
||||||
|
void routingStep(const DataFacade<Algorithm> &facade,
|
||||||
|
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
|
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
|
NodeID &middle_node,
|
||||||
|
EdgeWeight &path_upper_bound,
|
||||||
|
const bool force_loop_forward,
|
||||||
|
const bool force_loop_reverse,
|
||||||
|
Args... args)
|
||||||
|
{
|
||||||
|
const auto node = forward_heap.DeleteMin();
|
||||||
|
const auto weight = forward_heap.GetKey(node);
|
||||||
|
|
||||||
|
BOOST_ASSERT(!facade.ExcludeNode(node));
|
||||||
|
|
||||||
|
// Upper bound for the path source -> target with
|
||||||
|
// weight(source -> node) = weight weight(to -> target) ≤ reverse_weight
|
||||||
|
// is weight + reverse_weight
|
||||||
|
// More tighter upper bound requires additional condition reverse_heap.WasRemoved(to)
|
||||||
|
// with weight(to -> target) = reverse_weight and all weights ≥ 0
|
||||||
|
if (reverse_heap.WasInserted(node))
|
||||||
|
{
|
||||||
|
auto reverse_weight = reverse_heap.GetKey(node);
|
||||||
|
auto path_weight = weight + reverse_weight;
|
||||||
|
|
||||||
|
// if loops are forced, they are so at the source
|
||||||
|
if (!(force_loop_forward && forward_heap.GetData(node).parent == node) &&
|
||||||
|
!(force_loop_reverse && reverse_heap.GetData(node).parent == node) &&
|
||||||
|
(path_weight >= 0) && (path_weight < path_upper_bound))
|
||||||
|
{
|
||||||
|
middle_node = node;
|
||||||
|
path_upper_bound = path_weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relax outgoing edges from node
|
||||||
|
relaxOutgoingEdges<DIRECTION>(facade, forward_heap, node, weight, args...);
|
||||||
|
}
|
||||||
|
|
||||||
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
|
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
|
||||||
// This gives us a packed path (node ids) from the base graph around s and t,
|
// This gives us a packed path (node ids) from the base graph around s and t,
|
||||||
// and overlay node ids otherwise. We then have to unpack the overlay clique
|
// and overlay node ids otherwise. We then have to unpack the overlay clique
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#ifndef EXTRACTION_RELATION_HPP
|
||||||
|
#define EXTRACTION_RELATION_HPP
|
||||||
|
|
||||||
|
#include <osmium/osm/relation.hpp>
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ExtractionRelation
|
||||||
|
{
|
||||||
|
using AttributesMap = std::unordered_map<std::string, std::string>;
|
||||||
|
using OsmIDTyped = std::pair<osmium::object_id_type, osmium::item_type>;
|
||||||
|
|
||||||
|
struct OsmIDTypedHash
|
||||||
|
{
|
||||||
|
std::size_t operator()(const OsmIDTyped &id) const
|
||||||
|
{
|
||||||
|
return id.first ^ (static_cast<std::uint64_t>(id.second) << 56);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ExtractionRelation() : is_restriction(false) {}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
is_restriction = false;
|
||||||
|
values.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsRestriction() const { return is_restriction; }
|
||||||
|
|
||||||
|
AttributesMap &GetMember(const osmium::RelationMember &member)
|
||||||
|
{
|
||||||
|
return values[OsmIDTyped(member.ref(), member.type())];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_restriction;
|
||||||
|
std::unordered_map<OsmIDTyped, AttributesMap, OsmIDTypedHash> values;
|
||||||
|
};
|
||||||
|
|
||||||
|
// It contains data of all parsed relations for each node/way element
|
||||||
|
class ExtractionRelationContainer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AttributesMap = ExtractionRelation::AttributesMap;
|
||||||
|
using OsmIDTyped = ExtractionRelation::OsmIDTyped;
|
||||||
|
using RelationList = std::vector<AttributesMap>;
|
||||||
|
|
||||||
|
void AddRelation(const ExtractionRelation &rel)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!rel.is_restriction);
|
||||||
|
for (auto it : rel.values)
|
||||||
|
data[it.first].push_back(it.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
const RelationList &Get(const OsmIDTyped &id) const
|
||||||
|
{
|
||||||
|
const auto it = data.find(id);
|
||||||
|
if (it != data.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
static RelationList empty;
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<OsmIDTyped, RelationList, ExtractionRelation::OsmIDTypedHash> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif // EXTRACTION_RELATION_HPP
|
||||||
@@ -15,6 +15,7 @@ namespace osmium
|
|||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
class Way;
|
class Way;
|
||||||
|
class Relation;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace std
|
namespace std
|
||||||
@@ -44,6 +45,7 @@ namespace extractor
|
|||||||
class ExtractionContainers;
|
class ExtractionContainers;
|
||||||
struct ExtractionNode;
|
struct ExtractionNode;
|
||||||
struct ExtractionWay;
|
struct ExtractionWay;
|
||||||
|
struct ExtractionRelation;
|
||||||
struct ProfileProperties;
|
struct ProfileProperties;
|
||||||
struct InputConditionalTurnRestriction;
|
struct InputConditionalTurnRestriction;
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,14 @@ class CoordinateExtractor
|
|||||||
const double length,
|
const double length,
|
||||||
const double rate) const;
|
const double rate) const;
|
||||||
|
|
||||||
|
// find the coordinate at a specific distance in the vector
|
||||||
|
util::Coordinate
|
||||||
|
ExtractCoordinateAtLength(const double distance,
|
||||||
|
const std::vector<util::Coordinate> &coordinates) const;
|
||||||
|
util::Coordinate ExtractCoordinateAtLength(const double distance,
|
||||||
|
const std::vector<util::Coordinate> &coordinates,
|
||||||
|
const std::vector<double> &length_cache) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
const extractor::CompressedEdgeContainer &compressed_geometries;
|
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||||
@@ -241,14 +249,6 @@ class CoordinateExtractor
|
|||||||
const double segment_length,
|
const double segment_length,
|
||||||
const std::vector<double> &segment_distances,
|
const std::vector<double> &segment_distances,
|
||||||
const std::uint8_t considered_lanes) const;
|
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
|
} // namespace guidance
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace osmium
|
|||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
class Way;
|
class Way;
|
||||||
|
class Relation;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@@ -33,8 +34,10 @@ namespace extractor
|
|||||||
{
|
{
|
||||||
|
|
||||||
class RestrictionParser;
|
class RestrictionParser;
|
||||||
|
class ExtractionRelationContainer;
|
||||||
struct ExtractionNode;
|
struct ExtractionNode;
|
||||||
struct ExtractionWay;
|
struct ExtractionWay;
|
||||||
|
struct ExtractionRelation;
|
||||||
struct ExtractionTurn;
|
struct ExtractionTurn;
|
||||||
struct ExtractionSegment;
|
struct ExtractionSegment;
|
||||||
|
|
||||||
@@ -59,12 +62,14 @@ class ScriptingEnvironment
|
|||||||
virtual void ProcessTurn(ExtractionTurn &turn) = 0;
|
virtual void ProcessTurn(ExtractionTurn &turn) = 0;
|
||||||
virtual void ProcessSegment(ExtractionSegment &segment) = 0;
|
virtual void ProcessSegment(ExtractionSegment &segment) = 0;
|
||||||
|
|
||||||
virtual void
|
virtual void ProcessElements(
|
||||||
ProcessElements(const osmium::memory::Buffer &buffer,
|
const osmium::memory::Buffer &buffer,
|
||||||
const RestrictionParser &restriction_parser,
|
const RestrictionParser &restriction_parser,
|
||||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
const ExtractionRelationContainer &relations,
|
||||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) = 0;
|
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||||
|
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> &resulting_relations,
|
||||||
|
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef SCRIPTING_ENVIRONMENT_LUA_HPP
|
#ifndef SCRIPTING_ENVIRONMENT_LUA_HPP
|
||||||
#define SCRIPTING_ENVIRONMENT_LUA_HPP
|
#define SCRIPTING_ENVIRONMENT_LUA_HPP
|
||||||
|
|
||||||
|
#include "extractor/extraction_relation.hpp"
|
||||||
#include "extractor/raster_source.hpp"
|
#include "extractor/raster_source.hpp"
|
||||||
#include "extractor/scripting_environment.hpp"
|
#include "extractor/scripting_environment.hpp"
|
||||||
|
|
||||||
@@ -19,8 +20,13 @@ namespace extractor
|
|||||||
|
|
||||||
struct LuaScriptingContext final
|
struct LuaScriptingContext final
|
||||||
{
|
{
|
||||||
void ProcessNode(const osmium::Node &, ExtractionNode &result);
|
void ProcessNode(const osmium::Node &,
|
||||||
void ProcessWay(const osmium::Way &, ExtractionWay &result);
|
ExtractionNode &result,
|
||||||
|
const ExtractionRelationContainer::RelationList &relations);
|
||||||
|
void ProcessWay(const osmium::Way &,
|
||||||
|
ExtractionWay &result,
|
||||||
|
const ExtractionRelationContainer::RelationList &relations);
|
||||||
|
void ProcessRelation(const osmium::Relation &, ExtractionRelation &result);
|
||||||
|
|
||||||
ProfileProperties properties;
|
ProfileProperties properties;
|
||||||
RasterContainer raster_sources;
|
RasterContainer raster_sources;
|
||||||
@@ -29,11 +35,13 @@ struct LuaScriptingContext final
|
|||||||
bool has_turn_penalty_function;
|
bool has_turn_penalty_function;
|
||||||
bool has_node_function;
|
bool has_node_function;
|
||||||
bool has_way_function;
|
bool has_way_function;
|
||||||
|
bool has_relation_function;
|
||||||
bool has_segment_function;
|
bool has_segment_function;
|
||||||
|
|
||||||
sol::function turn_function;
|
sol::function turn_function;
|
||||||
sol::function way_function;
|
sol::function way_function;
|
||||||
sol::function node_function;
|
sol::function node_function;
|
||||||
|
sol::function relation_function;
|
||||||
sol::function segment_function;
|
sol::function segment_function;
|
||||||
|
|
||||||
int api_version;
|
int api_version;
|
||||||
@@ -51,7 +59,7 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const constexpr int SUPPORTED_MIN_API_VERSION = 0;
|
static const constexpr int SUPPORTED_MIN_API_VERSION = 0;
|
||||||
static const constexpr int SUPPORTED_MAX_API_VERSION = 2;
|
static const constexpr int SUPPORTED_MAX_API_VERSION = 3;
|
||||||
|
|
||||||
explicit Sol2ScriptingEnvironment(const std::string &file_name);
|
explicit Sol2ScriptingEnvironment(const std::string &file_name);
|
||||||
~Sol2ScriptingEnvironment() override = default;
|
~Sol2ScriptingEnvironment() override = default;
|
||||||
@@ -65,12 +73,14 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
|
|||||||
void ProcessTurn(ExtractionTurn &turn) override;
|
void ProcessTurn(ExtractionTurn &turn) override;
|
||||||
void ProcessSegment(ExtractionSegment &segment) override;
|
void ProcessSegment(ExtractionSegment &segment) override;
|
||||||
|
|
||||||
void
|
void ProcessElements(
|
||||||
ProcessElements(const osmium::memory::Buffer &buffer,
|
const osmium::memory::Buffer &buffer,
|
||||||
const RestrictionParser &restriction_parser,
|
const RestrictionParser &restriction_parser,
|
||||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
const ExtractionRelationContainer &relations,
|
||||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) override;
|
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||||
|
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> &resulting_relations,
|
||||||
|
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LuaScriptingContext &GetSol2Context();
|
LuaScriptingContext &GetSol2Context();
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
|||||||
params->Get(Nan::New("max_locations_map_matching").ToLocalChecked());
|
params->Get(Nan::New("max_locations_map_matching").ToLocalChecked());
|
||||||
auto max_results_nearest = params->Get(Nan::New("max_results_nearest").ToLocalChecked());
|
auto max_results_nearest = params->Get(Nan::New("max_results_nearest").ToLocalChecked());
|
||||||
auto max_alternatives = params->Get(Nan::New("max_alternatives").ToLocalChecked());
|
auto max_alternatives = params->Get(Nan::New("max_alternatives").ToLocalChecked());
|
||||||
|
auto use_threads_number = params->Get(Nan::New("use_threads_number").ToLocalChecked());
|
||||||
|
|
||||||
if (!max_locations_trip->IsUndefined() && !max_locations_trip->IsNumber())
|
if (!max_locations_trip->IsUndefined() && !max_locations_trip->IsNumber())
|
||||||
{
|
{
|
||||||
@@ -217,6 +218,11 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
|||||||
Nan::ThrowError("max_alternatives must be an integral number");
|
Nan::ThrowError("max_alternatives must be an integral number");
|
||||||
return engine_config_ptr();
|
return engine_config_ptr();
|
||||||
}
|
}
|
||||||
|
if (!use_threads_number->IsUndefined() && !use_threads_number->IsNumber())
|
||||||
|
{
|
||||||
|
Nan::ThrowError("use_threads_number must be an integral number");
|
||||||
|
return engine_config_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
if (max_locations_trip->IsNumber())
|
if (max_locations_trip->IsNumber())
|
||||||
engine_config->max_locations_trip = static_cast<int>(max_locations_trip->NumberValue());
|
engine_config->max_locations_trip = static_cast<int>(max_locations_trip->NumberValue());
|
||||||
@@ -233,6 +239,8 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
|||||||
engine_config->max_results_nearest = static_cast<int>(max_results_nearest->NumberValue());
|
engine_config->max_results_nearest = static_cast<int>(max_results_nearest->NumberValue());
|
||||||
if (max_alternatives->IsNumber())
|
if (max_alternatives->IsNumber())
|
||||||
engine_config->max_alternatives = static_cast<int>(max_alternatives->NumberValue());
|
engine_config->max_alternatives = static_cast<int>(max_alternatives->NumberValue());
|
||||||
|
if (use_threads_number->IsNumber())
|
||||||
|
engine_config->use_threads_number = static_cast<int>(use_threads_number->NumberValue());
|
||||||
|
|
||||||
return engine_config;
|
return engine_config;
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-2
@@ -53,10 +53,40 @@ class Log
|
|||||||
virtual ~Log();
|
virtual ~Log();
|
||||||
std::mutex &get_mutex();
|
std::mutex &get_mutex();
|
||||||
|
|
||||||
template <typename T> inline std::ostream &operator<<(const T &data) { return stream << data; }
|
template <typename T> inline Log &operator<<(const T &data)
|
||||||
|
{
|
||||||
|
const auto &policy = LogPolicy::GetInstance();
|
||||||
|
if (!policy.IsMute() && level <= policy.GetLevel())
|
||||||
|
{
|
||||||
|
stream << data;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> inline Log &operator<<(const std::atomic<T> &data)
|
||||||
|
{
|
||||||
|
const auto &policy = LogPolicy::GetInstance();
|
||||||
|
if (!policy.IsMute() && level <= policy.GetLevel())
|
||||||
|
{
|
||||||
|
stream << T(data);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::ostream &(manip)(std::ostream &);
|
||||||
|
|
||||||
|
inline Log &operator<<(manip &m)
|
||||||
|
{
|
||||||
|
const auto &policy = LogPolicy::GetInstance();
|
||||||
|
if (!policy.IsMute() && level <= policy.GetLevel())
|
||||||
|
{
|
||||||
|
stream << m;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LogLevel level;
|
const LogLevel level;
|
||||||
std::ostringstream buffer;
|
std::ostringstream buffer;
|
||||||
std::ostream &stream;
|
std::ostream &stream;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ class Percent
|
|||||||
// When not on a TTY, print newlines after each progress indicator so
|
// When not on a TTY, print newlines after each progress indicator so
|
||||||
// so that progress is visible to line-buffered logging systems
|
// so that progress is visible to line-buffered logging systems
|
||||||
if (!IsStdoutATTY())
|
if (!IsStdoutATTY())
|
||||||
log << "" << std::endl;
|
log << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "osrm",
|
"name": "osrm",
|
||||||
"version": "5.12.0-roundaboutexits.1",
|
"version": "5.13.0-glibc.2",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -536,7 +536,7 @@ function process_way(profile, way, result)
|
|||||||
|
|
||||||
-- handle turn lanes and road classification, used for guidance
|
-- handle turn lanes and road classification, used for guidance
|
||||||
WayHandlers.classification,
|
WayHandlers.classification,
|
||||||
|
|
||||||
-- handle allowed start/end modes
|
-- handle allowed start/end modes
|
||||||
WayHandlers.startpoint,
|
WayHandlers.startpoint,
|
||||||
|
|
||||||
@@ -544,7 +544,10 @@ function process_way(profile, way, result)
|
|||||||
WayHandlers.roundabouts,
|
WayHandlers.roundabouts,
|
||||||
|
|
||||||
-- set name, ref and pronunciation
|
-- set name, ref and pronunciation
|
||||||
WayHandlers.names
|
WayHandlers.names,
|
||||||
|
|
||||||
|
-- set weight properties of the way
|
||||||
|
WayHandlers.weights
|
||||||
}
|
}
|
||||||
|
|
||||||
WayHandlers.run(profile,way,result,data,handlers)
|
WayHandlers.run(profile,way,result,data,handlers)
|
||||||
|
|||||||
@@ -250,10 +250,12 @@ function setup()
|
|||||||
|
|
||||||
-- List only exceptions
|
-- List only exceptions
|
||||||
maxspeed_table = {
|
maxspeed_table = {
|
||||||
|
["be:motorway"] = 120,
|
||||||
["ch:rural"] = 80,
|
["ch:rural"] = 80,
|
||||||
["ch:trunk"] = 100,
|
["ch:trunk"] = 100,
|
||||||
["ch:motorway"] = 120,
|
["ch:motorway"] = 120,
|
||||||
["de:living_street"] = 7,
|
["de:living_street"] = 7,
|
||||||
|
["dk:rural"] = 80,
|
||||||
["ru:living_street"] = 20,
|
["ru:living_street"] = 20,
|
||||||
["ru:urban"] = 60,
|
["ru:urban"] = 60,
|
||||||
["ua:urban"] = 60,
|
["ua:urban"] = 60,
|
||||||
|
|||||||
+4
-1
@@ -237,7 +237,10 @@ function process_way(profile, way, result)
|
|||||||
WayHandlers.startpoint,
|
WayHandlers.startpoint,
|
||||||
|
|
||||||
-- set name, ref and pronunciation
|
-- set name, ref and pronunciation
|
||||||
WayHandlers.names
|
WayHandlers.names,
|
||||||
|
|
||||||
|
-- set weight properties of the way
|
||||||
|
WayHandlers.weights
|
||||||
}
|
}
|
||||||
|
|
||||||
WayHandlers.run(profile,way,result,data,handlers)
|
WayHandlers.run(profile,way,result,data,handlers)
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ with open(taginfo_path) as f:
|
|||||||
|
|
||||||
valid_strings = [t["key"] for t in taginfo["tags"]]
|
valid_strings = [t["key"] for t in taginfo["tags"]]
|
||||||
valid_strings += [t["value"] for t in taginfo["tags"] if "value" in t]
|
valid_strings += [t["value"] for t in taginfo["tags"] if "value" in t]
|
||||||
|
valid_strings += [t["value"].lower() for t in taginfo["tags"] if "value" in t] # lower is for max speed
|
||||||
|
valid_strings = set(valid_strings)
|
||||||
|
|
||||||
string_regxp = re.compile("\"([\d\w\_:]+)\"")
|
string_regxp = re.compile("\"([\d\w\_:]+)\"")
|
||||||
|
|
||||||
|
|||||||
+21
-9
@@ -145,7 +145,8 @@ class SVGPrinter (gdb.Command):
|
|||||||
self.to_svg = {
|
self.to_svg = {
|
||||||
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> &': self.Facade,
|
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::ch::Algorithm> &': self.Facade,
|
||||||
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::corech::Algorithm> &': self.Facade,
|
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::corech::Algorithm> &': self.Facade,
|
||||||
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::mld::Algorithm> &': self.Facade}
|
'const osrm::engine::datafacade::ContiguousInternalMemoryDataFacade<osrm::engine::routing_algorithms::mld::Algorithm> &': self.Facade,
|
||||||
|
'osrm::engine::DataFacade': self.Facade}
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -258,17 +259,27 @@ class SVGPrinter (gdb.Command):
|
|||||||
geometry_first = geometry['_M_impl']['_M_start']
|
geometry_first = geometry['_M_impl']['_M_start']
|
||||||
for segment, weight in enumerate(iterate(weights)):
|
for segment, weight in enumerate(iterate(weights)):
|
||||||
ref = 's' + str(node) + '.' + str(segment)
|
ref = 's' + str(node) + '.' + str(segment)
|
||||||
result += '<path id="' + ref + '" class="segment" d="' \
|
fr = lonlat(call(facade, 'GetCoordinateOfNode', geometry_first.dereference()))
|
||||||
+ 'M' + t(lonlat(call(facade, 'GetCoordinateOfNode', geometry_first.dereference()))) + ' ' \
|
to = lonlat(call(facade, 'GetCoordinateOfNode', (geometry_first+1).dereference()))
|
||||||
+ 'L' + t(lonlat(call(facade, 'GetCoordinateOfNode', (geometry_first+1).dereference()))) + '" />'\
|
if fr == to:
|
||||||
+ '<text class="segment weight ' + direction + '">'\
|
## node penalty on zero length segment (traffic light)
|
||||||
+ '<textPath xlink:href="#' + ref + '" startOffset="50%">' \
|
result += '<text class="segment weight ' + direction \
|
||||||
+ segment_weight(weight) + '</textPath></text>\n'
|
+ '" x="' + str(tx(fr[0])) + '" y="' + str(ty(fr[1])) \
|
||||||
|
+ '" font="Arial" font-size="32" rotate="0" text-anchor="middle" >' \
|
||||||
|
+ '🚦 ' + segment_weight(weight) + '</text>\n'
|
||||||
|
else:
|
||||||
|
## normal segment
|
||||||
|
result += '<path id="' + ref + '" class="segment" d="' \
|
||||||
|
+ 'M' + t(fr) + ' ' \
|
||||||
|
+ 'L' + t(to) + '" />'\
|
||||||
|
+ '<text class="segment weight ' + direction + '">'\
|
||||||
|
+ '<textPath xlink:href="#' + ref + '" startOffset="50%">' \
|
||||||
|
+ segment_weight(weight) + '</textPath></text>\n'
|
||||||
geometry_first += 1
|
geometry_first += 1
|
||||||
|
|
||||||
## add edge-based edges
|
## add edge-based edges
|
||||||
s0, s1 = geometry['_M_impl']['_M_start'].dereference(), (geometry['_M_impl']['_M_start'] + 1).dereference()
|
s0, s1 = geometry['_M_impl']['_M_start'].dereference(), (geometry['_M_impl']['_M_start'] + 1).dereference()
|
||||||
for edge in range(call(facade, 'BeginEdges', node), call(facade, 'EndEdges', node)):
|
for edge in []: # range(call(facade, 'BeginEdges', node), call(facade, 'EndEdges', node)): adjust to GetAdjacentEdgeRange
|
||||||
target, edge_data = call(facade, 'GetTarget', edge), call(facade, 'GetEdgeData', edge)
|
target, edge_data = call(facade, 'GetTarget', edge), call(facade, 'GetEdgeData', edge)
|
||||||
direction = 'both' if edge_data['forward'] and edge_data['backward'] else 'forward' if edge_data['forward'] else 'backward'
|
direction = 'both' if edge_data['forward'] and edge_data['backward'] else 'forward' if edge_data['forward'] else 'backward'
|
||||||
target_geometry = SVGPrinter.getByGeometryId(facade, call(facade, 'GetGeometryIndex', target), 'Geometry')
|
target_geometry = SVGPrinter.getByGeometryId(facade, call(facade, 'GetGeometryIndex', target), 'Geometry')
|
||||||
@@ -323,7 +334,8 @@ class SVGPrinter (gdb.Command):
|
|||||||
re_float = '[-+]?[0-9]*\.?[0-9]+'
|
re_float = '[-+]?[0-9]*\.?[0-9]+'
|
||||||
bbox = re.search('(' + re_float + '),(' + re_float + ');(' + re_float + '),(' + re_float +')', arg)
|
bbox = re.search('(' + re_float + '),(' + re_float + ');(' + re_float + '),(' + re_float +')', arg)
|
||||||
bbox = [float(x) for x in bbox.groups()] if bbox else [-180, -90, 180, 90]
|
bbox = [float(x) for x in bbox.groups()] if bbox else [-180, -90, 180, 90]
|
||||||
svg = self.to_svg[str(val.type)](val, width, height, bbox)
|
type = val.type.target().unqualified() if val.type.code == gdb.TYPE_CODE_REF else val.type
|
||||||
|
svg = self.to_svg[str(type)](val, width, height, bbox)
|
||||||
self.show_svg(svg, width, height)
|
self.show_svg(svg, width, height)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
print ('no SVG printer for: ' + str(e))
|
print ('no SVG printer for: ' + str(e))
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Configuration file for LeakSanitizer run on the Travis CI
|
||||||
|
|
||||||
|
# TBB leaks some memory allocated in singleton depending on deinitialization order
|
||||||
|
# Direct leak of 1560 byte(s) in 3 object(s) allocated from:
|
||||||
|
# #0 0x7f7ae72a80a0 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc80a0)
|
||||||
|
# #1 0x7f7ae595d13e (/usr/lib/x86_64-linux-gnu/libtbb.so.2+0x2213e)
|
||||||
|
|
||||||
|
leak:libtbb.so
|
||||||
@@ -20,7 +20,7 @@ bool EngineConfig::IsValid() const
|
|||||||
unlimited_or_more_than(max_locations_trip, 2) &&
|
unlimited_or_more_than(max_locations_trip, 2) &&
|
||||||
unlimited_or_more_than(max_locations_viaroute, 2) &&
|
unlimited_or_more_than(max_locations_viaroute, 2) &&
|
||||||
unlimited_or_more_than(max_results_nearest, 0) &&
|
unlimited_or_more_than(max_results_nearest, 0) &&
|
||||||
max_alternatives >= 0;
|
max_alternatives >= 0 && use_threads_number >= 1;
|
||||||
|
|
||||||
return ((use_shared_memory && all_path_are_empty) || storage_config.IsValid()) && limits_valid;
|
return ((use_shared_memory && all_path_are_empty) || storage_config.IsValid()) && limits_valid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#include "engine/routing_algorithms.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename Algorithm>
|
||||||
|
std::vector<EdgeDuration>
|
||||||
|
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
const std::vector<std::size_t> &source_indices,
|
||||||
|
const std::vector<std::size_t> &target_indices) const
|
||||||
|
{
|
||||||
|
return routing_algorithms::manyToManySearch(
|
||||||
|
heaps, *facade, phantom_nodes, source_indices, target_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
template std::vector<EdgeDuration>
|
||||||
|
RoutingAlgorithms<routing_algorithms::ch::Algorithm>::ManyToManySearch(
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
const std::vector<std::size_t> &source_indices,
|
||||||
|
const std::vector<std::size_t> &target_indices) const;
|
||||||
|
|
||||||
|
template std::vector<EdgeDuration>
|
||||||
|
RoutingAlgorithms<routing_algorithms::corech::Algorithm>::ManyToManySearch(
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
const std::vector<std::size_t> &source_indices,
|
||||||
|
const std::vector<std::size_t> &target_indices) const;
|
||||||
|
|
||||||
|
// One-to-many and many-to-one can be handled with MLD separately from many-to-many search.
|
||||||
|
// One-to-many (many-to-one) search is a unidirectional forward (backward) Dijkstra search
|
||||||
|
// with the candidate node level min(GetQueryLevel(phantom_node, phantom_nodes, node)
|
||||||
|
template <>
|
||||||
|
std::vector<EdgeDuration> RoutingAlgorithms<routing_algorithms::mld::Algorithm>::ManyToManySearch(
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
const std::vector<std::size_t> &source_indices,
|
||||||
|
const std::vector<std::size_t> &target_indices) const
|
||||||
|
{
|
||||||
|
if (source_indices.size() == 1)
|
||||||
|
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
||||||
|
return routing_algorithms::mld::oneToManySearch<routing_algorithms::FORWARD_DIRECTION>(
|
||||||
|
heaps, *facade, phantom_nodes, source_indices.front(), target_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_indices.size() == 1)
|
||||||
|
{
|
||||||
|
return routing_algorithms::mld::oneToManySearch<routing_algorithms::REVERSE_DIRECTION>(
|
||||||
|
heaps, *facade, phantom_nodes, target_indices.front(), source_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
return routing_algorithms::manyToManySearch(
|
||||||
|
heaps, *facade, phantom_nodes, source_indices, target_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace engine
|
||||||
|
} // namespace osrm
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
#include "engine/routing_algorithms/routing_base_ch.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/range/iterator_range_core.hpp>
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -19,17 +20,33 @@ namespace
|
|||||||
{
|
{
|
||||||
struct NodeBucket
|
struct NodeBucket
|
||||||
{
|
{
|
||||||
unsigned target_id; // essentially a row in the weight matrix
|
NodeID middle_node;
|
||||||
|
unsigned column_index; // a column in the weight/duration matrix
|
||||||
EdgeWeight weight;
|
EdgeWeight weight;
|
||||||
EdgeWeight duration;
|
EdgeDuration duration;
|
||||||
NodeBucket(const unsigned target_id, const EdgeWeight weight, const EdgeWeight duration)
|
|
||||||
: target_id(target_id), weight(weight), duration(duration)
|
NodeBucket(NodeID middle_node, unsigned column_index, EdgeWeight weight, EdgeDuration duration)
|
||||||
|
: middle_node(middle_node), column_index(column_index), weight(weight), duration(duration)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME This should be replaced by an std::unordered_multimap, though this needs benchmarking
|
// partial order comparison
|
||||||
using SearchSpaceWithBuckets = std::unordered_map<NodeID, std::vector<NodeBucket>>;
|
bool operator<(const NodeBucket &rhs) const { return middle_node < rhs.middle_node; }
|
||||||
|
|
||||||
|
// functor for equal_range
|
||||||
|
struct Compare
|
||||||
|
{
|
||||||
|
bool operator()(const NodeBucket &lhs, const NodeID &rhs) const
|
||||||
|
{
|
||||||
|
return lhs.middle_node < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const NodeID &lhs, const NodeBucket &rhs) const
|
||||||
|
{
|
||||||
|
return lhs < rhs.middle_node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
inline bool addLoopWeight(const DataFacade<ch::Algorithm> &facade,
|
inline bool addLoopWeight(const DataFacade<ch::Algorithm> &facade,
|
||||||
const NodeID node,
|
const NodeID node,
|
||||||
@@ -74,12 +91,12 @@ void relaxOutgoingEdges(const DataFacade<ch::Algorithm> &facade,
|
|||||||
{
|
{
|
||||||
const NodeID to = facade.GetTarget(edge);
|
const NodeID to = facade.GetTarget(edge);
|
||||||
|
|
||||||
const EdgeWeight edge_weight = data.weight;
|
const auto edge_weight = data.weight;
|
||||||
const EdgeWeight edge_duration = data.duration;
|
const auto edge_duration = data.duration;
|
||||||
|
|
||||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||||
const EdgeWeight to_weight = weight + edge_weight;
|
const auto to_weight = weight + edge_weight;
|
||||||
const EdgeWeight to_duration = duration + edge_duration;
|
const auto to_duration = duration + edge_duration;
|
||||||
|
|
||||||
// New Node discovered -> Add to Heap + Node Info Storage
|
// New Node discovered -> Add to Heap + Node Info Storage
|
||||||
if (!query_heap.WasInserted(to))
|
if (!query_heap.WasInserted(to))
|
||||||
@@ -87,7 +104,8 @@ void relaxOutgoingEdges(const DataFacade<ch::Algorithm> &facade,
|
|||||||
query_heap.Insert(to, to_weight, {node, to_duration});
|
query_heap.Insert(to, to_weight, {node, to_duration});
|
||||||
}
|
}
|
||||||
// Found a shorter Path -> Update weight
|
// Found a shorter Path -> Update weight
|
||||||
else if (to_weight < query_heap.GetKey(to))
|
else if (std::tie(to_weight, to_duration) <
|
||||||
|
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
||||||
{
|
{
|
||||||
// new parent
|
// new parent
|
||||||
query_heap.GetData(to) = {node, to_duration};
|
query_heap.GetData(to) = {node, to_duration};
|
||||||
@@ -103,13 +121,60 @@ addLoopWeight(const DataFacade<mld::Algorithm> &, const NodeID, EdgeWeight &, Ed
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool DIRECTION>
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
NodeID node,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
|
||||||
|
if (phantom_node.enabled)
|
||||||
|
return partition.GetHighestDifferentLevel(phantom_node.id, node);
|
||||||
|
return INVALID_LEVEL_ID;
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
||||||
|
highest_diffrent_level(phantom_node.reverse_segment_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
NodeID node,
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
const std::size_t phantom_index,
|
||||||
|
const std::vector<std::size_t> &phantom_indices)
|
||||||
|
{
|
||||||
|
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
|
||||||
|
|
||||||
|
const auto &forward_segment = phantom_node.forward_segment_id;
|
||||||
|
const auto forward_level =
|
||||||
|
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
|
||||||
|
: INVALID_LEVEL_ID;
|
||||||
|
|
||||||
|
const auto &reverse_segment = phantom_node.reverse_segment_id;
|
||||||
|
const auto reverse_level =
|
||||||
|
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
|
||||||
|
: INVALID_LEVEL_ID;
|
||||||
|
|
||||||
|
return std::min(forward_level, reverse_level);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get minimum level over all phantoms of the highest different level with respect to node
|
||||||
|
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
|
||||||
|
auto result = min_level(phantom_nodes[phantom_index]);
|
||||||
|
for (const auto &index : phantom_indices)
|
||||||
|
{
|
||||||
|
result = std::min(result, min_level(phantom_nodes[index]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool DIRECTION, typename... Args>
|
||||||
void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||||
const NodeID node,
|
const NodeID node,
|
||||||
const EdgeWeight weight,
|
const EdgeWeight weight,
|
||||||
const EdgeDuration duration,
|
const EdgeDuration duration,
|
||||||
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||||
const PhantomNode &phantom_node)
|
Args... args)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!facade.ExcludeNode(node));
|
BOOST_ASSERT(!facade.ExcludeNode(node));
|
||||||
|
|
||||||
@@ -117,13 +182,7 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
|||||||
const auto &cells = facade.GetCellStorage();
|
const auto &cells = facade.GetCellStorage();
|
||||||
const auto &metric = facade.GetCellMetric();
|
const auto &metric = facade.GetCellMetric();
|
||||||
|
|
||||||
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
|
const auto level = getNodeQueryLevel(partition, node, args...);
|
||||||
if (phantom_node.enabled)
|
|
||||||
return partition.GetHighestDifferentLevel(phantom_node.id, node);
|
|
||||||
return INVALID_LEVEL_ID;
|
|
||||||
};
|
|
||||||
const auto level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
|
||||||
highest_diffrent_level(phantom_node.reverse_segment_id));
|
|
||||||
|
|
||||||
const auto &node_data = query_heap.GetData(node);
|
const auto &node_data = query_heap.GetData(node);
|
||||||
|
|
||||||
@@ -148,7 +207,8 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
|||||||
{
|
{
|
||||||
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
||||||
}
|
}
|
||||||
else if (to_weight < query_heap.GetKey(to))
|
else if (std::tie(to_weight, to_duration) <
|
||||||
|
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
||||||
{
|
{
|
||||||
query_heap.GetData(to) = {node, true, to_duration};
|
query_heap.GetData(to) = {node, true, to_duration};
|
||||||
query_heap.DecreaseKey(to, to_weight);
|
query_heap.DecreaseKey(to, to_weight);
|
||||||
@@ -177,7 +237,8 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
|||||||
{
|
{
|
||||||
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
||||||
}
|
}
|
||||||
else if (to_weight < query_heap.GetKey(to))
|
else if (std::tie(to_weight, to_duration) <
|
||||||
|
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
||||||
{
|
{
|
||||||
query_heap.GetData(to) = {node, true, to_duration};
|
query_heap.GetData(to) = {node, true, to_duration};
|
||||||
query_heap.DecreaseKey(to, to_weight);
|
query_heap.DecreaseKey(to, to_weight);
|
||||||
@@ -201,12 +262,12 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EdgeWeight edge_weight = data.weight;
|
const auto edge_weight = data.weight;
|
||||||
const EdgeWeight edge_duration = data.duration;
|
const auto edge_duration = data.duration;
|
||||||
|
|
||||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||||
const EdgeWeight to_weight = weight + edge_weight;
|
const auto to_weight = weight + edge_weight;
|
||||||
const EdgeWeight to_duration = duration + edge_duration;
|
const auto to_duration = duration + edge_duration;
|
||||||
|
|
||||||
// New Node discovered -> Add to Heap + Node Info Storage
|
// New Node discovered -> Add to Heap + Node Info Storage
|
||||||
if (!query_heap.WasInserted(to))
|
if (!query_heap.WasInserted(to))
|
||||||
@@ -214,7 +275,8 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
|||||||
query_heap.Insert(to, to_weight, {node, false, to_duration});
|
query_heap.Insert(to, to_weight, {node, false, to_duration});
|
||||||
}
|
}
|
||||||
// Found a shorter Path -> Update weight
|
// Found a shorter Path -> Update weight
|
||||||
else if (to_weight < query_heap.GetKey(to))
|
else if (std::tie(to_weight, to_duration) <
|
||||||
|
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
||||||
{
|
{
|
||||||
// new parent
|
// new parent
|
||||||
query_heap.GetData(to) = {node, false, to_duration};
|
query_heap.GetData(to) = {node, false, to_duration};
|
||||||
@@ -229,49 +291,47 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
const unsigned row_idx,
|
const unsigned row_idx,
|
||||||
const unsigned number_of_targets,
|
const unsigned number_of_targets,
|
||||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||||
const SearchSpaceWithBuckets &search_space_with_buckets,
|
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||||
std::vector<EdgeWeight> &weights_table,
|
std::vector<EdgeWeight> &weights_table,
|
||||||
std::vector<EdgeWeight> &durations_table,
|
std::vector<EdgeDuration> &durations_table,
|
||||||
const PhantomNode &phantom_node)
|
const PhantomNode &phantom_node)
|
||||||
{
|
{
|
||||||
const NodeID node = query_heap.DeleteMin();
|
const auto node = query_heap.DeleteMin();
|
||||||
const EdgeWeight source_weight = query_heap.GetKey(node);
|
const auto source_weight = query_heap.GetKey(node);
|
||||||
const EdgeWeight source_duration = query_heap.GetData(node).duration;
|
const auto source_duration = query_heap.GetData(node).duration;
|
||||||
|
|
||||||
// check if each encountered node has an entry
|
// check if each encountered node has an entry
|
||||||
const auto bucket_iterator = search_space_with_buckets.find(node);
|
const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||||
// iterate bucket if there exists one
|
search_space_with_buckets.end(),
|
||||||
if (bucket_iterator != search_space_with_buckets.end())
|
node,
|
||||||
|
NodeBucket::Compare());
|
||||||
|
for (const auto ¤t_bucket : boost::make_iterator_range(bucket_list))
|
||||||
{
|
{
|
||||||
const std::vector<NodeBucket> &bucket_list = bucket_iterator->second;
|
// get target id from bucket entry
|
||||||
for (const NodeBucket ¤t_bucket : bucket_list)
|
const auto column_idx = current_bucket.column_index;
|
||||||
|
const auto target_weight = current_bucket.weight;
|
||||||
|
const auto target_duration = current_bucket.duration;
|
||||||
|
|
||||||
|
auto ¤t_weight = weights_table[row_idx * number_of_targets + column_idx];
|
||||||
|
auto ¤t_duration = durations_table[row_idx * number_of_targets + column_idx];
|
||||||
|
|
||||||
|
// check if new weight is better
|
||||||
|
auto new_weight = source_weight + target_weight;
|
||||||
|
auto new_duration = source_duration + target_duration;
|
||||||
|
|
||||||
|
if (new_weight < 0)
|
||||||
{
|
{
|
||||||
// get target id from bucket entry
|
if (addLoopWeight(facade, node, new_weight, new_duration))
|
||||||
const unsigned column_idx = current_bucket.target_id;
|
|
||||||
const EdgeWeight target_weight = current_bucket.weight;
|
|
||||||
const EdgeWeight target_duration = current_bucket.duration;
|
|
||||||
|
|
||||||
auto ¤t_weight = weights_table[row_idx * number_of_targets + column_idx];
|
|
||||||
auto ¤t_duration = durations_table[row_idx * number_of_targets + column_idx];
|
|
||||||
|
|
||||||
// check if new weight is better
|
|
||||||
auto new_weight = source_weight + target_weight;
|
|
||||||
auto new_duration = source_duration + target_duration;
|
|
||||||
|
|
||||||
if (new_weight < 0)
|
|
||||||
{
|
{
|
||||||
if (addLoopWeight(facade, node, new_weight, new_duration))
|
current_weight = std::min(current_weight, new_weight);
|
||||||
{
|
current_duration = std::min(current_duration, new_duration);
|
||||||
current_weight = std::min(current_weight, new_weight);
|
|
||||||
current_duration = std::min(current_duration, new_duration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (new_weight < current_weight)
|
|
||||||
{
|
|
||||||
current_weight = new_weight;
|
|
||||||
current_duration = new_duration;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration))
|
||||||
|
{
|
||||||
|
current_weight = new_weight;
|
||||||
|
current_duration = new_duration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relaxOutgoingEdges<FORWARD_DIRECTION>(
|
relaxOutgoingEdges<FORWARD_DIRECTION>(
|
||||||
@@ -282,15 +342,15 @@ template <typename Algorithm>
|
|||||||
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||||
const unsigned column_idx,
|
const unsigned column_idx,
|
||||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||||
SearchSpaceWithBuckets &search_space_with_buckets,
|
std::vector<NodeBucket> &search_space_with_buckets,
|
||||||
const PhantomNode &phantom_node)
|
const PhantomNode &phantom_node)
|
||||||
{
|
{
|
||||||
const NodeID node = query_heap.DeleteMin();
|
const auto node = query_heap.DeleteMin();
|
||||||
const EdgeWeight target_weight = query_heap.GetKey(node);
|
const auto target_weight = query_heap.GetKey(node);
|
||||||
const EdgeWeight target_duration = query_heap.GetData(node).duration;
|
const auto target_duration = query_heap.GetData(node).duration;
|
||||||
|
|
||||||
// store settled nodes in search space bucket
|
// store settled nodes in search space bucket
|
||||||
search_space_with_buckets[node].emplace_back(column_idx, target_weight, target_duration);
|
search_space_with_buckets.emplace_back(node, column_idx, target_weight, target_duration);
|
||||||
|
|
||||||
relaxOutgoingEdges<REVERSE_DIRECTION>(
|
relaxOutgoingEdges<REVERSE_DIRECTION>(
|
||||||
facade, node, target_weight, target_duration, query_heap, phantom_node);
|
facade, node, target_weight, target_duration, query_heap, phantom_node);
|
||||||
@@ -298,111 +358,297 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Algorithm>
|
template <typename Algorithm>
|
||||||
std::vector<EdgeWeight> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
std::vector<std::size_t> source_indices,
|
||||||
const std::vector<std::size_t> &target_indices)
|
std::vector<std::size_t> target_indices)
|
||||||
{
|
{
|
||||||
const auto number_of_sources =
|
if (source_indices.empty())
|
||||||
source_indices.empty() ? phantom_nodes.size() : source_indices.size();
|
{
|
||||||
const auto number_of_targets =
|
source_indices.resize(phantom_nodes.size());
|
||||||
target_indices.empty() ? phantom_nodes.size() : target_indices.size();
|
std::iota(source_indices.begin(), source_indices.end(), 0);
|
||||||
|
}
|
||||||
|
if (target_indices.empty())
|
||||||
|
{
|
||||||
|
target_indices.resize(phantom_nodes.size());
|
||||||
|
std::iota(target_indices.begin(), target_indices.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto number_of_sources = source_indices.size();
|
||||||
|
const auto number_of_targets = target_indices.size();
|
||||||
const auto number_of_entries = number_of_sources * number_of_targets;
|
const auto number_of_entries = number_of_sources * number_of_targets;
|
||||||
|
|
||||||
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
||||||
std::vector<EdgeWeight> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||||
|
|
||||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(facade.GetNumberOfNodes());
|
std::mutex lock;
|
||||||
|
std::vector<NodeBucket> search_space_with_buckets;
|
||||||
|
|
||||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
// Backward search for target phantoms
|
||||||
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<std::size_t>{0, target_indices.size()},
|
||||||
|
[&](const tbb::blocked_range<std::size_t> &chunk) {
|
||||||
|
for (auto column_idx = chunk.begin(), end = chunk.end(); column_idx != end;
|
||||||
|
++column_idx)
|
||||||
|
{
|
||||||
|
const auto index = target_indices[column_idx];
|
||||||
|
const auto &phantom = phantom_nodes[index];
|
||||||
|
|
||||||
SearchSpaceWithBuckets search_space_with_buckets;
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||||
|
facade.GetNumberOfNodes());
|
||||||
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
|
insertTargetInHeap(query_heap, phantom);
|
||||||
|
|
||||||
unsigned column_idx = 0;
|
// explore search space
|
||||||
const auto search_target_phantom = [&](const PhantomNode &phantom) {
|
std::vector<NodeBucket> local_buckets;
|
||||||
// clear heap and insert target nodes
|
while (!query_heap.Empty())
|
||||||
query_heap.Clear();
|
{
|
||||||
insertTargetInHeap(query_heap, phantom);
|
backwardRoutingStep(facade, column_idx, query_heap, local_buckets, phantom);
|
||||||
|
}
|
||||||
|
|
||||||
// explore search space
|
{ // Insert local buckets into the global search space
|
||||||
while (!query_heap.Empty())
|
std::lock_guard<std::mutex> guard{lock};
|
||||||
{
|
search_space_with_buckets.insert(std::end(search_space_with_buckets),
|
||||||
backwardRoutingStep(facade, column_idx, query_heap, search_space_with_buckets, phantom);
|
std::begin(local_buckets),
|
||||||
}
|
std::end(local_buckets));
|
||||||
++column_idx;
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// for each source do forward search
|
tbb::parallel_sort(search_space_with_buckets.begin(), search_space_with_buckets.end());
|
||||||
unsigned row_idx = 0;
|
|
||||||
const auto search_source_phantom = [&](const PhantomNode &phantom) {
|
|
||||||
// clear heap and insert source nodes
|
|
||||||
query_heap.Clear();
|
|
||||||
insertSourceInHeap(query_heap, phantom);
|
|
||||||
|
|
||||||
// explore search space
|
// For each source do forward search
|
||||||
while (!query_heap.Empty())
|
tbb::parallel_for(tbb::blocked_range<std::size_t>{0, source_indices.size()},
|
||||||
{
|
[&](const tbb::blocked_range<std::size_t> &chunk) {
|
||||||
forwardRoutingStep(facade,
|
for (auto row_idx = chunk.begin(), end = chunk.end(); row_idx != end;
|
||||||
row_idx,
|
++row_idx)
|
||||||
number_of_targets,
|
{
|
||||||
query_heap,
|
const auto index = source_indices[row_idx];
|
||||||
search_space_with_buckets,
|
const auto &phantom = phantom_nodes[index];
|
||||||
weights_table,
|
|
||||||
durations_table,
|
|
||||||
phantom);
|
|
||||||
}
|
|
||||||
++row_idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (target_indices.empty())
|
// clear heap and insert source nodes
|
||||||
{
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||||
for (const auto &phantom : phantom_nodes)
|
facade.GetNumberOfNodes());
|
||||||
{
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
search_target_phantom(phantom);
|
insertSourceInHeap(query_heap, phantom);
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (const auto index : target_indices)
|
|
||||||
{
|
|
||||||
const auto &phantom = phantom_nodes[index];
|
|
||||||
search_target_phantom(phantom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source_indices.empty())
|
// explore search space
|
||||||
{
|
while (!query_heap.Empty())
|
||||||
for (const auto &phantom : phantom_nodes)
|
{
|
||||||
{
|
forwardRoutingStep(facade,
|
||||||
search_source_phantom(phantom);
|
row_idx,
|
||||||
}
|
number_of_targets,
|
||||||
}
|
query_heap,
|
||||||
else
|
search_space_with_buckets,
|
||||||
{
|
weights_table,
|
||||||
for (const auto index : source_indices)
|
durations_table,
|
||||||
{
|
phantom);
|
||||||
const auto &phantom = phantom_nodes[index];
|
}
|
||||||
search_source_phantom(phantom);
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return durations_table;
|
return durations_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
template std::vector<EdgeWeight>
|
template std::vector<EdgeDuration>
|
||||||
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||||
const DataFacade<ch::Algorithm> &facade,
|
const DataFacade<ch::Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
std::vector<std::size_t> source_indices,
|
||||||
const std::vector<std::size_t> &target_indices);
|
std::vector<std::size_t> target_indices);
|
||||||
|
|
||||||
template std::vector<EdgeWeight>
|
template std::vector<EdgeDuration>
|
||||||
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||||
const DataFacade<mld::Algorithm> &facade,
|
const DataFacade<mld::Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
std::vector<std::size_t> source_indices,
|
||||||
const std::vector<std::size_t> &target_indices);
|
std::vector<std::size_t> target_indices);
|
||||||
|
|
||||||
|
namespace mld
|
||||||
|
{
|
||||||
|
|
||||||
|
// Unidirectional multi-layer Dijkstra search for 1-to-N and N-to-1 matrices
|
||||||
|
template <bool DIRECTION>
|
||||||
|
std::vector<EdgeDuration> oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
|
const DataFacade<Algorithm> &facade,
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
std::size_t phantom_index,
|
||||||
|
std::vector<std::size_t> phantom_indices)
|
||||||
|
{
|
||||||
|
if (phantom_indices.empty())
|
||||||
|
{
|
||||||
|
phantom_indices.resize(phantom_nodes.size());
|
||||||
|
std::iota(phantom_indices.begin(), phantom_indices.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
||||||
|
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||||
|
|
||||||
|
// Collect destination (source) nodes into a map
|
||||||
|
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration>>
|
||||||
|
target_nodes_index;
|
||||||
|
target_nodes_index.reserve(phantom_indices.size());
|
||||||
|
for (std::size_t index = 0; index < phantom_indices.size(); ++index)
|
||||||
|
{
|
||||||
|
const auto &phantom_index = phantom_indices[index];
|
||||||
|
const auto &phantom_node = phantom_nodes[phantom_index];
|
||||||
|
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
|
{
|
||||||
|
if (phantom_node.IsValidForwardTarget())
|
||||||
|
target_nodes_index.insert(
|
||||||
|
{phantom_node.forward_segment_id.id,
|
||||||
|
std::make_tuple(index,
|
||||||
|
phantom_node.GetForwardWeightPlusOffset(),
|
||||||
|
phantom_node.GetForwardDuration())});
|
||||||
|
if (phantom_node.IsValidReverseTarget())
|
||||||
|
target_nodes_index.insert(
|
||||||
|
{phantom_node.reverse_segment_id.id,
|
||||||
|
std::make_tuple(index,
|
||||||
|
phantom_node.GetReverseWeightPlusOffset(),
|
||||||
|
phantom_node.GetReverseDuration())});
|
||||||
|
}
|
||||||
|
else if (DIRECTION == REVERSE_DIRECTION)
|
||||||
|
{
|
||||||
|
if (phantom_node.IsValidForwardSource())
|
||||||
|
target_nodes_index.insert(
|
||||||
|
{phantom_node.forward_segment_id.id,
|
||||||
|
std::make_tuple(index,
|
||||||
|
-phantom_node.GetForwardWeightPlusOffset(),
|
||||||
|
-phantom_node.GetForwardDuration())});
|
||||||
|
if (phantom_node.IsValidReverseSource())
|
||||||
|
target_nodes_index.insert(
|
||||||
|
{phantom_node.reverse_segment_id.id,
|
||||||
|
std::make_tuple(index,
|
||||||
|
-phantom_node.GetReverseWeightPlusOffset(),
|
||||||
|
-phantom_node.GetReverseDuration())});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize query heap
|
||||||
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(facade.GetNumberOfNodes());
|
||||||
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
|
|
||||||
|
// Check if node is in the destinations list and update weights/durations
|
||||||
|
auto update_values = [&](NodeID node, EdgeWeight weight, EdgeDuration duration) {
|
||||||
|
auto candidates = target_nodes_index.equal_range(node);
|
||||||
|
for (auto it = candidates.first; it != candidates.second;)
|
||||||
|
{
|
||||||
|
std::size_t index;
|
||||||
|
EdgeWeight target_weight;
|
||||||
|
EdgeDuration target_duration;
|
||||||
|
std::tie(index, target_weight, target_duration) = it->second;
|
||||||
|
|
||||||
|
const auto path_weight = weight + target_weight;
|
||||||
|
if (path_weight >= 0)
|
||||||
|
{
|
||||||
|
const auto path_duration = duration + target_duration;
|
||||||
|
|
||||||
|
if (std::tie(path_weight, path_duration) <
|
||||||
|
std::tie(weights[index], durations[index]))
|
||||||
|
{
|
||||||
|
weights[index] = path_weight;
|
||||||
|
durations[index] = path_duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove node from destinations list
|
||||||
|
it = target_nodes_index.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check a single path result and insert adjacent nodes into heap
|
||||||
|
auto insert_node = [&](NodeID node, EdgeWeight initial_weight, EdgeDuration initial_duration) {
|
||||||
|
|
||||||
|
// Update single node paths
|
||||||
|
update_values(node, initial_weight, initial_duration);
|
||||||
|
|
||||||
|
// Place adjacent nodes into heap
|
||||||
|
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
||||||
|
{
|
||||||
|
const auto &data = facade.GetEdgeData(edge);
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
|
||||||
|
{
|
||||||
|
query_heap.Insert(facade.GetTarget(edge),
|
||||||
|
data.weight + initial_weight,
|
||||||
|
{node, data.duration + initial_duration});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{ // Place source (destination) adjacent nodes into the heap
|
||||||
|
const auto &phantom_node = phantom_nodes[phantom_index];
|
||||||
|
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (phantom_node.IsValidForwardSource())
|
||||||
|
insert_node(phantom_node.forward_segment_id.id,
|
||||||
|
-phantom_node.GetForwardWeightPlusOffset(),
|
||||||
|
-phantom_node.GetForwardDuration());
|
||||||
|
|
||||||
|
if (phantom_node.IsValidReverseSource())
|
||||||
|
insert_node(phantom_node.reverse_segment_id.id,
|
||||||
|
-phantom_node.GetReverseWeightPlusOffset(),
|
||||||
|
-phantom_node.GetReverseDuration());
|
||||||
|
}
|
||||||
|
else if (DIRECTION == REVERSE_DIRECTION)
|
||||||
|
{
|
||||||
|
if (phantom_node.IsValidForwardTarget())
|
||||||
|
insert_node(phantom_node.forward_segment_id.id,
|
||||||
|
phantom_node.GetForwardWeightPlusOffset(),
|
||||||
|
phantom_node.GetForwardDuration());
|
||||||
|
|
||||||
|
if (phantom_node.IsValidReverseTarget())
|
||||||
|
insert_node(phantom_node.reverse_segment_id.id,
|
||||||
|
phantom_node.GetReverseWeightPlusOffset(),
|
||||||
|
phantom_node.GetReverseDuration());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!query_heap.Empty() && !target_nodes_index.empty())
|
||||||
|
{
|
||||||
|
// Extract node from the heap
|
||||||
|
const auto node = query_heap.DeleteMin();
|
||||||
|
const auto weight = query_heap.GetKey(node);
|
||||||
|
const auto duration = query_heap.GetData(node).duration;
|
||||||
|
|
||||||
|
// Update values
|
||||||
|
update_values(node, weight, duration);
|
||||||
|
|
||||||
|
// Relax outgoing edges
|
||||||
|
relaxOutgoingEdges<DIRECTION>(facade,
|
||||||
|
node,
|
||||||
|
weight,
|
||||||
|
duration,
|
||||||
|
query_heap,
|
||||||
|
phantom_nodes,
|
||||||
|
phantom_index,
|
||||||
|
phantom_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
return durations;
|
||||||
|
}
|
||||||
|
|
||||||
|
template std::vector<EdgeDuration>
|
||||||
|
oneToManySearch<FORWARD_DIRECTION>(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
|
const DataFacade<Algorithm> &facade,
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
std::size_t phantom_index,
|
||||||
|
std::vector<std::size_t> phantom_indices);
|
||||||
|
|
||||||
|
template std::vector<EdgeDuration>
|
||||||
|
oneToManySearch<REVERSE_DIRECTION>(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
|
const DataFacade<Algorithm> &facade,
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
std::size_t phantom_index,
|
||||||
|
std::vector<std::size_t> phantom_indices);
|
||||||
|
} // mld
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "extractor/edge_based_edge.hpp"
|
#include "extractor/edge_based_edge.hpp"
|
||||||
#include "extractor/extraction_containers.hpp"
|
#include "extractor/extraction_containers.hpp"
|
||||||
#include "extractor/extraction_node.hpp"
|
#include "extractor/extraction_node.hpp"
|
||||||
|
#include "extractor/extraction_relation.hpp"
|
||||||
#include "extractor/extraction_way.hpp"
|
#include "extractor/extraction_way.hpp"
|
||||||
#include "extractor/extractor_callbacks.hpp"
|
#include "extractor/extractor_callbacks.hpp"
|
||||||
#include "extractor/files.hpp"
|
#include "extractor/files.hpp"
|
||||||
@@ -288,12 +289,13 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
|
|
||||||
const osmium::io::File input_file(config.input_path.string());
|
const osmium::io::File input_file(config.input_path.string());
|
||||||
osmium::thread::Pool pool(number_of_threads);
|
osmium::thread::Pool pool(number_of_threads);
|
||||||
osmium::io::Reader reader(
|
|
||||||
input_file,
|
|
||||||
pool,
|
|
||||||
(config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no));
|
|
||||||
|
|
||||||
const osmium::io::Header header = reader.header();
|
std::unique_ptr<osmium::io::Reader> reader(new osmium::io::Reader(
|
||||||
|
input_file,
|
||||||
|
osmium::osm_entity_bits::relation,
|
||||||
|
(config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no)));
|
||||||
|
|
||||||
|
osmium::io::Header header = reader->header();
|
||||||
|
|
||||||
unsigned number_of_nodes = 0;
|
unsigned number_of_nodes = 0;
|
||||||
unsigned number_of_ways = 0;
|
unsigned number_of_ways = 0;
|
||||||
@@ -331,6 +333,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
|
|
||||||
timestamp_file.WriteFrom(timestamp.c_str(), timestamp.length());
|
timestamp_file.WriteFrom(timestamp.c_str(), timestamp.length());
|
||||||
|
|
||||||
|
ExtractionRelationContainer relations;
|
||||||
std::vector<std::string> restrictions = scripting_environment.GetRestrictions();
|
std::vector<std::string> restrictions = scripting_environment.GetRestrictions();
|
||||||
// setup restriction parser
|
// setup restriction parser
|
||||||
const RestrictionParser restriction_parser(
|
const RestrictionParser restriction_parser(
|
||||||
@@ -338,20 +341,19 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
config.parse_conditionals,
|
config.parse_conditionals,
|
||||||
restrictions);
|
restrictions);
|
||||||
|
|
||||||
std::mutex process_mutex;
|
|
||||||
|
|
||||||
using SharedBuffer = std::shared_ptr<const osmium::memory::Buffer>;
|
using SharedBuffer = std::shared_ptr<const osmium::memory::Buffer>;
|
||||||
struct ParsedBuffer
|
struct ParsedBuffer
|
||||||
{
|
{
|
||||||
SharedBuffer buffer;
|
SharedBuffer buffer;
|
||||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> resulting_nodes;
|
std::vector<std::pair<const osmium::Node &, ExtractionNode>> resulting_nodes;
|
||||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> resulting_ways;
|
std::vector<std::pair<const osmium::Way &, ExtractionWay>> resulting_ways;
|
||||||
|
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> resulting_relations;
|
||||||
std::vector<InputConditionalTurnRestriction> resulting_restrictions;
|
std::vector<InputConditionalTurnRestriction> resulting_restrictions;
|
||||||
};
|
};
|
||||||
|
|
||||||
tbb::filter_t<void, SharedBuffer> buffer_reader(
|
tbb::filter_t<void, SharedBuffer> buffer_reader(
|
||||||
tbb::filter::serial_in_order, [&](tbb::flow_control &fc) {
|
tbb::filter::serial_in_order, [&](tbb::flow_control &fc) {
|
||||||
if (auto buffer = reader.read())
|
if (auto buffer = reader->read())
|
||||||
{
|
{
|
||||||
return std::make_shared<const osmium::memory::Buffer>(std::move(buffer));
|
return std::make_shared<const osmium::memory::Buffer>(std::move(buffer));
|
||||||
}
|
}
|
||||||
@@ -370,8 +372,10 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
parsed_buffer->buffer = buffer;
|
parsed_buffer->buffer = buffer;
|
||||||
scripting_environment.ProcessElements(*buffer,
|
scripting_environment.ProcessElements(*buffer,
|
||||||
restriction_parser,
|
restriction_parser,
|
||||||
|
relations,
|
||||||
parsed_buffer->resulting_nodes,
|
parsed_buffer->resulting_nodes,
|
||||||
parsed_buffer->resulting_ways,
|
parsed_buffer->resulting_ways,
|
||||||
|
parsed_buffer->resulting_relations,
|
||||||
parsed_buffer->resulting_restrictions);
|
parsed_buffer->resulting_restrictions);
|
||||||
return parsed_buffer;
|
return parsed_buffer;
|
||||||
});
|
});
|
||||||
@@ -391,13 +395,46 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
|||||||
{
|
{
|
||||||
extractor_callbacks->ProcessWay(result.first, result.second);
|
extractor_callbacks->ProcessWay(result.first, result.second);
|
||||||
}
|
}
|
||||||
number_of_relations += parsed_buffer->resulting_restrictions.size();
|
});
|
||||||
|
|
||||||
|
tbb::filter_t<std::shared_ptr<ParsedBuffer>, void> buffer_storage_relation(
|
||||||
|
tbb::filter::serial_in_order, [&](const std::shared_ptr<ParsedBuffer> parsed_buffer) {
|
||||||
|
if (!parsed_buffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
number_of_relations += parsed_buffer->resulting_relations.size();
|
||||||
|
for (const auto &result : parsed_buffer->resulting_relations)
|
||||||
|
{
|
||||||
|
/// TODO: add restriction processing
|
||||||
|
if (result.second.is_restriction)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
relations.AddRelation(result.second);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &result : parsed_buffer->resulting_restrictions)
|
for (const auto &result : parsed_buffer->resulting_restrictions)
|
||||||
{
|
{
|
||||||
extractor_callbacks->ProcessRestriction(result);
|
extractor_callbacks->ProcessRestriction(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* Main trick that we can use the same pipeline. It just receive relation objects
|
||||||
|
* from osmium. So other containers would be empty and doesn't process anything
|
||||||
|
*/
|
||||||
|
util::Log() << "Parse relations ...";
|
||||||
|
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 1.5,
|
||||||
|
buffer_reader & buffer_transform & buffer_storage_relation);
|
||||||
|
reader->close();
|
||||||
|
|
||||||
|
/* At this step we just filter ways and nodes from osmium, so any relation wouldn't be
|
||||||
|
* processed there.
|
||||||
|
*/
|
||||||
|
util::Log() << "Parse ways and nodes ...";
|
||||||
|
reader.reset(new osmium::io::Reader(
|
||||||
|
input_file,
|
||||||
|
osmium::osm_entity_bits::node | osmium::osm_entity_bits::way,
|
||||||
|
(config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no)));
|
||||||
|
|
||||||
// Number of pipeline tokens that yielded the best speedup was about 1.5 * num_cores
|
// Number of pipeline tokens that yielded the best speedup was about 1.5 * num_cores
|
||||||
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 1.5,
|
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 1.5,
|
||||||
buffer_reader & buffer_transform & buffer_storage);
|
buffer_reader & buffer_transform & buffer_storage);
|
||||||
|
|||||||
@@ -287,23 +287,36 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
|||||||
return lane_description;
|
return lane_description;
|
||||||
};
|
};
|
||||||
|
|
||||||
// convert the lane description into an ID and, if necessary, remember the description in the
|
// If we could parse turn lanes but could not parse number of lanes,
|
||||||
// description_map
|
// count the turn lanes and use them for the way's number of lanes.
|
||||||
const auto requestId = [&](const std::string &lane_string) {
|
auto road_classification = parsed_way.road_classification;
|
||||||
if (lane_string.empty())
|
std::uint8_t road_deduced_num_lanes = 0;
|
||||||
return INVALID_LANE_DESCRIPTIONID;
|
|
||||||
TurnLaneDescription lane_description = laneStringToDescription(std::move(lane_string));
|
|
||||||
|
|
||||||
return lane_description_map.ConcurrentFindOrAdd(lane_description);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Deduplicates street names, refs, destinations, pronunciation, exits.
|
// Deduplicates street names, refs, destinations, pronunciation, exits.
|
||||||
// In case we do not already store the key, inserts (key, id) tuple and return id.
|
// In case we do not already store the key, inserts (key, id) tuple and return id.
|
||||||
// Otherwise fetches the id based on the name and returns it without insertion.
|
// Otherwise fetches the id based on the name and returns it without insertion.
|
||||||
const auto turn_lane_id_forward = requestId(parsed_way.turn_lanes_forward);
|
auto turn_lane_id_forward = INVALID_LANE_DESCRIPTIONID;
|
||||||
const auto turn_lane_id_backward = requestId(parsed_way.turn_lanes_backward);
|
auto turn_lane_id_backward = INVALID_LANE_DESCRIPTIONID;
|
||||||
|
|
||||||
const auto road_classification = parsed_way.road_classification;
|
// RoadClassification represents a the class for unidirectional ways,
|
||||||
|
// therefore we need to add up deduced forward and backward lane counts.
|
||||||
|
|
||||||
|
if (!parsed_way.turn_lanes_forward.empty())
|
||||||
|
{
|
||||||
|
auto desc = laneStringToDescription(parsed_way.turn_lanes_forward);
|
||||||
|
turn_lane_id_forward = lane_description_map.ConcurrentFindOrAdd(desc);
|
||||||
|
road_deduced_num_lanes += desc.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsed_way.turn_lanes_backward.empty())
|
||||||
|
{
|
||||||
|
auto desc = laneStringToDescription(parsed_way.turn_lanes_backward);
|
||||||
|
turn_lane_id_backward = lane_description_map.ConcurrentFindOrAdd(desc);
|
||||||
|
road_deduced_num_lanes += desc.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
road_classification.SetNumberOfLanes(std::max(road_deduced_num_lanes, // len(turn:lanes)
|
||||||
|
road_classification.GetNumberOfLanes()));
|
||||||
|
|
||||||
// Get the unique identifier for the street name, destination, and ref
|
// Get the unique identifier for the street name, destination, and ref
|
||||||
const auto name_iterator = string_map.find(MapKey(parsed_way.name,
|
const auto name_iterator = string_map.find(MapKey(parsed_way.name,
|
||||||
|
|||||||
@@ -54,12 +54,19 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
|
|||||||
const boost::optional<NodeID> sorting_base,
|
const boost::optional<NodeID> sorting_base,
|
||||||
const bool use_low_precision_angles) const
|
const bool use_low_precision_angles) const
|
||||||
{
|
{
|
||||||
IntersectionShape intersection;
|
|
||||||
// reserve enough items (+ the possibly missing u-turn edge)
|
|
||||||
const auto intersection_degree = node_based_graph.GetOutDegree(node_at_center_of_intersection);
|
const auto intersection_degree = node_based_graph.GetOutDegree(node_at_center_of_intersection);
|
||||||
intersection.reserve(intersection_degree);
|
|
||||||
const util::Coordinate turn_coordinate = coordinates[node_at_center_of_intersection];
|
const util::Coordinate turn_coordinate = coordinates[node_at_center_of_intersection];
|
||||||
|
|
||||||
|
// compute bearings in a relatively small circle to prevent wrong roads order with true bearings
|
||||||
|
struct RoadWithInitialBearing
|
||||||
|
{
|
||||||
|
double bearing;
|
||||||
|
IntersectionShapeData road;
|
||||||
|
};
|
||||||
|
std::vector<RoadWithInitialBearing> initial_roads_ordering;
|
||||||
|
// reserve enough items (+ the possibly missing u-turn edge)
|
||||||
|
initial_roads_ordering.reserve(intersection_degree);
|
||||||
|
|
||||||
// number of lanes at the intersection changes how far we look down the road
|
// number of lanes at the intersection changes how far we look down the road
|
||||||
const auto edge_range = node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection);
|
const auto edge_range = node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection);
|
||||||
const auto max_lanes_intersection = std::accumulate(
|
const auto max_lanes_intersection = std::accumulate(
|
||||||
@@ -82,6 +89,11 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
|
|||||||
auto coordinates = coordinate_extractor.GetCoordinatesAlongRoad(
|
auto coordinates = coordinate_extractor.GetCoordinatesAlongRoad(
|
||||||
node_at_center_of_intersection, edge_connected_to_intersection, !INVERT, to_node);
|
node_at_center_of_intersection, edge_connected_to_intersection, !INVERT, to_node);
|
||||||
|
|
||||||
|
const auto close_coordinate =
|
||||||
|
coordinate_extractor.ExtractCoordinateAtLength(2. /*m*/, coordinates);
|
||||||
|
const auto initial_bearing =
|
||||||
|
util::coordinate_calculation::bearing(turn_coordinate, close_coordinate);
|
||||||
|
|
||||||
const auto segment_length = util::coordinate_calculation::getLength(
|
const auto segment_length = util::coordinate_calculation::getLength(
|
||||||
coordinates.begin(),
|
coordinates.begin(),
|
||||||
coordinates.end(),
|
coordinates.end(),
|
||||||
@@ -123,31 +135,79 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
|
|||||||
BOOST_ASSERT(std::abs(bearing) <= 0.1);
|
BOOST_ASSERT(std::abs(bearing) <= 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
intersection.push_back({edge_connected_to_intersection, bearing, segment_length});
|
initial_roads_ordering.push_back(
|
||||||
|
{initial_bearing, {edge_connected_to_intersection, bearing, segment_length}});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!intersection.empty())
|
if (!initial_roads_ordering.empty())
|
||||||
{
|
{
|
||||||
const auto base_bearing = [&]() {
|
const auto base_initial_bearing = [&]() {
|
||||||
if (sorting_base)
|
if (sorting_base)
|
||||||
{
|
{
|
||||||
const auto itr =
|
const auto itr = std::find_if(initial_roads_ordering.begin(),
|
||||||
std::find_if(intersection.begin(),
|
initial_roads_ordering.end(),
|
||||||
intersection.end(),
|
[&](const auto &data) {
|
||||||
[&](const IntersectionShapeData &data) {
|
return node_based_graph.GetTarget(
|
||||||
return node_based_graph.GetTarget(data.eid) == *sorting_base;
|
data.road.eid) == *sorting_base;
|
||||||
});
|
});
|
||||||
if (itr != intersection.end())
|
if (itr != initial_roads_ordering.end())
|
||||||
return util::bearing::reverse(itr->bearing);
|
return util::bearing::reverse(itr->bearing);
|
||||||
}
|
}
|
||||||
return util::bearing::reverse(intersection.begin()->bearing);
|
return util::bearing::reverse(initial_roads_ordering.begin()->bearing);
|
||||||
}();
|
}();
|
||||||
std::sort(intersection.begin(),
|
|
||||||
intersection.end(),
|
// sort roads with respect to the initial bearings, a tie-breaker for equal initial bearings
|
||||||
makeCompareShapeDataAngleToBearing(base_bearing));
|
// is to order roads via final bearings to have roads in clockwise order
|
||||||
|
//
|
||||||
|
// rhs <---. lhs <----.
|
||||||
|
// / /
|
||||||
|
// lhs / rhs /
|
||||||
|
//
|
||||||
|
// lhs road is before rhs one rhs road is before lhs one
|
||||||
|
// bearing::angleBetween < 180 bearing::angleBetween > 180
|
||||||
|
const auto initial_bearing_order = makeCompareShapeDataAngleToBearing(base_initial_bearing);
|
||||||
|
std::sort(initial_roads_ordering.begin(),
|
||||||
|
initial_roads_ordering.end(),
|
||||||
|
[&initial_bearing_order](const auto &lhs, const auto &rhs) {
|
||||||
|
return initial_bearing_order(lhs, rhs) ||
|
||||||
|
(lhs.bearing == rhs.bearing &&
|
||||||
|
util::bearing::angleBetween(lhs.road.bearing, rhs.road.bearing) <
|
||||||
|
180);
|
||||||
|
});
|
||||||
|
|
||||||
|
// copy intersection data in the initial order
|
||||||
|
IntersectionShape intersection;
|
||||||
|
intersection.reserve(initial_roads_ordering.size());
|
||||||
|
std::transform(initial_roads_ordering.begin(),
|
||||||
|
initial_roads_ordering.end(),
|
||||||
|
std::back_inserter(intersection),
|
||||||
|
[](const auto &entry) { return entry.road; });
|
||||||
|
|
||||||
|
if (intersection.size() > 2)
|
||||||
|
{ // Check bearings ordering with respect to true bearings
|
||||||
|
const auto base_bearing = intersection.front().bearing;
|
||||||
|
const auto bearings_order =
|
||||||
|
makeCompareShapeDataAngleToBearing(util::bearing::reverse(base_bearing));
|
||||||
|
for (auto curr = intersection.begin(), next = std::next(curr);
|
||||||
|
next != intersection.end();
|
||||||
|
++curr, ++next)
|
||||||
|
{
|
||||||
|
if (bearings_order(*next, *curr))
|
||||||
|
{ // If the true bearing is out of the initial order (next before current) then
|
||||||
|
// adjust the next bearing to keep the order. The adjustment angle is at most
|
||||||
|
// 0.5° or a half-angle between the current bearing and the base bearing.
|
||||||
|
// to prevent overlapping over base bearing + 360°.
|
||||||
|
const auto angle_adjustment = std::min(
|
||||||
|
.5, util::restrictAngleToValidRange(base_bearing - curr->bearing) / 2.);
|
||||||
|
next->bearing =
|
||||||
|
util::restrictAngleToValidRange(curr->bearing + angle_adjustment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
return intersection;
|
return IntersectionShape{};
|
||||||
}
|
}
|
||||||
|
|
||||||
// a
|
// a
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "extractor/extraction_helper_functions.hpp"
|
#include "extractor/extraction_helper_functions.hpp"
|
||||||
#include "extractor/extraction_node.hpp"
|
#include "extractor/extraction_node.hpp"
|
||||||
|
#include "extractor/extraction_relation.hpp"
|
||||||
#include "extractor/extraction_segment.hpp"
|
#include "extractor/extraction_segment.hpp"
|
||||||
#include "extractor/extraction_turn.hpp"
|
#include "extractor/extraction_turn.hpp"
|
||||||
#include "extractor/extraction_way.hpp"
|
#include "extractor/extraction_way.hpp"
|
||||||
@@ -31,6 +32,9 @@ template <> struct is_container<osmium::Node> : std::false_type
|
|||||||
template <> struct is_container<osmium::Way> : std::false_type
|
template <> struct is_container<osmium::Way> : std::false_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
template <> struct is_container<osmium::Relation> : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@@ -216,6 +220,14 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
"sharp_left",
|
"sharp_left",
|
||||||
extractor::guidance::DirectionModifier::SharpLeft);
|
extractor::guidance::DirectionModifier::SharpLeft);
|
||||||
|
|
||||||
|
context.state.new_enum("item_type",
|
||||||
|
"node",
|
||||||
|
osmium::item_type::node,
|
||||||
|
"way",
|
||||||
|
osmium::item_type::way,
|
||||||
|
"relation",
|
||||||
|
osmium::item_type::relation);
|
||||||
|
|
||||||
context.state.new_usertype<RasterContainer>("raster",
|
context.state.new_usertype<RasterContainer>("raster",
|
||||||
"load",
|
"load",
|
||||||
&RasterContainer::LoadRasterSource,
|
&RasterContainer::LoadRasterSource,
|
||||||
@@ -276,6 +288,30 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
"version",
|
"version",
|
||||||
&osmium::Way::version);
|
&osmium::Way::version);
|
||||||
|
|
||||||
|
context.state.new_usertype<osmium::RelationMember>(
|
||||||
|
"RelationMember",
|
||||||
|
"role",
|
||||||
|
&osmium::RelationMember::role,
|
||||||
|
"type",
|
||||||
|
&osmium::RelationMember::type,
|
||||||
|
"id",
|
||||||
|
[](const osmium::RelationMember &member) -> osmium::object_id_type {
|
||||||
|
return member.ref();
|
||||||
|
});
|
||||||
|
|
||||||
|
context.state.new_usertype<osmium::Relation>(
|
||||||
|
"Relation",
|
||||||
|
"get_value_by_key",
|
||||||
|
&get_value_by_key<osmium::Relation>,
|
||||||
|
"id",
|
||||||
|
&osmium::Relation::id,
|
||||||
|
"version",
|
||||||
|
&osmium::Relation::version,
|
||||||
|
"members",
|
||||||
|
[](const osmium::Relation &rel) -> const osmium::RelationMemberList & {
|
||||||
|
return rel.members();
|
||||||
|
});
|
||||||
|
|
||||||
context.state.new_usertype<osmium::Node>("Node",
|
context.state.new_usertype<osmium::Node>("Node",
|
||||||
"location",
|
"location",
|
||||||
&osmium::Node::location,
|
&osmium::Node::location,
|
||||||
@@ -284,7 +320,7 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
"id",
|
"id",
|
||||||
&osmium::Node::id,
|
&osmium::Node::id,
|
||||||
"version",
|
"version",
|
||||||
&osmium::Way::version);
|
&osmium::Node::version);
|
||||||
|
|
||||||
context.state.new_usertype<ExtractionNode>("ResultNode",
|
context.state.new_usertype<ExtractionNode>("ResultNode",
|
||||||
"traffic_lights",
|
"traffic_lights",
|
||||||
@@ -366,6 +402,18 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
sol::property([](const ExtractionWay &way) { return way.backward_restricted; },
|
sol::property([](const ExtractionWay &way) { return way.backward_restricted; },
|
||||||
[](ExtractionWay &way, bool flag) { way.backward_restricted = flag; }));
|
[](ExtractionWay &way, bool flag) { way.backward_restricted = flag; }));
|
||||||
|
|
||||||
|
context.state.new_usertype<ExtractionRelation>(
|
||||||
|
"ExtractionRelation",
|
||||||
|
sol::meta_function::new_index,
|
||||||
|
[](ExtractionRelation &rel, const osmium::RelationMember &member)
|
||||||
|
-> ExtractionRelation::AttributesMap & { return rel.GetMember(member); },
|
||||||
|
sol::meta_function::index,
|
||||||
|
[](ExtractionRelation &rel, const osmium::RelationMember &member)
|
||||||
|
-> ExtractionRelation::AttributesMap & { return rel.GetMember(member); },
|
||||||
|
"restriction",
|
||||||
|
sol::property([](const ExtractionRelation &rel) { return rel.is_restriction; },
|
||||||
|
[](ExtractionRelation &rel, bool flag) { rel.is_restriction = flag; }));
|
||||||
|
|
||||||
context.state.new_usertype<ExtractionSegment>("ExtractionSegment",
|
context.state.new_usertype<ExtractionSegment>("ExtractionSegment",
|
||||||
"source",
|
"source",
|
||||||
&ExtractionSegment::source,
|
&ExtractionSegment::source,
|
||||||
@@ -457,10 +505,7 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
util::Log() << "Using profile api version " << context.api_version;
|
util::Log() << "Using profile api version " << context.api_version;
|
||||||
|
|
||||||
// version-dependent parts of the api
|
// version-dependent parts of the api
|
||||||
switch (context.api_version)
|
auto initV2Context = [&]() {
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
// clear global not used in v2
|
// clear global not used in v2
|
||||||
context.state["properties"] = sol::nullopt;
|
context.state["properties"] = sol::nullopt;
|
||||||
|
|
||||||
@@ -543,6 +588,22 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
if (force_split_edges != sol::nullopt)
|
if (force_split_edges != sol::nullopt)
|
||||||
context.properties.force_split_edges = force_split_edges.value();
|
context.properties.force_split_edges = force_split_edges.value();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (context.api_version)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
initV2Context();
|
||||||
|
context.relation_function = function_table.value()["process_relation"];
|
||||||
|
|
||||||
|
context.has_relation_function = context.relation_function.valid();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
initV2Context();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
@@ -615,12 +676,15 @@ LuaScriptingContext &Sol2ScriptingEnvironment::GetSol2Context()
|
|||||||
void Sol2ScriptingEnvironment::ProcessElements(
|
void Sol2ScriptingEnvironment::ProcessElements(
|
||||||
const osmium::memory::Buffer &buffer,
|
const osmium::memory::Buffer &buffer,
|
||||||
const RestrictionParser &restriction_parser,
|
const RestrictionParser &restriction_parser,
|
||||||
|
const ExtractionRelationContainer &relations,
|
||||||
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
|
||||||
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
|
||||||
|
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> &resulting_relations,
|
||||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions)
|
std::vector<InputConditionalTurnRestriction> &resulting_restrictions)
|
||||||
{
|
{
|
||||||
ExtractionNode result_node;
|
ExtractionNode result_node;
|
||||||
ExtractionWay result_way;
|
ExtractionWay result_way;
|
||||||
|
ExtractionRelation result_relation;
|
||||||
auto &local_context = this->GetSol2Context();
|
auto &local_context = this->GetSol2Context();
|
||||||
|
|
||||||
for (auto entity = buffer.cbegin(), end = buffer.cend(); entity != end; ++entity)
|
for (auto entity = buffer.cbegin(), end = buffer.cend(); entity != end; ++entity)
|
||||||
@@ -628,33 +692,47 @@ void Sol2ScriptingEnvironment::ProcessElements(
|
|||||||
switch (entity->type())
|
switch (entity->type())
|
||||||
{
|
{
|
||||||
case osmium::item_type::node:
|
case osmium::item_type::node:
|
||||||
|
{
|
||||||
|
const auto &node = static_cast<const osmium::Node &>(*entity);
|
||||||
result_node.clear();
|
result_node.clear();
|
||||||
if (local_context.has_node_function &&
|
if (local_context.has_node_function &&
|
||||||
(!static_cast<const osmium::Node &>(*entity).tags().empty() ||
|
(!node.tags().empty() || local_context.properties.call_tagless_node_function))
|
||||||
local_context.properties.call_tagless_node_function))
|
|
||||||
{
|
{
|
||||||
local_context.ProcessNode(static_cast<const osmium::Node &>(*entity), result_node);
|
const auto &id = ExtractionRelation::OsmIDTyped(node.id(), osmium::item_type::node);
|
||||||
|
local_context.ProcessNode(node, result_node, relations.Get(id));
|
||||||
}
|
}
|
||||||
resulting_nodes.push_back(std::pair<const osmium::Node &, ExtractionNode>(
|
resulting_nodes.push_back({node, std::move(result_node)});
|
||||||
static_cast<const osmium::Node &>(*entity), std::move(result_node)));
|
}
|
||||||
break;
|
break;
|
||||||
case osmium::item_type::way:
|
case osmium::item_type::way:
|
||||||
|
{
|
||||||
|
const osmium::Way &way = static_cast<const osmium::Way &>(*entity);
|
||||||
result_way.clear();
|
result_way.clear();
|
||||||
if (local_context.has_way_function)
|
if (local_context.has_way_function)
|
||||||
{
|
{
|
||||||
local_context.ProcessWay(static_cast<const osmium::Way &>(*entity), result_way);
|
const auto &id = ExtractionRelation::OsmIDTyped(way.id(), osmium::item_type::way);
|
||||||
|
local_context.ProcessWay(way, result_way, relations.Get(id));
|
||||||
}
|
}
|
||||||
resulting_ways.push_back(std::pair<const osmium::Way &, ExtractionWay>(
|
resulting_ways.push_back({way, std::move(result_way)});
|
||||||
static_cast<const osmium::Way &>(*entity), std::move(result_way)));
|
}
|
||||||
break;
|
break;
|
||||||
case osmium::item_type::relation:
|
case osmium::item_type::relation:
|
||||||
{
|
{
|
||||||
auto result_res =
|
const auto &relation = static_cast<const osmium::Relation &>(*entity);
|
||||||
restriction_parser.TryParse(static_cast<const osmium::Relation &>(*entity));
|
if (auto result_res = restriction_parser.TryParse(relation))
|
||||||
if (result_res)
|
|
||||||
{
|
{
|
||||||
resulting_restrictions.push_back(*result_res);
|
resulting_restrictions.push_back(*result_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (local_context.api_version > 2)
|
||||||
|
{
|
||||||
|
result_relation.clear();
|
||||||
|
if (local_context.has_relation_function)
|
||||||
|
{
|
||||||
|
local_context.ProcessRelation(relation, result_relation);
|
||||||
|
}
|
||||||
|
resulting_relations.push_back({relation, std::move(result_relation)});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -732,6 +810,7 @@ std::vector<std::vector<std::string>> Sol2ScriptingEnvironment::GetExcludableCla
|
|||||||
auto &context = GetSol2Context();
|
auto &context = GetSol2Context();
|
||||||
switch (context.api_version)
|
switch (context.api_version)
|
||||||
{
|
{
|
||||||
|
case 3:
|
||||||
case 2:
|
case 2:
|
||||||
return Sol2ScriptingEnvironment::GetStringListsFromTable("excludable");
|
return Sol2ScriptingEnvironment::GetStringListsFromTable("excludable");
|
||||||
default:
|
default:
|
||||||
@@ -744,6 +823,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetClassNames()
|
|||||||
auto &context = GetSol2Context();
|
auto &context = GetSol2Context();
|
||||||
switch (context.api_version)
|
switch (context.api_version)
|
||||||
{
|
{
|
||||||
|
case 3:
|
||||||
case 2:
|
case 2:
|
||||||
return Sol2ScriptingEnvironment::GetStringListFromTable("classes");
|
return Sol2ScriptingEnvironment::GetStringListFromTable("classes");
|
||||||
default:
|
default:
|
||||||
@@ -756,6 +836,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetNameSuffixList()
|
|||||||
auto &context = GetSol2Context();
|
auto &context = GetSol2Context();
|
||||||
switch (context.api_version)
|
switch (context.api_version)
|
||||||
{
|
{
|
||||||
|
case 3:
|
||||||
case 2:
|
case 2:
|
||||||
return Sol2ScriptingEnvironment::GetStringListFromTable("suffix_list");
|
return Sol2ScriptingEnvironment::GetStringListFromTable("suffix_list");
|
||||||
case 1:
|
case 1:
|
||||||
@@ -770,6 +851,7 @@ std::vector<std::string> Sol2ScriptingEnvironment::GetRestrictions()
|
|||||||
auto &context = GetSol2Context();
|
auto &context = GetSol2Context();
|
||||||
switch (context.api_version)
|
switch (context.api_version)
|
||||||
{
|
{
|
||||||
|
case 3:
|
||||||
case 2:
|
case 2:
|
||||||
return Sol2ScriptingEnvironment::GetStringListFromTable("restrictions");
|
return Sol2ScriptingEnvironment::GetStringListFromTable("restrictions");
|
||||||
case 1:
|
case 1:
|
||||||
@@ -785,6 +867,7 @@ void Sol2ScriptingEnvironment::ProcessTurn(ExtractionTurn &turn)
|
|||||||
|
|
||||||
switch (context.api_version)
|
switch (context.api_version)
|
||||||
{
|
{
|
||||||
|
case 3:
|
||||||
case 2:
|
case 2:
|
||||||
if (context.has_turn_penalty_function)
|
if (context.has_turn_penalty_function)
|
||||||
{
|
{
|
||||||
@@ -851,6 +934,7 @@ void Sol2ScriptingEnvironment::ProcessSegment(ExtractionSegment &segment)
|
|||||||
{
|
{
|
||||||
switch (context.api_version)
|
switch (context.api_version)
|
||||||
{
|
{
|
||||||
|
case 3:
|
||||||
case 2:
|
case 2:
|
||||||
context.segment_function(context.profile_table, segment);
|
context.segment_function(context.profile_table, segment);
|
||||||
break;
|
break;
|
||||||
@@ -866,12 +950,17 @@ void Sol2ScriptingEnvironment::ProcessSegment(ExtractionSegment &segment)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaScriptingContext::ProcessNode(const osmium::Node &node, ExtractionNode &result)
|
void LuaScriptingContext::ProcessNode(const osmium::Node &node,
|
||||||
|
ExtractionNode &result,
|
||||||
|
const ExtractionRelationContainer::RelationList &relations)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(state.lua_state() != nullptr);
|
BOOST_ASSERT(state.lua_state() != nullptr);
|
||||||
|
|
||||||
switch (api_version)
|
switch (api_version)
|
||||||
{
|
{
|
||||||
|
case 3:
|
||||||
|
node_function(profile_table, node, result, relations);
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
node_function(profile_table, node, result);
|
node_function(profile_table, node, result);
|
||||||
break;
|
break;
|
||||||
@@ -882,12 +971,17 @@ void LuaScriptingContext::ProcessNode(const osmium::Node &node, ExtractionNode &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaScriptingContext::ProcessWay(const osmium::Way &way, ExtractionWay &result)
|
void LuaScriptingContext::ProcessWay(const osmium::Way &way,
|
||||||
|
ExtractionWay &result,
|
||||||
|
const ExtractionRelationContainer::RelationList &relations)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(state.lua_state() != nullptr);
|
BOOST_ASSERT(state.lua_state() != nullptr);
|
||||||
|
|
||||||
switch (api_version)
|
switch (api_version)
|
||||||
{
|
{
|
||||||
|
case 3:
|
||||||
|
way_function(profile_table, way, result, relations);
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
way_function(profile_table, way, result);
|
way_function(profile_table, way, result);
|
||||||
break;
|
break;
|
||||||
@@ -897,5 +991,15 @@ void LuaScriptingContext::ProcessWay(const osmium::Way &way, ExtractionWay &resu
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LuaScriptingContext::ProcessRelation(const osmium::Relation &relation,
|
||||||
|
ExtractionRelation &result)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(state.lua_state() != nullptr);
|
||||||
|
BOOST_ASSERT(api_version > 2);
|
||||||
|
|
||||||
|
relation_function(profile_table, relation, result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|||||||
+48
-53
@@ -52,46 +52,49 @@ const static unsigned INIT_OK_START_ENGINE = 0;
|
|||||||
const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
|
const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
|
||||||
const static unsigned INIT_FAILED = -1;
|
const static unsigned INIT_FAILED = -1;
|
||||||
|
|
||||||
static EngineConfig::Algorithm stringToAlgorithm(std::string algorithm)
|
namespace osrm
|
||||||
{
|
{
|
||||||
boost::to_lower(algorithm);
|
namespace engine
|
||||||
|
{
|
||||||
|
std::istream &operator>>(std::istream &in, EngineConfig::Algorithm &algorithm)
|
||||||
|
{
|
||||||
|
std::string token;
|
||||||
|
in >> token;
|
||||||
|
boost::to_lower(token);
|
||||||
|
|
||||||
if (algorithm == "ch")
|
if (token == "ch")
|
||||||
return EngineConfig::Algorithm::CH;
|
algorithm = EngineConfig::Algorithm::CH;
|
||||||
if (algorithm == "corech")
|
else if (token == "corech")
|
||||||
return EngineConfig::Algorithm::CoreCH;
|
algorithm = EngineConfig::Algorithm::CoreCH;
|
||||||
if (algorithm == "mld")
|
else if (token == "mld")
|
||||||
return EngineConfig::Algorithm::MLD;
|
algorithm = EngineConfig::Algorithm::MLD;
|
||||||
throw util::RuntimeError(algorithm, ErrorCode::UnknownAlgorithm, SOURCE_REF);
|
else
|
||||||
|
throw util::RuntimeError(token, ErrorCode::UnknownAlgorithm, SOURCE_REF);
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate boost::program_options object for the routing part
|
// generate boost::program_options object for the routing part
|
||||||
inline unsigned generateServerProgramOptions(const int argc,
|
inline unsigned generateServerProgramOptions(const int argc,
|
||||||
const char *argv[],
|
const char *argv[],
|
||||||
std::string verbosity,
|
|
||||||
boost::filesystem::path &base_path,
|
boost::filesystem::path &base_path,
|
||||||
std::string &ip_address,
|
std::string &ip_address,
|
||||||
int &ip_port,
|
int &ip_port,
|
||||||
int &requested_num_threads,
|
|
||||||
bool &use_shared_memory,
|
|
||||||
std::string &algorithm,
|
|
||||||
bool &trial,
|
bool &trial,
|
||||||
int &max_locations_trip,
|
EngineConfig &config)
|
||||||
int &max_locations_viaroute,
|
|
||||||
int &max_locations_distance_table,
|
|
||||||
int &max_locations_map_matching,
|
|
||||||
int &max_results_nearest,
|
|
||||||
int &max_alternatives)
|
|
||||||
{
|
{
|
||||||
using boost::program_options::value;
|
using boost::program_options::value;
|
||||||
using boost::filesystem::path;
|
using boost::filesystem::path;
|
||||||
|
|
||||||
|
const auto hardware_threads = std::max<int>(1, std::thread::hardware_concurrency());
|
||||||
|
|
||||||
// declare a group of options that will be allowed only on command line
|
// declare a group of options that will be allowed only on command line
|
||||||
boost::program_options::options_description generic_options("Options");
|
boost::program_options::options_description generic_options("Options");
|
||||||
generic_options.add_options() //
|
generic_options.add_options() //
|
||||||
("version,v", "Show version")("help,h", "Show this help message")(
|
("version,v", "Show version")("help,h", "Show this help message")(
|
||||||
"verbosity,l",
|
"verbosity,l",
|
||||||
boost::program_options::value<std::string>(&verbosity)->default_value("INFO"),
|
boost::program_options::value<std::string>(&config.verbosity)->default_value("INFO"),
|
||||||
std::string("Log verbosity level: " + util::LogPolicy::GetLevels()).c_str())(
|
std::string("Log verbosity level: " + util::LogPolicy::GetLevels()).c_str())(
|
||||||
"trial", value<bool>(&trial)->implicit_value(true), "Quit after initialization");
|
"trial", value<bool>(&trial)->implicit_value(true), "Quit after initialization");
|
||||||
|
|
||||||
@@ -105,31 +108,32 @@ inline unsigned generateServerProgramOptions(const int argc,
|
|||||||
value<int>(&ip_port)->default_value(5000),
|
value<int>(&ip_port)->default_value(5000),
|
||||||
"TCP/IP port") //
|
"TCP/IP port") //
|
||||||
("threads,t",
|
("threads,t",
|
||||||
value<int>(&requested_num_threads)->default_value(8),
|
value<int>(&config.use_threads_number)->default_value(hardware_threads),
|
||||||
"Number of threads to use") //
|
"Number of threads to use") //
|
||||||
("shared-memory,s",
|
("shared-memory,s",
|
||||||
value<bool>(&use_shared_memory)->implicit_value(true)->default_value(false),
|
value<bool>(&config.use_shared_memory)->implicit_value(true)->default_value(false),
|
||||||
"Load data from shared memory") //
|
"Load data from shared memory") //
|
||||||
("algorithm,a",
|
("algorithm,a",
|
||||||
value<std::string>(&algorithm)->default_value("CH"),
|
value<EngineConfig::Algorithm>(&config.algorithm)
|
||||||
|
->default_value(EngineConfig::Algorithm::CH, "CH"),
|
||||||
"Algorithm to use for the data. Can be CH, CoreCH, MLD.") //
|
"Algorithm to use for the data. Can be CH, CoreCH, MLD.") //
|
||||||
("max-viaroute-size",
|
("max-viaroute-size",
|
||||||
value<int>(&max_locations_viaroute)->default_value(500),
|
value<int>(&config.max_locations_viaroute)->default_value(500),
|
||||||
"Max. locations supported in viaroute query") //
|
"Max. locations supported in viaroute query") //
|
||||||
("max-trip-size",
|
("max-trip-size",
|
||||||
value<int>(&max_locations_trip)->default_value(100),
|
value<int>(&config.max_locations_trip)->default_value(100),
|
||||||
"Max. locations supported in trip query") //
|
"Max. locations supported in trip query") //
|
||||||
("max-table-size",
|
("max-table-size",
|
||||||
value<int>(&max_locations_distance_table)->default_value(100),
|
value<int>(&config.max_locations_distance_table)->default_value(100),
|
||||||
"Max. locations supported in distance table query") //
|
"Max. locations supported in distance table query") //
|
||||||
("max-matching-size",
|
("max-matching-size",
|
||||||
value<int>(&max_locations_map_matching)->default_value(100),
|
value<int>(&config.max_locations_map_matching)->default_value(100),
|
||||||
"Max. locations supported in map matching query") //
|
"Max. locations supported in map matching query") //
|
||||||
("max-nearest-size",
|
("max-nearest-size",
|
||||||
value<int>(&max_results_nearest)->default_value(100),
|
value<int>(&config.max_results_nearest)->default_value(100),
|
||||||
"Max. results supported in nearest query") //
|
"Max. results supported in nearest query") //
|
||||||
("max-alternatives",
|
("max-alternatives",
|
||||||
value<int>(&max_alternatives)->default_value(3),
|
value<int>(&config.max_alternatives)->default_value(3),
|
||||||
"Max. number of alternatives supported in the MLD route query");
|
"Max. number of alternatives supported in the MLD route query");
|
||||||
|
|
||||||
// hidden options, will be allowed on command line, but will not be shown to the user
|
// hidden options, will be allowed on command line, but will not be shown to the user
|
||||||
@@ -180,19 +184,22 @@ inline unsigned generateServerProgramOptions(const int argc,
|
|||||||
|
|
||||||
boost::program_options::notify(option_variables);
|
boost::program_options::notify(option_variables);
|
||||||
|
|
||||||
if (!use_shared_memory && option_variables.count("base"))
|
if (!config.use_shared_memory && option_variables.count("base"))
|
||||||
{
|
{
|
||||||
return INIT_OK_START_ENGINE;
|
return INIT_OK_START_ENGINE;
|
||||||
}
|
}
|
||||||
else if (use_shared_memory && !option_variables.count("base"))
|
else if (config.use_shared_memory && !option_variables.count("base"))
|
||||||
{
|
{
|
||||||
return INIT_OK_START_ENGINE;
|
return INIT_OK_START_ENGINE;
|
||||||
}
|
}
|
||||||
else if (use_shared_memory && option_variables.count("base"))
|
else if (config.use_shared_memory && option_variables.count("base"))
|
||||||
{
|
{
|
||||||
util::Log(logWARNING) << "Shared memory settings conflict with path settings.";
|
util::Log(logWARNING) << "Shared memory settings conflict with path settings.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust number of threads to hardware concurrency
|
||||||
|
config.use_threads_number = std::min(hardware_threads, config.use_threads_number);
|
||||||
|
|
||||||
std::cout << visible_options;
|
std::cout << visible_options;
|
||||||
return INIT_OK_DO_NOT_START_ENGINE;
|
return INIT_OK_DO_NOT_START_ENGINE;
|
||||||
}
|
}
|
||||||
@@ -203,28 +210,13 @@ int main(int argc, const char *argv[]) try
|
|||||||
|
|
||||||
bool trial_run = false;
|
bool trial_run = false;
|
||||||
std::string ip_address;
|
std::string ip_address;
|
||||||
int ip_port, requested_thread_num;
|
int ip_port;
|
||||||
|
|
||||||
EngineConfig config;
|
EngineConfig config;
|
||||||
std::string verbosity;
|
|
||||||
boost::filesystem::path base_path;
|
boost::filesystem::path base_path;
|
||||||
std::string algorithm;
|
|
||||||
const unsigned init_result = generateServerProgramOptions(argc,
|
const unsigned init_result =
|
||||||
argv,
|
generateServerProgramOptions(argc, argv, base_path, ip_address, ip_port, trial_run, config);
|
||||||
verbosity,
|
|
||||||
base_path,
|
|
||||||
ip_address,
|
|
||||||
ip_port,
|
|
||||||
requested_thread_num,
|
|
||||||
config.use_shared_memory,
|
|
||||||
algorithm,
|
|
||||||
trial_run,
|
|
||||||
config.max_locations_trip,
|
|
||||||
config.max_locations_viaroute,
|
|
||||||
config.max_locations_distance_table,
|
|
||||||
config.max_locations_map_matching,
|
|
||||||
config.max_results_nearest,
|
|
||||||
config.max_alternatives);
|
|
||||||
if (init_result == INIT_OK_DO_NOT_START_ENGINE)
|
if (init_result == INIT_OK_DO_NOT_START_ENGINE)
|
||||||
{
|
{
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
@@ -234,7 +226,7 @@ int main(int argc, const char *argv[]) try
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::LogPolicy::GetInstance().SetLevel(verbosity);
|
util::LogPolicy::GetInstance().SetLevel(config.verbosity);
|
||||||
|
|
||||||
if (!base_path.empty())
|
if (!base_path.empty())
|
||||||
{
|
{
|
||||||
@@ -253,7 +245,6 @@ int main(int argc, const char *argv[]) try
|
|||||||
}
|
}
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
config.algorithm = stringToAlgorithm(algorithm);
|
|
||||||
|
|
||||||
util::Log() << "starting up engines, " << OSRM_VERSION;
|
util::Log() << "starting up engines, " << OSRM_VERSION;
|
||||||
|
|
||||||
@@ -262,6 +253,10 @@ int main(int argc, const char *argv[]) try
|
|||||||
util::Log() << "Loading from shared memory";
|
util::Log() << "Loading from shared memory";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the same number of threads for Server and TBB threads pools
|
||||||
|
// It doubles number of used threads
|
||||||
|
auto requested_thread_num = config.use_threads_number;
|
||||||
|
|
||||||
util::Log() << "Threads: " << requested_thread_num;
|
util::Log() << "Threads: " << requested_thread_num;
|
||||||
util::Log() << "IP address: " << ip_address;
|
util::Log() << "IP address: " << ip_address;
|
||||||
util::Log() << "IP port: " << ip_port;
|
util::Log() << "IP port: " << ip_port;
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#ifdef GLIBC_WORKAROUND
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
// https://github.com/bitcoin/bitcoin/pull/4042
|
||||||
|
// allows building against libstdc++-dev-4.9 while avoiding
|
||||||
|
// GLIBCXX_3.4.20 dep
|
||||||
|
// This is needed because libstdc++ itself uses this API - its not
|
||||||
|
// just an issue of your code using it, ughhh
|
||||||
|
|
||||||
|
// Note: only necessary on Linux
|
||||||
|
#ifdef __linux__
|
||||||
|
#define _ENABLE_GLIBC_WORKAROUND
|
||||||
|
#warning building with workaround
|
||||||
|
#else
|
||||||
|
#warning not building with workaround
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ENABLE_GLIBC_WORKAROUND
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
void __throw_out_of_range_fmt(const char *, ...) __attribute__((__noreturn__));
|
||||||
|
void __throw_out_of_range_fmt(const char *err, ...)
|
||||||
|
{
|
||||||
|
// Safe and over-simplified version. Ignore the format and print it as-is.
|
||||||
|
__throw_out_of_range(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // _ENABLE_GLIBC_WORKAROUND
|
||||||
|
|
||||||
|
#endif // GLIBC_WORKAROUND
|
||||||
+1
-1
@@ -48,7 +48,7 @@ void LogPolicy::SetLevel(std::string const &level)
|
|||||||
else if (boost::iequals(level, "DEBUG"))
|
else if (boost::iequals(level, "DEBUG"))
|
||||||
m_level = logDEBUG;
|
m_level = logDEBUG;
|
||||||
else
|
else
|
||||||
;
|
m_level = logINFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPolicy &LogPolicy::GetInstance()
|
LogPolicy &LogPolicy::GetInstance()
|
||||||
|
|||||||
+26
-23
@@ -144,29 +144,32 @@
|
|||||||
{"key": "maxspeed", "value": "rural"},
|
{"key": "maxspeed", "value": "rural"},
|
||||||
{"key": "maxspeed", "value": "trunk"},
|
{"key": "maxspeed", "value": "trunk"},
|
||||||
{"key": "maxspeed", "value": "motorway"},
|
{"key": "maxspeed", "value": "motorway"},
|
||||||
{"key": "maxspeed", "value": "ch:rural"},
|
{"key": "maxspeed", "value": "BE:motorway"},
|
||||||
{"key": "maxspeed", "value": "ch:trunk"},
|
{"key": "maxspeed", "value": "CH:rural"},
|
||||||
{"key": "maxspeed", "value": "ch:motorway"},
|
{"key": "maxspeed", "value": "CH:trunk"},
|
||||||
{"key": "maxspeed", "value": "de:living_street"},
|
{"key": "maxspeed", "value": "CH:motorway"},
|
||||||
{"key": "maxspeed", "value": "ru:living_street"},
|
{"key": "maxspeed", "value": "DE:living_street"},
|
||||||
{"key": "maxspeed", "value": "ru:urban"},
|
{"key": "maxspeed", "value": "DK:rural"},
|
||||||
{"key": "maxspeed", "value": "ua:urban"},
|
{"key": "maxspeed", "value": "RU:living_street"},
|
||||||
{"key": "maxspeed", "value": "at:rural"},
|
{"key": "maxspeed", "value": "RU:urban"},
|
||||||
{"key": "maxspeed", "value": "de:rural"},
|
{"key": "maxspeed", "value": "UA:urban"},
|
||||||
{"key": "maxspeed", "value": "at:trunk"},
|
{"key": "maxspeed", "value": "AT:rural"},
|
||||||
{"key": "maxspeed", "value": "cz:trunk"},
|
{"key": "maxspeed", "value": "DE:rural"},
|
||||||
{"key": "maxspeed", "value": "ro:trunk"},
|
{"key": "maxspeed", "value": "DK:rural"},
|
||||||
{"key": "maxspeed", "value": "cz:motorway"},
|
{"key": "maxspeed", "value": "AT:trunk"},
|
||||||
{"key": "maxspeed", "value": "de:motorway"},
|
{"key": "maxspeed", "value": "CZ:trunk"},
|
||||||
{"key": "maxspeed", "value": "ru:motorway"},
|
{"key": "maxspeed", "value": "RO:trunk"},
|
||||||
{"key": "maxspeed", "value": "gb:nsl_single"},
|
{"key": "maxspeed", "value": "CZ:motorway"},
|
||||||
{"key": "maxspeed", "value": "gb:nsl_dual"},
|
{"key": "maxspeed", "value": "DE:motorway"},
|
||||||
{"key": "maxspeed", "value": "gb:motorway"},
|
{"key": "maxspeed", "value": "RU:motorway"},
|
||||||
{"key": "maxspeed", "value": "uk:nsl_single"},
|
{"key": "maxspeed", "value": "GB:nsl_single"},
|
||||||
{"key": "maxspeed", "value": "uk:nsl_dual"},
|
{"key": "maxspeed", "value": "GB:nsl_dual"},
|
||||||
{"key": "maxspeed", "value": "uk:motorway"},
|
{"key": "maxspeed", "value": "GB:motorway"},
|
||||||
{"key": "maxspeed", "value": "nl:rural"},
|
{"key": "maxspeed", "value": "UK:nsl_single"},
|
||||||
{"key": "maxspeed", "value": "nl:trunk"},
|
{"key": "maxspeed", "value": "UK:nsl_dual"},
|
||||||
|
{"key": "maxspeed", "value": "UK:motorway"},
|
||||||
|
{"key": "maxspeed", "value": "NL:rural"},
|
||||||
|
{"key": "maxspeed", "value": "NL:trunk"},
|
||||||
{"key": "smoothness", "value": "intermediate"},
|
{"key": "smoothness", "value": "intermediate"},
|
||||||
{"key": "smoothness", "value": "bad"},
|
{"key": "smoothness", "value": "bad"},
|
||||||
{"key": "smoothness", "value": "very_bad"},
|
{"key": "smoothness", "value": "very_bad"},
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
n1 v1 dV c1 t2014-01-01T00:00:00Z i1 utest T x1.02 y1.02
|
n1 v1 dV c1 t2014-01-01T00:00:00Z i1 utest T x1.02 y1.02
|
||||||
|
|||||||
@@ -34,11 +34,14 @@ class MockScriptingEnvironment : public extractor::ScriptingEnvironment
|
|||||||
void ProcessTurn(extractor::ExtractionTurn &) override final {}
|
void ProcessTurn(extractor::ExtractionTurn &) override final {}
|
||||||
void ProcessSegment(extractor::ExtractionSegment &) override final {}
|
void ProcessSegment(extractor::ExtractionSegment &) override final {}
|
||||||
|
|
||||||
void ProcessElements(const osmium::memory::Buffer &,
|
void ProcessElements(
|
||||||
const extractor::RestrictionParser &,
|
const osmium::memory::Buffer &,
|
||||||
std::vector<std::pair<const osmium::Node &, extractor::ExtractionNode>> &,
|
const extractor::RestrictionParser &,
|
||||||
std::vector<std::pair<const osmium::Way &, extractor::ExtractionWay>> &,
|
const extractor::ExtractionRelationContainer &,
|
||||||
std::vector<extractor::InputConditionalTurnRestriction> &) override final
|
std::vector<std::pair<const osmium::Node &, extractor::ExtractionNode>> &,
|
||||||
|
std::vector<std::pair<const osmium::Way &, extractor::ExtractionWay>> &,
|
||||||
|
std::vector<std::pair<const osmium::Relation &, extractor::ExtractionRelation>> &,
|
||||||
|
std::vector<extractor::InputConditionalTurnRestriction> &) override final
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user