Compare commits
158 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1eda57c13 | |||
| 8b45ff7a18 | |||
| 4c665b24d9 | |||
| 381d492a8f | |||
| e250c83c21 | |||
| e2e326d15e | |||
| 4abca85474 | |||
| 2c78d862a3 | |||
| b1451a7421 | |||
| da1c251144 | |||
| 1eab7b41d1 | |||
| 1dca8ae76a | |||
| 002e86863d | |||
| 1d82b01816 | |||
| 714719c377 | |||
| 77b4fbb69c | |||
| 11fde865f7 | |||
| 717406043a | |||
| 1ef85c57cc | |||
| d0180517a8 | |||
| 520b7ebbb6 | |||
| 2caba96076 | |||
| 81bc2f41a6 | |||
| 06e010b4d0 | |||
| 92d3ce789b | |||
| 01ca32c81c | |||
| 2e17f3010a | |||
| c4238c4ed6 | |||
| 3d781e6f28 | |||
| 4976233cff | |||
| 98ea2a0b09 | |||
| f978900ab0 | |||
| 8b6580128b | |||
| 4dde9c7bbe | |||
| 973837207b | |||
| 364e35af06 | |||
| 985ab58f45 | |||
| cb1db646f2 | |||
| a67c4bf84d | |||
| 498259b220 | |||
| 5327f8da4e | |||
| 802ccfb497 | |||
| ec369d560a | |||
| 535647e439 | |||
| 954121634f | |||
| 594a45e7e0 | |||
| 96c7b47afe | |||
| b7e7d32361 | |||
| 2f9cb44368 | |||
| d80318f8ea | |||
| b1791d1ab3 | |||
| a53da9095a | |||
| 72e03f9af9 | |||
| 5597415f28 | |||
| 5476f6ab27 | |||
| 0971f06193 | |||
| 85515f063a | |||
| 69d7825542 | |||
| 9b779c704f | |||
| 5bd7d04fe3 | |||
| 0f78f7b2cc | |||
| 8473be69d2 | |||
| c0124f7d77 | |||
| b630b4e32a | |||
| 89fabc1b9c | |||
| a649a8a5cf | |||
| f928956584 | |||
| 7ff68792d7 | |||
| 3088dd0342 | |||
| d2590989f5 | |||
| 3a7b377586 | |||
| 82b5648c97 | |||
| 1628a3c4d5 | |||
| e5d8319c43 | |||
| 06699132eb | |||
| 918e794d6a | |||
| 8dd8ee1fc2 | |||
| c3d0efda93 | |||
| 3b4e2e83ef | |||
| c459530cb6 | |||
| 2a15e6dec8 | |||
| 1a1293608d | |||
| 318df9deaa | |||
| cacb162520 | |||
| 105709cb43 | |||
| 9695fa7941 | |||
| fd9bebbfa7 | |||
| db18e8669f | |||
| 9b4a4fdd82 | |||
| cdc7e5f021 | |||
| adc87149e2 | |||
| 8adbfe06ed | |||
| ae805f9ec8 | |||
| be24689b0f | |||
| 41c31a2388 | |||
| 8b866502d1 | |||
| 7837cd61df | |||
| b573485c31 | |||
| 4e68f3a7e1 | |||
| 5ba26d3d6d | |||
| a6cf2eee7e | |||
| 6843eb1479 | |||
| b331885d3c | |||
| 73716bd651 | |||
| 9edd161da3 | |||
| 1bc3ff6491 | |||
| b0f2ef287e | |||
| 16f53ff81a | |||
| 7a260dc2ba | |||
| 1c0d951f5e | |||
| 77a740c0fb | |||
| 61101db8cf | |||
| b51632a2fb | |||
| 9d10503a9c | |||
| 7d50e5afe0 | |||
| 549216c792 | |||
| 1990de7dcc | |||
| 89f6e2d55b | |||
| c628ecbf24 | |||
| b6f19cd544 | |||
| 14860b62e9 | |||
| 9970b7d580 | |||
| 7feb79ef91 | |||
| 6f84812903 | |||
| 8085e86170 | |||
| 35973576d9 | |||
| 7740d5d7c0 | |||
| c4eff6cd65 | |||
| 5c4353b46e | |||
| 05a5918909 | |||
| 80ad38bbc6 | |||
| 6bee8866de | |||
| ba92674c6e | |||
| 68019a1fb2 | |||
| 3a9acde2c3 | |||
| a3a7a822e1 | |||
| c7d22c2b92 | |||
| b2aeb47630 | |||
| 0a1d1901cc | |||
| 29db0c80d9 | |||
| 4654751872 | |||
| b5b18d8afc | |||
| 15139c934f | |||
| 7b8619e37c | |||
| f52b5c31b6 | |||
| e98859e4c0 | |||
| c5cc4c5a74 | |||
| e3b831364f | |||
| 730d2b5ef2 | |||
| 16abee1022 | |||
| 69fa52a010 | |||
| e1efa4c6ab | |||
| 17cd1575f6 | |||
| 3cd8e0fef8 | |||
| 397bb694fd | |||
| 473ebfcbf6 | |||
| a06171438e | |||
| ea0881553e |
@@ -68,6 +68,10 @@ Thumbs.db
|
||||
/*.local.bat
|
||||
/CMakeSettings.json
|
||||
|
||||
# Jetbrains related files #
|
||||
###########################
|
||||
.idea/
|
||||
|
||||
# stxxl related files #
|
||||
#######################
|
||||
.stxxl
|
||||
|
||||
+193
-66
@@ -15,10 +15,9 @@ branches:
|
||||
- master
|
||||
# enable building tags
|
||||
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||
- "5.17"
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
npm: true
|
||||
ccache: true
|
||||
apt: true
|
||||
directories:
|
||||
@@ -35,7 +34,11 @@ env:
|
||||
- CMAKE_VERSION=3.7.2
|
||||
- MASON="$(pwd)/scripts/mason.sh"
|
||||
- ENABLE_NODE_BINDINGS=On
|
||||
- NODE="4"
|
||||
- NODE="10"
|
||||
|
||||
stages:
|
||||
- core
|
||||
- optional
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
@@ -44,18 +47,19 @@ matrix:
|
||||
include:
|
||||
|
||||
# Debug Builds
|
||||
- os: linux
|
||||
- stage: core
|
||||
os: linux
|
||||
compiler: "format-taginfo-docs"
|
||||
env: NODE=6
|
||||
env: NODE=10
|
||||
sudo: false
|
||||
before_install:
|
||||
install:
|
||||
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
|
||||
- source $NVM_DIR/nvm.sh
|
||||
- nvm install $NODE
|
||||
- nvm use $NODE
|
||||
- npm --version
|
||||
- npm install --ignore-scripts
|
||||
- npm link --ignore-scripts
|
||||
- npm ci --ignore-scripts
|
||||
script:
|
||||
- ./scripts/check_taginfo.py taginfo.json profiles/car.lua
|
||||
- ${MASON} install clang-format 3.8.1
|
||||
@@ -157,17 +161,17 @@ matrix:
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.2
|
||||
compiler: "mason-osx-release-node-8"
|
||||
compiler: "mason-osx-release-node-10"
|
||||
# we use the xcode provides clang and don't install our own
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="8"
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="10"
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.2
|
||||
compiler: "mason-osx-release-node-4"
|
||||
compiler: "mason-osx-release-node-8"
|
||||
# we use the xcode provides clang and don't install our own
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="4"
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="8"
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
@@ -181,54 +185,6 @@ matrix:
|
||||
env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
|
||||
|
||||
# Node build jobs. These skip running the tests.
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-4-mason-linux-release"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="4"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-4-mason-linux-debug"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="4"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-8-mason-linux-release"
|
||||
@@ -277,7 +233,183 @@ matrix:
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-10-mason-linux-release"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="10"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-10-mason-linux-debug"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="10"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: osx
|
||||
stage: optional
|
||||
osx_image: xcode9.2
|
||||
compiler: "mason-osx-release-node-latest"
|
||||
# we use the xcode provides clang and don't install our own
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="node"
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-latest-mason-linux-release"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="node"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-latest-mason-linux-debug"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="node"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.2
|
||||
compiler: "mason-osx-release-node-lts"
|
||||
# we use the xcode provides clang and don't install our own
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="--lts"
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-lts-mason-linux-release"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="--lts"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-lts-mason-linux-debug"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="--lts"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
allow_failures:
|
||||
- compiler: "mason-osx-release-node-latest"
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="node"
|
||||
- compiler: "node-latest-mason-linux-release"
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="node"
|
||||
- compiler: "node-latest-mason-linux-debug"
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="node"
|
||||
- compiler: "mason-osx-release-node-lts"
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="--lts"
|
||||
- compiler: "node-lts-mason-linux-release"
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="--lts"
|
||||
- compiler: "node-lts-mason-linux-debug"
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="--lts"
|
||||
|
||||
before_install:
|
||||
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
|
||||
- source $NVM_DIR/nvm.sh
|
||||
- nvm install $NODE
|
||||
- nvm use $NODE
|
||||
@@ -295,15 +427,10 @@ before_install:
|
||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
sudo mdutil -i off /
|
||||
fi
|
||||
- |
|
||||
if [[ ! -f $(which yarn) ]]; then
|
||||
npm install -g yarn
|
||||
fi
|
||||
- export PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
|
||||
- export PUBLISH=$([[ "${TRAVIS_TAG:-}" == "v${PACKAGE_JSON_VERSION}" ]] && echo "On" || echo "Off")
|
||||
- echo "Using ${JOBS} jobs"
|
||||
- yarn install --ignore-scripts
|
||||
- yarn check --ignore-scripts --integrity
|
||||
- npm ci --ignore-scripts
|
||||
# Bootstrap cmake to be able to run mason
|
||||
- CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/${CMAKE_VERSION}.tar.gz"
|
||||
- CMAKE_DIR="mason_packages/${TRAVIS_OS_NAME}-x86_64/cmake/${CMAKE_VERSION}"
|
||||
@@ -382,4 +509,4 @@ script:
|
||||
fi
|
||||
- |
|
||||
- popd
|
||||
- yarn test
|
||||
- npm test
|
||||
|
||||
+71
-5
@@ -1,9 +1,75 @@
|
||||
# 5.17.3
|
||||
- Changes from 5.17.2:
|
||||
- Bugfixes:
|
||||
- FIXED: Increased probability of returning alternatives and quality of the ones returned for MLD. [#5048](https://github.com/Project-OSRM/osrm-backend/issues/5048)
|
||||
# Unreleased
|
||||
- Changes from 5.21.0
|
||||
- Build:
|
||||
- ADDED: optionally build Node `lts` and `latest` bindings [#5347](https://github.com/Project-OSRM/osrm-backend/pull/5347)
|
||||
- Features:
|
||||
- ADDED: new waypoints parameter to the `route` plugin, enabling silent waypoints [#5345](https://github.com/Project-OSRM/osrm-backend/pull/5345)
|
||||
- ADDED: data timestamp information in the response (saved in new file `.osrm.timestamp`). [#5115](https://github.com/Project-OSRM/osrm-backend/issues/5115)
|
||||
|
||||
# 5.17.2
|
||||
# 5.21.0
|
||||
- Changes from 5.20.0
|
||||
- Features:
|
||||
- ADDED: all waypoints in responses now contain a distance property between the original coordinate and the snapped location. [#5255](https://github.com/Project-OSRM/osrm-backend/pull/5255)
|
||||
- ADDED: if `fallback_speed` is used, a new structure `fallback_speed_cells` will describe which cells contain estimated values [#5259](https://github.com/Project-OSRM/osrm-backend/pull/5259)
|
||||
- REMOVED: we no longer publish Node 4 or 6 binary modules (they are still buildable from source) [#5314](https://github.com/Project-OSRM/osrm-backend/pull/5314)
|
||||
- Table:
|
||||
- ADDED: new parameter `scale_factor` which will scale the cell `duration` values by this factor. [#5298](https://github.com/Project-OSRM/osrm-backend/pull/5298)
|
||||
- FIXED: only trigger `scale_factor` code to scan matrix when necessary. [#5303](https://github.com/Project-OSRM/osrm-backend/pull/5303)
|
||||
- FIXED: fix bug in reverse offset calculation that sometimes lead to negative (and other incorrect) values in distance table results [#5315](https://github.com/Project-OSRM/osrm-backend/pull/5315)
|
||||
- Docker:
|
||||
- FIXED: use consistent boost version between build and runtime [#5311](https://github.com/Project-OSRM/osrm-backend/pull/5311)
|
||||
- FIXED: don't override default permissions on /opt [#5311](https://github.com/Project-OSRM/osrm-backend/pull/5311)
|
||||
- Matching:
|
||||
- CHANGED: matching will now consider edges marked with is_startpoint=false, allowing matching over ferries and other previously non-matchable edge types. [#5297](https://github.com/Project-OSRM/osrm-backend/pull/5297)
|
||||
- Profile:
|
||||
- ADDED: Parse `source:maxspeed` and `maxspeed:type` tags to apply maxspeeds and add belgian flanders rural speed limit. [#5217](https://github.com/Project-OSRM/osrm-backend/pull/5217)
|
||||
- CHANGED: Refactor maxspeed parsing to use common library. [#5144](https://github.com/Project-OSRM/osrm-backend/pull/5144)
|
||||
|
||||
# 5.20.0
|
||||
- Changes from 5.19.0:
|
||||
- Table:
|
||||
- CHANGED: switch to pre-calculated distances for table responses for large speedup and 10% memory increase. [#5251](https://github.com/Project-OSRM/osrm-backend/pull/5251)
|
||||
- ADDED: new parameter `fallback_speed` which will fill `null` cells with estimated value [#5257](https://github.com/Project-OSRM/osrm-backend/pull/5257)
|
||||
- CHANGED: Remove API check for matrix sources/destination length to be less than or equal to coordinates length. [#5298](https://github.com/Project-OSRM/osrm-backend/pull/5289)
|
||||
- FIXED: Fix crashing bug when using fallback_speed parameter with more sources than destinations. [#5291](https://github.com/Project-OSRM/osrm-backend/pull/5291)
|
||||
- Features:
|
||||
- ADDED: direct mmapping of datafiles is now supported via the `--mmap` switch. [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
|
||||
- REMOVED: the previous `--memory_file` switch is now deprecated and will fallback to `--mmap` [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
|
||||
- ADDED: Now publishing Node 10.x LTS binary modules [#5246](https://github.com/Project-OSRM/osrm-backend/pull/5246)
|
||||
- Windows:
|
||||
- FIXED: Windows builds again. [#5249](https://github.com/Project-OSRM/osrm-backend/pull/5249)
|
||||
- Docker:
|
||||
- CHANGED: switch from Alpine Linux to Debian Buster base images [#5281](https://github.com/Project-OSRM/osrm-backend/pull/5281)
|
||||
|
||||
# 5.19.0
|
||||
- Changes from 5.18.0:
|
||||
- Optimizations:
|
||||
- CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188)
|
||||
- ADDED: Node bindings can return pre-rendered JSON buffer. [#5189](https://github.com/Project-OSRM/osrm-backend/pull/5189)
|
||||
- Profiles:
|
||||
- CHANGED: Bicycle profile now blacklists barriers instead of whitelisting them [#5076
|
||||
](https://github.com/Project-OSRM/osrm-backend/pull/5076/)
|
||||
- CHANGED: Foot profile now blacklists barriers instead of whitelisting them [#5077
|
||||
](https://github.com/Project-OSRM/osrm-backend/pull/5077/)
|
||||
- CHANGED: Support maxlength and maxweight in car profile [#5101](https://github.com/Project-OSRM/osrm-backend/pull/5101]
|
||||
- Bugfixes:
|
||||
- FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114)
|
||||
- Misc:
|
||||
- CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185)
|
||||
|
||||
# 5.18.0
|
||||
- Changes from 5.17.0:
|
||||
- Features:
|
||||
- ADDED: `table` plugin now optionally returns `distance` matrix as part of response [#4990](https://github.com/Project-OSRM/osrm-backend/pull/4990)
|
||||
- ADDED: New optional parameter `annotations` for `table` that accepts `distance`, `duration`, or both `distance,duration` as values [#4990](https://github.com/Project-OSRM/osrm-backend/pull/4990)
|
||||
- Infrastructure:
|
||||
- ADDED: Updated libosmium and added protozero and vtzero libraries [#5037](https://github.com/Project-OSRM/osrm-backend/pull/5037)
|
||||
- CHANGED: Use vtzero library in tile plugin [#4686](https://github.com/Project-OSRM/osrm-backend/pull/4686)
|
||||
- Profile:
|
||||
- ADDED: Bicycle profile now returns classes for ferry and tunnel routes. [#5054](https://github.com/Project-OSRM/osrm-backend/pull/5054)
|
||||
- ADDED: Bicycle profile allows to exclude ferry routes (default to not enabled) [#5054](https://github.com/Project-OSRM/osrm-backend/pull/5054)
|
||||
|
||||
# 5.17.1
|
||||
- Changes from 5.17.0:
|
||||
- Bugfixes:
|
||||
- FIXED: Do not combine a segregated edge with a roundabout [#5039](https://github.com/Project-OSRM/osrm-backend/issues/5039)
|
||||
|
||||
+24
-13
@@ -167,7 +167,7 @@ add_executable(osrm-customize src/tools/customize.cpp)
|
||||
add_executable(osrm-contract src/tools/contract.cpp)
|
||||
add_executable(osrm-routed src/tools/routed.cpp $<TARGET_OBJECTS:SERVER> $<TARGET_OBJECTS:UTIL>)
|
||||
add_executable(osrm-datastore src/tools/store.cpp $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL>)
|
||||
add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL> )
|
||||
add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL>)
|
||||
add_library(osrm_contract src/osrm/contractor.cpp $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>)
|
||||
add_library(osrm_extract src/osrm/extractor.cpp $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:MICROTAR> $<TARGET_OBJECTS:UTIL>)
|
||||
add_library(osrm_guidance $<TARGET_OBJECTS:GUIDANCE> $<TARGET_OBJECTS:UTIL>)
|
||||
@@ -416,11 +416,30 @@ if(UNIX AND NOT APPLE)
|
||||
set(MAYBE_RT_LIBRARY -lrt)
|
||||
endif()
|
||||
|
||||
# Disallow deprecated protozero APIs
|
||||
add_definitions(-DPROTOZERO_STRICT_API)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# Third-party libraries
|
||||
set(RAPIDJSON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/rapidjson/include")
|
||||
include_directories(SYSTEM ${RAPIDJSON_INCLUDE_DIR})
|
||||
|
||||
set(MICROTAR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src")
|
||||
include_directories(SYSTEM ${MICROTAR_INCLUDE_DIR})
|
||||
|
||||
set(MBXGEOM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/geometry.hpp-0.9.2/include")
|
||||
include_directories(SYSTEM ${MBXGEOM_INCLUDE_DIR})
|
||||
set(CHEAPRULER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/cheap-ruler-cpp-2.5.4/include")
|
||||
include_directories(SYSTEM ${CHEAPRULER_INCLUDE_DIR})
|
||||
|
||||
add_library(MICROTAR OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src/microtar.c")
|
||||
set_property(TARGET MICROTAR PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(PROTOZERO_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/protozero/include")
|
||||
include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR})
|
||||
|
||||
set(VTZERO_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/vtzero/include")
|
||||
include_directories(SYSTEM ${VTZERO_INCLUDE_DIR})
|
||||
|
||||
|
||||
# if mason is enabled no find_package calls are made
|
||||
# to ensure that we are only compiling and linking against
|
||||
# fully portable mason packages
|
||||
@@ -554,14 +573,6 @@ else()
|
||||
include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
set(RAPIDJSON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/rapidjson/include")
|
||||
include_directories(SYSTEM ${RAPIDJSON_INCLUDE_DIR})
|
||||
|
||||
set(MICROTAR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src")
|
||||
include_directories(SYSTEM ${MICROTAR_INCLUDE_DIR})
|
||||
add_library(MICROTAR OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src/microtar.c")
|
||||
set_property(TARGET MICROTAR PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# prefix compilation with ccache by default if available and on clang or gcc
|
||||
if(ENABLE_CCACHE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU"))
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
@@ -862,4 +873,4 @@ if (ENABLE_NODE_BINDINGS)
|
||||
endforeach()
|
||||
add_library(check-headers STATIC EXCLUDE_FROM_ALL ${sources})
|
||||
set_target_properties(check-headers PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${check_headers_dir})
|
||||
endif()
|
||||
endif()
|
||||
@@ -9,7 +9,7 @@ High performance routing engine written in C++14 designed to run on OpenStreetMa
|
||||
The following services are available via HTTP API, C++ library interface and NodeJs wrapper:
|
||||
- Nearest - Snaps coordinates to the street network and returns the nearest matches
|
||||
- Route - Finds the fastest route between coordinates
|
||||
- Table - Computes the duration of the fastest route between all pairs of supplied coordinates
|
||||
- Table - Computes the duration or distances of the fastest route between all pairs of supplied coordinates
|
||||
- Match - Snaps noisy GPS traces to the road network in the most plausible way
|
||||
- Trip - Solves the Traveling Salesman Problem using a greedy heuristic
|
||||
- Tile - Generates Mapbox Vector Tiles with internal routing metadata
|
||||
@@ -50,7 +50,7 @@ If you want to use the CH pipeline instead replace `osrm-partition` and `osrm-cu
|
||||
|
||||
### Using Docker
|
||||
|
||||
We base our Docker images ([backend](https://hub.docker.com/r/osrm/osrm-backend/), [frontend](https://hub.docker.com/r/osrm/osrm-frontend/)) on Alpine Linux and make sure they are as lightweight as possible.
|
||||
We base our Docker images ([backend](https://hub.docker.com/r/osrm/osrm-backend/), [frontend](https://hub.docker.com/r/osrm/osrm-frontend/)) on Debian and make sure they are as lightweight as possible.
|
||||
|
||||
Download OpenStreetMap extracts for example from [Geofabrik](http://download.geofabrik.de/)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY "FALSE")
|
||||
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md")
|
||||
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Open Source Routing Machine (OSRM) is a high-performance routing engine. It combines sophisticated routing algorithms with the open and free data of the OpenStreetMap.")
|
||||
SET(CPACK_PACKAGE_CONTACT "Project OSRM <info@project-osrm.org>")
|
||||
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENCE.TXT")
|
||||
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE.TXT")
|
||||
|
||||
SET(CPACK_STRIP_FILES "TRUE")
|
||||
file(GLOB_RECURSE ProfileGlob ${CMAKE_SOURCE_DIR}/profiles/*)
|
||||
|
||||
+1
-1
@@ -3,5 +3,5 @@ module.exports = {
|
||||
verify: '--strict --tags ~@stress --tags ~@todo --tags ~@mld-only -f progress --require features/support --require features/step_definitions',
|
||||
todo: '--strict --tags @todo --require features/support --require features/step_definitions',
|
||||
all: '--strict --require features/support --require features/step_definitions',
|
||||
mld: '--strict --tags ~@stress --tags ~@todo --require features/support --require features/step_definitions -f progress'
|
||||
mld: '--strict --tags ~@stress --tags ~@todo --tags ~@ch --require features/support --require features/step_definitions -f progress'
|
||||
};
|
||||
|
||||
+19
-15
@@ -1,16 +1,14 @@
|
||||
FROM alpine:3.6 as buildstage
|
||||
|
||||
FROM debian:stretch-slim as builder
|
||||
ARG DOCKER_TAG
|
||||
ARG BUILD_CONCURRENCY
|
||||
RUN mkdir -p /src && mkdir -p /opt
|
||||
COPY . /src
|
||||
WORKDIR /src
|
||||
|
||||
RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
||||
echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||
apk update && \
|
||||
apk upgrade && \
|
||||
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 && \
|
||||
NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
||||
RUN NPROC=${BUILD_CONCURRENCY:-$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1)} && \
|
||||
apt-get update && \
|
||||
apt-get -y --no-install-recommends install cmake make git gcc g++ libbz2-dev libxml2-dev \
|
||||
libzip-dev libboost1.62-all-dev lua5.2 liblua5.2-dev libtbb-dev -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 && \
|
||||
echo "Building OSRM ${DOCKER_TAG}" && \
|
||||
git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \
|
||||
echo "Building OSRM gitsha $(cat /opt/OSRM_GITSHA)" && \
|
||||
@@ -26,20 +24,26 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
|
||||
make -j${NPROC} install && \
|
||||
cd ../profiles && \
|
||||
cp -r * /opt && \
|
||||
\
|
||||
strip /usr/local/bin/* && \
|
||||
rm -rf /src /usr/local/lib/libosrm*
|
||||
|
||||
|
||||
# Multistage build to reduce image size - https://docs.docker.com/engine/userguide/eng-image/multistage-build/#use-multi-stage-builds
|
||||
# Only the content below ends up in the image, this helps remove /src from the image (which is large)
|
||||
FROM alpine:3.6 as runstage
|
||||
FROM debian:stretch-slim as runstage
|
||||
RUN mkdir -p /src && mkdir -p /opt
|
||||
RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||
apk update && \
|
||||
apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.2 expat libtbb@testing
|
||||
COPY --from=buildstage /usr/local /usr/local
|
||||
COPY --from=buildstage /opt /opt
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends libboost-program-options1.62.0 libboost-regex1.62.0 \
|
||||
libboost-date-time1.62.0 libboost-chrono1.62.0 libboost-filesystem1.62.0 \
|
||||
libboost-iostreams1.62.0 libboost-thread1.62.0 expat liblua5.2-0 libtbb2 &&\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=builder /usr/local /usr/local
|
||||
COPY --from=builder /opt /opt
|
||||
RUN /usr/local/bin/osrm-extract --help && \
|
||||
/usr/local/bin/osrm-routed --help && \
|
||||
/usr/local/bin/osrm-contract --help && \
|
||||
/usr/local/bin/osrm-partition --help && \
|
||||
/usr/local/bin/osrm-customize --help
|
||||
WORKDIR /opt
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@
|
||||
# ensure that "COPY . /src" is referring to the repo root, not the directory
|
||||
# that contains the Dockerfile.
|
||||
# This script gets executed with a pwd of wherever the Dockerfile is.
|
||||
docker build --build-arg DOCKER_TAG=${DOCKER_TAG} -t $IMAGE_NAME -f Dockerfile ..
|
||||
docker build --build-arg BUILD_CONCURRENCY=${CONCURRENCY:-1} --build-arg DOCKER_TAG=${DOCKER_TAG} -t $IMAGE_NAME -f Dockerfile ..
|
||||
|
||||
+135
-10
@@ -70,6 +70,8 @@ curl 'http://router.project-osrm.org/route/v1/driving/polyline(ofp_Ik_vpAilAyu@t
|
||||
|
||||
### Responses
|
||||
|
||||
#### Code
|
||||
|
||||
Every response object has a `code` property containing one of the strings below or a service dependent code:
|
||||
|
||||
| Type | Description |
|
||||
@@ -87,12 +89,17 @@ Every response object has a `code` property containing one of the strings below
|
||||
- `message` is a **optional** human-readable error message. All other status types are service dependent.
|
||||
- In case of an error the HTTP status code will be `400`. Otherwise the HTTP status code will be `200` and `code` will be `Ok`.
|
||||
|
||||
#### Data version
|
||||
|
||||
Every response object has a `data_version` propetry containing timestamp from the original OpenStreetMap file. This field is optional. It can be ommited if data_version parametr was not set on osrm-extract stage or OSM file has not `osmosis_replication_timestamp` section.
|
||||
|
||||
#### Example response
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "Ok",
|
||||
"message": "Everything worked"
|
||||
"message": "Everything worked",
|
||||
"data_version": "2017-11-17T21:43:02Z"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -119,7 +126,6 @@ In addition to the [general options](#general-options) the following options are
|
||||
|
||||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
||||
- `waypoints` array of `Waypoint` objects sorted by distance to the input coordinate. Each object has at least the following additional properties:
|
||||
- `distance`: Distance in meters to the supplied input coordinate.
|
||||
- `nodes`: Array of OpenStreetMap node ids.
|
||||
|
||||
#### Example Requests
|
||||
@@ -196,6 +202,7 @@ In addition to the [general options](#general-options) the following options are
|
||||
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|
||||
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
|
||||
|continue\_straight |`default` (default), `true`, `false` |Forces the route to keep going straight at waypoints constraining uturns there even if it would be faster. Default value depends on the profile. |
|
||||
|waypoints | `{index};{index};{index}...` |Treats input coordinates indicated by given indices as waypoints in returned Match object. Default is to treat all input coordinates as waypoints. |
|
||||
|
||||
\* Please note that even if alternative routes are requested, a result cannot be guaranteed.
|
||||
|
||||
@@ -222,13 +229,13 @@ curl 'http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397
|
||||
|
||||
### Table service
|
||||
|
||||
Computes the duration of the fastest route between all pairs of supplied coordinates.
|
||||
Computes the duration of the fastest route between all pairs of supplied coordinates. Returns the durations or distances or both between the coordinate pairs. Note that the distances are not the shortest distance between two coordinates, but rather the distances of the fastest routes. Duration is in seconds and distances is in meters.
|
||||
|
||||
```endpoint
|
||||
GET /table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&destinations=[{elem}...]
|
||||
GET /table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&{destinations}=[{elem}...]&annotations={duration|distance|duration,distance}
|
||||
```
|
||||
|
||||
**Coordinates**
|
||||
**Options**
|
||||
|
||||
In addition to the [general options](#general-options) the following options are supported for this service:
|
||||
|
||||
@@ -236,6 +243,10 @@ In addition to the [general options](#general-options) the following options are
|
||||
|------------|--------------------------------------------------|---------------------------------------------|
|
||||
|sources |`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as source. |
|
||||
|destinations|`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as destination.|
|
||||
|annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. |
|
||||
|fallback_speed|`double > 0`| If no route found between a source/destination pair, calculate the as-the-crow-flies distance, then use this speed to estimate duration.|
|
||||
|fallback_coordinate|`input` (default), or `snapped`| When using a `fallback_speed`, use the user-supplied coordinate (`input`), or the snapped location (`snapped`) for calculating distances.|
|
||||
|scale_factor|`double > 0`| Use in conjunction with `annotations=durations`. Scales the table `duration` values by this number.|
|
||||
|
||||
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
|
||||
to number of input locations;
|
||||
@@ -253,14 +264,23 @@ sources=0;5;7&destinations=5;1;4;2;3;6
|
||||
#### Example Request
|
||||
|
||||
```curl
|
||||
# Returns a 3x3 matrix:
|
||||
# Returns a 3x3 duration matrix:
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219'
|
||||
|
||||
# Returns a 1x3 matrix
|
||||
# Returns a 1x3 duration matrix
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?sources=0'
|
||||
|
||||
# Returns a asymmetric 3x2 matrix with from the polyline encoded locations `qikdcB}~dpXkkHz`:
|
||||
# Returns a asymmetric 3x2 duration matrix with from the polyline encoded locations `qikdcB}~dpXkkHz`:
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHulFzeMe`EuvKpnCglA)?sources=0;1;3&destinations=2;4'
|
||||
|
||||
# Returns a 3x3 duration matrix:
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?annotations=duration'
|
||||
|
||||
# Returns a 3x3 distance matrix for CH:
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?annotations=distance'
|
||||
|
||||
# Returns a 3x3 duration matrix and a 3x3 distance matrix for CH:
|
||||
curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397634,52.529407;13.428555,52.523219?annotations=distance,duration'
|
||||
```
|
||||
|
||||
**Response**
|
||||
@@ -268,17 +288,120 @@ curl 'http://router.project-osrm.org/table/v1/driving/polyline(egs_Iq_aqAppHzbHu
|
||||
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
|
||||
- `durations` array of arrays that stores the matrix in row-major order. `durations[i][j]` gives the travel time from
|
||||
the i-th waypoint to the j-th waypoint. Values are given in seconds. Can be `null` if no route between `i` and `j` can be found.
|
||||
- `distances` array of arrays that stores the matrix in row-major order. `distances[i][j]` gives the travel distance from
|
||||
the i-th waypoint to the j-th waypoint. Values are given in meters. Can be `null` if no route between `i` and `j` can be found. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned.
|
||||
- `sources` array of `Waypoint` objects describing all sources in order
|
||||
- `destinations` array of `Waypoint` objects describing all destinations in order
|
||||
- `fallback_speed_cells` (optional) array of arrays containing `i,j` pairs indicating which cells contain estimated values based on `fallback_speed`. Will be absent if `fallback_speed` is not used.
|
||||
|
||||
In case of error the following `code`s are supported in addition to the general ones:
|
||||
|
||||
| Type | Description |
|
||||
|-------------------|-----------------|
|
||||
| Type | Description |
|
||||
|------------------|-----------------|
|
||||
| `NoTable` | No route found. |
|
||||
| `NotImplemented` | This request is not supported |
|
||||
|
||||
All other properties might be undefined.
|
||||
|
||||
#### Example Response
|
||||
|
||||
```json
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"location": [
|
||||
13.3888,
|
||||
52.517033
|
||||
],
|
||||
"hint": "PAMAgEVJAoAUAAAAIAAAAAcAAAAAAAAArss0Qa7LNEHiVIRA4lSEQAoAAAAQAAAABAAAAAAAAADMAAAAAEzMAKlYIQM8TMwArVghAwEA3wps52D3",
|
||||
"name": "Friedrichstraße"
|
||||
},
|
||||
{
|
||||
"location": [
|
||||
13.397631,
|
||||
52.529432
|
||||
],
|
||||
"hint": "WIQBgL6mAoAEAAAABgAAAAAAAAA7AAAAhU6PQHvHj0IAAAAAQbyYQgQAAAAGAAAAAAAAADsAAADMAAAAf27MABiJIQOCbswA_4ghAwAAXwVs52D3",
|
||||
"name": "Torstraße"
|
||||
},
|
||||
{
|
||||
"location": [
|
||||
13.428554,
|
||||
52.523239
|
||||
],
|
||||
"hint": "7UcAgP___38fAAAAUQAAACYAAABTAAAAhSQKQrXq5kKRbiZCWJo_Qx8AAABRAAAAJgAAAFMAAADMAAAASufMAOdwIQNL58wA03AhAwMAvxBs52D3",
|
||||
"name": "Platz der Vereinten Nationen"
|
||||
}
|
||||
],
|
||||
"durations": [
|
||||
[
|
||||
0,
|
||||
192.6,
|
||||
382.8
|
||||
],
|
||||
[
|
||||
199,
|
||||
0,
|
||||
283.9
|
||||
],
|
||||
[
|
||||
344.7,
|
||||
222.3,
|
||||
0
|
||||
]
|
||||
],
|
||||
"destinations": [
|
||||
{
|
||||
"location": [
|
||||
13.3888,
|
||||
52.517033
|
||||
],
|
||||
"hint": "PAMAgEVJAoAUAAAAIAAAAAcAAAAAAAAArss0Qa7LNEHiVIRA4lSEQAoAAAAQAAAABAAAAAAAAADMAAAAAEzMAKlYIQM8TMwArVghAwEA3wps52D3",
|
||||
"name": "Friedrichstraße"
|
||||
},
|
||||
{
|
||||
"location": [
|
||||
13.397631,
|
||||
52.529432
|
||||
],
|
||||
"hint": "WIQBgL6mAoAEAAAABgAAAAAAAAA7AAAAhU6PQHvHj0IAAAAAQbyYQgQAAAAGAAAAAAAAADsAAADMAAAAf27MABiJIQOCbswA_4ghAwAAXwVs52D3",
|
||||
"name": "Torstraße"
|
||||
},
|
||||
{
|
||||
"location": [
|
||||
13.428554,
|
||||
52.523239
|
||||
],
|
||||
"hint": "7UcAgP___38fAAAAUQAAACYAAABTAAAAhSQKQrXq5kKRbiZCWJo_Qx8AAABRAAAAJgAAAFMAAADMAAAASufMAOdwIQNL58wA03AhAwMAvxBs52D3",
|
||||
"name": "Platz der Vereinten Nationen"
|
||||
}
|
||||
],
|
||||
"code": "Ok",
|
||||
"distances": [
|
||||
[
|
||||
0,
|
||||
1886.89,
|
||||
3791.3
|
||||
],
|
||||
[
|
||||
1824,
|
||||
0,
|
||||
2838.09
|
||||
],
|
||||
[
|
||||
3275.36,
|
||||
2361.73,
|
||||
0
|
||||
]
|
||||
],
|
||||
"fallback_speed_cells": [
|
||||
[ 0, 1 ],
|
||||
[ 1, 0 ]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Match service
|
||||
|
||||
Map matching matches/snaps given GPS points to the road network in the most plausible way.
|
||||
@@ -442,6 +565,7 @@ Vector tiles contain two layers:
|
||||
| `weight ` | `integer` | how long this segment takes to traverse, in units (may differ from `duration` when artificial biasing is applied in the Lua profiles). ACTUAL ROUTING USES THIS VALUE. |
|
||||
| `name` | `string` | the name of the road this segment belongs to |
|
||||
| `rate` | `float` | the value of `length/weight` - analagous to `speed`, but using the `weight` value rather than `duration`, rounded to the nearest integer |
|
||||
| `is_startpoint` | `boolean` | whether this segment can be used as a start/endpoint for routes |
|
||||
|
||||
`turns` layer:
|
||||
|
||||
@@ -796,6 +920,7 @@ Object used to describe waypoint on a route.
|
||||
|
||||
- `name` Name of the street the coordinate snapped to
|
||||
- `location` Array that contains the `[longitude, latitude]` pair of the snapped coordinate
|
||||
- `distance` The distance, in metres, from the input coordinate to the snapped coordinate
|
||||
- `hint` Unique internal identifier of the segment (ephemeral, not constant over data updates)
|
||||
This can be used on subsequent request to significantly speed up the query and to connect multiple services.
|
||||
E.g. you can use the `hint` value obtained by the `nearest` query as `hint` values for `route` inputs.
|
||||
|
||||
+50
-21
@@ -25,7 +25,9 @@ var osrm = new OSRM('network.osrm');
|
||||
Make sure you prepared the dataset with the correct toolchain.
|
||||
- `options.shared_memory` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Connects to the persistent shared memory datastore.
|
||||
This requires you to run `osrm-datastore` prior to creating an `OSRM` object.
|
||||
- `options.memory_file` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Path to a file on disk to store the memory using mmap.
|
||||
- `options.memory_file` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** *DEPRECATED*
|
||||
Old behaviour: Path to a file on disk to store the memory using mmap. Current behaviour: setting this value is the same as setting `mmap_memory: true`.
|
||||
- `options.mmap_memory` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Map on-disk files to virtual memory addresses (mmap), rather than loading into RAM.
|
||||
- `options.path` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true.
|
||||
- `options.max_locations_trip` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in trip query (default: unlimited).
|
||||
- `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query (default: unlimited).
|
||||
@@ -55,8 +57,9 @@ Returns the fastest route between two or more coordinates while visiting the way
|
||||
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`)
|
||||
- `options.continue_straight` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile.
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `options.waypoints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index.
|
||||
`null`/`true`/`false`
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -88,7 +91,7 @@ Note: `coordinates` in the general options only supports a single `{longitude},{
|
||||
- `options.number` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Number of nearest segments that should be returned.
|
||||
Must be an integer greater than or equal to `1`. (optional, default `1`)
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -110,8 +113,8 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
|
||||
|
||||
### table
|
||||
|
||||
Computes duration tables for the given locations. Allows for both symmetric and asymmetric
|
||||
tables.
|
||||
Computes duration table for the given locations. Allows for both symmetric and asymmetric
|
||||
tables. Optionally returns distance table.
|
||||
|
||||
**Parameters**
|
||||
|
||||
@@ -127,7 +130,10 @@ tables.
|
||||
- `options.destinations` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer <
|
||||
#coordinates`) to use location with given index as destination. Default is to use all.
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `options.fallback_speed` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second.
|
||||
- `options.fallback_coordinate` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies diestance between two points.
|
||||
- `options.scale_factor` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Multiply the table duration values in the table by this number for more controlled input into a route optimization solver.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -152,6 +158,7 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
|
||||
Values are given in seconds.
|
||||
**`sources`**: array of [`Ẁaypoint`](#waypoint) objects describing all sources in order.
|
||||
**`destinations`**: array of [`Ẁaypoint`](#waypoint) objects describing all destinations in order.
|
||||
**`fallback_speed_cells`**: (optional) if `fallback_speed` is used, will be an array of arrays of `row,column` values, indicating which cells contain estimated values.
|
||||
|
||||
### tile
|
||||
|
||||
@@ -167,7 +174,7 @@ and what weights they have applied.
|
||||
- `ZXY` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** an array consisting of `x`, `y`, and `z` values representing tile coordinates like
|
||||
[wiki.openstreetmap.org/wiki/Slippy_map_tilenames](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames)
|
||||
and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -204,7 +211,8 @@ if they can not be matched successfully.
|
||||
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`.
|
||||
- `options.gaps` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore` (optional, default `split`).
|
||||
- `options.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`).
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `options.waypoints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -268,7 +276,7 @@ Right now, the following combinations are possible:
|
||||
- `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route starts at `any` or `first` coordinate. (optional, default `any`)
|
||||
- `options.destination` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route ends at `any` or `last` coordinate. (optional, default `any`)
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -297,9 +305,30 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
|
||||
2) `waypoint_index`: index of the point in the trip.
|
||||
**`trips`**: an array of [`Route`](#route) objects that assemble the trace.
|
||||
|
||||
## Responses
|
||||
## Plugin behaviour
|
||||
|
||||
Responses
|
||||
All plugins support a second additional object that is available to configure some NodeJS specific behaviours.
|
||||
|
||||
- `plugin_config` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query.
|
||||
- `plugin_config.format` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The format of the result object to various API calls. Valid options are `object` (default), which returns a standard Javascript object, as described above, and `json_buffer`, which will return a NodeJS **[Buffer](https://nodejs.org/api/buffer.html)** object, containing a JSON string. The latter has the advantage that it can be immediately serialized to disk/sent over the network, and the generation of the string is performed outside the main NodeJS event loop. This option is ignored by the `tile` plugin.
|
||||
|
||||
**Examples**
|
||||
|
||||
```javascript
|
||||
var osrm = new OSRM('network.osrm');
|
||||
var options = {
|
||||
coordinates: [
|
||||
[13.36761474609375, 52.51663871100423],
|
||||
[13.374481201171875, 52.506191342034576]
|
||||
]
|
||||
};
|
||||
osrm.route(options, { format: "json_buffer" }, function(err, response) {
|
||||
if (err) throw err;
|
||||
console.log(response.toString("utf-8"));
|
||||
});
|
||||
```
|
||||
|
||||
## Responses
|
||||
|
||||
### Route
|
||||
|
||||
@@ -307,8 +336,8 @@ Represents a route through (potentially multiple) waypoints.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](../http.md#route)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#route-object)
|
||||
|
||||
### RouteLeg
|
||||
|
||||
@@ -316,8 +345,8 @@ Represents a route between two waypoints.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](../http.md#routeleg)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#routeleg-object)
|
||||
|
||||
### RouteStep
|
||||
|
||||
@@ -326,15 +355,15 @@ single way to the subsequent step.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#routestep)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#routestep-object)
|
||||
|
||||
### StepManeuver
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#stepmaneuver)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#stepmaneuver-object)
|
||||
|
||||
### Waypoint
|
||||
|
||||
@@ -342,5 +371,5 @@ Object used to describe waypoint on a route.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#waypoint)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#waypoint-object)
|
||||
|
||||
+5
-5
@@ -68,7 +68,7 @@ If you want to prioritize certain streets, increase the rate on these.
|
||||
|
||||
## Elements
|
||||
### api_version
|
||||
A profile should set `api_version` at the top of your profile. This is done to ensure that older profiles are still supported when the api changes. If `api_version` is not defined, 0 will be assumed. The current api version is 2.
|
||||
A profile should set `api_version` at the top of your profile. This is done to ensure that older profiles are still supported when the api changes. If `api_version` is not defined, 0 will be assumed. The current api version is 4.
|
||||
|
||||
### Library files
|
||||
The folder [profiles/lib/](../profiles/lib/) contains LUA library files for handling many common processing tasks.
|
||||
@@ -138,7 +138,7 @@ Given an OpenStreetMap way, the `process_way` function will either return nothin
|
||||
Argument | Description
|
||||
---------|-------------------------------------------------------
|
||||
profile | The configuration table you returned in `setup`.
|
||||
node | The input way to process (read-only).
|
||||
way | The input way to process (read-only).
|
||||
result | The output that you will modify.
|
||||
relations| Storage of relations to access relations, where `way` is a member.
|
||||
|
||||
@@ -199,7 +199,7 @@ source.lon | Read | Float | Co-ordinates of segment start
|
||||
source.lat | Read | Float | ""
|
||||
target.lon | Read | Float | Co-ordinates of segment end
|
||||
target.lat | Read | Float | ""
|
||||
target.distance | Read | Float | Length of segment
|
||||
distance | Read | Float | Length of segment
|
||||
weight | Read/write | Float | Routing weight for this segment
|
||||
duration | Read/write | Float | Duration for this segment
|
||||
|
||||
@@ -224,8 +224,8 @@ source_highway_turn_classification | Read | Integer |
|
||||
source_access_turn_classification | Read | Integer | Classification based on access tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15))
|
||||
source_speed | Read | Integer | Speed on this source road in km/h
|
||||
source_priority_class | Read | Enum | The type of road priority class of the source. Defined in `include/extractor/guidance/road_classification.hpp`
|
||||
target_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
||||
target_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||
target_restricted | Read | Boolean | Is the target a restricted access road? (See definition in `process_way`)
|
||||
target_mode | Read | Enum | Travel mode after the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||
target_is_motorway | Read | Boolean | Is the target road a motorway?
|
||||
target_is_link | Read | Boolean | Is the target road a link?
|
||||
target_number_of_lanes | Read | Integer | How many lanes does the target road have? (default when not tagged: 0)
|
||||
|
||||
+3
-3
@@ -43,9 +43,9 @@ We may introduce forward-compatible changes: query parameters and response prope
|
||||
|
||||
1. Check out the appropriate release branch `x.y`
|
||||
2. Make sure `CHANGELOG.md` is up to date.
|
||||
3. Make sure the `package.json` is up to date.
|
||||
4. Make sure all tests are passing (e.g. Travis CI gives you a :thumbs_up:)
|
||||
5. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries.
|
||||
3. Make sure the `package.json` on branch `x.y` has been committed.
|
||||
4. Make sure all tests are passing (e.g. Travis CI gives you a :green_apple:)
|
||||
5. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries. Commit should be one in which the `package.json` version matches the version you want to release.
|
||||
6. Use `npm run docs` to generate the API documentation. Copy `build/docs/*` to `https://github.com/Project-OSRM/project-osrm.github.com` in the `docs/vN.N.N/api` directory
|
||||
7. Push tags and commits: `git push; git push --tags`
|
||||
8. On https://github.com/Project-OSRM/osrm-backend/releases press `Draft a new release`,
|
||||
|
||||
@@ -19,7 +19,7 @@ Feature: Barriers
|
||||
| entrance | x |
|
||||
| wall | |
|
||||
| fence | |
|
||||
| some_tag | |
|
||||
| some_tag | x |
|
||||
| block | x |
|
||||
|
||||
Scenario: Bike - Access tag trumphs barriers
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
@routing @bicycle @mode
|
||||
Feature: Bicycle - Mode flag
|
||||
Background:
|
||||
Given the profile "bicycle"
|
||||
|
||||
Scenario: Bicycle - We tag ferries with a class
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | route |
|
||||
| ab | primary | |
|
||||
| bc | | ferry |
|
||||
| cd | primary | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | turns | classes |
|
||||
| a | d | ab,bc,cd,cd | depart,notification right,notification left,arrive | [()],[(ferry)],[()],[()] |
|
||||
| d | a | cd,bc,ab,ab | depart,notification right,notification left,arrive | [()],[(ferry)],[()],[()] |
|
||||
| c | a | bc,ab,ab | depart,notification left,arrive | [(ferry)],[()],[()] |
|
||||
| d | b | cd,bc,bc | depart,notification right,arrive | [()],[(ferry)],[()] |
|
||||
| a | c | ab,bc,bc | depart,notification right,arrive | [()],[(ferry)],[()] |
|
||||
| b | d | bc,cd,cd | depart,notification left,arrive | [(ferry)],[()],[()] |
|
||||
|
||||
Scenario: Bicycle - We tag tunnel with a class
|
||||
Background:
|
||||
Given a grid size of 200 meters
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | tunnel |
|
||||
| ab | no |
|
||||
| bc | yes |
|
||||
| cd | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | turns | classes |
|
||||
| a | d | ab,bc,cd,cd | depart,new name right,new name left,arrive | [()],[(tunnel)],[()],[()] |
|
||||
|
||||
Scenario: Bicycle - We tag classes without intersections
|
||||
Background:
|
||||
Given a grid size of 200 meters
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | name | tunnel |
|
||||
| ab | road | |
|
||||
| bc | road | yes |
|
||||
| cd | road | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | turns | classes |
|
||||
| a | d | road,road | depart,arrive | [(),(tunnel),()],[()] |
|
||||
|
||||
Scenario: Bicycle - From roundabout on ferry
|
||||
Given the node map
|
||||
"""
|
||||
c
|
||||
/ \
|
||||
a---b d---f--h
|
||||
\ /
|
||||
e
|
||||
|
|
||||
g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway | highway | junction | route |
|
||||
| ab | yes | service | | |
|
||||
| cb | yes | service | roundabout | |
|
||||
| dc | yes | service | roundabout | |
|
||||
| be | yes | service | roundabout | |
|
||||
| ed | yes | service | roundabout | |
|
||||
| eg | yes | service | | |
|
||||
| df | | | | ferry |
|
||||
| fh | yes | service | | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | turns | classes |
|
||||
| a | h | ab,df,df,fh,fh | depart,roundabout-exit-2,exit roundabout slight right,notification straight,arrive | [()],[(),()],[(ferry)],[()],[()] |
|
||||
@@ -0,0 +1,55 @@
|
||||
@routing @bicycle @exclude
|
||||
Feature: Bicycle - Exclude flags
|
||||
Background:
|
||||
Given the profile file "bicycle" initialized with
|
||||
"""
|
||||
profile.excludable = Sequence { Set { 'ferry' } }
|
||||
"""
|
||||
Given the node map
|
||||
"""
|
||||
a....b~~~~~c...f
|
||||
: :
|
||||
d.....e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | route | duration | # |
|
||||
| ab | service | | | always drivable |
|
||||
| bc | | ferry | 00:00:01 | not drivable for exclude=ferry, but fast. |
|
||||
| bd | service | | | always drivable |
|
||||
| de | service | | | always drivable |
|
||||
| ec | service | | | always drivable |
|
||||
| cf | service | | | always drivable |
|
||||
|
||||
Scenario: Bicycle - exclude nothing
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | f | ab,bc,cf,cf |
|
||||
|
||||
When I match I should get
|
||||
| trace | matchings | duration |
|
||||
| abcf | abcf | 109 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | f |
|
||||
| a | 0 | 109 |
|
||||
| f | 109 | 0 |
|
||||
|
||||
Scenario: Bicycle - exclude ferry
|
||||
Given the query options
|
||||
| exclude | ferry |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | f | ab,bd,de,ec,cf,cf |
|
||||
|
||||
When I match I should get
|
||||
| trace | matchings | duration |
|
||||
| abcf | abcf | 301.2 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | f |
|
||||
| a | 0 | 301 +- 1 |
|
||||
| f | 301.2 +- 1 | 0 |
|
||||
|
||||
|
||||
@@ -109,3 +109,12 @@ Feature: Car - Handle ferry routes
|
||||
When I route I should get
|
||||
| from | to | route | modes | time |
|
||||
| c | d | bcde,bcde | ferry,ferry | 600s |
|
||||
|
||||
Given the query options
|
||||
| geometries | geojson |
|
||||
| overview | full |
|
||||
|
||||
# Note that matching *should* work across unsnappable ferries
|
||||
When I match I should get
|
||||
| trace | geometry | duration |
|
||||
| abcdef| 1,1,1.000899,1,1.000899,1,1.002697,1,1.002697,1,1.003596,1,1.003596,1,1.005394,1,1.005394,1,1.006293,1 | 610.9 |
|
||||
|
||||
@@ -137,3 +137,28 @@ OSRM will use 4/5 of the projected free-flow speed.
|
||||
| primary | | | 30 | -1 | | 23 km/h | | 6.7 |
|
||||
| primary | 20 | 30 | | -1 | | 15 km/h | | 4.4 |
|
||||
| primary | 20 | | 30 | -1 | | 23 km/h | | 6.7 |
|
||||
|
||||
|
||||
Scenario: Car - Respect source:maxspeed
|
||||
Given the node map
|
||||
"""
|
||||
a b c d e f g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | source:maxspeed | maxspeed |
|
||||
| ab | trunk | | |
|
||||
| bc | trunk | | 60 |
|
||||
| cd | trunk | FR:urban | |
|
||||
| de | trunk | CH:rural | |
|
||||
| ef | trunk | CH:trunk | |
|
||||
| fg | trunk | CH:motorway | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | speed |
|
||||
| a | b | ab,ab | 85 km/h |
|
||||
| b | c | bc,bc | 48 km/h |
|
||||
| c | d | cd,cd | 40 km/h |
|
||||
| d | e | de,de | 64 km/h |
|
||||
| e | f | ef,ef | 80 km/h |
|
||||
| f | g | fg,fg | 96 km/h |
|
||||
@@ -48,3 +48,22 @@ Feature: Car - Handle physical limitation
|
||||
| primary | | none | x |
|
||||
| primary | | no-sign | x |
|
||||
| primary | | unsigned | x |
|
||||
|
||||
Scenario: Car - Limited by length
|
||||
Then routability should be
|
||||
| highway | maxlength | bothw |
|
||||
| primary | | x |
|
||||
| primary | 1 | |
|
||||
| primary | 5 | x |
|
||||
| primary | unsigned | x |
|
||||
|
||||
Scenario: Car - Limited by weight
|
||||
Then routability should be
|
||||
| highway | maxweight | bothw |
|
||||
| primary | | x |
|
||||
| primary | 1 | |
|
||||
| primary | 3.5 | x |
|
||||
| primary | 35000 kg | x |
|
||||
| primary | 8.9t | x |
|
||||
| primary | 0.1 lbs | |
|
||||
| primary | unsigned | x |
|
||||
|
||||
@@ -35,3 +35,28 @@ Feature: Car - Allowed start/end modes
|
||||
| from | to | route | modes |
|
||||
| 1 | 2 | ab,ab | driving,driving |
|
||||
| 2 | 1 | ab,ab | driving,driving |
|
||||
|
||||
Scenario: Car - URL override of non-startpoints
|
||||
Given the node map
|
||||
"""
|
||||
a 1 b c 2 d
|
||||
"""
|
||||
|
||||
Given the query options
|
||||
| snapping | any |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | access |
|
||||
| ab | service | private |
|
||||
| bc | primary | |
|
||||
| cd | service | private |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | 2 | c |
|
||||
| 1 | 59.1 | 35.1 |
|
||||
| b | 35.1 | 11.1 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| 1 | 2 | ab,bc,cd |
|
||||
| 2 | 1 | cd,bc,ab |
|
||||
|
||||
@@ -19,7 +19,7 @@ Feature: Barriers
|
||||
| entrance | x |
|
||||
| wall | |
|
||||
| fence | |
|
||||
| some_tag | |
|
||||
| some_tag | x |
|
||||
| block | x |
|
||||
|
||||
Scenario: Foot - Access tag trumphs barriers
|
||||
|
||||
@@ -1209,3 +1209,33 @@ Feature: Simple Turns
|
||||
| a | c | knob,knob | depart,arrive |
|
||||
| d | e | soph,soph | depart,arrive |
|
||||
| d | a | soph,knob,knob | depart,turn left,arrive |
|
||||
|
||||
|
||||
# https://www.openstreetmap.org/node/30797565
|
||||
Scenario: No turn instruction when turning from unnamed onto unnamed
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
b----------------c
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | ref |
|
||||
| ab | trunk_link | | |
|
||||
| db | secondary | | L 460 |
|
||||
| bc | secondary | | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | turns |
|
||||
| d | c | ,, | depart,turn right,arrive |
|
||||
|
||||
@@ -84,7 +84,47 @@ class OSRMDirectLoader extends OSRMBaseLoader {
|
||||
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd));
|
||||
}
|
||||
});
|
||||
callback();
|
||||
|
||||
this.child.readyFunc = (data) => {
|
||||
if (/running and waiting for requests/.test(data)) {
|
||||
this.child.stdout.removeListener('data', this.child.readyFunc);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
this.child.stdout.on('data',this.child.readyFunc);
|
||||
}
|
||||
};
|
||||
|
||||
class OSRMmmapLoader extends OSRMBaseLoader {
|
||||
constructor (scope) {
|
||||
super(scope);
|
||||
}
|
||||
|
||||
load (inputFile, callback) {
|
||||
this.inputFile = inputFile;
|
||||
this.shutdown(() => {
|
||||
this.launch(callback);
|
||||
});
|
||||
}
|
||||
|
||||
osrmUp (callback) {
|
||||
if (this.osrmIsRunning()) return callback(new Error("osrm-routed already running!"));
|
||||
|
||||
const command_arguments = util.format('%s -p %d -i %s -a %s --mmap', this.inputFile, this.scope.OSRM_PORT, this.scope.OSRM_IP, this.scope.ROUTING_ALGORITHM);
|
||||
this.child = this.scope.runBin('osrm-routed', command_arguments, this.scope.environment, (err) => {
|
||||
if (err && err.signal !== 'SIGINT') {
|
||||
this.child = null;
|
||||
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd));
|
||||
}
|
||||
});
|
||||
|
||||
this.child.readyFunc = (data) => {
|
||||
if (/running and waiting for requests/.test(data)) {
|
||||
this.child.stdout.removeListener('data', this.child.readyFunc);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
this.child.stdout.on('data',this.child.readyFunc);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -135,22 +175,32 @@ class OSRMLoader {
|
||||
this.scope = scope;
|
||||
this.sharedLoader = new OSRMDatastoreLoader(this.scope);
|
||||
this.directLoader = new OSRMDirectLoader(this.scope);
|
||||
this.mmapLoader = new OSRMmmapLoader(this.scope);
|
||||
this.method = scope.DEFAULT_LOAD_METHOD;
|
||||
}
|
||||
|
||||
load (inputFile, callback) {
|
||||
if (!this.loader) {
|
||||
this.loader = {shutdown: (cb) => cb() };
|
||||
}
|
||||
if (this.method === 'datastore') {
|
||||
this.directLoader.shutdown((err) => {
|
||||
this.loader.shutdown((err) => {
|
||||
if (err) return callback(err);
|
||||
this.loader = this.sharedLoader;
|
||||
this.sharedLoader.load(inputFile, callback);
|
||||
});
|
||||
} else if (this.method === 'directly') {
|
||||
this.sharedLoader.shutdown((err) => {
|
||||
this.loader.shutdown((err) => {
|
||||
if (err) return callback(err);
|
||||
this.loader = this.directLoader;
|
||||
this.directLoader.load(inputFile, callback);
|
||||
});
|
||||
} else if (this.method === 'mmap') {
|
||||
this.loader.shutdown((err) => {
|
||||
if (err) return callback(err);
|
||||
this.loader = this.mmapLoader;
|
||||
this.mmapLoader.load(inputFile, callback);
|
||||
});
|
||||
} else {
|
||||
callback(new Error('*** Unknown load method ' + method));
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ module.exports = function () {
|
||||
this.reprocess(callback);
|
||||
});
|
||||
|
||||
this.Given(/^osrm\-routed is stopped$/, (callback) => {
|
||||
this.Given(/^osrm-routed is stopped$/, (callback) => {
|
||||
this.OSRMLoader.shutdown(callback);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,74 +1,106 @@
|
||||
var util = require('util');
|
||||
|
||||
module.exports = function () {
|
||||
this.When(/^I request a travel time matrix I should get$/, (table, callback) => {
|
||||
var NO_ROUTE = 2147483647; // MAX_INT
|
||||
const durationsRegex = new RegExp(/^I request a travel time matrix I should get$/);
|
||||
const distancesRegex = new RegExp(/^I request a travel distance matrix I should get$/);
|
||||
const estimatesRegex = new RegExp(/^I request a travel time matrix I should get estimates for$/);
|
||||
|
||||
var tableRows = table.raw();
|
||||
const DURATIONS_NO_ROUTE = 2147483647; // MAX_INT
|
||||
const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT
|
||||
|
||||
if (tableRows[0][0] !== '') throw new Error('*** Top-left cell of matrix table must be empty');
|
||||
this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', callback);}.bind(this));
|
||||
this.When(distancesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', callback);}.bind(this));
|
||||
this.When(estimatesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'fallback_speed_cells', callback);}.bind(this));
|
||||
};
|
||||
|
||||
var waypoints = [],
|
||||
columnHeaders = tableRows[0].slice(1),
|
||||
rowHeaders = tableRows.map((h) => h[0]).slice(1),
|
||||
symmetric = columnHeaders.length == rowHeaders.length && columnHeaders.every((ele, i) => ele === rowHeaders[i]);
|
||||
const durationsParse = function(v) { return isNaN(parseInt(v)); };
|
||||
const distancesParse = function(v) { return isNaN(parseFloat(v)); };
|
||||
const estimatesParse = function(v) { return isNaN(parseFloat(v)); };
|
||||
|
||||
if (symmetric) {
|
||||
columnHeaders.forEach((nodeName) => {
|
||||
var node = this.findNodeByName(nodeName);
|
||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||
waypoints.push({ coord: node, type: 'loc' });
|
||||
});
|
||||
} else {
|
||||
columnHeaders.forEach((nodeName) => {
|
||||
var node = this.findNodeByName(nodeName);
|
||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||
waypoints.push({ coord: node, type: 'dst' });
|
||||
});
|
||||
rowHeaders.forEach((nodeName) => {
|
||||
var node = this.findNodeByName(nodeName);
|
||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||
waypoints.push({ coord: node, type: 'src' });
|
||||
});
|
||||
}
|
||||
function tableParse(table, noRoute, annotation, callback) {
|
||||
|
||||
var actual = [];
|
||||
actual.push(table.headers);
|
||||
const parse = annotation == 'distances' ? distancesParse : (annotation == 'durations' ? durationsParse : estimatesParse);
|
||||
const params = this.queryParams;
|
||||
params.annotations = ['durations','fallback_speed_cells'].indexOf(annotation) !== -1 ? 'duration' : 'distance';
|
||||
|
||||
this.reprocessAndLoadData((e) => {
|
||||
if (e) return callback(e);
|
||||
// compute matrix
|
||||
var params = this.queryParams;
|
||||
var tableRows = table.raw();
|
||||
|
||||
this.requestTable(waypoints, params, (err, response) => {
|
||||
if (err) return callback(err);
|
||||
if (!response.body.length) return callback(new Error('Invalid response body'));
|
||||
if (tableRows[0][0] !== '') throw new Error('*** Top-left cell of matrix table must be empty');
|
||||
|
||||
var json = JSON.parse(response.body);
|
||||
var waypoints = [],
|
||||
columnHeaders = tableRows[0].slice(1),
|
||||
rowHeaders = tableRows.map((h) => h[0]).slice(1),
|
||||
symmetric = columnHeaders.length == rowHeaders.length && columnHeaders.every((ele, i) => ele === rowHeaders[i]);
|
||||
|
||||
var result = json['durations'].map(row => {
|
||||
if (symmetric) {
|
||||
columnHeaders.forEach((nodeName) => {
|
||||
var node = this.findNodeByName(nodeName);
|
||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||
waypoints.push({ coord: node, type: 'loc' });
|
||||
});
|
||||
} else {
|
||||
columnHeaders.forEach((nodeName) => {
|
||||
var node = this.findNodeByName(nodeName);
|
||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||
waypoints.push({ coord: node, type: 'dst' });
|
||||
});
|
||||
rowHeaders.forEach((nodeName) => {
|
||||
var node = this.findNodeByName(nodeName);
|
||||
if (!node) throw new Error(util.format('*** unknown node "%s"', nodeName));
|
||||
waypoints.push({ coord: node, type: 'src' });
|
||||
});
|
||||
}
|
||||
|
||||
var actual = [];
|
||||
actual.push(table.headers);
|
||||
|
||||
this.reprocessAndLoadData((e) => {
|
||||
if (e) return callback(e);
|
||||
// compute matrix
|
||||
|
||||
this.requestTable(waypoints, params, (err, response) => {
|
||||
if (err) return callback(err);
|
||||
if (!response.body.length) return callback(new Error('Invalid response body'));
|
||||
|
||||
var json = JSON.parse(response.body);
|
||||
|
||||
var result = {};
|
||||
if (annotation === 'fallback_speed_cells') {
|
||||
result = table.raw().map(row => row.map(() => ''));
|
||||
json[annotation].forEach(pair => {
|
||||
result[pair[0]+1][pair[1]+1] = 'Y';
|
||||
});
|
||||
result = result.slice(1).map(row => {
|
||||
var hashes = {};
|
||||
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = isNaN(parseInt(v)) ? '' : v; });
|
||||
row.slice(1).forEach((v,i) => {
|
||||
hashes[tableRows[0][i+1]] = v;
|
||||
});
|
||||
return hashes;
|
||||
});
|
||||
} else {
|
||||
result = json[annotation].map(row => {
|
||||
var hashes = {};
|
||||
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; });
|
||||
return hashes;
|
||||
});
|
||||
}
|
||||
|
||||
var testRow = (row, ri, cb) => {
|
||||
for (var k in result[ri]) {
|
||||
if (this.FuzzyMatch.match(result[ri][k], row[k])) {
|
||||
result[ri][k] = row[k];
|
||||
} else if (row[k] === '' && result[ri][k] === NO_ROUTE) {
|
||||
result[ri][k] = '';
|
||||
} else {
|
||||
result[ri][k] = result[ri][k].toString();
|
||||
}
|
||||
var testRow = (row, ri, cb) => {
|
||||
for (var k in result[ri]) {
|
||||
if (this.FuzzyMatch.match(result[ri][k], row[k])) {
|
||||
result[ri][k] = row[k];
|
||||
} else if (row[k] === '' && result[ri][k] === noRoute) {
|
||||
result[ri][k] = '';
|
||||
} else {
|
||||
result[ri][k] = result[ri][k].toString();
|
||||
}
|
||||
}
|
||||
|
||||
result[ri][''] = row[''];
|
||||
cb(null, result[ri]);
|
||||
};
|
||||
result[ri][''] = row[''];
|
||||
cb(null, result[ri]);
|
||||
};
|
||||
|
||||
this.processRowsAndDiff(table, testRow, callback);
|
||||
});
|
||||
this.processRowsAndDiff(table, testRow, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ module.exports = function () {
|
||||
});
|
||||
};
|
||||
|
||||
this.When(/^I run "osrm\-routed\s?(.*?)"$/, { timeout: this.TIMEOUT }, (options, callback) => {
|
||||
this.When(/^I run "osrm-routed\s?(.*?)"$/, { timeout: this.TIMEOUT }, (options, callback) => {
|
||||
this.runAndSafeOutput('osrm-routed', options, callback);
|
||||
});
|
||||
|
||||
this.When(/^I run "osrm\-(extract|contract|partition|customize)\s?(.*?)"$/, (binary, options, callback) => {
|
||||
this.When(/^I run "osrm-(extract|contract|partition|customize)\s?(.*?)"$/, (binary, options, callback) => {
|
||||
const stamp = this.processedCacheFile + '.stamp_' + binary;
|
||||
this.runAndSafeOutput('osrm-' + binary, options, (err) => {
|
||||
if (err) return callback(err);
|
||||
@@ -33,11 +33,11 @@ module.exports = function () {
|
||||
});
|
||||
});
|
||||
|
||||
this.When(/^I try to run "(osrm\-[a-z]+)\s?(.*?)"$/, (binary, options, callback) => {
|
||||
this.When(/^I try to run "(osrm-[a-z]+)\s?(.*?)"$/, (binary, options, callback) => {
|
||||
this.runAndSafeOutput(binary, options, () => { callback(); });
|
||||
});
|
||||
|
||||
this.When(/^I run "osrm\-datastore\s?(.*?)"(?: with input "([^"]*)")?$/, (options, input, callback) => {
|
||||
this.When(/^I run "osrm-datastore\s?(.*?)"(?: with input "([^"]*)")?$/, (options, input, callback) => {
|
||||
let child = this.runAndSafeOutput('osrm-datastore', options, callback);
|
||||
if (input !== undefined)
|
||||
child.stdin.write(input);
|
||||
@@ -55,13 +55,13 @@ module.exports = function () {
|
||||
this.Then(/^stdout should( not)? contain "(.*?)"$/, (not, str) => {
|
||||
const contains = this.stdout.indexOf(str) > -1;
|
||||
assert.ok(typeof not === 'undefined' ? contains : !contains,
|
||||
'stdout ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
|
||||
'stdout ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
|
||||
});
|
||||
|
||||
this.Then(/^stderr should( not)? contain "(.*?)"$/, (not, str) => {
|
||||
const contains = this.stderr.indexOf(str) > -1;
|
||||
assert.ok(typeof not === 'undefined' ? contains : !contains,
|
||||
'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
|
||||
'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
|
||||
});
|
||||
|
||||
this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => {
|
||||
|
||||
@@ -69,7 +69,7 @@ module.exports = function () {
|
||||
outputRow[direction] = result[direction].status ?
|
||||
'x' : '';
|
||||
break;
|
||||
case /^[\d\.]+ s/.test(want):
|
||||
case /^[\d.]+ s/.test(want):
|
||||
// the result here can come back as a non-number value like
|
||||
// `diff`, but we only want to apply the unit when it comes
|
||||
// back as a number, for tableDiff's literal comparison
|
||||
|
||||
@@ -29,7 +29,7 @@ module.exports = function() {
|
||||
|
||||
// setup cache for feature data
|
||||
// if OSRM_PROFILE is set to force a specific profile, then
|
||||
// include the profile name in the hash of the profile file
|
||||
// include the profile name in the hash of the profile file
|
||||
hash.hashOfFile(uri, this.OSRM_PROFILE, (err, hash) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
@@ -45,10 +45,10 @@ module.exports = function() {
|
||||
this.featureProcessedCacheDirectories[uri] = featureProcessedCacheDirectory;
|
||||
|
||||
d3.queue(1)
|
||||
.defer(mkdirp, featureProcessedCacheDirectory)
|
||||
.defer(this.cleanupFeatureCache.bind(this), featureCacheDirectory, hash)
|
||||
.defer(this.cleanupProcessedFeatureCache.bind(this), featureProcessedCacheDirectory, this.osrmHash)
|
||||
.awaitAll(callback);
|
||||
.defer(mkdirp, featureProcessedCacheDirectory)
|
||||
.defer(this.cleanupFeatureCache.bind(this), featureCacheDirectory, hash)
|
||||
.defer(this.cleanupProcessedFeatureCache.bind(this), featureProcessedCacheDirectory, this.osrmHash)
|
||||
.awaitAll(callback);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ module.exports = function() {
|
||||
fs.readdir(parentPath, (err, files) => {
|
||||
let q = d3.queue();
|
||||
files.filter(name => { return name !== featureHash;})
|
||||
.map((f) => { q.defer(rimraf, path.join(parentPath, f)); });
|
||||
.map((f) => { q.defer(rimraf, path.join(parentPath, f)); });
|
||||
q.awaitAll(callback);
|
||||
});
|
||||
};
|
||||
@@ -145,7 +145,7 @@ module.exports = function() {
|
||||
|
||||
// converts the scenario titles in file prefixes
|
||||
this.getScenarioID = (scenario) => {
|
||||
let name = scenario.getName().toLowerCase().replace(/[\/\-'=,\(\):\*#]/g, '')
|
||||
let name = scenario.getName().toLowerCase().replace(/[/\-'=,():*#]/g, '')
|
||||
.replace(/\s/g, '_').replace(/__/g, '_').replace(/\.\./g, '.')
|
||||
.substring(0, 64);
|
||||
return util.format('%d_%s', scenario.getLine(), name);
|
||||
|
||||
@@ -17,11 +17,12 @@ module.exports = {
|
||||
return true;
|
||||
|
||||
var matchPercent = want.match(/(.*)\s+~(.+)%$/),
|
||||
matchAbs = want.match(/(.*)\s+\+\-(.+)$/),
|
||||
matchAbs = want.match(/(.*)\s+\+-(.+)$/),
|
||||
matchRe = want.match(/^\/(.*)\/$/),
|
||||
// we use this for matching before/after bearing
|
||||
matchBearingListAbs = want.match(/^((\d+)->(\d+))(,(\d+)->(\d+))*\s+\+\-(.+)$/),
|
||||
matchIntersectionListAbs = want.match(/^(((((true|false):\d+)\s{0,1})+,{0,1})+;{0,1})+\s+\+\-(.+)$/);
|
||||
matchBearingListAbs = want.match(/^((\d+)->(\d+))(,(\d+)->(\d+))*\s+\+-(.+)$/),
|
||||
matchIntersectionListAbs = want.match(/^(((((true|false):\d+)\s{0,1})+,{0,1})+;{0,1})+\s+\+-(.+)$/),
|
||||
matchRangeNumbers = want.match(/\d+\+-\d+/);
|
||||
|
||||
function inRange(margin, got, want) {
|
||||
var fromR = parseFloat(want) - margin,
|
||||
@@ -30,12 +31,12 @@ module.exports = {
|
||||
}
|
||||
function parseIntersectionString(str) {
|
||||
return str.split(';')
|
||||
.map((turn_intersections) => turn_intersections
|
||||
.split(',')
|
||||
.map((intersection) => intersection
|
||||
.split(' ')
|
||||
.map((entry_bearing_pair) => entry_bearing_pair
|
||||
.split(':'))));
|
||||
.map((turn_intersections) => turn_intersections
|
||||
.split(',')
|
||||
.map((intersection) => intersection
|
||||
.split(' ')
|
||||
.map((entry_bearing_pair) => entry_bearing_pair
|
||||
.split(':'))));
|
||||
}
|
||||
|
||||
if (got === want) {
|
||||
@@ -105,6 +106,11 @@ module.exports = {
|
||||
return inRange(margin, got, matchAbs[1]);
|
||||
} else if (matchRe) { // regex: /a,b,.*/
|
||||
return got.match(matchRe[1]);
|
||||
} else if (matchRangeNumbers) {
|
||||
let real_want_and_margin = want.split('+-'),
|
||||
margin = parseFloat(real_want_and_margin[1].trim()),
|
||||
real_want = parseFloat(real_want_and_margin[0].trim());
|
||||
return inRange(margin, got, real_want);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ module.exports = function () {
|
||||
this.DEFAULT_ENVIRONMENT = Object.assign({STXXLCFG: stxxl_config}, process.env);
|
||||
this.DEFAULT_PROFILE = 'bicycle';
|
||||
this.DEFAULT_INPUT_FORMAT = 'osm';
|
||||
this.DEFAULT_LOAD_METHOD = 'datastore';
|
||||
this.DEFAULT_LOAD_METHOD = process.argv[process.argv.indexOf('-m') +1].match('mmap') ? 'mmap' : 'datastore';
|
||||
this.DEFAULT_ORIGIN = [1,1];
|
||||
this.OSM_USER = 'osrm';
|
||||
this.OSM_UID = 1;
|
||||
@@ -80,7 +80,7 @@ module.exports = function () {
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(util.format('Node Version', process.version));
|
||||
if (parseInt(process.version.match(/v(\d)/)[1]) < 4) throw new Error('*** Please upgrade to Node 4.+ to run OSRM cucumber tests');
|
||||
if (parseInt(process.version.match(/v(\d+)/)[1]) < 4) throw new Error('*** Please upgrade to Node 4.+ to run OSRM cucumber tests');
|
||||
|
||||
fs.exists(this.TEST_PATH, (exists) => {
|
||||
if (exists)
|
||||
|
||||
@@ -51,7 +51,7 @@ module.exports = function () {
|
||||
.defer(rimraf, this.scenarioLogFile)
|
||||
.awaitAll(callback);
|
||||
// uncomment to get path to logfile
|
||||
// console.log(" Writing logging output to " + this.scenarioLogFile)
|
||||
// console.log(' Writing logging output to ' + this.scenarioLogFile);
|
||||
});
|
||||
|
||||
this.After((scenario, callback) => {
|
||||
|
||||
@@ -75,6 +75,10 @@ module.exports = function () {
|
||||
got.message = json.message || '';
|
||||
}
|
||||
|
||||
if (headers.has('data_version')) {
|
||||
got.data_version = json.data_version || '';
|
||||
}
|
||||
|
||||
if (headers.has('#')) {
|
||||
// comment column
|
||||
got['#'] = row['#'];
|
||||
@@ -115,7 +119,7 @@ module.exports = function () {
|
||||
|
||||
if (headers.has('weight')) {
|
||||
if (row.weight.length) {
|
||||
if (!row.weight.match(/[\d\.]+/))
|
||||
if (!row.weight.match(/[\d.]+/))
|
||||
return cb(new Error('*** Weight must be specified as a numeric value. (ex: 8)'));
|
||||
got.weight = instructions ? util.format('%d', weight) : '';
|
||||
} else {
|
||||
@@ -151,7 +155,7 @@ module.exports = function () {
|
||||
if (headers.has('locations')){
|
||||
got.locations = (locations || '').trim();
|
||||
}
|
||||
/*
|
||||
/*
|
||||
if (headers.has('approaches')){
|
||||
got.approaches = (approaches || '').trim();
|
||||
}*/
|
||||
|
||||
@@ -17,9 +17,26 @@ Feature: Basic Routing
|
||||
| ab |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ab,ab |
|
||||
| b | a | ab,ab |
|
||||
| from | to | route | data_version |
|
||||
| a | b | ab,ab | |
|
||||
| b | a | ab,ab | |
|
||||
|
||||
Scenario: Data_version test
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the extract extra arguments "--data_version cucumber_data_version"
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | data_version |
|
||||
| a | b | ab,ab | cucumber_data_version |
|
||||
| b | a | ab,ab | cucumber_data_version |
|
||||
|
||||
Scenario: Routing in between two nodes of way
|
||||
Given the node map
|
||||
|
||||
@@ -226,3 +226,22 @@ Feature: Distance calculation
|
||||
| x | v | xv,xv | 424m +-1 |
|
||||
| x | w | xw,xw | 360m +-1 |
|
||||
| x | y | xy,xy | 316m +-1 |
|
||||
|
||||
|
||||
# Check rounding errors
|
||||
Scenario: Distances Long distances
|
||||
Given a grid size of 1000 meters
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abcd |
|
||||
|
||||
When I route I should get
|
||||
| from | to | distance |
|
||||
| a | b | 1000m +-3 |
|
||||
| a | c | 2000m +-3 |
|
||||
| a | d | 3000m +-3 |
|
||||
|
||||
@@ -1,74 +1,11 @@
|
||||
@matrix @testbot
|
||||
Feature: Basic Distance Matrix
|
||||
# note that results are travel time, specified in 1/10th of seconds
|
||||
# since testbot uses a default speed of 100m/10s, the result matches
|
||||
# the number of meters as long as the way type is the default 'primary'
|
||||
# note that results of travel distance are in metres
|
||||
|
||||
Background:
|
||||
Given the profile "testbot"
|
||||
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
|
||||
|
||||
Scenario: Testbot - Travel time matrix of minimal network
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 10 |
|
||||
| b | 10 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time matrix with different way speeds
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| ab | primary |
|
||||
| bc | secondary |
|
||||
| cd | tertiary |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 10 | 30 | 60 |
|
||||
| b | 10 | 0 | 20 | 50 |
|
||||
| c | 30 | 20 | 0 | 30 |
|
||||
| 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
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 10 |
|
||||
| b | 10 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time matrix of small grid
|
||||
Scenario: Testbot - Travel distance matrix of small grid
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
@@ -83,14 +20,175 @@ Feature: Basic Distance Matrix
|
||||
| be |
|
||||
| cf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
| b | 10 | 0 | 10 | 20 |
|
||||
| e | 20 | 10 | 0 | 10 |
|
||||
| f | 30 | 20 | 10 | 0 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
| e | 199.5 | 99.4 | 0 | 100.1 |
|
||||
| f | 299.5 | 199.5 | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time matrix of network with unroutable parts
|
||||
Scenario: Testbot - Travel distance matrix of minimal network exact distances
|
||||
Given the node map
|
||||
"""
|
||||
a z
|
||||
b
|
||||
c
|
||||
d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| az |
|
||||
| zbcd |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | z | b | c | d |
|
||||
| a | 0 | 100.1 | 199.5 | 298.9 | 398.3 |
|
||||
| z | 100.1 | 0 | 99.4 | 198.8 | 298.2 |
|
||||
| b | 199.5 | 99.4 | 0 | 99.4 | 198.8 |
|
||||
| c | 298.9 | 198.8 | 99.4 | 0 | 99.4 |
|
||||
| d | 398.3 | 298.2 | 198.8 | 99.4 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network with toll exclude
|
||||
Given the query options
|
||||
| exclude | toll |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | toll | # |
|
||||
| ab | motorway | | not drivable for exclude=motorway |
|
||||
| cd | primary | | always drivable |
|
||||
| ac | primary | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||
| bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100.1 | | |
|
||||
| b | 100.1 | 0 | | |
|
||||
| c | | | 0 | 100.1 |
|
||||
| d | | | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude
|
||||
Given the query options
|
||||
| exclude | motorway |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | # |
|
||||
| ab | motorway | not drivable for exclude=motorway |
|
||||
| cd | residential | |
|
||||
| ac | residential | |
|
||||
| bd | residential | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 298.9 | 99.4 | 199.5 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude
|
||||
Given the query options
|
||||
| exclude | motorway |
|
||||
And the extract extra arguments "--small-component-size 4"
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
ab efgh
|
||||
cd
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | # |
|
||||
| be | motorway | not drivable for exclude=motorway |
|
||||
| abcd | residential | |
|
||||
| efgh | residential | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e |
|
||||
| a | 0 | 50.1 | |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes
|
||||
Given the query options
|
||||
| exclude | motorway,toll |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b e f
|
||||
c d g h
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | toll | # |
|
||||
| be | motorway | | not drivable for exclude=motorway |
|
||||
| dg | primary | yes | not drivable for exclude=toll |
|
||||
| abcd | residential | | |
|
||||
| efgh | residential | | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | g |
|
||||
| a | 0 | 100.1 | | |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix with different way speeds
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| ab | primary |
|
||||
| bc | secondary |
|
||||
| cd | tertiary |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100.1 | 200.1 | 300.2 |
|
||||
| b | 100.1 | 0 | 100.1 | 200.1 |
|
||||
| c | 200.1 | 100.1 | 0 | 100.1 |
|
||||
| d | 300.2 | 200.1 | 100.1 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100.1 | 200.1 | 300.2 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 100.1 |
|
||||
| c | 200.1 |
|
||||
| d | 300.2 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of small grid
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
d e f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abc |
|
||||
| def |
|
||||
| ad |
|
||||
| be |
|
||||
| cf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
| e | 199.5 | 99.4 | 0 | 100.1 |
|
||||
| f | 299.5 | 199.5 | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of network with unroutable parts
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
@@ -100,12 +198,12 @@ Feature: Basic Distance Matrix
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 10 |
|
||||
| b | | 0 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 100.1 |
|
||||
| b | | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time matrix of network with oneways
|
||||
Scenario: Testbot - Travel distance matrix of network with oneways
|
||||
Given the node map
|
||||
"""
|
||||
x a b y
|
||||
@@ -118,14 +216,14 @@ Feature: Basic Distance Matrix
|
||||
| xa | |
|
||||
| by | |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | x | y | d | e |
|
||||
| x | 0 | 30 | 40 | 30 |
|
||||
| y | 50 | 0 | 30 | 20 |
|
||||
| d | 20 | 30 | 0 | 30 |
|
||||
| e | 30 | 40 | 10 | 0 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | x | y | d | e |
|
||||
| x | 0 | 300.2 | 399.6 | 299.5 |
|
||||
| y | 499 | 0 | 299.5 | 199.5 |
|
||||
| d | 199.5 | 299.5 | 0 | 298.9 |
|
||||
| e | 299.5 | 399.6 | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Rectangular travel time matrix
|
||||
Scenario: Testbot - Rectangular travel distance matrix
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
@@ -140,51 +238,57 @@ Feature: Basic Distance Matrix
|
||||
| be |
|
||||
| cf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
When I route I should get
|
||||
| from | to | distance |
|
||||
| e | a | 200m |
|
||||
| e | b | 100m |
|
||||
| f | a | 299.9m |
|
||||
| f | b | 200m |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 10 |
|
||||
| e | 20 |
|
||||
| f | 30 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
| b | 10 | 0 | 10 | 20 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 100.1 |
|
||||
| e | 199.5 |
|
||||
| f | 299.5 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 10 |
|
||||
| b | 10 | 0 |
|
||||
| e | 20 | 10 |
|
||||
| f | 30 | 20 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
| b | 10 | 0 | 10 | 20 |
|
||||
| e | 20 | 10 | 0 | 10 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 100.1 |
|
||||
| b | 100.1 | 0 |
|
||||
| e | 199.5 | 99.4 |
|
||||
| f | 299.5 | 199.5 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e |
|
||||
| a | 0 | 10 | 20 |
|
||||
| b | 10 | 0 | 10 |
|
||||
| e | 20 | 10 | 0 |
|
||||
| f | 30 | 20 | 10 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
| e | 199.5 | 99.4 | 0 | 100.1 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
| b | 10 | 0 | 10 | 20 |
|
||||
| e | 20 | 10 | 0 | 10 |
|
||||
| f | 30 | 20 | 10 | 0 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e |
|
||||
| a | 0 | 100.1 | 199.5 |
|
||||
| b | 100.1 | 0 | 99.4 |
|
||||
| e | 199.5 | 99.4 | 0 |
|
||||
| f | 299.5 | 199.5 | 100.1 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
| e | 199.5 | 99.4 | 0 | 100.1 |
|
||||
| f | 299.5 | 199.5 | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time 3x2 matrix
|
||||
Scenario: Testbot - Travel distance 3x2 matrix
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
@@ -199,10 +303,11 @@ Feature: Basic Distance Matrix
|
||||
| be |
|
||||
| cf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | b | e | f |
|
||||
| a | 10 | 20 | 30 |
|
||||
| b | 0 | 10 | 20 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | b | e | f |
|
||||
| a | 100.1 | 199.5 | 299.5 |
|
||||
| b | 0 | 99.4 | 199.5 |
|
||||
|
||||
Scenario: Testbot - All coordinates are from same small component
|
||||
Given a grid size of 300 meters
|
||||
@@ -221,10 +326,10 @@ Feature: Basic Distance Matrix
|
||||
| da |
|
||||
| fg |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | f | g |
|
||||
| f | 0 | 30 |
|
||||
| g | 30 | 0 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | f | g |
|
||||
| f | 0 | 298.2 |
|
||||
| g | 298.2 | 0 |
|
||||
|
||||
Scenario: Testbot - Coordinates are from different small component and snap to big CC
|
||||
Given a grid size of 300 meters
|
||||
@@ -244,14 +349,25 @@ Feature: Basic Distance Matrix
|
||||
| fg |
|
||||
| hi |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | f | g | h | i |
|
||||
| f | 0 | 30 | 0 | 30 |
|
||||
| g | 30 | 0 | 30 | 0 |
|
||||
| h | 0 | 30 | 0 | 30 |
|
||||
| i | 30 | 0 | 30 | 0 |
|
||||
When I route I should get
|
||||
| from | to | distance |
|
||||
| f | g | 300m |
|
||||
| f | i | 300m |
|
||||
| g | f | 300m |
|
||||
| g | h | 300m |
|
||||
| h | g | 300m |
|
||||
| h | i | 300m |
|
||||
| i | f | 300m |
|
||||
| i | h | 300m |
|
||||
|
||||
Scenario: Testbot - Travel time matrix with loops
|
||||
When I request a travel distance matrix I should get
|
||||
| | f | g | h | i |
|
||||
| f | 0 | 298.2 | 0 | 298.2 |
|
||||
| g | 298.2 | 0 | 298.2 | 0 |
|
||||
| h | 0 | 298.2 | 0 | 298.2 |
|
||||
| i | 298.2 | 0 | 298.2 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix with loops
|
||||
Given the node map
|
||||
"""
|
||||
a 1 2 b
|
||||
@@ -265,14 +381,15 @@ Feature: Basic Distance Matrix
|
||||
| cd | yes |
|
||||
| da | yes |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | 1 | 2 | 3 | 4 |
|
||||
| 1 | 0 | 10 +-1 | 40 +-1 | 50 +-1 |
|
||||
| 2 | 70 +-1 | 0 | 30 +-1 | 40 +-1 |
|
||||
| 3 | 40 +-1 | 50 +-1 | 0 | 10 +-1 |
|
||||
| 4 | 30 +-1 | 40 +-1 | 70 +-1 | 0 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | 1 | 2 | 3 | 4 |
|
||||
| 1 | 0 | 100.1 | 399.6 | 499.7 |
|
||||
| 2 | 699.1 | 0 | 299.5 | 399.6 |
|
||||
| 3 | 399.6 | 499.7 | 0 | 100.1 |
|
||||
| 4 | 299.5 | 399.6 | 699.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time matrix based on segment durations
|
||||
|
||||
Scenario: Testbot - Travel distance matrix based on segment durations
|
||||
Given the profile file
|
||||
"""
|
||||
local functions = require('testbot')
|
||||
@@ -301,20 +418,19 @@ Feature: Basic Distance Matrix
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abcd |
|
||||
| ce |
|
||||
| nodes |
|
||||
| abcd |
|
||||
| ce |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | c | d | e |
|
||||
| a | 0 | 11 | 22 | 33 | 33 |
|
||||
| b | 11 | 0 | 11 | 22 | 22 |
|
||||
| c | 22 | 11 | 0 | 11 | 11 |
|
||||
| d | 33 | 22 | 11 | 0 | 22 |
|
||||
| e | 33 | 22 | 11 | 22 | 0 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d | e |
|
||||
| a | 0 | 100.1 | 200.1 | 300.2 | 398.9 |
|
||||
| b | 100.1 | 0 | 100.1 | 200.1 | 298.9 |
|
||||
| c | 200.1 | 100.1 | 0 | 100.1 | 198.8 |
|
||||
| d | 300.2 | 200.1 | 100.1 | 0 | 298.9 |
|
||||
| e | 398.9 | 298.9 | 198.8 | 298.9 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Travel time matrix for alternative loop paths
|
||||
Scenario: Testbot - Travel distance matrix for alternative loop paths
|
||||
Given the profile file
|
||||
"""
|
||||
local functions = require('testbot')
|
||||
@@ -350,62 +466,260 @@ Feature: Basic Distance Matrix
|
||||
| dc | yes |
|
||||
| ca | yes |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
||||
| 1 | 0 | 11 | 3 | 2 | 6 | 5 | 8.9 | 7.9 |
|
||||
| 2 | 1 | 0 | 4 | 3 | 7 | 6 | 9.9 | 8.9 |
|
||||
| 3 | 9 | 8 | 0 | 11 | 3 | 2 | 5.9 | 4.9 |
|
||||
| 4 | 10 | 9 | 1 | 0 | 4 | 3 | 6.9 | 5.9 |
|
||||
| 5 | 6 | 5 | 9 | 8 | 0 | 11 | 2.9 | 1.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 |
|
||||
| 8 | 4.1 | 3.1 | 7.1 | 6.1 | 10.1 | 9.1 | 1 | 0 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
||||
| 1 | 0 | 1096.7 | 298.9 | 199.5 | 598.4 | 498.3 | 897.3 | 797.9 |
|
||||
| 2 | 100.1 | 0 | 398.9 | 299.5 | 698.5 | 598.4 | 997.3 | 897.9 |
|
||||
| 3 | 897.9 | 797.9 | 0 | 1097.4 | 299.5 | 199.5 | 598.4 | 499 |
|
||||
| 4 | 997.3 | 897.3 | 99.4 | 0 | 398.9 | 298.9 | 697.8 | 598.4 |
|
||||
| 5 | 598.4 | 498.3 | 897.3 | 797.9 | 0 | 1096.7 | 298.9 | 199.5 |
|
||||
| 6 | 698.5 | 598.4 | 997.3 | 897.9 | 100.1 | 0 | 398.9 | 299.5 |
|
||||
| 7 | 299.5 | 199.5 | 598.4 | 499 | 897.9 | 797.9 | 0 | 1097.4 |
|
||||
| 8 | 398.9 | 298.9 | 697.8 | 598.4 | 997.3 | 897.3 | 99.4 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | 1 |
|
||||
| 1 | 0 |
|
||||
| 2 | 100.1 |
|
||||
| 3 | 897.9 |
|
||||
| 4 | 997.3 |
|
||||
| 5 | 598.4 |
|
||||
| 6 | 698.5 |
|
||||
| 7 | 299.5 |
|
||||
| 8 | 398.9 |
|
||||
|
||||
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
|
||||
Scenario: Testbot - Travel distance matrix with ties
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
a b
|
||||
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| ac |
|
||||
| bd |
|
||||
| dc |
|
||||
|
||||
| nodes |
|
||||
| ab |
|
||||
| ac |
|
||||
| bd |
|
||||
| dc |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | distance | time | weight |
|
||||
| a | c | ac,ac | 200m | 5s | 5 |
|
||||
| from | to | route | distance | time | weight |
|
||||
| a | c | ac,ac | 200m | 20s | 20 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 1 | 5 | 10 |
|
||||
When I route I should get
|
||||
| from | to | route | distance |
|
||||
| a | b | ab,ab | 450m |
|
||||
| a | c | ac,ac | 200m |
|
||||
| a | d | ac,dc,dc | 499.9m |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 1 |
|
||||
| c | 15 |
|
||||
| d | 10 |
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 450.3 | 198.8 | 499 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 450.3 |
|
||||
| c | 198.8 |
|
||||
| d | 499 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | c |
|
||||
| a | 0 | 198.8 |
|
||||
| c | 198.8 | 0 |
|
||||
|
||||
|
||||
# Check rounding errors
|
||||
Scenario: Testbot - Long distances in tables
|
||||
Given a grid size of 1000 meters
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abcd |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 1000.7 | 2001.4 | 3002.1 |
|
||||
|
||||
|
||||
Scenario: Testbot - OneToMany vs ManyToOne
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| ac | |
|
||||
| bc | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b |
|
||||
| b | 240.4 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 240.4 |
|
||||
|
||||
Scenario: Testbot - Varying distances between nodes
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
|
||||
e
|
||||
|
||||
|
||||
|
||||
f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| feabcd | yes |
|
||||
| ec | |
|
||||
| fd | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d | e | f |
|
||||
| a | 0 | 100.1 | 300.2 | 650.5 | 1930.6 | 1533 |
|
||||
| b | 759 | 0 | 200.1 | 550.4 | 1830.5 | 1432.9 |
|
||||
| c | 558.8 | 658.9 | 0 | 350.3 | 1630.4 | 1232.8 |
|
||||
| d | 1478.9 | 1579 | 1779.1 | 0 | 1280.1 | 882.5 |
|
||||
| e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 |
|
||||
| f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 |
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1501.1 |
|
||||
| b | 300.2 | 0 | 600.5 | 1200.9 |
|
||||
| f | 900.7 | 600.5 | 0 | 300.2 |
|
||||
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1501.1 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 300.2 |
|
||||
| f | 900.7 |
|
||||
| 1 | 1501.1 |
|
||||
|
||||
Scenario: Testbot - Fise input coordinate
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | input |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1501.1 |
|
||||
| b | 300.2 | 0 | 600.5 | 1200.9 |
|
||||
| f | 900.7 | 600.5 | 0 | 300.2 |
|
||||
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1501.1 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 300.2 |
|
||||
| f | 900.7 |
|
||||
| 1 | 1501.1 |
|
||||
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | snapped |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1200.9 |
|
||||
| b | 300.2 | 0 | 600.5 | 900.7 |
|
||||
| f | 900.7 | 600.5 | 0 | 300.2 |
|
||||
| 1 | 1200.9 | 900.7 | 300.2 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1200.9 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 300.2 |
|
||||
| f | 900.7 |
|
||||
| 1 | 1200.9 |
|
||||
|
||||
Scenario: Ensure consistency with route, and make sure offsets work in both directions
|
||||
Given a grid size of 100 meters
|
||||
Given the node map
|
||||
"""
|
||||
a b c d e f g h i j
|
||||
1 2
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abcdef |
|
||||
| fghij |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | distance |
|
||||
| 1 | 2 | abcdef,fghij,fghij | 999.9m |
|
||||
|
||||
# TODO: this is "correct", but inconsistent with viaroute
|
||||
When I request a travel distance matrix I should get
|
||||
| | 1 | 2 |
|
||||
| 1 | 0 | 1000.7 |
|
||||
| 2 | 1000.7 | 0 |
|
||||
@@ -0,0 +1,777 @@
|
||||
@matrix @testbot
|
||||
Feature: Basic Duration Matrix
|
||||
# note that results of travel time are in seconds
|
||||
|
||||
Background:
|
||||
Given the profile "testbot"
|
||||
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
|
||||
|
||||
Scenario: Testbot - Travel time matrix of minimal network
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 10 |
|
||||
| b | 10 | 0 |
|
||||
|
||||
@ch
|
||||
Scenario: Testbot - Travel time matrix of minimal network with toll exclude
|
||||
Given the query options
|
||||
| exclude | toll |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | toll | # |
|
||||
| ab | motorway | | not drivable for exclude=motorway |
|
||||
| cd | primary | | always drivable |
|
||||
| ac | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||
| bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 15 | | |
|
||||
| b | 15 | 0 | | |
|
||||
| c | | | 0 | 10 |
|
||||
| d | | | 10 | 0 |
|
||||
|
||||
@ch
|
||||
Scenario: Testbot - Travel time matrix of minimal network with motorway exclude
|
||||
Given the query options
|
||||
| exclude | motorway |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | # |
|
||||
| ab | motorway | not drivable for exclude=motorway |
|
||||
| cd | residential | |
|
||||
| ac | residential | |
|
||||
| bd | residential | |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 45 | 15 | 30 |
|
||||
|
||||
@ch
|
||||
Scenario: Testbot - Travel time matrix of minimal network disconnected motorway exclude
|
||||
Given the query options
|
||||
| exclude | motorway |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
ab efgh
|
||||
cd
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | # |
|
||||
| be | motorway | not drivable for exclude=motorway |
|
||||
| abcd | residential | |
|
||||
| efgh | residential | |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e |
|
||||
| a | 0 | 7.5 | |
|
||||
|
||||
@ch
|
||||
Scenario: Testbot - Travel time matrix of minimal network with motorway and toll excludes
|
||||
Given the query options
|
||||
| exclude | motorway,toll |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b e f
|
||||
c d g h
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway | toll | # |
|
||||
| be | motorway | | not drivable for exclude=motorway |
|
||||
| dg | primary | yes | not drivable for exclude=toll |
|
||||
| abcd | residential | | |
|
||||
| efgh | residential | | |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | g |
|
||||
| a | 0 | 15 | | |
|
||||
|
||||
Scenario: Testbot - Travel time matrix with different way speeds
|
||||
Given the node map
|
||||
"""
|
||||
a b c d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| ab | primary |
|
||||
| bc | secondary |
|
||||
| cd | tertiary |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 10 | 30 | 60 |
|
||||
| b | 10 | 0 | 20 | 50 |
|
||||
| c | 30 | 20 | 0 | 30 |
|
||||
| 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 of small grid
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
d e f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abc |
|
||||
| def |
|
||||
| ad |
|
||||
| be |
|
||||
| cf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
| b | 10 | 0 | 10 | 20 |
|
||||
| e | 20 | 10 | 0 | 10 |
|
||||
| f | 30 | 20 | 10 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Travel time matrix of network with unroutable parts
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 10 |
|
||||
| b | | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Travel time matrix of network with oneways
|
||||
Given the node map
|
||||
"""
|
||||
x a b y
|
||||
d e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| abeda | yes |
|
||||
| xa | |
|
||||
| by | |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | x | y | d | e |
|
||||
| x | 0 | 30 | 40 | 30 |
|
||||
| y | 50 | 0 | 30 | 20 |
|
||||
| d | 20 | 30 | 0 | 30 |
|
||||
| e | 30 | 40 | 10 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Rectangular travel time matrix
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
d e f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abc |
|
||||
| def |
|
||||
| ad |
|
||||
| be |
|
||||
| cf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 10 |
|
||||
| e | 20 |
|
||||
| f | 30 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
| b | 10 | 0 | 10 | 20 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 10 |
|
||||
| b | 10 | 0 |
|
||||
| e | 20 | 10 |
|
||||
| f | 30 | 20 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
| b | 10 | 0 | 10 | 20 |
|
||||
| e | 20 | 10 | 0 | 10 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e |
|
||||
| a | 0 | 10 | 20 |
|
||||
| b | 10 | 0 | 10 |
|
||||
| e | 20 | 10 | 0 |
|
||||
| f | 30 | 20 | 10 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 10 | 20 | 30 |
|
||||
| b | 10 | 0 | 10 | 20 |
|
||||
| e | 20 | 10 | 0 | 10 |
|
||||
| f | 30 | 20 | 10 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time 3x2 matrix
|
||||
Given the node map
|
||||
"""
|
||||
a b c
|
||||
d e f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abc |
|
||||
| def |
|
||||
| ad |
|
||||
| be |
|
||||
| cf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | b | e | f |
|
||||
| a | 10 | 20 | 30 |
|
||||
| b | 0 | 10 | 20 |
|
||||
|
||||
|
||||
Scenario: Testbot - All coordinates are from same small component
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the node map
|
||||
"""
|
||||
a b f
|
||||
d e g
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| be |
|
||||
| ed |
|
||||
| da |
|
||||
| fg |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | f | g |
|
||||
| f | 0 | 30 |
|
||||
| g | 30 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Coordinates are from different small component and snap to big CC
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the node map
|
||||
"""
|
||||
a b f h
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| be |
|
||||
| ed |
|
||||
| da |
|
||||
| fg |
|
||||
| hi |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | f | g | h | i |
|
||||
| f | 0 | 30 | 0 | 30 |
|
||||
| g | 30 | 0 | 30 | 0 |
|
||||
| h | 0 | 30 | 0 | 30 |
|
||||
| i | 30 | 0 | 30 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Travel time matrix with loops
|
||||
Given the node map
|
||||
"""
|
||||
a 1 2 b
|
||||
d 4 3 c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| bc | yes |
|
||||
| cd | yes |
|
||||
| da | yes |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | 1 | 2 | 3 | 4 |
|
||||
| 1 | 0 | 10 +-1 | 40 +-1 | 50 +-1 |
|
||||
| 2 | 70 +-1 | 0 | 30 +-1 | 40 +-1 |
|
||||
| 3 | 40 +-1 | 50 +-1 | 0 | 10 +-1 |
|
||||
| 4 | 30 +-1 | 40 +-1 | 70 +-1 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Travel time matrix based on segment durations
|
||||
Given the profile file
|
||||
"""
|
||||
local functions = require('testbot')
|
||||
functions.setup_testbot = functions.setup
|
||||
|
||||
functions.setup = function()
|
||||
local profile = functions.setup_testbot()
|
||||
profile.traffic_signal_penalty = 0
|
||||
profile.u_turn_penalty = 0
|
||||
return profile
|
||||
end
|
||||
|
||||
functions.process_segment = function(profile, segment)
|
||||
segment.weight = 2
|
||||
segment.duration = 11
|
||||
end
|
||||
|
||||
return functions
|
||||
"""
|
||||
|
||||
And the node map
|
||||
"""
|
||||
a-b-c-d
|
||||
.
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abcd |
|
||||
| ce |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | c | d | e |
|
||||
| a | 0 | 11 | 22 | 33 | 33 |
|
||||
| b | 11 | 0 | 11 | 22 | 22 |
|
||||
| c | 22 | 11 | 0 | 11 | 11 |
|
||||
| d | 33 | 22 | 11 | 0 | 22 |
|
||||
| e | 33 | 22 | 11 | 22 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Travel time matrix for alternative loop paths
|
||||
Given the profile file
|
||||
"""
|
||||
local functions = require('testbot')
|
||||
functions.setup_testbot = functions.setup
|
||||
|
||||
functions.setup = function()
|
||||
local profile = functions.setup_testbot()
|
||||
profile.traffic_signal_penalty = 0
|
||||
profile.u_turn_penalty = 0
|
||||
profile.weight_precision = 3
|
||||
return profile
|
||||
end
|
||||
|
||||
functions.process_segment = function(profile, segment)
|
||||
segment.weight = 777
|
||||
segment.duration = 3
|
||||
end
|
||||
|
||||
return functions
|
||||
"""
|
||||
And the node map
|
||||
"""
|
||||
a 2 1 b
|
||||
7 4
|
||||
8 3
|
||||
c 5 6 d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| bd | yes |
|
||||
| dc | yes |
|
||||
| ca | yes |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
||||
| 1 | 0 | 11 | 3 | 2 | 6 | 5 | 8.9 | 7.9 |
|
||||
| 2 | 1 | 0 | 4 | 3 | 7 | 6 | 9.9 | 8.9 |
|
||||
| 3 | 9 | 8 | 0 | 11 | 3 | 2 | 5.9 | 4.9 |
|
||||
| 4 | 10 | 9 | 1 | 0 | 4 | 3 | 6.9 | 5.9 |
|
||||
| 5 | 6 | 5 | 9 | 8 | 0 | 11 | 2.9 | 1.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 |
|
||||
| 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 |
|
||||
|
||||
Scenario: Testbot - OneToMany vs ManyToOne
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
c
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes | oneway |
|
||||
| ab | yes |
|
||||
| ac | |
|
||||
| bc | |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| b | 24.1 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 24.1 |
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 30 |
|
||||
| b | 30 | 0 | 12 | 24 |
|
||||
| f | 18 | 12 | 0 | 30 |
|
||||
| 1 | 30 | 24 | 30 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 30 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 30 |
|
||||
| f | 18 |
|
||||
| 1 | 30 |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a | b | f | 1 |
|
||||
| a | | | Y | Y |
|
||||
| b | | | Y | Y |
|
||||
| f | Y | Y | | |
|
||||
| 1 | Y | Y | | |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a | b | f | 1 |
|
||||
| a | | | Y | Y |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a |
|
||||
| a | |
|
||||
| b | |
|
||||
| f | Y |
|
||||
| 1 | Y |
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates - use input coordinate
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | input |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 30 |
|
||||
| b | 30 | 0 | 12 | 24 |
|
||||
| f | 18 | 12 | 0 | 30 |
|
||||
| 1 | 30 | 24 | 30 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 30 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 30 |
|
||||
| f | 18 |
|
||||
| 1 | 30 |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a | b | f | 1 |
|
||||
| a | | | Y | Y |
|
||||
| b | | | Y | Y |
|
||||
| f | Y | Y | | |
|
||||
| 1 | Y | Y | | |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a | b | f | 1 |
|
||||
| a | | | Y | Y |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a |
|
||||
| a | |
|
||||
| b | |
|
||||
| f | Y |
|
||||
| 1 | Y |
|
||||
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | snapped |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 24 |
|
||||
| b | 30 | 0 | 12 | 18 |
|
||||
| f | 18 | 12 | 0 | 30 |
|
||||
| 1 | 24 | 18 | 30 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 24 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 30 |
|
||||
| f | 18 |
|
||||
| 1 | 24 |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a | b | f | 1 |
|
||||
| a | | | Y | Y |
|
||||
| b | | | Y | Y |
|
||||
| f | Y | Y | | |
|
||||
| 1 | Y | Y | | |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a | b | f | 1 |
|
||||
| a | | | Y | Y |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a |
|
||||
| a | |
|
||||
| b | |
|
||||
| f | Y |
|
||||
| 1 | Y |
|
||||
|
||||
Scenario: Testbot - Travel time matrix of minimal network with scale factor
|
||||
Given the query options
|
||||
| scale_factor | 2 |
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 20 |
|
||||
| b | 20 | 0 |
|
||||
Scenario: Testbot - Test fallback speeds and scale factor
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| scale_factor | 2 |
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | snapped |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 60 | 36 | 48 |
|
||||
| b | 60 | 0 | 24 | 36 |
|
||||
| f | 36 | 24 | 0 | 60 |
|
||||
| 1 | 48 | 36 | 60 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 60 | 36 | 48 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 60 |
|
||||
| f | 36 |
|
||||
| 1 | 48 |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a | b | f | 1 |
|
||||
| a | | | Y | Y |
|
||||
| b | | | Y | Y |
|
||||
| f | Y | Y | | |
|
||||
| 1 | Y | Y | | |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a | b | f | 1 |
|
||||
| a | | | Y | Y |
|
||||
|
||||
When I request a travel time matrix I should get estimates for
|
||||
| | a |
|
||||
| a | |
|
||||
| b | |
|
||||
| f | Y |
|
||||
| 1 | Y |
|
||||
|
||||
|
||||
Scenario: Testbot - Travel time matrix of minimal network with overflow scale factor
|
||||
Given the query options
|
||||
| scale_factor | 2147483647 |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 214748364.6 |
|
||||
| b | 214748364.6 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel time matrix of minimal network with fraction scale factor
|
||||
Given the query options
|
||||
| scale_factor | 0.5 |
|
||||
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 5 |
|
||||
| b | 5 | 0 |
|
||||
@@ -38,15 +38,15 @@ Feature: Multi level routing
|
||||
Scenario: Testbot - Multi level routing
|
||||
Given the node map
|
||||
"""
|
||||
a───b e───f
|
||||
│ │ │ │
|
||||
a────b e─────f
|
||||
\ │ │ /
|
||||
d───c h───g
|
||||
╲ ╱
|
||||
╳
|
||||
╱ ╲
|
||||
i───j m───n
|
||||
│ │ │ │
|
||||
l───k───p───o
|
||||
/ │ │ \
|
||||
l─────k───p─────o
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
@@ -67,44 +67,76 @@ Feature: Multi level routing
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| a | b | abcda,abcda | 20s |
|
||||
| a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 229.4s |
|
||||
| a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 144.7s |
|
||||
| a | o | abcda,cm,mnopm,mnopm,mnopm | 124.7s |
|
||||
| f | l | efghe,hj,ijkli,ijkli,ijkli | 124.7s |
|
||||
| f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 144.7s |
|
||||
| l | o | ijkli,kp,mnopm,mnopm | 60s |
|
||||
| a | b | abcda,abcda | 25s |
|
||||
| a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 239.2s |
|
||||
| a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 157.1s |
|
||||
| a | o | abcda,cm,mnopm,mnopm,mnopm | 137.1s |
|
||||
| f | l | efghe,hj,ijkli,ijkli | 136.7s |
|
||||
| f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 162.1s |
|
||||
| l | o | ijkli,kp,mnopm,mnopm | 80s |
|
||||
| c | m | cm,cm | 44.7s |
|
||||
| f | a | efghe,hj,ijkli,kp,mnopm,cm,abcda,abcda | 239.2s |
|
||||
| l | a | ijkli,kp,mnopm,cm,abcda,abcda | 157.1s |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 229.4 | 144.7 | 124.7 |
|
||||
| f | 229.4 | 0 | 124.7 | 144.7 |
|
||||
| l | 144.7 | 124.7 | 0 | 60 |
|
||||
| o | 124.7 | 144.7 | 60 | 0 |
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 239.2 | 157.1 | 137.1 |
|
||||
| f | 239.2 | 0 | 136.7 | 162.1 |
|
||||
| l | 157.1 | 136.7 | 0 | 80 |
|
||||
| o | 137.1 | 162.1 | 80 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 229.4 | 144.7 | 124.7 |
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 239.2 | 157.1 | 137.1 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| f | 229.4 |
|
||||
| l | 144.7 |
|
||||
| o | 124.7 |
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| f | 239.2 |
|
||||
| l | 157.1 |
|
||||
| o | 137.1 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 229.4 | 144.7 | 124.7 |
|
||||
| o | 124.7 | 144.7 | 60 | 0 |
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 239.2 | 157.1 | 137.1 |
|
||||
| o | 137.1 | 162.1 | 80 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | o |
|
||||
| a | 0 | 124.7 |
|
||||
| f | 229.4 | 144.7 |
|
||||
| l | 144.7 | 60 |
|
||||
| o | 124.7 | 0 |
|
||||
| a | 0 | 137.1 |
|
||||
| f | 239.2 | 162.1 |
|
||||
| l | 157.1 | 80 |
|
||||
| o | 137.1 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
|
||||
| f | 2383.7 | 0 | 1293.3 | 1617.3 |
|
||||
| l | 1566.9 | 1293.3 | 0 | 800.5 |
|
||||
| o | 1366.8 | 1617.3 | 800.5 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| f | 2383.7 |
|
||||
| l | 1566.9 |
|
||||
| o | 1366.8 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
|
||||
| f | 2383.7 | 0 | 1293.3 | 1617.3 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | o |
|
||||
| a | 0 | 1366.8 |
|
||||
| f | 2383.7 | 1617.3 |
|
||||
| l | 1566.9 | 800.5 |
|
||||
| o | 1366.8 | 0 |
|
||||
|
||||
Scenario: Testbot - Multi level routing: horizontal road
|
||||
Given the node map
|
||||
|
||||
@@ -182,4 +182,4 @@ Feature: Snap start/end point to the nearest way
|
||||
| x | m | xe,xe |
|
||||
| x | n | xf,xf |
|
||||
| x | o | xg,xg |
|
||||
| x | p | xh,xh |
|
||||
| x | p | xh,xh |
|
||||
@@ -54,7 +54,7 @@ Feature: Traffic - speeds
|
||||
| a | d | ad,ad | 27 km/h | 1275.7,0 | 1 |
|
||||
| d | c | dc,dc | 36 km/h | 956.8,0 | 0 |
|
||||
| g | b | fb,fb | 36 km/h | 164.7,0 | 0 |
|
||||
| a | g | ad,df,fb,fb | 30 km/h | 1275.7,487.5,304.7,0 | 1:0:0 |
|
||||
| a | g | ad,df,fb,fb | 30 km/h | 1295.7,487.5,304.7,0 | 1:0:0 |
|
||||
|
||||
|
||||
Scenario: Weighting based on speed file weights, ETA based on file durations
|
||||
|
||||
@@ -18,6 +18,53 @@ Feature: Via points
|
||||
| waypoints | route |
|
||||
| a,b,c | abc,abc,abc,abc |
|
||||
|
||||
Scenario: Simple via point with waypoints collapsing
|
||||
Given the node map
|
||||
"""
|
||||
a
|
||||
|
||||
b 1c d
|
||||
2
|
||||
|
||||
e
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ace |
|
||||
| bcd |
|
||||
|
||||
Given the query options
|
||||
| waypoints | 0;2 |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| b,1,e | bcd,ace,ace | depart,turn right,arrive |
|
||||
| b,2,e | bcd,ace,ace | depart,turn right,arrive |
|
||||
|
||||
Scenario: Simple via point with waypoints collapsing
|
||||
Given the node map
|
||||
"""
|
||||
a 2 b
|
||||
|
||||
c d
|
||||
1 3
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bd |
|
||||
| cd |
|
||||
| ac |
|
||||
|
||||
Given the query options
|
||||
| waypoints | 0;2 |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| 1,2,3 | cd,ac,ab,bd,cd | depart,new name right,new name right,new name right,arrive |
|
||||
|
||||
Scenario: Simple via point with core factor
|
||||
Given the contract extra arguments "--core 0.8"
|
||||
Given the node map
|
||||
|
||||
@@ -12,23 +12,26 @@ namespace contractor
|
||||
struct ContractorEdgeData
|
||||
{
|
||||
ContractorEdgeData()
|
||||
: weight(0), duration(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0)
|
||||
: weight(0), duration(0), distance(0), id(0), originalEdges(0), shortcut(0), forward(0),
|
||||
backward(0)
|
||||
{
|
||||
}
|
||||
ContractorEdgeData(EdgeWeight weight,
|
||||
EdgeWeight duration,
|
||||
EdgeDistance distance,
|
||||
unsigned original_edges,
|
||||
unsigned id,
|
||||
bool shortcut,
|
||||
bool forward,
|
||||
bool backward)
|
||||
: weight(weight), duration(duration), id(id),
|
||||
: weight(weight), duration(duration), distance(distance), id(id),
|
||||
originalEdges(std::min((1u << 29) - 1u, original_edges)), shortcut(shortcut),
|
||||
forward(forward), backward(backward)
|
||||
{
|
||||
}
|
||||
EdgeWeight weight;
|
||||
EdgeWeight duration;
|
||||
EdgeDistance distance;
|
||||
unsigned id;
|
||||
unsigned originalEdges : 29;
|
||||
bool shortcut : 1;
|
||||
|
||||
@@ -41,6 +41,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
|
||||
input_edge.target,
|
||||
std::max(input_edge.data.weight, 1),
|
||||
input_edge.data.duration,
|
||||
input_edge.data.distance,
|
||||
1,
|
||||
input_edge.data.turn_id,
|
||||
false,
|
||||
@@ -51,6 +52,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
|
||||
input_edge.source,
|
||||
std::max(input_edge.data.weight, 1),
|
||||
input_edge.data.duration,
|
||||
input_edge.data.distance,
|
||||
1,
|
||||
input_edge.data.turn_id,
|
||||
false,
|
||||
@@ -82,6 +84,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
|
||||
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
|
||||
forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT;
|
||||
forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION;
|
||||
forward_edge.data.distance = reverse_edge.data.distance = MAXIMAL_EDGE_DISTANCE;
|
||||
// remove parallel edges
|
||||
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
|
||||
{
|
||||
@@ -90,12 +93,16 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
|
||||
forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight);
|
||||
forward_edge.data.duration =
|
||||
std::min(edges[i].data.duration, forward_edge.data.duration);
|
||||
forward_edge.data.distance =
|
||||
std::min(edges[i].data.distance, forward_edge.data.distance);
|
||||
}
|
||||
if (edges[i].data.backward)
|
||||
{
|
||||
reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight);
|
||||
reverse_edge.data.duration =
|
||||
std::min(edges[i].data.duration, reverse_edge.data.duration);
|
||||
reverse_edge.data.distance =
|
||||
std::min(edges[i].data.distance, reverse_edge.data.distance);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
@@ -151,6 +158,7 @@ template <class Edge, typename GraphT> inline std::vector<Edge> toEdges(GraphT g
|
||||
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
|
||||
new_edge.data.weight = data.weight;
|
||||
new_edge.data.duration = data.duration;
|
||||
new_edge.data.distance = data.distance;
|
||||
new_edge.data.shortcut = data.shortcut;
|
||||
new_edge.data.turn_id = data.id;
|
||||
BOOST_ASSERT_MSG(new_edge.data.turn_id != INT_MAX, // 2^31
|
||||
|
||||
@@ -17,7 +17,8 @@ struct QueryEdge
|
||||
struct EdgeData
|
||||
{
|
||||
explicit EdgeData()
|
||||
: turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false)
|
||||
: turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false),
|
||||
distance(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -25,10 +26,11 @@ struct QueryEdge
|
||||
const bool shortcut,
|
||||
const EdgeWeight weight,
|
||||
const EdgeWeight duration,
|
||||
const EdgeDistance distance,
|
||||
const bool forward,
|
||||
const bool backward)
|
||||
: turn_id(turn_id), shortcut(shortcut), weight(weight), duration(duration),
|
||||
forward(forward), backward(backward)
|
||||
forward(forward), backward(backward), distance(distance)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -40,6 +42,7 @@ struct QueryEdge
|
||||
turn_id = other.id;
|
||||
forward = other.forward;
|
||||
backward = other.backward;
|
||||
distance = other.distance;
|
||||
}
|
||||
// this ID is either the middle node of the shortcut, or the ID of the edge based node (node
|
||||
// based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle
|
||||
@@ -50,6 +53,7 @@ struct QueryEdge
|
||||
EdgeWeight duration : 30;
|
||||
std::uint32_t forward : 1;
|
||||
std::uint32_t backward : 1;
|
||||
EdgeDistance distance;
|
||||
} data;
|
||||
|
||||
QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
|
||||
@@ -69,7 +73,8 @@ struct QueryEdge
|
||||
return (source == right.source && target == right.target &&
|
||||
data.weight == right.data.weight && data.duration == right.data.duration &&
|
||||
data.shortcut == right.data.shortcut && data.forward == right.data.forward &&
|
||||
data.backward == right.data.backward && data.turn_id == right.data.turn_id);
|
||||
data.backward == right.data.backward && data.turn_id == right.data.turn_id &&
|
||||
data.distance == right.data.distance);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ class CellCustomizer
|
||||
{
|
||||
bool from_clique;
|
||||
EdgeDuration duration;
|
||||
EdgeDistance distance;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -60,7 +61,7 @@ class CellCustomizer
|
||||
}
|
||||
}
|
||||
heap.Clear();
|
||||
heap.Insert(source, 0, {false, 0});
|
||||
heap.Insert(source, 0, {false, 0, 0});
|
||||
|
||||
// explore search space
|
||||
while (!heap.Empty() && !destinations_set.empty())
|
||||
@@ -68,8 +69,18 @@ class CellCustomizer
|
||||
const NodeID node = heap.DeleteMin();
|
||||
const EdgeWeight weight = heap.GetKey(node);
|
||||
const EdgeDuration duration = heap.GetData(node).duration;
|
||||
const EdgeDistance distance = heap.GetData(node).distance;
|
||||
|
||||
RelaxNode(graph, cells, allowed_nodes, metric, heap, level, node, weight, duration);
|
||||
RelaxNode(graph,
|
||||
cells,
|
||||
allowed_nodes,
|
||||
metric,
|
||||
heap,
|
||||
level,
|
||||
node,
|
||||
weight,
|
||||
duration,
|
||||
distance);
|
||||
|
||||
destinations_set.erase(node);
|
||||
}
|
||||
@@ -77,21 +88,27 @@ class CellCustomizer
|
||||
// fill a map of destination nodes to placeholder pointers
|
||||
auto weights = cell.GetOutWeight(source);
|
||||
auto durations = cell.GetOutDuration(source);
|
||||
auto distances = cell.GetOutDistance(source);
|
||||
for (auto &destination : destinations)
|
||||
{
|
||||
BOOST_ASSERT(!weights.empty());
|
||||
BOOST_ASSERT(!durations.empty());
|
||||
BOOST_ASSERT(!distances.empty());
|
||||
|
||||
const bool inserted = heap.WasInserted(destination);
|
||||
weights.front() = inserted ? heap.GetKey(destination) : INVALID_EDGE_WEIGHT;
|
||||
durations.front() =
|
||||
inserted ? heap.GetData(destination).duration : MAXIMAL_EDGE_DURATION;
|
||||
distances.front() =
|
||||
inserted ? heap.GetData(destination).distance : INVALID_EDGE_DISTANCE;
|
||||
|
||||
weights.advance_begin(1);
|
||||
durations.advance_begin(1);
|
||||
distances.advance_begin(1);
|
||||
}
|
||||
BOOST_ASSERT(weights.empty());
|
||||
BOOST_ASSERT(durations.empty());
|
||||
BOOST_ASSERT(distances.empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +145,8 @@ class CellCustomizer
|
||||
LevelID level,
|
||||
NodeID node,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration) const
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance) const
|
||||
{
|
||||
auto first_level = level == 1;
|
||||
BOOST_ASSERT(heap.WasInserted(node));
|
||||
@@ -149,6 +167,7 @@ class CellCustomizer
|
||||
auto subcell = cells.GetCell(metric, level - 1, subcell_id);
|
||||
auto subcell_destination = subcell.GetDestinationNodes().begin();
|
||||
auto subcell_duration = subcell.GetOutDuration(node).begin();
|
||||
auto subcell_distance = subcell.GetOutDistance(node).begin();
|
||||
for (auto subcell_weight : subcell.GetOutWeight(node))
|
||||
{
|
||||
if (subcell_weight != INVALID_EDGE_WEIGHT)
|
||||
@@ -161,20 +180,24 @@ class CellCustomizer
|
||||
|
||||
const EdgeWeight to_weight = weight + subcell_weight;
|
||||
const EdgeDuration to_duration = duration + *subcell_duration;
|
||||
const EdgeDistance to_distance = distance + *subcell_distance;
|
||||
if (!heap.WasInserted(to))
|
||||
{
|
||||
heap.Insert(to, to_weight, {true, to_duration});
|
||||
heap.Insert(to, to_weight, {true, to_duration, to_distance});
|
||||
}
|
||||
else if (std::tie(to_weight, to_duration) <
|
||||
std::tie(heap.GetKey(to), heap.GetData(to).duration))
|
||||
else if (std::tie(to_weight, to_duration, to_distance) <
|
||||
std::tie(heap.GetKey(to),
|
||||
heap.GetData(to).duration,
|
||||
heap.GetData(to).distance))
|
||||
{
|
||||
heap.DecreaseKey(to, to_weight);
|
||||
heap.GetData(to) = {true, to_duration};
|
||||
heap.GetData(to) = {true, to_duration, to_distance};
|
||||
}
|
||||
}
|
||||
|
||||
++subcell_destination;
|
||||
++subcell_duration;
|
||||
++subcell_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,15 +218,18 @@ class CellCustomizer
|
||||
{
|
||||
const EdgeWeight to_weight = weight + data.weight;
|
||||
const EdgeDuration to_duration = duration + data.duration;
|
||||
const EdgeDistance to_distance = distance + data.distance;
|
||||
if (!heap.WasInserted(to))
|
||||
{
|
||||
heap.Insert(to, to_weight, {false, duration + data.duration});
|
||||
heap.Insert(
|
||||
to, to_weight, {false, duration + data.duration, distance + data.distance});
|
||||
}
|
||||
else if (std::tie(to_weight, to_duration) <
|
||||
std::tie(heap.GetKey(to), heap.GetData(to).duration))
|
||||
else if (std::tie(to_weight, to_duration, to_distance) <
|
||||
std::tie(
|
||||
heap.GetKey(to), heap.GetData(to).duration, heap.GetData(to).distance))
|
||||
{
|
||||
heap.DecreaseKey(to, to_weight);
|
||||
heap.GetData(to) = {false, to_duration};
|
||||
heap.GetData(to) = {false, to_duration, to_distance};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ template <storage::Ownership Ownership> struct CellMetricImpl
|
||||
|
||||
Vector<EdgeWeight> weights;
|
||||
Vector<EdgeDuration> durations;
|
||||
Vector<EdgeDistance> distances;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ struct CustomizationConfig final : storage::IOConfig
|
||||
".osrm.partition",
|
||||
".osrm.cells",
|
||||
".osrm.ebg_nodes",
|
||||
".osrm.properties"},
|
||||
".osrm.properties",
|
||||
".osrm.enw"},
|
||||
{},
|
||||
{".osrm.cell_metrics", ".osrm.mldgr"}),
|
||||
requested_num_threads(0)
|
||||
|
||||
@@ -16,28 +16,116 @@ namespace osrm
|
||||
namespace customizer
|
||||
{
|
||||
|
||||
using EdgeBasedGraphEdgeData = partitioner::EdgeBasedGraphEdgeData;
|
||||
|
||||
struct MultiLevelEdgeBasedGraph
|
||||
: public partitioner::MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::Container>
|
||||
struct EdgeBasedGraphEdgeData
|
||||
{
|
||||
using Base =
|
||||
partitioner::MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::Container>;
|
||||
using Base::Base;
|
||||
NodeID turn_id; // ID of the edge based node (node based edge)
|
||||
};
|
||||
|
||||
struct MultiLevelEdgeBasedGraphView
|
||||
: public partitioner::MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::View>
|
||||
template <typename EdgeDataT, storage::Ownership Ownership> class MultiLevelGraph;
|
||||
|
||||
namespace serialization
|
||||
{
|
||||
using Base = partitioner::MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::View>;
|
||||
using Base::Base;
|
||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||
void read(storage::tar::FileReader &reader,
|
||||
const std::string &name,
|
||||
MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||
|
||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||
void write(storage::tar::FileWriter &writer,
|
||||
const std::string &name,
|
||||
const MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||
}
|
||||
|
||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||
class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership>
|
||||
{
|
||||
private:
|
||||
using SuperT = partitioner::MultiLevelGraph<EdgeDataT, Ownership>;
|
||||
using PartitionerGraphT = partitioner::MultiLevelGraph<partitioner::EdgeBasedGraphEdgeData,
|
||||
storage::Ownership::Container>;
|
||||
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
|
||||
|
||||
public:
|
||||
using NodeArrayEntry = typename SuperT::NodeArrayEntry;
|
||||
using EdgeArrayEntry = typename SuperT::EdgeArrayEntry;
|
||||
using EdgeOffset = typename SuperT::EdgeOffset;
|
||||
|
||||
MultiLevelGraph() = default;
|
||||
MultiLevelGraph(MultiLevelGraph &&) = default;
|
||||
MultiLevelGraph(const MultiLevelGraph &) = default;
|
||||
MultiLevelGraph &operator=(MultiLevelGraph &&) = default;
|
||||
MultiLevelGraph &operator=(const MultiLevelGraph &) = default;
|
||||
|
||||
MultiLevelGraph(PartitionerGraphT &&graph,
|
||||
Vector<EdgeWeight> node_weights_,
|
||||
Vector<EdgeDuration> node_durations_,
|
||||
Vector<EdgeDistance> node_distances_)
|
||||
: node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
|
||||
node_distances(std::move(node_distances_))
|
||||
{
|
||||
util::ViewOrVector<PartitionerGraphT::EdgeArrayEntry, storage::Ownership::Container>
|
||||
original_edge_array;
|
||||
|
||||
std::tie(SuperT::node_array,
|
||||
original_edge_array,
|
||||
SuperT::node_to_edge_offset,
|
||||
SuperT::connectivity_checksum) = std::move(graph).data();
|
||||
|
||||
SuperT::edge_array.reserve(original_edge_array.size());
|
||||
for (const auto &edge : original_edge_array)
|
||||
{
|
||||
SuperT::edge_array.push_back({edge.target, {edge.data.turn_id}});
|
||||
is_forward_edge.push_back(edge.data.forward);
|
||||
is_backward_edge.push_back(edge.data.backward);
|
||||
}
|
||||
}
|
||||
|
||||
MultiLevelGraph(Vector<NodeArrayEntry> node_array_,
|
||||
Vector<EdgeArrayEntry> edge_array_,
|
||||
Vector<EdgeOffset> node_to_edge_offset_,
|
||||
Vector<EdgeWeight> node_weights_,
|
||||
Vector<EdgeDuration> node_durations_,
|
||||
Vector<EdgeDistance> node_distances_,
|
||||
Vector<bool> is_forward_edge_,
|
||||
Vector<bool> is_backward_edge_)
|
||||
: SuperT(std::move(node_array_), std::move(edge_array_), std::move(node_to_edge_offset_)),
|
||||
node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
|
||||
node_distances(std::move(node_distances_)), is_forward_edge(is_forward_edge_),
|
||||
is_backward_edge(is_backward_edge_)
|
||||
{
|
||||
}
|
||||
|
||||
EdgeWeight GetNodeWeight(NodeID node) const { return node_weights[node]; }
|
||||
|
||||
EdgeWeight GetNodeDuration(NodeID node) const { return node_durations[node]; }
|
||||
|
||||
EdgeDistance GetNodeDistance(NodeID node) const { return node_distances[node]; }
|
||||
|
||||
bool IsForwardEdge(EdgeID edge) const { return is_forward_edge[edge]; }
|
||||
|
||||
bool IsBackwardEdge(EdgeID edge) const { return is_backward_edge[edge]; }
|
||||
|
||||
friend void
|
||||
serialization::read<EdgeDataT, Ownership>(storage::tar::FileReader &reader,
|
||||
const std::string &name,
|
||||
MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||
friend void
|
||||
serialization::write<EdgeDataT, Ownership>(storage::tar::FileWriter &writer,
|
||||
const std::string &name,
|
||||
const MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||
|
||||
protected:
|
||||
Vector<EdgeWeight> node_weights;
|
||||
Vector<EdgeDuration> node_durations;
|
||||
Vector<EdgeDistance> node_distances;
|
||||
Vector<bool> is_forward_edge;
|
||||
Vector<bool> is_backward_edge;
|
||||
};
|
||||
|
||||
struct StaticEdgeBasedGraphEdge : MultiLevelEdgeBasedGraph::InputEdge
|
||||
{
|
||||
using Base = MultiLevelEdgeBasedGraph::InputEdge;
|
||||
using Base::Base;
|
||||
};
|
||||
using MultiLevelEdgeBasedGraph =
|
||||
MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::Container>;
|
||||
using MultiLevelEdgeBasedGraphView =
|
||||
MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::View>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,39 @@ writeCellMetrics(const boost::filesystem::path &path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reads .osrm.mldgr file
|
||||
template <typename MultiLevelGraphT>
|
||||
inline void readGraph(const boost::filesystem::path &path,
|
||||
MultiLevelGraphT &graph,
|
||||
std::uint32_t &connectivity_checksum)
|
||||
{
|
||||
static_assert(std::is_same<customizer::MultiLevelEdgeBasedGraphView, MultiLevelGraphT>::value ||
|
||||
std::is_same<customizer::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value,
|
||||
"");
|
||||
|
||||
storage::tar::FileReader reader{path, storage::tar::FileReader::VerifyFingerprint};
|
||||
|
||||
reader.ReadInto("/mld/connectivity_checksum", connectivity_checksum);
|
||||
serialization::read(reader, "/mld/multilevelgraph", graph);
|
||||
}
|
||||
|
||||
// writes .osrm.mldgr file
|
||||
template <typename MultiLevelGraphT>
|
||||
inline void writeGraph(const boost::filesystem::path &path,
|
||||
const MultiLevelGraphT &graph,
|
||||
const std::uint32_t connectivity_checksum)
|
||||
{
|
||||
static_assert(std::is_same<customizer::MultiLevelEdgeBasedGraphView, MultiLevelGraphT>::value ||
|
||||
std::is_same<customizer::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value,
|
||||
"");
|
||||
|
||||
storage::tar::FileWriter writer{path, storage::tar::FileWriter::GenerateFingerprint};
|
||||
|
||||
writer.WriteElementCount64("/mld/connectivity_checksum", 1);
|
||||
writer.WriteFrom("/mld/connectivity_checksum", connectivity_checksum);
|
||||
serialization::write(writer, "/mld/multilevelgraph", graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef OSRM_CUSTOMIZER_SERIALIZATION_HPP
|
||||
#define OSRM_CUSTOMIZER_SERIALIZATION_HPP
|
||||
|
||||
#include "customizer/edge_based_graph.hpp"
|
||||
|
||||
#include "partitioner/cell_storage.hpp"
|
||||
|
||||
#include "storage/serialization.hpp"
|
||||
@@ -21,6 +23,7 @@ inline void read(storage::tar::FileReader &reader,
|
||||
{
|
||||
storage::serialization::read(reader, name + "/weights", metric.weights);
|
||||
storage::serialization::read(reader, name + "/durations", metric.durations);
|
||||
storage::serialization::read(reader, name + "/distances", metric.distances);
|
||||
}
|
||||
|
||||
template <storage::Ownership Ownership>
|
||||
@@ -30,6 +33,37 @@ inline void write(storage::tar::FileWriter &writer,
|
||||
{
|
||||
storage::serialization::write(writer, name + "/weights", metric.weights);
|
||||
storage::serialization::write(writer, name + "/durations", metric.durations);
|
||||
storage::serialization::write(writer, name + "/distances", metric.distances);
|
||||
}
|
||||
|
||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||
inline void read(storage::tar::FileReader &reader,
|
||||
const std::string &name,
|
||||
MultiLevelGraph<EdgeDataT, Ownership> &graph)
|
||||
{
|
||||
storage::serialization::read(reader, name + "/node_array", graph.node_array);
|
||||
storage::serialization::read(reader, name + "/node_weights", graph.node_weights);
|
||||
storage::serialization::read(reader, name + "/node_durations", graph.node_durations);
|
||||
storage::serialization::read(reader, name + "/node_distances", graph.node_distances);
|
||||
storage::serialization::read(reader, name + "/edge_array", graph.edge_array);
|
||||
storage::serialization::read(reader, name + "/is_forward_edge", graph.is_forward_edge);
|
||||
storage::serialization::read(reader, name + "/is_backward_edge", graph.is_backward_edge);
|
||||
storage::serialization::read(reader, name + "/node_to_edge_offset", graph.node_to_edge_offset);
|
||||
}
|
||||
|
||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||
inline void write(storage::tar::FileWriter &writer,
|
||||
const std::string &name,
|
||||
const MultiLevelGraph<EdgeDataT, Ownership> &graph)
|
||||
{
|
||||
storage::serialization::write(writer, name + "/node_array", graph.node_array);
|
||||
storage::serialization::write(writer, name + "/node_weights", graph.node_weights);
|
||||
storage::serialization::write(writer, name + "/node_durations", graph.node_durations);
|
||||
storage::serialization::write(writer, name + "/node_distances", graph.node_distances);
|
||||
storage::serialization::write(writer, name + "/edge_array", graph.edge_array);
|
||||
storage::serialization::write(writer, name + "/is_forward_edge", graph.is_forward_edge);
|
||||
storage::serialization::write(writer, name + "/is_backward_edge", graph.is_backward_edge);
|
||||
storage::serialization::write(writer, name + "/node_to_edge_offset", graph.node_to_edge_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ template <typename AlgorithmT> struct HasMapMatching final : std::false_type
|
||||
template <typename AlgorithmT> struct HasManyToManySearch final : std::false_type
|
||||
{
|
||||
};
|
||||
template <typename AlgorithmT> struct SupportsDistanceAnnotationType final : std::false_type
|
||||
{
|
||||
};
|
||||
template <typename AlgorithmT> struct HasGetTileTurns final : std::false_type
|
||||
{
|
||||
};
|
||||
@@ -73,6 +76,9 @@ template <> struct HasMapMatching<ch::Algorithm> final : std::true_type
|
||||
template <> struct HasManyToManySearch<ch::Algorithm> final : std::true_type
|
||||
{
|
||||
};
|
||||
template <> struct SupportsDistanceAnnotationType<ch::Algorithm> final : std::true_type
|
||||
{
|
||||
};
|
||||
template <> struct HasGetTileTurns<ch::Algorithm> final : std::true_type
|
||||
{
|
||||
};
|
||||
@@ -96,6 +102,9 @@ template <> struct HasMapMatching<mld::Algorithm> final : std::true_type
|
||||
template <> struct HasManyToManySearch<mld::Algorithm> final : std::true_type
|
||||
{
|
||||
};
|
||||
template <> struct SupportsDistanceAnnotationType<mld::Algorithm> final : std::false_type
|
||||
{
|
||||
};
|
||||
template <> struct HasGetTileTurns<mld::Algorithm> final : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "engine/api/json_factory.hpp"
|
||||
#include "engine/hint.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/range/algorithm/transform.hpp>
|
||||
@@ -53,6 +54,8 @@ class BaseAPI
|
||||
// TODO: check forward/reverse
|
||||
return json::makeWaypoint(
|
||||
phantom.location,
|
||||
util::coordinate_calculation::fccApproximateDistance(phantom.location,
|
||||
phantom.input_location),
|
||||
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string(),
|
||||
Hint{phantom, facade.GetCheckSum()});
|
||||
}
|
||||
@@ -61,6 +64,8 @@ class BaseAPI
|
||||
// TODO: check forward/reverse
|
||||
return json::makeWaypoint(
|
||||
phantom.location,
|
||||
util::coordinate_calculation::fccApproximateDistance(phantom.location,
|
||||
phantom.input_location),
|
||||
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))
|
||||
.to_string());
|
||||
}
|
||||
|
||||
@@ -63,6 +63,13 @@ namespace api
|
||||
*/
|
||||
struct BaseParameters
|
||||
{
|
||||
|
||||
enum class SnappingType
|
||||
{
|
||||
Default,
|
||||
Any
|
||||
};
|
||||
|
||||
std::vector<util::Coordinate> coordinates;
|
||||
std::vector<boost::optional<Hint>> hints;
|
||||
std::vector<boost::optional<double>> radiuses;
|
||||
@@ -73,15 +80,19 @@ struct BaseParameters
|
||||
// Adds hints to response which can be included in subsequent requests, see `hints` above.
|
||||
bool generate_hints = true;
|
||||
|
||||
SnappingType snapping = SnappingType::Default;
|
||||
|
||||
BaseParameters(const std::vector<util::Coordinate> coordinates_ = {},
|
||||
const std::vector<boost::optional<Hint>> hints_ = {},
|
||||
std::vector<boost::optional<double>> radiuses_ = {},
|
||||
std::vector<boost::optional<Bearing>> bearings_ = {},
|
||||
std::vector<boost::optional<Approach>> approaches_ = {},
|
||||
bool generate_hints_ = true,
|
||||
std::vector<std::string> exclude = {})
|
||||
std::vector<std::string> exclude = {},
|
||||
const SnappingType snapping_ = SnappingType::Default)
|
||||
: coordinates(coordinates_), hints(hints_), radiuses(radiuses_), bearings(bearings_),
|
||||
approaches(approaches_), exclude(std::move(exclude)), generate_hints(generate_hints_)
|
||||
approaches(approaches_), exclude(std::move(exclude)), generate_hints(generate_hints_),
|
||||
snapping(snapping_)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace json
|
||||
namespace detail
|
||||
{
|
||||
|
||||
util::json::Array coordinateToLonLat(const util::Coordinate coordinate);
|
||||
util::json::Array coordinateToLonLat(const util::Coordinate &coordinate);
|
||||
|
||||
/**
|
||||
* Ensures that a bearing value is a whole number, and clamped to the range 0-359
|
||||
@@ -86,11 +86,14 @@ util::json::Object makeRoute(const guidance::Route &route,
|
||||
const char *weight_name);
|
||||
|
||||
// Creates a Waypoint without Hint, see the Hint overload below
|
||||
util::json::Object makeWaypoint(const util::Coordinate location, std::string name);
|
||||
util::json::Object
|
||||
makeWaypoint(const util::Coordinate &location, const double &distance, std::string name);
|
||||
|
||||
// Creates a Waypoint with Hint, see the overload above when Hint is not needed
|
||||
util::json::Object
|
||||
makeWaypoint(const util::Coordinate location, std::string name, const Hint &hint);
|
||||
util::json::Object makeWaypoint(const util::Coordinate &location,
|
||||
const double &distance,
|
||||
std::string name,
|
||||
const Hint &hint);
|
||||
|
||||
util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps);
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ struct MatchParameters : public RouteParameters
|
||||
RouteParameters::GeometriesType::Polyline,
|
||||
RouteParameters::OverviewType::Simplified,
|
||||
{}),
|
||||
gaps(GapsType::Split), tidy(false), waypoints()
|
||||
gaps(GapsType::Split), tidy(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -79,24 +79,19 @@ struct MatchParameters : public RouteParameters
|
||||
bool tidy_,
|
||||
std::vector<std::size_t> waypoints_,
|
||||
Args... args_)
|
||||
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)},
|
||||
gaps(gaps_), tidy(tidy_), waypoints{std::move(waypoints_)}
|
||||
: RouteParameters{std::forward<Args>(args_)..., waypoints_},
|
||||
timestamps{std::move(timestamps_)}, gaps(gaps_), tidy(tidy_)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<unsigned> timestamps;
|
||||
GapsType gaps;
|
||||
bool tidy;
|
||||
std::vector<std::size_t> waypoints;
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
const auto valid_waypoints =
|
||||
std::all_of(waypoints.begin(), waypoints.end(), [this](const auto &w) {
|
||||
return w < coordinates.size();
|
||||
});
|
||||
return RouteParameters::IsValid() &&
|
||||
(timestamps.empty() || timestamps.size() == coordinates.size()) && valid_waypoints;
|
||||
(timestamps.empty() || timestamps.size() == coordinates.size());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ class NearestAPI final : public BaseAPI
|
||||
[this](const PhantomNodeWithDistance &phantom_with_distance) {
|
||||
auto &phantom_node = phantom_with_distance.phantom_node;
|
||||
auto waypoint = MakeWaypoint(phantom_node);
|
||||
waypoint.values["distance"] = phantom_with_distance.distance;
|
||||
|
||||
util::json::Array nodes;
|
||||
|
||||
|
||||
@@ -44,8 +44,11 @@ class RouteAPI : public BaseAPI
|
||||
{
|
||||
}
|
||||
|
||||
void MakeResponse(const InternalManyRoutesResult &raw_routes,
|
||||
util::json::Object &response) const
|
||||
void
|
||||
MakeResponse(const InternalManyRoutesResult &raw_routes,
|
||||
const std::vector<PhantomNodes>
|
||||
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter
|
||||
util::json::Object &response) const
|
||||
{
|
||||
BOOST_ASSERT(!raw_routes.routes.empty());
|
||||
|
||||
@@ -62,10 +65,14 @@ class RouteAPI : public BaseAPI
|
||||
route.target_traversed_in_reverse));
|
||||
}
|
||||
|
||||
response.values["waypoints"] =
|
||||
BaseAPI::MakeWaypoints(raw_routes.routes[0].segment_end_coordinates);
|
||||
response.values["waypoints"] = BaseAPI::MakeWaypoints(all_start_end_points);
|
||||
response.values["routes"] = std::move(jsRoutes);
|
||||
response.values["code"] = "Ok";
|
||||
auto data_timestamp = facade.GetTimestamp();
|
||||
if (!data_timestamp.empty())
|
||||
{
|
||||
response.values["data_version"] = data_timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -98,7 +98,8 @@ struct RouteParameters : public BaseParameters
|
||||
annotations_type{AnnotationsType::None},
|
||||
geometries{geometries_},
|
||||
overview{overview_},
|
||||
continue_straight{continue_straight_}
|
||||
continue_straight{continue_straight_},
|
||||
waypoints()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -114,7 +115,9 @@ struct RouteParameters : public BaseParameters
|
||||
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
|
||||
number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_},
|
||||
annotations_type{annotations_ ? AnnotationsType::All : AnnotationsType::None},
|
||||
geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_}
|
||||
geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_},
|
||||
waypoints()
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
@@ -131,7 +134,43 @@ struct RouteParameters : public BaseParameters
|
||||
number_of_alternatives{alternatives_ ? 1u : 0u},
|
||||
annotations{annotations_ == AnnotationsType::None ? false : true},
|
||||
annotations_type{annotations_}, geometries{geometries_}, overview{overview_},
|
||||
continue_straight{continue_straight_}
|
||||
continue_straight{continue_straight_}, waypoints()
|
||||
{
|
||||
}
|
||||
|
||||
// RouteParameters constructor adding the `waypoints` parameter
|
||||
template <typename... Args>
|
||||
RouteParameters(const bool steps_,
|
||||
const bool alternatives_,
|
||||
const bool annotations_,
|
||||
const GeometriesType geometries_,
|
||||
const OverviewType overview_,
|
||||
const boost::optional<bool> continue_straight_,
|
||||
std::vector<std::size_t> waypoints_,
|
||||
const Args... args_)
|
||||
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
|
||||
number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_},
|
||||
annotations_type{annotations_ ? AnnotationsType::All : AnnotationsType::None},
|
||||
geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_},
|
||||
waypoints{waypoints_}
|
||||
{
|
||||
}
|
||||
|
||||
// RouteParameters constructor adding the `waypoints` parameter
|
||||
template <typename... Args>
|
||||
RouteParameters(const bool steps_,
|
||||
const bool alternatives_,
|
||||
const AnnotationsType annotations_,
|
||||
const GeometriesType geometries_,
|
||||
const OverviewType overview_,
|
||||
const boost::optional<bool> continue_straight_,
|
||||
std::vector<std::size_t> waypoints_,
|
||||
Args... args_)
|
||||
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
|
||||
number_of_alternatives{alternatives_ ? 1u : 0u},
|
||||
annotations{annotations_ == AnnotationsType::None ? false : true},
|
||||
annotations_type{annotations_}, geometries{geometries_}, overview{overview_},
|
||||
continue_straight{continue_straight_}, waypoints{waypoints_}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -144,12 +183,17 @@ struct RouteParameters : public BaseParameters
|
||||
GeometriesType geometries = GeometriesType::Polyline;
|
||||
OverviewType overview = OverviewType::Simplified;
|
||||
boost::optional<bool> continue_straight;
|
||||
std::vector<std::size_t> waypoints;
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
const auto coordinates_ok = coordinates.size() >= 2;
|
||||
const auto base_params_ok = BaseParameters::IsValid();
|
||||
return coordinates_ok && base_params_ok;
|
||||
const auto valid_waypoints =
|
||||
std::all_of(waypoints.begin(), waypoints.end(), [this](const auto &w) {
|
||||
return w < coordinates.size();
|
||||
});
|
||||
return coordinates_ok && base_params_ok && valid_waypoints;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -173,8 +217,8 @@ inline RouteParameters::AnnotationsType operator|=(RouteParameters::AnnotationsT
|
||||
{
|
||||
return lhs = lhs | rhs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // ns api
|
||||
} // ns engine
|
||||
} // ns osrm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,14 +31,25 @@ namespace api
|
||||
class TableAPI final : public BaseAPI
|
||||
{
|
||||
public:
|
||||
struct TableCellRef
|
||||
{
|
||||
TableCellRef(const std::size_t &row, const std::size_t &column) : row{row}, column{column}
|
||||
{
|
||||
}
|
||||
std::size_t row;
|
||||
std::size_t column;
|
||||
};
|
||||
|
||||
TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters ¶meters_)
|
||||
: BaseAPI(facade_, parameters_), parameters(parameters_)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void MakeResponse(const std::vector<EdgeWeight> &durations,
|
||||
const std::vector<PhantomNode> &phantoms,
|
||||
util::json::Object &response) const
|
||||
virtual void
|
||||
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
||||
const std::vector<PhantomNode> &phantoms,
|
||||
const std::vector<TableCellRef> &fallback_speed_cells,
|
||||
util::json::Object &response) const
|
||||
{
|
||||
auto number_of_sources = parameters.sources.size();
|
||||
auto number_of_destinations = parameters.destinations.size();
|
||||
@@ -64,8 +75,23 @@ class TableAPI final : public BaseAPI
|
||||
response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations);
|
||||
}
|
||||
|
||||
response.values["durations"] =
|
||||
MakeTable(durations, number_of_sources, number_of_destinations);
|
||||
if (parameters.annotations & TableParameters::AnnotationsType::Duration)
|
||||
{
|
||||
response.values["durations"] =
|
||||
MakeDurationTable(tables.first, number_of_sources, number_of_destinations);
|
||||
}
|
||||
|
||||
if (parameters.annotations & TableParameters::AnnotationsType::Distance)
|
||||
{
|
||||
response.values["distances"] =
|
||||
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations);
|
||||
}
|
||||
|
||||
if (parameters.fallback_speed != INVALID_FALLBACK_SPEED && parameters.fallback_speed > 0)
|
||||
{
|
||||
response.values["fallback_speed_cells"] = MakeEstimatesTable(fallback_speed_cells);
|
||||
}
|
||||
|
||||
response.values["code"] = "Ok";
|
||||
}
|
||||
|
||||
@@ -97,9 +123,9 @@ class TableAPI final : public BaseAPI
|
||||
return json_waypoints;
|
||||
}
|
||||
|
||||
virtual util::json::Array MakeTable(const std::vector<EdgeWeight> &values,
|
||||
std::size_t number_of_rows,
|
||||
std::size_t number_of_columns) const
|
||||
virtual util::json::Array MakeDurationTable(const std::vector<EdgeWeight> &values,
|
||||
std::size_t number_of_rows,
|
||||
std::size_t number_of_columns) const
|
||||
{
|
||||
util::json::Array json_table;
|
||||
for (const auto row : util::irange<std::size_t>(0UL, number_of_rows))
|
||||
@@ -116,6 +142,7 @@ class TableAPI final : public BaseAPI
|
||||
{
|
||||
return util::json::Value(util::json::Null());
|
||||
}
|
||||
// division by 10 because the duration is in deciseconds (10s)
|
||||
return util::json::Value(util::json::Number(duration / 10.));
|
||||
});
|
||||
json_table.values.push_back(std::move(json_row));
|
||||
@@ -123,6 +150,48 @@ class TableAPI final : public BaseAPI
|
||||
return json_table;
|
||||
}
|
||||
|
||||
virtual util::json::Array MakeDistanceTable(const std::vector<EdgeDistance> &values,
|
||||
std::size_t number_of_rows,
|
||||
std::size_t number_of_columns) const
|
||||
{
|
||||
util::json::Array json_table;
|
||||
for (const auto row : util::irange<std::size_t>(0UL, number_of_rows))
|
||||
{
|
||||
util::json::Array json_row;
|
||||
auto row_begin_iterator = values.begin() + (row * number_of_columns);
|
||||
auto row_end_iterator = values.begin() + ((row + 1) * number_of_columns);
|
||||
json_row.values.resize(number_of_columns);
|
||||
std::transform(row_begin_iterator,
|
||||
row_end_iterator,
|
||||
json_row.values.begin(),
|
||||
[](const EdgeDistance distance) {
|
||||
if (distance == INVALID_EDGE_DISTANCE)
|
||||
{
|
||||
return util::json::Value(util::json::Null());
|
||||
}
|
||||
// round to single decimal place
|
||||
return util::json::Value(
|
||||
util::json::Number(std::round(distance * 10) / 10.));
|
||||
});
|
||||
json_table.values.push_back(std::move(json_row));
|
||||
}
|
||||
return json_table;
|
||||
}
|
||||
|
||||
virtual util::json::Array
|
||||
MakeEstimatesTable(const std::vector<TableCellRef> &fallback_speed_cells) const
|
||||
{
|
||||
util::json::Array json_table;
|
||||
std::for_each(
|
||||
fallback_speed_cells.begin(), fallback_speed_cells.end(), [&](const auto &cell) {
|
||||
util::json::Array row;
|
||||
row.values.push_back(util::json::Number(cell.row));
|
||||
row.values.push_back(util::json::Number(cell.column));
|
||||
json_table.values.push_back(std::move(row));
|
||||
});
|
||||
return json_table;
|
||||
}
|
||||
|
||||
const TableParameters ¶meters;
|
||||
};
|
||||
|
||||
|
||||
@@ -59,6 +59,27 @@ struct TableParameters : public BaseParameters
|
||||
{
|
||||
std::vector<std::size_t> sources;
|
||||
std::vector<std::size_t> destinations;
|
||||
double fallback_speed = INVALID_FALLBACK_SPEED;
|
||||
|
||||
enum class FallbackCoordinateType
|
||||
{
|
||||
Input = 0,
|
||||
Snapped = 1
|
||||
};
|
||||
|
||||
FallbackCoordinateType fallback_coordinate_type = FallbackCoordinateType::Input;
|
||||
|
||||
enum class AnnotationsType
|
||||
{
|
||||
None = 0,
|
||||
Duration = 0x01,
|
||||
Distance = 0x02,
|
||||
All = Duration | Distance
|
||||
};
|
||||
|
||||
AnnotationsType annotations = AnnotationsType::Duration;
|
||||
|
||||
double scale_factor = 1;
|
||||
|
||||
TableParameters() = default;
|
||||
template <typename... Args>
|
||||
@@ -70,6 +91,32 @@ struct TableParameters : public BaseParameters
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
TableParameters(std::vector<std::size_t> sources_,
|
||||
std::vector<std::size_t> destinations_,
|
||||
const AnnotationsType annotations_,
|
||||
Args... args_)
|
||||
: BaseParameters{std::forward<Args>(args_)...}, sources{std::move(sources_)},
|
||||
destinations{std::move(destinations_)}, annotations{annotations_}
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
TableParameters(std::vector<std::size_t> sources_,
|
||||
std::vector<std::size_t> destinations_,
|
||||
const AnnotationsType annotations_,
|
||||
double fallback_speed_,
|
||||
FallbackCoordinateType fallback_coordinate_type_,
|
||||
double scale_factor_,
|
||||
Args... args_)
|
||||
: BaseParameters{std::forward<Args>(args_)...}, sources{std::move(sources_)},
|
||||
destinations{std::move(destinations_)}, fallback_speed{fallback_speed_},
|
||||
fallback_coordinate_type{fallback_coordinate_type_}, annotations{annotations_},
|
||||
scale_factor{scale_factor_}
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
if (!BaseParameters::IsValid())
|
||||
@@ -79,16 +126,9 @@ struct TableParameters : public BaseParameters
|
||||
if (coordinates.size() < 2)
|
||||
return false;
|
||||
|
||||
// 1/ The user is able to specify duplicates in srcs and dsts, in that case it's her fault
|
||||
// 1/ The user is able to specify duplicates in srcs and dsts, in that case it's their fault
|
||||
|
||||
// 2/ len(srcs) and len(dsts) smaller or equal to len(locations)
|
||||
if (sources.size() > coordinates.size())
|
||||
return false;
|
||||
|
||||
if (destinations.size() > coordinates.size())
|
||||
return false;
|
||||
|
||||
// 3/ 0 <= index < len(locations)
|
||||
// 2/ 0 <= index < len(locations)
|
||||
const auto not_in_range = [this](const std::size_t x) { return x >= coordinates.size(); };
|
||||
|
||||
if (std::any_of(begin(sources), end(sources), not_in_range))
|
||||
@@ -97,9 +137,35 @@ struct TableParameters : public BaseParameters
|
||||
if (std::any_of(begin(destinations), end(destinations), not_in_range))
|
||||
return false;
|
||||
|
||||
if (fallback_speed <= 0)
|
||||
return false;
|
||||
|
||||
if (scale_factor <= 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
inline bool operator&(TableParameters::AnnotationsType lhs, TableParameters::AnnotationsType rhs)
|
||||
{
|
||||
return static_cast<bool>(
|
||||
static_cast<std::underlying_type_t<TableParameters::AnnotationsType>>(lhs) &
|
||||
static_cast<std::underlying_type_t<TableParameters::AnnotationsType>>(rhs));
|
||||
}
|
||||
|
||||
inline TableParameters::AnnotationsType operator|(TableParameters::AnnotationsType lhs,
|
||||
TableParameters::AnnotationsType rhs)
|
||||
{
|
||||
return (TableParameters::AnnotationsType)(
|
||||
static_cast<std::underlying_type_t<TableParameters::AnnotationsType>>(lhs) |
|
||||
static_cast<std::underlying_type_t<TableParameters::AnnotationsType>>(rhs));
|
||||
}
|
||||
|
||||
inline TableParameters::AnnotationsType &operator|=(TableParameters::AnnotationsType &lhs,
|
||||
TableParameters::AnnotationsType rhs)
|
||||
{
|
||||
return lhs = lhs | rhs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define OSRM_ENGINE_DATAFACADE_ALGORITHM_DATAFACADE_HPP
|
||||
|
||||
#include "contractor/query_edge.hpp"
|
||||
#include "customizer/edge_based_graph.hpp"
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "engine/algorithm.hpp"
|
||||
|
||||
@@ -59,7 +60,7 @@ template <> class AlgorithmDataFacade<CH>
|
||||
template <> class AlgorithmDataFacade<MLD>
|
||||
{
|
||||
public:
|
||||
using EdgeData = extractor::EdgeBasedEdge::EdgeData;
|
||||
using EdgeData = customizer::EdgeBasedGraphEdgeData;
|
||||
using EdgeRange = util::range<EdgeID>;
|
||||
|
||||
// search graph access
|
||||
@@ -71,12 +72,22 @@ template <> class AlgorithmDataFacade<MLD>
|
||||
|
||||
virtual unsigned GetOutDegree(const NodeID n) const = 0;
|
||||
|
||||
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
|
||||
|
||||
virtual EdgeWeight GetNodeWeight(const NodeID node) const = 0;
|
||||
|
||||
virtual EdgeWeight GetNodeDuration(const NodeID node) const = 0; // TODO: to be removed
|
||||
|
||||
virtual EdgeDistance GetNodeDistance(const NodeID node) const = 0;
|
||||
|
||||
virtual bool IsForwardEdge(EdgeID edge) const = 0;
|
||||
|
||||
virtual bool IsBackwardEdge(EdgeID edge) const = 0;
|
||||
|
||||
virtual NodeID GetTarget(const EdgeID e) const = 0;
|
||||
|
||||
virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0;
|
||||
|
||||
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
|
||||
|
||||
virtual const partitioner::MultiLevelPartitionView &GetMultiLevelPartition() const = 0;
|
||||
|
||||
virtual const partitioner::CellStorageView &GetCellStorage() const = 0;
|
||||
|
||||
@@ -133,11 +133,11 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
using RTreeNode = SharedRTree::TreeNode;
|
||||
|
||||
extractor::ClassData exclude_mask;
|
||||
std::string m_timestamp;
|
||||
extractor::ProfileProperties *m_profile_properties;
|
||||
extractor::Datasources *m_datasources;
|
||||
|
||||
std::uint32_t m_check_sum;
|
||||
StringView m_data_timestamp;
|
||||
util::vector_view<util::Coordinate> m_coordinate_list;
|
||||
extractor::PackedOSMIDsView m_osmnodeid_list;
|
||||
util::vector_view<std::uint32_t> m_lane_description_offsets;
|
||||
@@ -184,6 +184,8 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
|
||||
m_check_sum = *index.GetBlockPtr<std::uint32_t>("/common/connectivity_checksum");
|
||||
|
||||
m_data_timestamp = make_timestamp_view(index, "/common/timestamp");
|
||||
|
||||
std::tie(m_coordinate_list, m_osmnodeid_list) =
|
||||
make_nbn_data_view(index, "/common/nbn_data");
|
||||
|
||||
@@ -283,13 +285,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
return segment_data.GetReverseDatasources(id);
|
||||
}
|
||||
|
||||
TurnPenalty GetWeightPenaltyForEdgeID(const unsigned id) const override final
|
||||
TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID id) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_turn_weight_penalties.size() > id);
|
||||
return m_turn_weight_penalties[id];
|
||||
}
|
||||
|
||||
TurnPenalty GetDurationPenaltyForEdgeID(const unsigned id) const override final
|
||||
TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID id) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_turn_duration_penalties.size() > id);
|
||||
return m_turn_duration_penalties[id];
|
||||
@@ -313,12 +315,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance,
|
||||
const Approach approach) const override final
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(
|
||||
input_coordinate, max_distance, approach);
|
||||
input_coordinate, max_distance, approach, use_all_edges);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
@@ -326,12 +329,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
const float max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const override final
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(
|
||||
input_coordinate, max_distance, bearing, bearing_range, approach);
|
||||
input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
@@ -385,23 +389,25 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const Approach approach) const override final
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, approach);
|
||||
input_coordinate, approach, use_all_edges);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const Approach approach) const override final
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, max_distance, approach);
|
||||
input_coordinate, max_distance, approach, use_all_edges);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
@@ -409,28 +415,35 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const override final
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, max_distance, bearing, bearing_range, approach);
|
||||
input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const override final
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const override final
|
||||
{
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
input_coordinate, bearing, bearing_range, approach);
|
||||
input_coordinate, bearing, bearing_range, approach, use_all_edges);
|
||||
}
|
||||
|
||||
std::uint32_t GetCheckSum() const override final { return m_check_sum; }
|
||||
|
||||
std::string GetTimestamp() const override final
|
||||
{
|
||||
return std::string(m_data_timestamp.begin(), m_data_timestamp.end());
|
||||
}
|
||||
|
||||
GeometryID GetGeometryIndex(const NodeID id) const override final
|
||||
{
|
||||
return edge_based_node_data.GetGeometryID(id);
|
||||
@@ -622,7 +635,6 @@ class ContiguousInternalMemoryDataFacade<CH>
|
||||
const std::size_t exclude_index)
|
||||
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
|
||||
ContiguousInternalMemoryAlgorithmDataFacade<CH>(allocator, metric_name, exclude_index)
|
||||
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -684,6 +696,36 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
|
||||
return query_graph.GetOutDegree(n);
|
||||
}
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.GetAdjacentEdgeRange(node);
|
||||
}
|
||||
|
||||
EdgeWeight GetNodeWeight(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.GetNodeWeight(node);
|
||||
}
|
||||
|
||||
EdgeDuration GetNodeDuration(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.GetNodeDuration(node);
|
||||
}
|
||||
|
||||
EdgeDistance GetNodeDistance(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.GetNodeDistance(node);
|
||||
}
|
||||
|
||||
bool IsForwardEdge(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.IsForwardEdge(node);
|
||||
}
|
||||
|
||||
bool IsBackwardEdge(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.IsBackwardEdge(node);
|
||||
}
|
||||
|
||||
NodeID GetTarget(const EdgeID e) const override final { return query_graph.GetTarget(e); }
|
||||
|
||||
const EdgeData &GetEdgeData(const EdgeID e) const override final
|
||||
@@ -691,11 +733,6 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
|
||||
return query_graph.GetEdgeData(e);
|
||||
}
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.GetAdjacentEdgeRange(node);
|
||||
}
|
||||
|
||||
EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const override final
|
||||
{
|
||||
return query_graph.GetBorderEdgeRange(level, node);
|
||||
@@ -720,7 +757,6 @@ class ContiguousInternalMemoryDataFacade<MLD> final
|
||||
const std::size_t exclude_index)
|
||||
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
|
||||
ContiguousInternalMemoryAlgorithmDataFacade<MLD>(allocator, metric_name, exclude_index)
|
||||
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#include <boost/range/any_range.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <string>
|
||||
@@ -75,6 +74,8 @@ class BaseDataFacade
|
||||
|
||||
virtual std::uint32_t GetCheckSum() const = 0;
|
||||
|
||||
virtual std::string GetTimestamp() const = 0;
|
||||
|
||||
// node and edge information access
|
||||
virtual util::Coordinate GetCoordinateOfNode(const NodeID id) const = 0;
|
||||
|
||||
@@ -87,9 +88,9 @@ class BaseDataFacade
|
||||
virtual NodeForwardRange GetUncompressedForwardGeometry(const EdgeID id) const = 0;
|
||||
virtual NodeReverseRange GetUncompressedReverseGeometry(const EdgeID id) const = 0;
|
||||
|
||||
virtual TurnPenalty GetWeightPenaltyForEdgeID(const unsigned id) const = 0;
|
||||
virtual TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID id) const = 0;
|
||||
|
||||
virtual TurnPenalty GetDurationPenaltyForEdgeID(const unsigned id) const = 0;
|
||||
virtual TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID id) const = 0;
|
||||
|
||||
// Gets the weight values for each segment in an uncompressed geometry.
|
||||
// Should always be 1 shorter than GetUncompressedGeometry
|
||||
@@ -127,11 +128,13 @@ class BaseDataFacade
|
||||
const float max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const = 0;
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const = 0;
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const float max_distance,
|
||||
const Approach approach) const = 0;
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const = 0;
|
||||
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
@@ -158,22 +161,26 @@ class BaseDataFacade
|
||||
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const Approach approach) const = 0;
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const = 0;
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const Approach approach) const = 0;
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const = 0;
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const = 0;
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const = 0;
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const = 0;
|
||||
const Approach approach,
|
||||
const bool use_all_edges = false) const = 0;
|
||||
|
||||
virtual bool HasLaneData(const EdgeID id) const = 0;
|
||||
virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <boost/iostreams/device/mapped_file.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -24,8 +25,7 @@ namespace datafacade
|
||||
class MMapMemoryAllocator : public ContiguousBlockAllocator
|
||||
{
|
||||
public:
|
||||
explicit MMapMemoryAllocator(const storage::StorageConfig &config,
|
||||
const boost::filesystem::path &memory_file);
|
||||
explicit MMapMemoryAllocator(const storage::StorageConfig &config);
|
||||
~MMapMemoryAllocator() override final;
|
||||
|
||||
// interface to give access to the datafacades
|
||||
@@ -33,8 +33,8 @@ class MMapMemoryAllocator : public ContiguousBlockAllocator
|
||||
|
||||
private:
|
||||
storage::SharedDataIndex index;
|
||||
util::vector_view<char> mapped_memory;
|
||||
boost::iostreams::mapped_file mapped_memory_file;
|
||||
std::vector<boost::iostreams::mapped_file> mapped_memory_files;
|
||||
std::string rtree_filename;
|
||||
};
|
||||
|
||||
} // namespace datafacade
|
||||
|
||||
@@ -32,9 +32,8 @@ class ExternalProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
|
||||
public:
|
||||
using Facade = typename DataFacadeProvider<AlgorithmT, FacadeT>::Facade;
|
||||
|
||||
ExternalProvider(const storage::StorageConfig &config,
|
||||
const boost::filesystem::path &memory_file)
|
||||
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config, memory_file))
|
||||
ExternalProvider(const storage::StorageConfig &config)
|
||||
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -63,12 +63,16 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
||||
<< "\" with algorithm " << routing_algorithms::name<Algorithm>();
|
||||
facade_provider = std::make_unique<WatchingProvider<Algorithm>>(config.dataset_name);
|
||||
}
|
||||
else if (!config.memory_file.empty())
|
||||
else if (!config.memory_file.empty() || config.use_mmap)
|
||||
{
|
||||
util::Log(logDEBUG) << "Using memory mapped filed at " << config.memory_file
|
||||
<< " with algorithm " << routing_algorithms::name<Algorithm>();
|
||||
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config,
|
||||
config.memory_file);
|
||||
if (!config.memory_file.empty())
|
||||
{
|
||||
util::Log(logWARNING)
|
||||
<< "The 'memory_file' option is DEPRECATED - using direct mmaping instead";
|
||||
}
|
||||
util::Log(logDEBUG) << "Using direct memory mapping with algorithm "
|
||||
<< routing_algorithms::name<Algorithm>();
|
||||
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -89,6 +89,7 @@ struct EngineConfig final
|
||||
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
||||
bool use_shared_memory = true;
|
||||
boost::filesystem::path memory_file;
|
||||
bool use_mmap = true;
|
||||
Algorithm algorithm = Algorithm::CH;
|
||||
std::string verbosity;
|
||||
std::string dataset_name;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -52,13 +53,15 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const Approach approach) const
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const
|
||||
{
|
||||
auto results = rtree.Nearest(
|
||||
input_coordinate,
|
||||
[this, approach, &input_coordinate](const CandidateSegment &segment) {
|
||||
return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)),
|
||||
CheckApproach(input_coordinate, segment, approach));
|
||||
[this, approach, &input_coordinate, use_all_edges](const CandidateSegment &segment) {
|
||||
return boolPairAnd(
|
||||
boolPairAnd(HasValidEdge(segment, use_all_edges), CheckSegmentExclude(segment)),
|
||||
CheckApproach(input_coordinate, segment, approach));
|
||||
},
|
||||
[this, max_distance, input_coordinate](const std::size_t,
|
||||
const CandidateSegment &segment) {
|
||||
@@ -75,15 +78,17 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const
|
||||
{
|
||||
auto results = rtree.Nearest(
|
||||
input_coordinate,
|
||||
[this, approach, &input_coordinate, bearing, bearing_range](
|
||||
[this, approach, &input_coordinate, bearing, bearing_range, use_all_edges](
|
||||
const CandidateSegment &segment) {
|
||||
auto use_direction =
|
||||
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
|
||||
boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)));
|
||||
boolPairAnd(HasValidEdge(segment, use_all_edges),
|
||||
CheckSegmentExclude(segment)));
|
||||
use_direction =
|
||||
boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach));
|
||||
return use_direction;
|
||||
@@ -200,18 +205,23 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const double max_distance,
|
||||
const Approach approach) const
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
auto results = rtree.Nearest(
|
||||
input_coordinate,
|
||||
[this, approach, &input_coordinate, &has_big_component, &has_small_component](
|
||||
const CandidateSegment &segment) {
|
||||
[this,
|
||||
approach,
|
||||
&input_coordinate,
|
||||
&has_big_component,
|
||||
&has_small_component,
|
||||
&use_all_edges](const CandidateSegment &segment) {
|
||||
auto use_segment =
|
||||
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
|
||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
||||
const auto valid_edges = HasValidEdge(segment);
|
||||
const auto valid_edges = HasValidEdge(segment, use_all_edges);
|
||||
const auto admissible_segments = CheckSegmentExclude(segment);
|
||||
use_directions = boolPairAnd(use_directions, admissible_segments);
|
||||
use_directions = boolPairAnd(use_directions, valid_edges);
|
||||
@@ -246,19 +256,24 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const Approach approach) const
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
auto results = rtree.Nearest(
|
||||
input_coordinate,
|
||||
[this, approach, &input_coordinate, &has_big_component, &has_small_component](
|
||||
const CandidateSegment &segment) {
|
||||
[this,
|
||||
approach,
|
||||
&input_coordinate,
|
||||
&has_big_component,
|
||||
&has_small_component,
|
||||
&use_all_edges](const CandidateSegment &segment) {
|
||||
auto use_segment =
|
||||
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
|
||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
||||
|
||||
const auto valid_edges = HasValidEdge(segment);
|
||||
const auto valid_edges = HasValidEdge(segment, use_all_edges);
|
||||
const auto admissible_segments = CheckSegmentExclude(segment);
|
||||
use_directions = boolPairAnd(use_directions, admissible_segments);
|
||||
use_directions = boolPairAnd(use_directions, valid_edges);
|
||||
@@ -293,7 +308,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
@@ -305,12 +321,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
bearing,
|
||||
bearing_range,
|
||||
&has_big_component,
|
||||
&has_small_component](const CandidateSegment &segment) {
|
||||
&has_small_component,
|
||||
&use_all_edges](const CandidateSegment &segment) {
|
||||
auto use_segment =
|
||||
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
|
||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
||||
const auto admissible_segments = CheckSegmentExclude(segment);
|
||||
use_directions = boolPairAnd(use_directions, HasValidEdge(segment));
|
||||
use_directions = boolPairAnd(use_directions, HasValidEdge(segment, use_all_edges));
|
||||
|
||||
if (use_segment)
|
||||
{
|
||||
@@ -351,7 +368,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
const double max_distance,
|
||||
const int bearing,
|
||||
const int bearing_range,
|
||||
const Approach approach) const
|
||||
const Approach approach,
|
||||
const bool use_all_edges) const
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
@@ -363,12 +381,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
bearing,
|
||||
bearing_range,
|
||||
&has_big_component,
|
||||
&has_small_component](const CandidateSegment &segment) {
|
||||
&has_small_component,
|
||||
&use_all_edges](const CandidateSegment &segment) {
|
||||
auto use_segment =
|
||||
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
|
||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
||||
const auto admissible_segments = CheckSegmentExclude(segment);
|
||||
use_directions = boolPairAnd(use_directions, HasValidEdge(segment));
|
||||
use_directions = boolPairAnd(use_directions, HasValidEdge(segment, use_all_edges));
|
||||
|
||||
if (use_segment)
|
||||
{
|
||||
@@ -447,6 +466,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
const auto forward_durations = datafacade.GetUncompressedForwardDurations(geometry_id);
|
||||
const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id);
|
||||
|
||||
const auto forward_geometry = datafacade.GetUncompressedForwardGeometry(geometry_id);
|
||||
|
||||
const auto forward_weight_offset =
|
||||
std::accumulate(forward_weights.begin(),
|
||||
forward_weights.begin() + data.fwd_segment_position,
|
||||
@@ -457,12 +478,26 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
forward_durations.begin() + data.fwd_segment_position,
|
||||
EdgeDuration{0});
|
||||
|
||||
EdgeWeight forward_weight = forward_weights[data.fwd_segment_position];
|
||||
EdgeDuration forward_duration = forward_durations[data.fwd_segment_position];
|
||||
EdgeDistance forward_distance_offset = 0;
|
||||
// Sum up the distance from the start to the fwd_segment_position
|
||||
for (auto current = forward_geometry.begin();
|
||||
current < forward_geometry.begin() + data.fwd_segment_position;
|
||||
++current)
|
||||
{
|
||||
forward_distance_offset += util::coordinate_calculation::fccApproximateDistance(
|
||||
datafacade.GetCoordinateOfNode(*current),
|
||||
datafacade.GetCoordinateOfNode(*std::next(current)));
|
||||
}
|
||||
|
||||
BOOST_ASSERT(data.fwd_segment_position <
|
||||
std::distance(forward_durations.begin(), forward_durations.end()));
|
||||
|
||||
EdgeWeight forward_weight = forward_weights[data.fwd_segment_position];
|
||||
EdgeDuration forward_duration = forward_durations[data.fwd_segment_position];
|
||||
EdgeDistance forward_distance = util::coordinate_calculation::fccApproximateDistance(
|
||||
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position)),
|
||||
point_on_segment);
|
||||
|
||||
const auto reverse_weight_offset =
|
||||
std::accumulate(reverse_weights.begin(),
|
||||
reverse_weights.end() - data.fwd_segment_position - 1,
|
||||
@@ -473,10 +508,24 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
reverse_durations.end() - data.fwd_segment_position - 1,
|
||||
EdgeDuration{0});
|
||||
|
||||
EdgeDistance reverse_distance_offset = 0;
|
||||
// Sum up the distance from just after the fwd_segment_position to the end
|
||||
for (auto current = forward_geometry.begin() + data.fwd_segment_position + 1;
|
||||
current != std::prev(forward_geometry.end());
|
||||
++current)
|
||||
{
|
||||
reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance(
|
||||
datafacade.GetCoordinateOfNode(*current),
|
||||
datafacade.GetCoordinateOfNode(*std::next(current)));
|
||||
}
|
||||
|
||||
EdgeWeight reverse_weight =
|
||||
reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1];
|
||||
EdgeDuration reverse_duration =
|
||||
reverse_durations[reverse_durations.size() - data.fwd_segment_position - 1];
|
||||
EdgeDistance reverse_distance = util::coordinate_calculation::fccApproximateDistance(
|
||||
point_on_segment,
|
||||
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1)));
|
||||
|
||||
ratio = std::min(1.0, std::max(0.0, ratio));
|
||||
if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
|
||||
@@ -510,6 +559,10 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
reverse_weight,
|
||||
forward_weight_offset,
|
||||
reverse_weight_offset,
|
||||
forward_distance,
|
||||
reverse_distance,
|
||||
forward_distance_offset,
|
||||
reverse_distance_offset,
|
||||
forward_duration,
|
||||
reverse_duration,
|
||||
forward_duration_offset,
|
||||
@@ -595,7 +648,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
* which means that this edge is not currently traversible. If this is the case,
|
||||
* then we shouldn't snap to this edge.
|
||||
*/
|
||||
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment) const
|
||||
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment,
|
||||
const bool use_all_edges = false) const
|
||||
{
|
||||
|
||||
bool forward_edge_valid = false;
|
||||
@@ -619,6 +673,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
reverse_edge_valid = data.reverse_segment_id.enabled;
|
||||
}
|
||||
|
||||
forward_edge_valid = forward_edge_valid && (data.is_startpoint || use_all_edges);
|
||||
reverse_edge_valid = reverse_edge_valid && (data.is_startpoint || use_all_edges);
|
||||
|
||||
return std::make_pair(forward_edge_valid, reverse_edge_valid);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@ struct Hint
|
||||
friend std::ostream &operator<<(std::ostream &, const Hint &);
|
||||
};
|
||||
|
||||
static_assert(sizeof(Hint) == 64 + 4, "Hint is bigger than expected");
|
||||
constexpr std::size_t ENCODED_HINT_SIZE = 92;
|
||||
static_assert(sizeof(Hint) == 80 + 4, "Hint is bigger than expected");
|
||||
constexpr std::size_t ENCODED_HINT_SIZE = 112;
|
||||
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
|
||||
"ENCODED_HINT_SIZE does not match size of Hint");
|
||||
}
|
||||
|
||||
@@ -47,10 +47,13 @@ struct PhantomNode
|
||||
: forward_segment_id{SPECIAL_SEGMENTID, false},
|
||||
reverse_segment_id{SPECIAL_SEGMENTID, false}, forward_weight(INVALID_EDGE_WEIGHT),
|
||||
reverse_weight(INVALID_EDGE_WEIGHT), forward_weight_offset(0), reverse_weight_offset(0),
|
||||
forward_distance(INVALID_EDGE_DISTANCE), reverse_distance(INVALID_EDGE_DISTANCE),
|
||||
forward_distance_offset(0), reverse_distance_offset(0),
|
||||
forward_duration(MAXIMAL_EDGE_DURATION), reverse_duration(MAXIMAL_EDGE_DURATION),
|
||||
forward_duration_offset(0), reverse_duration_offset(0), fwd_segment_position(0),
|
||||
is_valid_forward_source{false}, is_valid_forward_target{false},
|
||||
is_valid_reverse_source{false}, is_valid_reverse_target{false}, bearing(0)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
@@ -78,6 +81,30 @@ struct PhantomNode
|
||||
return reverse_duration + reverse_duration_offset;
|
||||
}
|
||||
|
||||
// DO THIS FOR DISTANCE
|
||||
|
||||
EdgeDistance GetForwardDistance() const
|
||||
{
|
||||
// ..... <-- forward_distance
|
||||
// .... <-- offset
|
||||
// ......... <-- desired distance
|
||||
// x <-- this is PhantomNode.location
|
||||
// 0----1----2----3----4 <-- EdgeBasedGraph Node segments
|
||||
BOOST_ASSERT(forward_segment_id.enabled);
|
||||
return forward_distance + forward_distance_offset;
|
||||
}
|
||||
|
||||
EdgeDistance GetReverseDistance() const
|
||||
{
|
||||
// .......... <-- reverse_distance
|
||||
// ... <-- offset
|
||||
// ............. <-- desired distance
|
||||
// x <-- this is PhantomNode.location
|
||||
// 0----1----2----3----4 <-- EdgeBasedGraph Node segments
|
||||
BOOST_ASSERT(reverse_segment_id.enabled);
|
||||
return reverse_distance + reverse_distance_offset;
|
||||
}
|
||||
|
||||
bool IsBidirected() const { return forward_segment_id.enabled && reverse_segment_id.enabled; }
|
||||
|
||||
bool IsValid(const unsigned number_of_nodes) const
|
||||
@@ -88,6 +115,8 @@ struct PhantomNode
|
||||
(reverse_weight != INVALID_EDGE_WEIGHT)) &&
|
||||
((forward_duration != MAXIMAL_EDGE_DURATION) ||
|
||||
(reverse_duration != MAXIMAL_EDGE_DURATION)) &&
|
||||
((forward_distance != INVALID_EDGE_DISTANCE) ||
|
||||
(reverse_distance != INVALID_EDGE_DISTANCE)) &&
|
||||
(component.id != INVALID_COMPONENTID);
|
||||
}
|
||||
|
||||
@@ -130,6 +159,10 @@ struct PhantomNode
|
||||
EdgeWeight reverse_weight,
|
||||
EdgeWeight forward_weight_offset,
|
||||
EdgeWeight reverse_weight_offset,
|
||||
EdgeDistance forward_distance,
|
||||
EdgeDistance reverse_distance,
|
||||
EdgeDistance forward_distance_offset,
|
||||
EdgeDistance reverse_distance_offset,
|
||||
EdgeWeight forward_duration,
|
||||
EdgeWeight reverse_duration,
|
||||
EdgeWeight forward_duration_offset,
|
||||
@@ -144,7 +177,9 @@ struct PhantomNode
|
||||
: forward_segment_id{other.forward_segment_id},
|
||||
reverse_segment_id{other.reverse_segment_id}, forward_weight{forward_weight},
|
||||
reverse_weight{reverse_weight}, forward_weight_offset{forward_weight_offset},
|
||||
reverse_weight_offset{reverse_weight_offset}, forward_duration{forward_duration},
|
||||
reverse_weight_offset{reverse_weight_offset}, forward_distance{forward_distance},
|
||||
reverse_distance{reverse_distance}, forward_distance_offset{forward_distance_offset},
|
||||
reverse_distance_offset{reverse_distance_offset}, forward_duration{forward_duration},
|
||||
reverse_duration{reverse_duration}, forward_duration_offset{forward_duration_offset},
|
||||
reverse_duration_offset{reverse_duration_offset},
|
||||
component{component.id, component.is_tiny}, location{location},
|
||||
@@ -162,13 +197,17 @@ struct PhantomNode
|
||||
EdgeWeight reverse_weight;
|
||||
EdgeWeight forward_weight_offset; // TODO: try to remove -> requires path unpacking changes
|
||||
EdgeWeight reverse_weight_offset; // TODO: try to remove -> requires path unpacking changes
|
||||
EdgeDistance forward_distance;
|
||||
EdgeDistance reverse_distance;
|
||||
EdgeDistance forward_distance_offset; // TODO: try to remove -> requires path unpacking changes
|
||||
EdgeDistance reverse_distance_offset; // TODO: try to remove -> requires path unpacking changes
|
||||
EdgeWeight forward_duration;
|
||||
EdgeWeight reverse_duration;
|
||||
EdgeWeight forward_duration_offset; // TODO: try to remove -> requires path unpacking changes
|
||||
EdgeWeight reverse_duration_offset; // TODO: try to remove -> requires path unpacking changes
|
||||
ComponentID component;
|
||||
|
||||
util::Coordinate location;
|
||||
util::Coordinate location; // this is the coordinate of x
|
||||
util::Coordinate input_location;
|
||||
unsigned short fwd_segment_position;
|
||||
// is phantom node valid to be used as source or target
|
||||
@@ -180,7 +219,7 @@ struct PhantomNode
|
||||
unsigned short bearing : 12;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PhantomNode) == 64, "PhantomNode has more padding then expected");
|
||||
static_assert(sizeof(PhantomNode) == 80, "PhantomNode has more padding then expected");
|
||||
|
||||
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
|
||||
|
||||
|
||||
@@ -138,7 +138,8 @@ class BasePlugin
|
||||
std::vector<std::vector<PhantomNodeWithDistance>>
|
||||
GetPhantomNodesInRange(const datafacade::BaseDataFacade &facade,
|
||||
const api::BaseParameters ¶meters,
|
||||
const std::vector<double> radiuses) const
|
||||
const std::vector<double> radiuses,
|
||||
bool use_all_edges = false) const
|
||||
{
|
||||
std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
|
||||
parameters.coordinates.size());
|
||||
@@ -171,12 +172,13 @@ class BasePlugin
|
||||
radiuses[i],
|
||||
parameters.bearings[i]->bearing,
|
||||
parameters.bearings[i]->range,
|
||||
approach);
|
||||
approach,
|
||||
use_all_edges);
|
||||
}
|
||||
else
|
||||
{
|
||||
phantom_nodes[i] = facade.NearestPhantomNodesInRange(
|
||||
parameters.coordinates[i], radiuses[i], approach);
|
||||
parameters.coordinates[i], radiuses[i], approach, use_all_edges);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,6 +270,7 @@ class BasePlugin
|
||||
const bool use_bearings = !parameters.bearings.empty();
|
||||
const bool use_radiuses = !parameters.radiuses.empty();
|
||||
const bool use_approaches = !parameters.approaches.empty();
|
||||
const bool use_all_edges = parameters.snapping == api::BaseParameters::SnappingType::Any;
|
||||
|
||||
BOOST_ASSERT(parameters.IsValid());
|
||||
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
||||
@@ -294,7 +297,8 @@ class BasePlugin
|
||||
*parameters.radiuses[i],
|
||||
parameters.bearings[i]->bearing,
|
||||
parameters.bearings[i]->range,
|
||||
approach);
|
||||
approach,
|
||||
use_all_edges);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -303,7 +307,8 @@ class BasePlugin
|
||||
parameters.coordinates[i],
|
||||
parameters.bearings[i]->bearing,
|
||||
parameters.bearings[i]->range,
|
||||
approach);
|
||||
approach,
|
||||
use_all_edges);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -312,13 +317,16 @@ class BasePlugin
|
||||
{
|
||||
phantom_node_pairs[i] =
|
||||
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
parameters.coordinates[i], *parameters.radiuses[i], approach);
|
||||
parameters.coordinates[i],
|
||||
*parameters.radiuses[i],
|
||||
approach,
|
||||
use_all_edges);
|
||||
}
|
||||
else
|
||||
{
|
||||
phantom_node_pairs[i] =
|
||||
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
parameters.coordinates[i], approach);
|
||||
parameters.coordinates[i], approach, use_all_edges);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,11 @@ class RoutingAlgorithmsInterface
|
||||
virtual InternalRouteResult
|
||||
DirectShortestPathSearch(const PhantomNodes &phantom_node_pair) const = 0;
|
||||
|
||||
virtual std::vector<EdgeDuration>
|
||||
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||
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 bool calculate_distance) const = 0;
|
||||
|
||||
virtual routing_algorithms::SubMatchingList
|
||||
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
|
||||
@@ -53,6 +54,7 @@ class RoutingAlgorithmsInterface
|
||||
virtual bool HasDirectShortestPathSearch() const = 0;
|
||||
virtual bool HasMapMatching() const = 0;
|
||||
virtual bool HasManyToManySearch() const = 0;
|
||||
virtual bool SupportsDistanceAnnotationType() const = 0;
|
||||
virtual bool HasGetTileTurns() const = 0;
|
||||
virtual bool HasExcludeFlags() const = 0;
|
||||
virtual bool IsValid() const = 0;
|
||||
@@ -81,10 +83,11 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
||||
InternalRouteResult
|
||||
DirectShortestPathSearch(const PhantomNodes &phantom_nodes) const final override;
|
||||
|
||||
std::vector<EdgeDuration>
|
||||
virtual std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||
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 bool calculate_distance) const final override;
|
||||
|
||||
routing_algorithms::SubMatchingList
|
||||
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
|
||||
@@ -124,6 +127,11 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
||||
return routing_algorithms::HasManyToManySearch<Algorithm>::value;
|
||||
}
|
||||
|
||||
bool SupportsDistanceAnnotationType() const final override
|
||||
{
|
||||
return routing_algorithms::SupportsDistanceAnnotationType<Algorithm>::value;
|
||||
}
|
||||
|
||||
bool HasGetTileTurns() const final override
|
||||
{
|
||||
return routing_algorithms::HasGetTileTurns<Algorithm>::value;
|
||||
@@ -184,10 +192,11 @@ inline routing_algorithms::SubMatchingList RoutingAlgorithms<Algorithm>::MapMatc
|
||||
}
|
||||
|
||||
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
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
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 bool calculate_distance) const
|
||||
{
|
||||
BOOST_ASSERT(!phantom_nodes.empty());
|
||||
|
||||
@@ -205,8 +214,12 @@ std::vector<EdgeDuration> RoutingAlgorithms<Algorithm>::ManyToManySearch(
|
||||
std::iota(target_indices.begin(), target_indices.end(), 0);
|
||||
}
|
||||
|
||||
return routing_algorithms::manyToManySearch(
|
||||
heaps, *facade, phantom_nodes, std::move(source_indices), std::move(target_indices));
|
||||
return routing_algorithms::manyToManySearch(heaps,
|
||||
*facade,
|
||||
phantom_nodes,
|
||||
std::move(source_indices),
|
||||
std::move(target_indices),
|
||||
calculate_distance);
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
|
||||
@@ -15,23 +15,46 @@ namespace engine
|
||||
{
|
||||
namespace routing_algorithms
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
struct NodeBucket
|
||||
{
|
||||
NodeID middle_node;
|
||||
unsigned column_index; // a column in the weight/duration matrix
|
||||
NodeID parent_node;
|
||||
unsigned column_index : 31; // a column in the weight/duration matrix
|
||||
unsigned from_clique_arc : 1;
|
||||
EdgeWeight weight;
|
||||
EdgeDuration duration;
|
||||
EdgeDistance distance;
|
||||
|
||||
NodeBucket(NodeID middle_node, unsigned column_index, EdgeWeight weight, EdgeDuration duration)
|
||||
: middle_node(middle_node), column_index(column_index), weight(weight), duration(duration)
|
||||
NodeBucket(NodeID middle_node,
|
||||
NodeID parent_node,
|
||||
bool from_clique_arc,
|
||||
unsigned column_index,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance)
|
||||
: middle_node(middle_node), parent_node(parent_node), column_index(column_index),
|
||||
from_clique_arc(from_clique_arc), weight(weight), duration(duration), distance(distance)
|
||||
{
|
||||
}
|
||||
|
||||
NodeBucket(NodeID middle_node,
|
||||
NodeID parent_node,
|
||||
unsigned column_index,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance)
|
||||
: middle_node(middle_node), parent_node(parent_node), column_index(column_index),
|
||||
from_clique_arc(false), weight(weight), duration(duration), distance(distance)
|
||||
{
|
||||
}
|
||||
|
||||
// partial order comparison
|
||||
bool operator<(const NodeBucket &rhs) const { return middle_node < rhs.middle_node; }
|
||||
bool operator<(const NodeBucket &rhs) const
|
||||
{
|
||||
return std::tie(middle_node, column_index) < std::tie(rhs.middle_node, rhs.column_index);
|
||||
}
|
||||
|
||||
// functor for equal_range
|
||||
struct Compare
|
||||
@@ -46,15 +69,35 @@ struct NodeBucket
|
||||
return lhs < rhs.middle_node;
|
||||
}
|
||||
};
|
||||
|
||||
// functor for equal_range
|
||||
struct ColumnCompare
|
||||
{
|
||||
unsigned column_idx;
|
||||
|
||||
ColumnCompare(unsigned column_idx) : column_idx(column_idx){};
|
||||
|
||||
bool operator()(const NodeBucket &lhs, const NodeID &rhs) const // lowerbound
|
||||
{
|
||||
return std::tie(lhs.middle_node, lhs.column_index) < std::tie(rhs, column_idx);
|
||||
}
|
||||
|
||||
bool operator()(const NodeID &lhs, const NodeBucket &rhs) const // upperbound
|
||||
{
|
||||
return std::tie(lhs, column_idx) < std::tie(rhs.middle_node, rhs.column_index);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <typename Algorithm>
|
||||
std::vector<EdgeDuration> manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices);
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
|
||||
@@ -85,13 +85,17 @@ void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()});
|
||||
{phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance()});
|
||||
}
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
{phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()});
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance()});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,13 +106,17 @@ void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
{phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()});
|
||||
{phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance()});
|
||||
}
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
{phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()});
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance()});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +189,7 @@ void annotatePath(const FacadeT &facade,
|
||||
BOOST_ASSERT(datasource_vector.size() > 0);
|
||||
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
|
||||
BOOST_ASSERT(duration_vector.size() + 1 == id_vector.size());
|
||||
|
||||
const bool is_first_segment = unpacked_path.empty();
|
||||
|
||||
const std::size_t start_index =
|
||||
@@ -405,6 +414,22 @@ InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
||||
return raw_route_data;
|
||||
}
|
||||
|
||||
template <typename FacadeT> EdgeDistance computeEdgeDistance(const FacadeT &facade, NodeID node_id)
|
||||
{
|
||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||
|
||||
EdgeDistance total_distance = 0.0;
|
||||
|
||||
auto geometry_range = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
||||
for (auto current = geometry_range.begin(); current < geometry_range.end() - 1; ++current)
|
||||
{
|
||||
total_distance += util::coordinate_calculation::fccApproximateDistance(
|
||||
facade.GetCoordinateOfNode(*current), facade.GetCoordinateOfNode(*std::next(current)));
|
||||
}
|
||||
|
||||
return total_distance;
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
@@ -186,9 +186,10 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
|
||||
template <bool UseDuration>
|
||||
EdgeWeight getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
||||
std::tuple<EdgeWeight, EdgeDistance> getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
||||
{
|
||||
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT;
|
||||
EdgeDistance loop_distance = MAXIMAL_EDGE_DISTANCE;
|
||||
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = facade.GetEdgeData(edge);
|
||||
@@ -198,11 +199,15 @@ EdgeWeight getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
||||
if (to == node)
|
||||
{
|
||||
const auto value = UseDuration ? data.duration : data.weight;
|
||||
loop_weight = std::min(loop_weight, value);
|
||||
if (value < loop_weight)
|
||||
{
|
||||
loop_weight = value;
|
||||
loop_distance = data.distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return loop_weight;
|
||||
return std::make_tuple(loop_weight, loop_distance);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,6 +293,106 @@ void unpackPath(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BidirectionalIterator>
|
||||
EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
||||
BidirectionalIterator packed_path_begin,
|
||||
BidirectionalIterator packed_path_end)
|
||||
{
|
||||
// Make sure we have at least something to unpack
|
||||
if (packed_path_begin == packed_path_end ||
|
||||
std::distance(packed_path_begin, packed_path_end) <= 1)
|
||||
return 0;
|
||||
|
||||
std::stack<std::tuple<NodeID, NodeID, bool>> recursion_stack;
|
||||
std::stack<EdgeDistance> distance_stack;
|
||||
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
for (auto current = std::prev(packed_path_end); current > packed_path_begin;
|
||||
current = std::prev(current))
|
||||
{
|
||||
recursion_stack.emplace(*std::prev(current), *current, false);
|
||||
}
|
||||
|
||||
std::tuple<NodeID, NodeID, bool> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
// Have we processed the edge before? tells us if we have values in the durations stack that
|
||||
// we can add up
|
||||
if (!std::get<2>(edge))
|
||||
{ // haven't processed edge before, so process it in the body!
|
||||
|
||||
std::get<2>(edge) = true; // mark that this edge will now be processed
|
||||
|
||||
// Look for an edge on the forward CH graph (.forward)
|
||||
EdgeID smaller_edge_id =
|
||||
facade.FindSmallestEdge(std::get<0>(edge), std::get<1>(edge), [](const auto &data) {
|
||||
return data.forward;
|
||||
});
|
||||
|
||||
// If we didn't find one there, the we might be looking at a part of the path that
|
||||
// was found using the backward search. Here, we flip the node order (.second,
|
||||
// .first) and only consider edges with the `.backward` flag.
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
smaller_edge_id =
|
||||
facade.FindSmallestEdge(std::get<1>(edge),
|
||||
std::get<0>(edge),
|
||||
[](const auto &data) { return data.backward; });
|
||||
}
|
||||
|
||||
// If we didn't find anything *still*, then something is broken and someone has
|
||||
// called this function with bad values.
|
||||
BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID");
|
||||
|
||||
const auto &data = facade.GetEdgeData(smaller_edge_id);
|
||||
BOOST_ASSERT_MSG(data.weight != std::numeric_limits<EdgeWeight>::max(),
|
||||
"edge weight invalid");
|
||||
|
||||
// If the edge is a shortcut, we need to add the two halfs to the stack.
|
||||
if (data.shortcut)
|
||||
{ // unpack
|
||||
const NodeID middle_node_id = data.turn_id;
|
||||
// Note the order here - we're adding these to a stack, so we
|
||||
// want the first->middle to get visited before middle->second
|
||||
recursion_stack.emplace(edge);
|
||||
recursion_stack.emplace(middle_node_id, std::get<1>(edge), false);
|
||||
recursion_stack.emplace(std::get<0>(edge), middle_node_id, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// compute the duration here and put it onto the duration stack using method
|
||||
// similar to annotatePath but smaller
|
||||
EdgeDistance distance = computeEdgeDistance(facade, std::get<0>(edge));
|
||||
distance_stack.emplace(distance);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // the edge has already been processed. this means that there are enough values in the
|
||||
// distances stack
|
||||
|
||||
BOOST_ASSERT_MSG(distance_stack.size() >= 2,
|
||||
"There are not enough (at least 2) values on the distance stack");
|
||||
EdgeDistance distance1 = distance_stack.top();
|
||||
distance_stack.pop();
|
||||
EdgeDistance distance2 = distance_stack.top();
|
||||
distance_stack.pop();
|
||||
EdgeDistance distance = distance1 + distance2;
|
||||
distance_stack.emplace(distance);
|
||||
}
|
||||
}
|
||||
|
||||
EdgeDistance total_distance = 0;
|
||||
while (!distance_stack.empty())
|
||||
{
|
||||
total_distance += distance_stack.top();
|
||||
distance_stack.pop();
|
||||
}
|
||||
|
||||
return total_distance;
|
||||
}
|
||||
|
||||
template <typename RandomIter, typename FacadeT>
|
||||
void unpackPath(const FacadeT &facade,
|
||||
RandomIter packed_path_begin,
|
||||
@@ -340,6 +445,11 @@ void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHe
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> &packed_path);
|
||||
|
||||
void retrievePackedPathFromSingleManyToManyHeap(
|
||||
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &search_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> &packed_path);
|
||||
|
||||
// assumes that heaps are already setup correctly.
|
||||
// ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
|
||||
// Offsets.
|
||||
|
||||
@@ -54,7 +54,7 @@ inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return tr
|
||||
|
||||
// Restricted search (Args is LevelID, CellID):
|
||||
// * use the fixed level for queries
|
||||
// * check if the node cell is the same as the specified parent onr
|
||||
// * check if the node cell is the same as the specified parent
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &, NodeID, LevelID level, CellID)
|
||||
{
|
||||
@@ -65,6 +65,61 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
||||
{
|
||||
return cell == parent;
|
||||
}
|
||||
|
||||
// Unrestricted search with a single phantom node (Args is const PhantomNode &):
|
||||
// * use partition.GetQueryLevel to find the node query level
|
||||
// * allow to traverse all cells
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
const 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;
|
||||
};
|
||||
|
||||
const auto node_level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
||||
highest_diffrent_level(phantom_node.reverse_segment_id));
|
||||
|
||||
return node_level;
|
||||
}
|
||||
|
||||
// Unrestricted search with a single phantom node and a vector of phantom nodes:
|
||||
// * use partition.GetQueryLevel to find the node query level
|
||||
// * allow to traverse all cells
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Heaps only record for each node its predecessor ("parent") on the shortest path.
|
||||
@@ -74,6 +129,46 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
||||
using PackedEdge = std::tuple</*from*/ NodeID, /*to*/ NodeID, /*from_clique_arc*/ bool>;
|
||||
using PackedPath = std::vector<PackedEdge>;
|
||||
|
||||
template <bool DIRECTION, typename OutIter>
|
||||
inline void retrievePackedPathFromSingleManyToManyHeap(
|
||||
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap, const NodeID middle, OutIter out)
|
||||
{
|
||||
|
||||
NodeID current = middle;
|
||||
NodeID parent = heap.GetData(current).parent;
|
||||
|
||||
while (current != parent)
|
||||
{
|
||||
const auto &data = heap.GetData(current);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
*out = std::make_tuple(parent, current, data.from_clique_arc);
|
||||
++out;
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
*out = std::make_tuple(current, parent, data.from_clique_arc);
|
||||
++out;
|
||||
}
|
||||
|
||||
current = parent;
|
||||
parent = heap.GetData(parent).parent;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
inline PackedPath retrievePackedPathFromSingleManyToManyHeap(
|
||||
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap, const NodeID middle)
|
||||
{
|
||||
|
||||
PackedPath packed_path;
|
||||
retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(
|
||||
heap, middle, std::back_inserter(packed_path));
|
||||
|
||||
return packed_path;
|
||||
}
|
||||
|
||||
template <bool DIRECTION, typename OutIter>
|
||||
inline void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||
const NodeID middle,
|
||||
@@ -206,15 +301,22 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
||||
for (const auto edge : facade.GetBorderEdgeRange(level, node))
|
||||
{
|
||||
const auto &edge_data = facade.GetEdgeData(edge);
|
||||
if (DIRECTION == FORWARD_DIRECTION ? edge_data.forward : edge_data.backward)
|
||||
|
||||
if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge)
|
||||
: facade.IsBackwardEdge(edge))
|
||||
{
|
||||
const NodeID to = facade.GetTarget(edge);
|
||||
|
||||
if (!facade.ExcludeNode(to) &&
|
||||
checkParentCellRestriction(partition.GetCell(level + 1, to), args...))
|
||||
{
|
||||
BOOST_ASSERT_MSG(edge_data.weight > 0, "edge_weight invalid");
|
||||
const EdgeWeight to_weight = weight + edge_data.weight;
|
||||
const auto node_weight =
|
||||
facade.GetNodeWeight(DIRECTION == FORWARD_DIRECTION ? node : to);
|
||||
const auto turn_penalty = facade.GetWeightPenaltyForEdgeID(edge_data.turn_id);
|
||||
|
||||
// TODO: BOOST_ASSERT(edge_data.weight == node_weight + turn_penalty);
|
||||
|
||||
const EdgeWeight to_weight = weight + node_weight + turn_penalty;
|
||||
|
||||
if (!forward_heap.WasInserted(to))
|
||||
{
|
||||
|
||||
@@ -30,7 +30,11 @@ struct HeapData
|
||||
struct ManyToManyHeapData : HeapData
|
||||
{
|
||||
EdgeWeight duration;
|
||||
ManyToManyHeapData(NodeID p, EdgeWeight duration) : HeapData(p), duration(duration) {}
|
||||
EdgeDistance distance;
|
||||
ManyToManyHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance)
|
||||
: HeapData(p), duration(duration), distance(distance)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
|
||||
@@ -75,12 +79,16 @@ struct MultiLayerDijkstraHeapData
|
||||
struct ManyToManyMultiLayerDijkstraHeapData : MultiLayerDijkstraHeapData
|
||||
{
|
||||
EdgeWeight duration;
|
||||
ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration)
|
||||
: MultiLayerDijkstraHeapData(p), duration(duration)
|
||||
EdgeDistance distance;
|
||||
ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance)
|
||||
: MultiLayerDijkstraHeapData(p), duration(duration), distance(distance)
|
||||
{
|
||||
}
|
||||
ManyToManyMultiLayerDijkstraHeapData(NodeID p, bool from, EdgeWeight duration)
|
||||
: MultiLayerDijkstraHeapData(p, from), duration(duration)
|
||||
ManyToManyMultiLayerDijkstraHeapData(NodeID p,
|
||||
bool from,
|
||||
EdgeWeight duration,
|
||||
EdgeDistance distance)
|
||||
: MultiLayerDijkstraHeapData(p, from), duration(duration), distance(distance)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,20 +15,25 @@ struct EdgeBasedEdge
|
||||
public:
|
||||
struct EdgeData
|
||||
{
|
||||
EdgeData() : turn_id(0), weight(0), duration(0), forward(false), backward(false) {}
|
||||
EdgeData()
|
||||
: turn_id(0), weight(0), distance(0), duration(0), forward(false), backward(false)
|
||||
{
|
||||
}
|
||||
|
||||
EdgeData(const NodeID turn_id,
|
||||
const EdgeWeight weight,
|
||||
const EdgeDistance distance,
|
||||
const EdgeWeight duration,
|
||||
const bool forward,
|
||||
const bool backward)
|
||||
: turn_id(turn_id), weight(weight), duration(duration), forward(forward),
|
||||
backward(backward)
|
||||
: turn_id(turn_id), weight(weight), distance(distance), duration(duration),
|
||||
forward(forward), backward(backward)
|
||||
{
|
||||
}
|
||||
|
||||
NodeID turn_id; // ID of the edge based node (node based edge)
|
||||
EdgeWeight weight;
|
||||
EdgeDistance distance;
|
||||
EdgeWeight duration : 30;
|
||||
std::uint32_t forward : 1;
|
||||
std::uint32_t backward : 1;
|
||||
@@ -43,6 +48,7 @@ struct EdgeBasedEdge
|
||||
const NodeID edge_id,
|
||||
const EdgeWeight weight,
|
||||
const EdgeWeight duration,
|
||||
const EdgeDistance distance,
|
||||
const bool forward,
|
||||
const bool backward);
|
||||
EdgeBasedEdge(const NodeID source, const NodeID target, const EdgeBasedEdge::EdgeData &data);
|
||||
@@ -53,7 +59,7 @@ struct EdgeBasedEdge
|
||||
NodeID target;
|
||||
EdgeData data;
|
||||
};
|
||||
static_assert(sizeof(extractor::EdgeBasedEdge) == 20,
|
||||
static_assert(sizeof(extractor::EdgeBasedEdge) == 24,
|
||||
"Size of extractor::EdgeBasedEdge type is "
|
||||
"bigger than expected. This will influence "
|
||||
"memory consumption.");
|
||||
@@ -67,9 +73,10 @@ inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
|
||||
const NodeID turn_id,
|
||||
const EdgeWeight weight,
|
||||
const EdgeWeight duration,
|
||||
const EdgeDistance distance,
|
||||
const bool forward,
|
||||
const bool backward)
|
||||
: source(source), target(target), data{turn_id, weight, duration, forward, backward}
|
||||
: source(source), target(target), data{turn_id, weight, distance, duration, forward, backward}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -89,8 +89,9 @@ class EdgeBasedGraphFactory
|
||||
// The following get access functions destroy the content in the factory
|
||||
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
|
||||
void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes);
|
||||
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
|
||||
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
|
||||
void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations);
|
||||
void GetEdgeBasedNodeDistances(std::vector<EdgeDistance> &output_node_distances);
|
||||
std::uint32_t GetConnectivityChecksum() const;
|
||||
|
||||
std::uint64_t GetNumberOfEdgeBasedNodes() const;
|
||||
@@ -110,13 +111,11 @@ class EdgeBasedGraphFactory
|
||||
std::vector<ConditionalTurnPenalty>
|
||||
IndexConditionals(std::vector<Conditional> &&conditionals) const;
|
||||
|
||||
//! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
|
||||
//! graph
|
||||
std::vector<bool> m_edge_based_node_is_startpoint;
|
||||
|
||||
//! node weights that indicate the length of the segment (node based) represented by the
|
||||
//! edge-based node
|
||||
std::vector<EdgeWeight> m_edge_based_node_weights;
|
||||
std::vector<EdgeDuration> m_edge_based_node_durations;
|
||||
std::vector<EdgeDistance> m_edge_based_node_distances;
|
||||
|
||||
//! list of edge based nodes (compressed segments)
|
||||
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
|
||||
|
||||
@@ -22,7 +22,9 @@ struct EdgeBasedNodeSegment
|
||||
EdgeBasedNodeSegment()
|
||||
: forward_segment_id{SPECIAL_SEGMENTID, false},
|
||||
reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID), v(SPECIAL_NODEID),
|
||||
fwd_segment_position(std::numeric_limits<unsigned short>::max())
|
||||
fwd_segment_position(std::numeric_limits<unsigned short>::max() >>
|
||||
1), // >> 1 because we've only got 15 bits
|
||||
is_startpoint(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -30,9 +32,10 @@ struct EdgeBasedNodeSegment
|
||||
const SegmentID reverse_segment_id_,
|
||||
NodeID u,
|
||||
NodeID v,
|
||||
unsigned short fwd_segment_position)
|
||||
unsigned short fwd_segment_position,
|
||||
bool is_startpoint_)
|
||||
: forward_segment_id(forward_segment_id_), reverse_segment_id(reverse_segment_id_), u(u),
|
||||
v(v), fwd_segment_position(fwd_segment_position)
|
||||
v(v), fwd_segment_position(fwd_segment_position), is_startpoint(is_startpoint_)
|
||||
{
|
||||
BOOST_ASSERT(forward_segment_id.enabled || reverse_segment_id.enabled);
|
||||
}
|
||||
@@ -41,7 +44,8 @@ struct EdgeBasedNodeSegment
|
||||
SegmentID reverse_segment_id; // edge-based graph node ID in reverse direction (v->u if exists)
|
||||
NodeID u; // node-based graph node ID of the start node
|
||||
NodeID v; // node-based graph node ID of the target node
|
||||
unsigned short fwd_segment_position; // segment id in a compressed geometry
|
||||
unsigned short fwd_segment_position : 15; // segment id in a compressed geometry
|
||||
bool is_startpoint : 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,8 +85,9 @@ class Extractor
|
||||
// output data
|
||||
EdgeBasedNodeDataContainer &edge_based_nodes_container,
|
||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
std::vector<EdgeDuration> &edge_based_node_durations,
|
||||
std::vector<EdgeDistance> &edge_based_node_distances,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::uint32_t &connectivity_checksum);
|
||||
|
||||
@@ -95,7 +96,6 @@ class Extractor
|
||||
const std::vector<EdgeBasedNodeSegment> &input_node_segments,
|
||||
EdgeBasedNodeDataContainer &nodes_container) const;
|
||||
void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments,
|
||||
std::vector<bool> node_is_startpoint,
|
||||
const std::vector<util::Coordinate> &coordinates);
|
||||
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ struct ExtractorConfig final : storage::IOConfig
|
||||
".osrm.geometry",
|
||||
".osrm.nbg_nodes",
|
||||
".osrm.ebg_nodes",
|
||||
".osrm.timestamp",
|
||||
".osrm.edges",
|
||||
".osrm.ebg",
|
||||
".osrm.ramIndex",
|
||||
@@ -82,6 +83,7 @@ struct ExtractorConfig final : storage::IOConfig
|
||||
boost::filesystem::path input_path;
|
||||
boost::filesystem::path profile_path;
|
||||
std::vector<boost::filesystem::path> location_dependent_data_paths;
|
||||
std::string data_version;
|
||||
|
||||
unsigned requested_num_threads;
|
||||
unsigned small_component_size;
|
||||
|
||||
@@ -308,6 +308,26 @@ inline void writeTurnLaneData(const boost::filesystem::path &path,
|
||||
storage::serialization::write(writer, "/common/turn_lanes/data", turn_lane_data);
|
||||
}
|
||||
|
||||
// reads .osrm.timestamp
|
||||
template <typename TimestampDataT>
|
||||
inline void readTimestamp(const boost::filesystem::path &path, TimestampDataT ×tamp)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
|
||||
storage::tar::FileReader reader{path, fingerprint};
|
||||
|
||||
storage::serialization::read(reader, "/common/timestamp", timestamp);
|
||||
}
|
||||
|
||||
// writes .osrm.timestamp
|
||||
template <typename TimestampDataT>
|
||||
inline void writeTimestamp(const boost::filesystem::path &path, const TimestampDataT ×tamp)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
|
||||
storage::tar::FileWriter writer{path, fingerprint};
|
||||
|
||||
storage::serialization::write(writer, "/common/timestamp", timestamp);
|
||||
}
|
||||
|
||||
// reads .osrm.maneuver_overrides
|
||||
template <typename StorageManeuverOverrideT, typename NodeSequencesT>
|
||||
inline void readManeuverOverrides(const boost::filesystem::path &path,
|
||||
@@ -453,8 +473,8 @@ void writeNames(const boost::filesystem::path &path, const NameTableT &table)
|
||||
serialization::write(writer, "/common/names", table);
|
||||
}
|
||||
|
||||
template <typename NodeWeigtsVectorT>
|
||||
void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVectorT &weights)
|
||||
template <typename NodeWeightsVectorT>
|
||||
void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeightsVectorT &weights)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
|
||||
storage::tar::FileReader reader{path, fingerprint};
|
||||
@@ -462,14 +482,52 @@ void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVec
|
||||
storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights);
|
||||
}
|
||||
|
||||
template <typename NodeWeigtsVectorT>
|
||||
void writeEdgeBasedNodeWeights(const boost::filesystem::path &path,
|
||||
const NodeWeigtsVectorT &weights)
|
||||
template <typename NodeDistancesVectorT>
|
||||
void readEdgeBasedNodeDistances(const boost::filesystem::path &path,
|
||||
NodeDistancesVectorT &distances)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
|
||||
storage::tar::FileReader reader{path, fingerprint};
|
||||
|
||||
storage::serialization::read(reader, "/extractor/edge_based_node_distances", distances);
|
||||
}
|
||||
|
||||
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT, typename NodeDistancesVectorT>
|
||||
void writeEdgeBasedNodeWeightsDurationsDistances(const boost::filesystem::path &path,
|
||||
const NodeWeightsVectorT &weights,
|
||||
const NodeDurationsVectorT &durations,
|
||||
const NodeDistancesVectorT &distances)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
|
||||
storage::tar::FileWriter writer{path, fingerprint};
|
||||
|
||||
storage::serialization::write(writer, "/extractor/edge_based_node_weights", weights);
|
||||
storage::serialization::write(writer, "/extractor/edge_based_node_durations", durations);
|
||||
storage::serialization::write(writer, "/extractor/edge_based_node_distances", distances);
|
||||
}
|
||||
|
||||
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT>
|
||||
void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
|
||||
NodeWeightsVectorT &weights,
|
||||
NodeDurationsVectorT &durations)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
|
||||
storage::tar::FileReader reader{path, fingerprint};
|
||||
|
||||
storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights);
|
||||
storage::serialization::read(reader, "/extractor/edge_based_node_durations", durations);
|
||||
}
|
||||
|
||||
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT>
|
||||
void writeEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
|
||||
const NodeWeightsVectorT &weights,
|
||||
const NodeDurationsVectorT &durations)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
|
||||
storage::tar::FileWriter writer{path, fingerprint};
|
||||
|
||||
storage::serialization::write(writer, "/extractor/edge_based_node_weights", weights);
|
||||
storage::serialization::write(writer, "/extractor/edge_based_node_durations", durations);
|
||||
}
|
||||
|
||||
template <typename RTreeT>
|
||||
|
||||
@@ -63,7 +63,7 @@ struct InternalExtractorEdge
|
||||
WeightData weight_data,
|
||||
DurationData duration_data,
|
||||
util::Coordinate source_coordinate)
|
||||
: result(source, target, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)),
|
||||
: result(source, target, 0, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)),
|
||||
duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ struct NodeBasedEdge
|
||||
NodeID target,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance,
|
||||
GeometryID geometry_id,
|
||||
AnnotationID annotation_data,
|
||||
NodeBasedEdgeClassification flags);
|
||||
@@ -107,6 +108,7 @@ struct NodeBasedEdge
|
||||
NodeID target; // 32 4
|
||||
EdgeWeight weight; // 32 4
|
||||
EdgeDuration duration; // 32 4
|
||||
EdgeDistance distance; // 32 4
|
||||
GeometryID geometry_id; // 32 4
|
||||
AnnotationID annotation_data; // 32 4
|
||||
NodeBasedEdgeClassification flags; // 32 4
|
||||
@@ -120,6 +122,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
OSMNodeID target,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance,
|
||||
GeometryID geometry_id,
|
||||
AnnotationID annotation_data,
|
||||
NodeBasedEdgeClassification flags);
|
||||
@@ -137,7 +140,8 @@ inline NodeBasedEdgeClassification::NodeBasedEdgeClassification()
|
||||
}
|
||||
|
||||
inline NodeBasedEdge::NodeBasedEdge()
|
||||
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), annotation_data(-1)
|
||||
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), distance(0),
|
||||
annotation_data(-1)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -145,11 +149,12 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
|
||||
NodeID target,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance,
|
||||
GeometryID geometry_id,
|
||||
AnnotationID annotation_data,
|
||||
NodeBasedEdgeClassification flags)
|
||||
: source(source), target(target), weight(weight), duration(duration), geometry_id(geometry_id),
|
||||
annotation_data(annotation_data), flags(flags)
|
||||
: source(source), target(target), weight(weight), duration(duration), distance(distance),
|
||||
geometry_id(geometry_id), annotation_data(annotation_data), flags(flags)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -175,11 +180,18 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
OSMNodeID target,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance,
|
||||
GeometryID geometry_id,
|
||||
AnnotationID annotation_data,
|
||||
NodeBasedEdgeClassification flags)
|
||||
: NodeBasedEdge(
|
||||
SPECIAL_NODEID, SPECIAL_NODEID, weight, duration, geometry_id, annotation_data, flags),
|
||||
: NodeBasedEdge(SPECIAL_NODEID,
|
||||
SPECIAL_NODEID,
|
||||
weight,
|
||||
duration,
|
||||
distance,
|
||||
geometry_id,
|
||||
annotation_data,
|
||||
flags),
|
||||
osm_source_id(std::move(source)), osm_target_id(std::move(target))
|
||||
{
|
||||
}
|
||||
@@ -189,7 +201,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM()
|
||||
{
|
||||
}
|
||||
|
||||
static_assert(sizeof(extractor::NodeBasedEdge) == 28,
|
||||
static_assert(sizeof(extractor::NodeBasedEdge) == 32,
|
||||
"Size of extractor::NodeBasedEdge type is "
|
||||
"bigger than expected. This will influence "
|
||||
"memory consumption.");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define OSRM_BINDINGS_NODE_SUPPORT_HPP
|
||||
|
||||
#include "nodejs/json_v8_renderer.hpp"
|
||||
#include "util/json_renderer.hpp"
|
||||
|
||||
#include "osrm/approach.hpp"
|
||||
#include "osrm/bearing.hpp"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -42,6 +44,13 @@ using match_parameters_ptr = std::unique_ptr<osrm::MatchParameters>;
|
||||
using nearest_parameters_ptr = std::unique_ptr<osrm::NearestParameters>;
|
||||
using table_parameters_ptr = std::unique_ptr<osrm::TableParameters>;
|
||||
|
||||
struct PluginParameters
|
||||
{
|
||||
bool renderJSONToBuffer = false;
|
||||
};
|
||||
|
||||
using ObjectOrString = typename mapbox::util::variant<osrm::json::Object, std::string>;
|
||||
|
||||
template <typename ResultT> inline v8::Local<v8::Value> render(const ResultT &result);
|
||||
|
||||
template <> v8::Local<v8::Value> inline render(const std::string &result)
|
||||
@@ -49,11 +58,21 @@ template <> v8::Local<v8::Value> inline render(const std::string &result)
|
||||
return Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked();
|
||||
}
|
||||
|
||||
template <> v8::Local<v8::Value> inline render(const osrm::json::Object &result)
|
||||
template <> v8::Local<v8::Value> inline render(const ObjectOrString &result)
|
||||
{
|
||||
v8::Local<v8::Value> value;
|
||||
renderToV8(value, result);
|
||||
return value;
|
||||
if (result.is<osrm::json::Object>())
|
||||
{
|
||||
// Convert osrm::json object tree into matching v8 object tree
|
||||
v8::Local<v8::Value> value;
|
||||
renderToV8(value, result.get<osrm::json::Object>());
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return the string object as a node Buffer
|
||||
return Nan::CopyBuffer(result.get<std::string>().data(), result.get<std::string>().size())
|
||||
.ToLocalChecked();
|
||||
}
|
||||
}
|
||||
|
||||
inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result)
|
||||
@@ -123,6 +142,10 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
||||
if (shared_memory.IsEmpty())
|
||||
return engine_config_ptr();
|
||||
|
||||
auto mmap_memory = params->Get(Nan::New("mmap_memory").ToLocalChecked());
|
||||
if (mmap_memory.IsEmpty())
|
||||
return engine_config_ptr();
|
||||
|
||||
if (!memory_file->IsUndefined())
|
||||
{
|
||||
if (path->IsUndefined())
|
||||
@@ -171,6 +194,18 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
||||
return engine_config_ptr();
|
||||
}
|
||||
}
|
||||
if (!mmap_memory->IsUndefined())
|
||||
{
|
||||
if (mmap_memory->IsBoolean())
|
||||
{
|
||||
engine_config->use_mmap = Nan::To<bool>(mmap_memory).FromJust();
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("mmap_memory option must be a boolean");
|
||||
return engine_config_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
if (path->IsUndefined() && !engine_config->use_shared_memory)
|
||||
{
|
||||
@@ -814,6 +849,50 @@ inline bool parseCommonParameters(const v8::Local<v8::Object> &obj, ParamType &p
|
||||
return true;
|
||||
}
|
||||
|
||||
inline PluginParameters
|
||||
argumentsToPluginParameters(const Nan::FunctionCallbackInfo<v8::Value> &args)
|
||||
{
|
||||
if (args.Length() < 3 || !args[1]->IsObject())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
v8::Local<v8::Object> obj = Nan::To<v8::Object>(args[1]).ToLocalChecked();
|
||||
if (obj->Has(Nan::New("format").ToLocalChecked()))
|
||||
{
|
||||
|
||||
v8::Local<v8::Value> format = obj->Get(Nan::New("format").ToLocalChecked());
|
||||
if (format.IsEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!format->IsString())
|
||||
{
|
||||
Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\"");
|
||||
return {};
|
||||
}
|
||||
|
||||
const Nan::Utf8String format_utf8str(format);
|
||||
std::string format_str{*format_utf8str, *format_utf8str + format_utf8str.length()};
|
||||
|
||||
if (format_str == "object")
|
||||
{
|
||||
return {false};
|
||||
}
|
||||
else if (format_str == "json_buffer")
|
||||
{
|
||||
return {true};
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\"");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
inline route_parameters_ptr
|
||||
argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
bool requires_multiple_coordinates)
|
||||
@@ -865,6 +944,101 @@ argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->Has(Nan::New("waypoints").ToLocalChecked()))
|
||||
{
|
||||
v8::Local<v8::Value> waypoints = obj->Get(Nan::New("waypoints").ToLocalChecked());
|
||||
if (waypoints.IsEmpty())
|
||||
return route_parameters_ptr();
|
||||
|
||||
// must be array
|
||||
if (!waypoints->IsArray())
|
||||
{
|
||||
Nan::ThrowError(
|
||||
"Waypoints must be an array of integers corresponding to the input coordinates.");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
|
||||
auto waypoints_array = v8::Local<v8::Array>::Cast(waypoints);
|
||||
// must have at least two elements
|
||||
if (waypoints_array->Length() < 2)
|
||||
{
|
||||
Nan::ThrowError("At least two waypoints must be provided");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
auto coords_size = params->coordinates.size();
|
||||
auto waypoints_array_size = waypoints_array->Length();
|
||||
|
||||
const auto first_index = Nan::To<std::uint32_t>(waypoints_array->Get(0)).FromJust();
|
||||
const auto last_index =
|
||||
Nan::To<std::uint32_t>(waypoints_array->Get(waypoints_array_size - 1)).FromJust();
|
||||
if (first_index != 0 || last_index != coords_size - 1)
|
||||
{
|
||||
Nan::ThrowError("First and last waypoints values must correspond to first and last "
|
||||
"coordinate indices");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < waypoints_array_size; ++i)
|
||||
{
|
||||
v8::Local<v8::Value> waypoint_value = waypoints_array->Get(i);
|
||||
// all elements must be numbers
|
||||
if (!waypoint_value->IsNumber())
|
||||
{
|
||||
Nan::ThrowError("Waypoint values must be an array of integers");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
// check that the waypoint index corresponds with an inpute coordinate
|
||||
const auto index = Nan::To<std::uint32_t>(waypoint_value).FromJust();
|
||||
if (index >= coords_size)
|
||||
{
|
||||
Nan::ThrowError("Waypoints must correspond with the index of an input coordinate");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
params->waypoints.emplace_back(static_cast<unsigned>(waypoint_value->NumberValue()));
|
||||
}
|
||||
|
||||
if (!params->waypoints.empty())
|
||||
{
|
||||
for (std::size_t i = 0; i < params->waypoints.size() - 1; i++)
|
||||
{
|
||||
if (params->waypoints[i] >= params->waypoints[i + 1])
|
||||
{
|
||||
Nan::ThrowError("Waypoints must be supplied in increasing order");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->Has(Nan::New("snapping").ToLocalChecked()))
|
||||
{
|
||||
v8::Local<v8::Value> snapping = obj->Get(Nan::New("snapping").ToLocalChecked());
|
||||
if (snapping.IsEmpty())
|
||||
return route_parameters_ptr();
|
||||
|
||||
if (!snapping->IsString())
|
||||
{
|
||||
Nan::ThrowError("Snapping must be a string: [default, any]");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
const Nan::Utf8String snapping_utf8str(snapping);
|
||||
std::string snapping_str{*snapping_utf8str, *snapping_utf8str + snapping_utf8str.length()};
|
||||
|
||||
if (snapping_str == "default")
|
||||
{
|
||||
params->snapping = osrm::RouteParameters::SnappingType::Default;
|
||||
}
|
||||
else if (snapping_str == "any")
|
||||
{
|
||||
params->snapping = osrm::RouteParameters::SnappingType::Any;
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("'snapping' param must be one of [default, any]");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
bool parsedSuccessfully = parseCommonParameters(obj, params);
|
||||
if (!parsedSuccessfully)
|
||||
{
|
||||
@@ -1064,6 +1238,110 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->Has(Nan::New("annotations").ToLocalChecked()))
|
||||
{
|
||||
v8::Local<v8::Value> annotations = obj->Get(Nan::New("annotations").ToLocalChecked());
|
||||
if (annotations.IsEmpty())
|
||||
return table_parameters_ptr();
|
||||
|
||||
if (!annotations->IsArray())
|
||||
{
|
||||
Nan::ThrowError(
|
||||
"Annotations must an array containing 'duration' or 'distance', or both");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
|
||||
params->annotations = osrm::TableParameters::AnnotationsType::None;
|
||||
|
||||
v8::Local<v8::Array> annotations_array = v8::Local<v8::Array>::Cast(annotations);
|
||||
for (std::size_t i = 0; i < annotations_array->Length(); ++i)
|
||||
{
|
||||
const Nan::Utf8String annotations_utf8str(annotations_array->Get(i));
|
||||
std::string annotations_str{*annotations_utf8str,
|
||||
*annotations_utf8str + annotations_utf8str.length()};
|
||||
|
||||
if (annotations_str == "duration")
|
||||
{
|
||||
params->annotations =
|
||||
params->annotations | osrm::TableParameters::AnnotationsType::Duration;
|
||||
}
|
||||
else if (annotations_str == "distance")
|
||||
{
|
||||
params->annotations =
|
||||
params->annotations | osrm::TableParameters::AnnotationsType::Distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("this 'annotations' param is not supported");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->Has(Nan::New("fallback_speed").ToLocalChecked()))
|
||||
{
|
||||
auto fallback_speed = obj->Get(Nan::New("fallback_speed").ToLocalChecked());
|
||||
|
||||
if (!fallback_speed->IsNumber())
|
||||
{
|
||||
Nan::ThrowError("fallback_speed must be a number");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
else if (fallback_speed->NumberValue() <= 0)
|
||||
{
|
||||
Nan::ThrowError("fallback_speed must be > 0");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
|
||||
params->fallback_speed = static_cast<double>(fallback_speed->NumberValue());
|
||||
}
|
||||
|
||||
if (obj->Has(Nan::New("fallback_coordinate").ToLocalChecked()))
|
||||
{
|
||||
auto fallback_coordinate = obj->Get(Nan::New("fallback_coordinate").ToLocalChecked());
|
||||
|
||||
if (!fallback_coordinate->IsString())
|
||||
{
|
||||
Nan::ThrowError("fallback_coordinate must be a string: [input, snapped]");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
|
||||
std::string fallback_coordinate_str = *v8::String::Utf8Value(fallback_coordinate);
|
||||
|
||||
if (fallback_coordinate_str == "snapped")
|
||||
{
|
||||
params->fallback_coordinate_type =
|
||||
osrm::TableParameters::FallbackCoordinateType::Snapped;
|
||||
}
|
||||
else if (fallback_coordinate_str == "input")
|
||||
{
|
||||
params->fallback_coordinate_type = osrm::TableParameters::FallbackCoordinateType::Input;
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("'fallback_coordinate' param must be one of [input, snapped]");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->Has(Nan::New("scale_factor").ToLocalChecked()))
|
||||
{
|
||||
auto scale_factor = obj->Get(Nan::New("scale_factor").ToLocalChecked());
|
||||
|
||||
if (!scale_factor->IsNumber())
|
||||
{
|
||||
Nan::ThrowError("scale_factor must be a number");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
else if (scale_factor->NumberValue() <= 0)
|
||||
{
|
||||
Nan::ThrowError("scale_factor must be > 0");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
|
||||
params->scale_factor = static_cast<double>(scale_factor->NumberValue());
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -1317,6 +1595,6 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
return params;
|
||||
}
|
||||
|
||||
} // ns node_osrm
|
||||
} // namespace node_osrm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -75,28 +75,35 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
|
||||
// Implementation of the cell view. We need a template parameter here
|
||||
// because we need to derive a read-only and read-write view from this.
|
||||
template <typename WeightValueT, typename DurationValueT> class CellImpl
|
||||
template <typename WeightValueT, typename DurationValueT, typename DistanceValueT>
|
||||
class CellImpl
|
||||
{
|
||||
private:
|
||||
using WeightPtrT = WeightValueT *;
|
||||
using DurationPtrT = DurationValueT *;
|
||||
using DistancePtrT = DistanceValueT *;
|
||||
BoundarySize num_source_nodes;
|
||||
BoundarySize num_destination_nodes;
|
||||
|
||||
WeightPtrT const weights;
|
||||
DurationPtrT const durations;
|
||||
DistancePtrT const distances;
|
||||
const NodeID *const source_boundary;
|
||||
const NodeID *const destination_boundary;
|
||||
|
||||
using RowIterator = WeightPtrT;
|
||||
// Possibly replace with
|
||||
// http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/reference/adaptors/reference/strided.html
|
||||
class ColumnIterator : public boost::iterator_facade<ColumnIterator,
|
||||
WeightValueT,
|
||||
|
||||
template <typename ValuePtrT>
|
||||
class ColumnIterator : public boost::iterator_facade<ColumnIterator<ValuePtrT>,
|
||||
decltype(*std::declval<ValuePtrT>()),
|
||||
boost::random_access_traversal_tag>
|
||||
{
|
||||
typedef boost::iterator_facade<ColumnIterator,
|
||||
WeightValueT,
|
||||
|
||||
using ValueT = decltype(*std::declval<ValuePtrT>());
|
||||
typedef boost::iterator_facade<ColumnIterator<ValueT>,
|
||||
ValueT,
|
||||
boost::random_access_traversal_tag>
|
||||
base_t;
|
||||
|
||||
@@ -108,7 +115,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
|
||||
explicit ColumnIterator() : current(nullptr), stride(1) {}
|
||||
|
||||
explicit ColumnIterator(WeightPtrT begin, std::size_t row_length)
|
||||
explicit ColumnIterator(ValuePtrT begin, std::size_t row_length)
|
||||
: current(begin), stride(row_length)
|
||||
{
|
||||
BOOST_ASSERT(begin != nullptr);
|
||||
@@ -126,7 +133,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
}
|
||||
|
||||
friend class ::boost::iterator_core_access;
|
||||
WeightPtrT current;
|
||||
ValuePtrT current;
|
||||
const std::size_t stride;
|
||||
};
|
||||
|
||||
@@ -147,12 +154,13 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
auto iter =
|
||||
std::find(destination_boundary, destination_boundary + num_destination_nodes, node);
|
||||
if (iter == destination_boundary + num_destination_nodes)
|
||||
return boost::make_iterator_range(ColumnIterator{}, ColumnIterator{});
|
||||
return boost::make_iterator_range(ColumnIterator<ValuePtr>{},
|
||||
ColumnIterator<ValuePtr>{});
|
||||
|
||||
auto column = std::distance(destination_boundary, iter);
|
||||
auto begin = ColumnIterator{ptr + column, num_destination_nodes};
|
||||
auto end = ColumnIterator{ptr + column + num_source_nodes * num_destination_nodes,
|
||||
num_destination_nodes};
|
||||
auto begin = ColumnIterator<ValuePtr>{ptr + column, num_destination_nodes};
|
||||
auto end = ColumnIterator<ValuePtr>{
|
||||
ptr + column + num_source_nodes * num_destination_nodes, num_destination_nodes};
|
||||
return boost::make_iterator_range(begin, end);
|
||||
}
|
||||
|
||||
@@ -165,6 +173,10 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
|
||||
auto GetInDuration(NodeID node) const { return GetInRange(durations, node); }
|
||||
|
||||
auto GetInDistance(NodeID node) const { return GetInRange(distances, node); }
|
||||
|
||||
auto GetOutDistance(NodeID node) const { return GetOutRange(distances, node); }
|
||||
|
||||
auto GetSourceNodes() const
|
||||
{
|
||||
return boost::make_iterator_range(source_boundary, source_boundary + num_source_nodes);
|
||||
@@ -179,17 +191,20 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
CellImpl(const CellData &data,
|
||||
WeightPtrT const all_weights,
|
||||
DurationPtrT const all_durations,
|
||||
DistancePtrT const all_distances,
|
||||
const NodeID *const all_sources,
|
||||
const NodeID *const all_destinations)
|
||||
: num_source_nodes{data.num_source_nodes},
|
||||
num_destination_nodes{data.num_destination_nodes},
|
||||
weights{all_weights + data.value_offset},
|
||||
durations{all_durations + data.value_offset},
|
||||
distances{all_distances + data.value_offset},
|
||||
source_boundary{all_sources + data.source_boundary_offset},
|
||||
destination_boundary{all_destinations + data.destination_boundary_offset}
|
||||
{
|
||||
BOOST_ASSERT(all_weights != nullptr);
|
||||
BOOST_ASSERT(all_durations != nullptr);
|
||||
BOOST_ASSERT(all_distances != nullptr);
|
||||
BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr);
|
||||
BOOST_ASSERT(num_destination_nodes == 0 || all_destinations != nullptr);
|
||||
}
|
||||
@@ -201,7 +216,8 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
const NodeID *const all_destinations)
|
||||
: num_source_nodes{data.num_source_nodes},
|
||||
num_destination_nodes{data.num_destination_nodes}, weights{nullptr},
|
||||
durations{nullptr}, source_boundary{all_sources + data.source_boundary_offset},
|
||||
durations{nullptr}, distances{nullptr},
|
||||
source_boundary{all_sources + data.source_boundary_offset},
|
||||
destination_boundary{all_destinations + data.destination_boundary_offset}
|
||||
{
|
||||
BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr);
|
||||
@@ -212,8 +228,8 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
std::size_t LevelIDToIndex(LevelID level) const { return level - 1; }
|
||||
|
||||
public:
|
||||
using Cell = CellImpl<EdgeWeight, EdgeDuration>;
|
||||
using ConstCell = CellImpl<const EdgeWeight, const EdgeDuration>;
|
||||
using Cell = CellImpl<EdgeWeight, EdgeDuration, EdgeDistance>;
|
||||
using ConstCell = CellImpl<const EdgeWeight, const EdgeDuration, const EdgeDistance>;
|
||||
|
||||
CellStorageImpl() {}
|
||||
|
||||
@@ -361,6 +377,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
|
||||
metric.weights.resize(total_size + 1, INVALID_EDGE_WEIGHT);
|
||||
metric.durations.resize(total_size + 1, MAXIMAL_EDGE_DURATION);
|
||||
metric.distances.resize(total_size + 1, INVALID_EDGE_DISTANCE);
|
||||
|
||||
return metric;
|
||||
}
|
||||
@@ -388,6 +405,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
return ConstCell{cells[cell_index],
|
||||
metric.weights.data(),
|
||||
metric.durations.data(),
|
||||
metric.distances.data(),
|
||||
source_boundary.empty() ? nullptr : source_boundary.data(),
|
||||
destination_boundary.empty() ? nullptr : destination_boundary.data()};
|
||||
}
|
||||
@@ -415,6 +433,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
return Cell{cells[cell_index],
|
||||
metric.weights.data(),
|
||||
metric.durations.data(),
|
||||
metric.distances.data(),
|
||||
source_boundary.data(),
|
||||
destination_boundary.data()};
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ splitBidirectionalEdges(const std::vector<extractor::EdgeBasedEdge> &edges)
|
||||
edge.data.turn_id,
|
||||
std::max(edge.data.weight, 1),
|
||||
edge.data.duration,
|
||||
edge.data.distance,
|
||||
edge.data.forward,
|
||||
edge.data.backward);
|
||||
|
||||
@@ -51,6 +52,7 @@ splitBidirectionalEdges(const std::vector<extractor::EdgeBasedEdge> &edges)
|
||||
edge.data.turn_id,
|
||||
std::max(edge.data.weight, 1),
|
||||
edge.data.duration,
|
||||
edge.data.distance,
|
||||
edge.data.backward,
|
||||
edge.data.forward);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#ifndef OSRM_PARTITIONER_SERILIZATION_HPP
|
||||
#define OSRM_PARTITIONER_SERILIZATION_HPP
|
||||
|
||||
#include "customizer/edge_based_graph.hpp"
|
||||
|
||||
#include "partitioner/serialization.hpp"
|
||||
|
||||
#include "storage/io.hpp"
|
||||
@@ -14,39 +12,6 @@ namespace partitioner
|
||||
namespace files
|
||||
{
|
||||
|
||||
// reads .osrm.mldgr file
|
||||
template <typename MultiLevelGraphT>
|
||||
inline void readGraph(const boost::filesystem::path &path,
|
||||
MultiLevelGraphT &graph,
|
||||
std::uint32_t &connectivity_checksum)
|
||||
{
|
||||
static_assert(std::is_same<customizer::MultiLevelEdgeBasedGraphView, MultiLevelGraphT>::value ||
|
||||
std::is_same<customizer::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value,
|
||||
"");
|
||||
|
||||
storage::tar::FileReader reader{path, storage::tar::FileReader::VerifyFingerprint};
|
||||
|
||||
reader.ReadInto("/mld/connectivity_checksum", connectivity_checksum);
|
||||
serialization::read(reader, "/mld/multilevelgraph", graph);
|
||||
}
|
||||
|
||||
// writes .osrm.mldgr file
|
||||
template <typename MultiLevelGraphT>
|
||||
inline void writeGraph(const boost::filesystem::path &path,
|
||||
const MultiLevelGraphT &graph,
|
||||
const std::uint32_t connectivity_checksum)
|
||||
{
|
||||
static_assert(std::is_same<customizer::MultiLevelEdgeBasedGraphView, MultiLevelGraphT>::value ||
|
||||
std::is_same<customizer::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value,
|
||||
"");
|
||||
|
||||
storage::tar::FileWriter writer{path, storage::tar::FileWriter::GenerateFingerprint};
|
||||
|
||||
writer.WriteElementCount64("/mld/connectivity_checksum", 1);
|
||||
writer.WriteFrom("/mld/connectivity_checksum", connectivity_checksum);
|
||||
serialization::write(writer, "/mld/multilevelgraph", graph);
|
||||
}
|
||||
|
||||
// read .osrm.partition file
|
||||
template <typename MultiLevelPartitionT>
|
||||
inline void readPartition(const boost::filesystem::path &path, MultiLevelPartitionT &mlp)
|
||||
@@ -102,6 +67,35 @@ inline void writeCells(const boost::filesystem::path &path, CellStorageT &storag
|
||||
|
||||
serialization::write(writer, "/mld/cellstorage", storage);
|
||||
}
|
||||
|
||||
// reads .osrm.mldgr file
|
||||
template <typename MultiLevelGraphT>
|
||||
inline void readGraph(const boost::filesystem::path &path,
|
||||
MultiLevelGraphT &graph,
|
||||
std::uint32_t &connectivity_checksum)
|
||||
{
|
||||
static_assert(std::is_same<partitioner::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value, "");
|
||||
|
||||
storage::tar::FileReader reader{path, storage::tar::FileReader::VerifyFingerprint};
|
||||
|
||||
reader.ReadInto("/mld/connectivity_checksum", connectivity_checksum);
|
||||
serialization::read(reader, "/mld/multilevelgraph", graph);
|
||||
}
|
||||
|
||||
// writes .osrm.mldgr file
|
||||
template <typename MultiLevelGraphT>
|
||||
inline void writeGraph(const boost::filesystem::path &path,
|
||||
const MultiLevelGraphT &graph,
|
||||
const std::uint32_t connectivity_checksum)
|
||||
{
|
||||
static_assert(std::is_same<partitioner::MultiLevelEdgeBasedGraph, MultiLevelGraphT>::value, "");
|
||||
|
||||
storage::tar::FileWriter writer{path, storage::tar::FileWriter::GenerateFingerprint};
|
||||
|
||||
writer.WriteElementCount64("/mld/connectivity_checksum", 1);
|
||||
writer.WriteFrom("/mld/connectivity_checksum", connectivity_checksum);
|
||||
serialization::write(writer, "/mld/multilevelgraph", graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef OSRM_PARTITIONER_MULTI_LEVEL_GRAPH_HPP
|
||||
#define OSRM_PARTITIONER_MULTI_LEVEL_GRAPH_HPP
|
||||
|
||||
#include "partitioner/edge_based_graph.hpp"
|
||||
#include "partitioner/multi_level_partition.hpp"
|
||||
|
||||
#include "storage/shared_memory_ownership.hpp"
|
||||
@@ -42,6 +43,8 @@ class MultiLevelGraph : public util::StaticGraph<EdgeDataT, Ownership>
|
||||
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
|
||||
|
||||
public:
|
||||
using SuperT::SuperT;
|
||||
|
||||
// We limit each node to have 255 edges
|
||||
// this is very generous, we could probably pack this
|
||||
using EdgeOffset = std::uint8_t;
|
||||
@@ -146,6 +149,14 @@ class MultiLevelGraph : public util::StaticGraph<EdgeDataT, Ownership>
|
||||
return max_border_node_id;
|
||||
}
|
||||
|
||||
auto data() && // rvalue ref-qualifier is a safety-belt
|
||||
{
|
||||
return std::make_tuple(std::move(SuperT::node_array),
|
||||
std::move(SuperT::edge_array),
|
||||
std::move(node_to_edge_offset),
|
||||
connectivity_checksum);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename ContainerT>
|
||||
auto GetHighestBorderLevel(const MultiLevelPartition &mlp, const ContainerT &edges) const
|
||||
@@ -218,9 +229,13 @@ class MultiLevelGraph : public util::StaticGraph<EdgeDataT, Ownership>
|
||||
const std::string &name,
|
||||
const MultiLevelGraph<EdgeDataT, Ownership> &graph);
|
||||
|
||||
protected:
|
||||
Vector<EdgeOffset> node_to_edge_offset;
|
||||
std::uint32_t connectivity_checksum;
|
||||
};
|
||||
|
||||
using MultiLevelEdgeBasedGraph =
|
||||
MultiLevelGraph<EdgeBasedGraphEdgeData, storage::Ownership::Container>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace partitioner
|
||||
struct PartitionerConfig final : storage::IOConfig
|
||||
{
|
||||
PartitionerConfig()
|
||||
: IOConfig({".osrm", ".osrm.fileIndex", ".osrm.ebg_nodes"},
|
||||
: IOConfig({".osrm", ".osrm.fileIndex", ".osrm.ebg_nodes", ".osrm.enw"},
|
||||
{".osrm.hsgr", ".osrm.cnbg"},
|
||||
{".osrm.ebg",
|
||||
".osrm.cnbg",
|
||||
|
||||
@@ -19,26 +19,6 @@ namespace partitioner
|
||||
namespace serialization
|
||||
{
|
||||
|
||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||
inline void read(storage::tar::FileReader &reader,
|
||||
const std::string &name,
|
||||
MultiLevelGraph<EdgeDataT, Ownership> &graph)
|
||||
{
|
||||
storage::serialization::read(reader, name + "/node_array", graph.node_array);
|
||||
storage::serialization::read(reader, name + "/edge_array", graph.edge_array);
|
||||
storage::serialization::read(reader, name + "/node_to_edge_offset", graph.node_to_edge_offset);
|
||||
}
|
||||
|
||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||
inline void write(storage::tar::FileWriter &writer,
|
||||
const std::string &name,
|
||||
const MultiLevelGraph<EdgeDataT, Ownership> &graph)
|
||||
{
|
||||
storage::serialization::write(writer, name + "/node_array", graph.node_array);
|
||||
storage::serialization::write(writer, name + "/edge_array", graph.edge_array);
|
||||
storage::serialization::write(writer, name + "/node_to_edge_offset", graph.node_to_edge_offset);
|
||||
}
|
||||
|
||||
template <storage::Ownership Ownership>
|
||||
inline void read(storage::tar::FileReader &reader,
|
||||
const std::string &name,
|
||||
|
||||
@@ -162,6 +162,13 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
(-approach_type %
|
||||
';')[ph::bind(&engine::api::BaseParameters::approaches, qi::_r1) = qi::_1];
|
||||
|
||||
snapping_type.add("default", engine::api::BaseParameters::SnappingType::Default)(
|
||||
"any", engine::api::BaseParameters::SnappingType::Any);
|
||||
|
||||
snapping_rule =
|
||||
qi::lit("snapping=") >
|
||||
snapping_type[ph::bind(&engine::api::BaseParameters::snapping, qi::_r1) = qi::_1];
|
||||
|
||||
exclude_rule = qi::lit("exclude=") >
|
||||
(qi::as_string[+qi::char_("a-zA-Z0-9")] %
|
||||
',')[ph::bind(&engine::api::BaseParameters::exclude, qi::_r1) = qi::_1];
|
||||
@@ -171,13 +178,16 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
| bearings_rule(qi::_r1) //
|
||||
| generate_hints_rule(qi::_r1) //
|
||||
| approach_rule(qi::_r1) //
|
||||
| exclude_rule(qi::_r1);
|
||||
| exclude_rule(qi::_r1) //
|
||||
| snapping_rule(qi::_r1);
|
||||
}
|
||||
|
||||
protected:
|
||||
qi::rule<Iterator, Signature> base_rule;
|
||||
qi::rule<Iterator, Signature> query_rule;
|
||||
|
||||
qi::real_parser<double, json_policy> double_;
|
||||
|
||||
private:
|
||||
qi::rule<Iterator, Signature> bearings_rule;
|
||||
qi::rule<Iterator, Signature> radiuses_rule;
|
||||
@@ -195,9 +205,10 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
qi::rule<Iterator, unsigned char()> base64_char;
|
||||
qi::rule<Iterator, std::string()> polyline_chars;
|
||||
qi::rule<Iterator, double()> unlimited_rule;
|
||||
qi::real_parser<double, json_policy> double_;
|
||||
qi::rule<Iterator, Signature> snapping_rule;
|
||||
|
||||
qi::symbols<char, engine::Approach> approach_type;
|
||||
qi::symbols<char, engine::api::BaseParameters::SnappingType> snapping_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,17 +42,12 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
|
||||
(qi::uint_ %
|
||||
';')[ph::bind(&engine::api::MatchParameters::timestamps, qi::_r1) = qi::_1];
|
||||
|
||||
waypoints_rule =
|
||||
qi::lit("waypoints=") >
|
||||
(size_t_ % ';')[ph::bind(&engine::api::MatchParameters::waypoints, qi::_r1) = qi::_1];
|
||||
|
||||
gaps_type.add("split", engine::api::MatchParameters::GapsType::Split)(
|
||||
"ignore", engine::api::MatchParameters::GapsType::Ignore);
|
||||
|
||||
root_rule =
|
||||
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
||||
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) |
|
||||
waypoints_rule(qi::_r1) |
|
||||
(qi::lit("gaps=") >
|
||||
gaps_type[ph::bind(&engine::api::MatchParameters::gaps, qi::_r1) = qi::_1]) |
|
||||
(qi::lit("tidy=") >
|
||||
@@ -63,7 +58,6 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
|
||||
private:
|
||||
qi::rule<Iterator, Signature> root_rule;
|
||||
qi::rule<Iterator, Signature> timestamps_rule;
|
||||
qi::rule<Iterator, Signature> waypoints_rule;
|
||||
qi::rule<Iterator, std::size_t()> size_t_;
|
||||
|
||||
qi::symbols<char, engine::api::MatchParameters::GapsType> gaps_type;
|
||||
|
||||
@@ -48,6 +48,14 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
|
||||
|
||||
RouteParametersGrammar(qi::rule<Iterator, Signature> &root_rule_) : BaseGrammar(root_rule_)
|
||||
{
|
||||
#ifdef BOOST_HAS_LONG_LONG
|
||||
if (std::is_same<std::size_t, unsigned long long>::value)
|
||||
size_t_ = qi::ulong_long;
|
||||
else
|
||||
size_t_ = qi::ulong_;
|
||||
#else
|
||||
size_t_ = qi::ulong_;
|
||||
#endif
|
||||
using AnnotationsType = engine::api::RouteParameters::AnnotationsType;
|
||||
|
||||
const auto add_annotation = [](engine::api::RouteParameters &route_parameters,
|
||||
@@ -70,8 +78,12 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
|
||||
"distance", AnnotationsType::Distance)("weight", AnnotationsType::Weight)(
|
||||
"datasources", AnnotationsType::Datasources)("speed", AnnotationsType::Speed);
|
||||
|
||||
waypoints_rule =
|
||||
qi::lit("waypoints=") >
|
||||
(size_t_ % ';')[ph::bind(&engine::api::RouteParameters::waypoints, qi::_r1) = qi::_1];
|
||||
|
||||
base_rule =
|
||||
BaseGrammar::base_rule(qi::_r1) |
|
||||
BaseGrammar::base_rule(qi::_r1) | waypoints_rule(qi::_r1) |
|
||||
(qi::lit("steps=") >
|
||||
qi::bool_[ph::bind(&engine::api::RouteParameters::steps, qi::_r1) = qi::_1]) |
|
||||
(qi::lit("geometries=") >
|
||||
@@ -94,6 +106,8 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
|
||||
private:
|
||||
qi::rule<Iterator, Signature> root_rule;
|
||||
qi::rule<Iterator, Signature> route_rule;
|
||||
qi::rule<Iterator, Signature> waypoints_rule;
|
||||
qi::rule<Iterator, std::size_t()> size_t_;
|
||||
|
||||
qi::symbols<char, engine::api::RouteParameters::GeometriesType> geometries_type;
|
||||
qi::symbols<char, engine::api::RouteParameters::OverviewType> overview_type;
|
||||
|
||||
@@ -22,11 +22,11 @@ namespace qi = boost::spirit::qi;
|
||||
|
||||
template <typename Iterator = std::string::iterator,
|
||||
typename Signature = void(engine::api::TableParameters &)>
|
||||
struct TableParametersGrammar final : public BaseParametersGrammar<Iterator, Signature>
|
||||
struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature>
|
||||
{
|
||||
using BaseGrammar = BaseParametersGrammar<Iterator, Signature>;
|
||||
|
||||
TableParametersGrammar() : BaseGrammar(root_rule)
|
||||
TableParametersGrammar() : TableParametersGrammar(root_rule)
|
||||
{
|
||||
#ifdef BOOST_HAS_LONG_LONG
|
||||
if (std::is_same<std::size_t, unsigned long long>::value)
|
||||
@@ -48,18 +48,63 @@ struct TableParametersGrammar final : public BaseParametersGrammar<Iterator, Sig
|
||||
(qi::lit("all") |
|
||||
(size_t_ % ';')[ph::bind(&engine::api::TableParameters::sources, qi::_r1) = qi::_1]);
|
||||
|
||||
fallback_speed_rule =
|
||||
qi::lit("fallback_speed=") >
|
||||
(double_)[ph::bind(&engine::api::TableParameters::fallback_speed, qi::_r1) = qi::_1];
|
||||
|
||||
fallback_coordinate_type.add("input",
|
||||
engine::api::TableParameters::FallbackCoordinateType::Input)(
|
||||
"snapped", engine::api::TableParameters::FallbackCoordinateType::Snapped);
|
||||
|
||||
scale_factor_rule =
|
||||
qi::lit("scale_factor=") >
|
||||
(double_)[ph::bind(&engine::api::TableParameters::scale_factor, qi::_r1) = qi::_1];
|
||||
|
||||
table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1);
|
||||
|
||||
root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
||||
-('?' > (table_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1)) % '&');
|
||||
-('?' > (table_rule(qi::_r1) | base_rule(qi::_r1) | scale_factor_rule(qi::_r1) |
|
||||
fallback_speed_rule(qi::_r1) |
|
||||
(qi::lit("fallback_coordinate=") >
|
||||
fallback_coordinate_type
|
||||
[ph::bind(&engine::api::TableParameters::fallback_coordinate_type,
|
||||
qi::_r1) = qi::_1])) %
|
||||
'&');
|
||||
}
|
||||
|
||||
TableParametersGrammar(qi::rule<Iterator, Signature> &root_rule_) : BaseGrammar(root_rule_)
|
||||
{
|
||||
using AnnotationsType = engine::api::TableParameters::AnnotationsType;
|
||||
|
||||
annotations.add("duration", AnnotationsType::Duration)("distance",
|
||||
AnnotationsType::Distance);
|
||||
|
||||
annotations_list = annotations[qi::_val |= qi::_1] % ',';
|
||||
|
||||
base_rule = BaseGrammar::base_rule(qi::_r1) |
|
||||
(qi::lit("annotations=") >
|
||||
annotations_list[ph::bind(&engine::api::TableParameters::annotations,
|
||||
qi::_r1) = qi::_1]);
|
||||
}
|
||||
|
||||
protected:
|
||||
qi::rule<Iterator, Signature> base_rule;
|
||||
|
||||
private:
|
||||
using json_policy = no_trailing_dot_policy<double, 'j', 's', 'o', 'n'>;
|
||||
|
||||
qi::rule<Iterator, Signature> root_rule;
|
||||
qi::rule<Iterator, Signature> table_rule;
|
||||
qi::rule<Iterator, Signature> sources_rule;
|
||||
qi::rule<Iterator, Signature> destinations_rule;
|
||||
qi::rule<Iterator, Signature> fallback_speed_rule;
|
||||
qi::rule<Iterator, Signature> scale_factor_rule;
|
||||
qi::rule<Iterator, std::size_t()> size_t_;
|
||||
qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations;
|
||||
qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list;
|
||||
qi::symbols<char, engine::api::TableParameters::FallbackCoordinateType>
|
||||
fallback_coordinate_type;
|
||||
qi::real_parser<double, json_policy> double_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,15 @@ struct Block
|
||||
{
|
||||
std::uint64_t num_entries;
|
||||
std::uint64_t byte_size;
|
||||
std::uint64_t offset;
|
||||
|
||||
Block() : num_entries(0), byte_size(0) {}
|
||||
Block() : num_entries(0), byte_size(0), offset(0) {}
|
||||
Block(std::uint64_t num_entries, std::uint64_t byte_size, std::uint64_t offset)
|
||||
: num_entries(num_entries), byte_size(byte_size), offset(offset)
|
||||
{
|
||||
}
|
||||
Block(std::uint64_t num_entries, std::uint64_t byte_size)
|
||||
: num_entries(num_entries), byte_size(byte_size)
|
||||
: num_entries(num_entries), byte_size(byte_size), offset(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -29,7 +34,7 @@ using NamedBlock = std::tuple<std::string, Block>;
|
||||
template <typename T> Block make_block(uint64_t num_entries)
|
||||
{
|
||||
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
|
||||
return Block{num_entries, sizeof(T) * num_entries};
|
||||
return Block{num_entries, sizeof(T) * num_entries, 0};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "storage/shared_datatype.hpp"
|
||||
#include "storage/tar.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
#include <boost/iterator/function_input_iterator.hpp>
|
||||
|
||||
@@ -30,22 +31,37 @@ namespace serialization
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename BlockT = unsigned char>
|
||||
inline BlockT packBits(const T &data, std::size_t index, std::size_t count)
|
||||
inline BlockT packBits(const T &data, std::size_t base_index, const std::size_t count)
|
||||
{
|
||||
static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool");
|
||||
static_assert(std::is_unsigned<BlockT>::value, "BlockT must be unsigned type");
|
||||
static_assert(std::is_integral<BlockT>::value, "BlockT must be an integral type");
|
||||
static_assert(CHAR_BIT == 8, "Non-8-bit bytes not supported, sorry!");
|
||||
BOOST_ASSERT(sizeof(BlockT) * CHAR_BIT >= count);
|
||||
|
||||
// Note: if this packing is changed, be sure to update vector_view<bool>
|
||||
// as well, so that on-disk and in-memory layouts match.
|
||||
BlockT value = 0;
|
||||
for (std::size_t bit = 0; bit < count; ++bit, ++index)
|
||||
value = (value << 1) | data[index];
|
||||
for (std::size_t bit = 0; bit < count; ++bit)
|
||||
{
|
||||
value |= (data[base_index + bit] ? BlockT{1} : BlockT{0}) << bit;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, typename BlockT = unsigned char>
|
||||
inline void unpackBits(T &data, std::size_t index, std::size_t count, BlockT value)
|
||||
inline void
|
||||
unpackBits(T &data, const std::size_t base_index, const std::size_t count, const BlockT value)
|
||||
{
|
||||
static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool");
|
||||
const BlockT mask = BlockT{1} << (count - 1);
|
||||
for (std::size_t bit = 0; bit < count; value <<= 1, ++bit, ++index)
|
||||
data[index] = value & mask;
|
||||
static_assert(std::is_unsigned<BlockT>::value, "BlockT must be unsigned type");
|
||||
static_assert(std::is_integral<BlockT>::value, "BlockT must be an integral type");
|
||||
static_assert(CHAR_BIT == 8, "Non-8-bit bytes not supported, sorry!");
|
||||
BOOST_ASSERT(sizeof(BlockT) * CHAR_BIT >= count);
|
||||
for (std::size_t bit = 0; bit < count; ++bit)
|
||||
{
|
||||
data[base_index + bit] = value & (BlockT{1} << bit);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VectorT>
|
||||
@@ -55,15 +71,16 @@ void readBoolVector(tar::FileReader &reader, const std::string &name, VectorT &d
|
||||
data.resize(count);
|
||||
std::uint64_t index = 0;
|
||||
|
||||
constexpr std::uint64_t WORD_BITS = CHAR_BIT * sizeof(std::uint64_t);
|
||||
using BlockType = std::uint64_t;
|
||||
constexpr std::uint64_t BLOCK_BITS = CHAR_BIT * sizeof(BlockType);
|
||||
|
||||
const auto decode = [&](const std::uint64_t block) {
|
||||
auto read_size = std::min<std::size_t>(count - index, WORD_BITS);
|
||||
unpackBits<VectorT, std::uint64_t>(data, index, read_size, block);
|
||||
index += WORD_BITS;
|
||||
const auto decode = [&](const BlockType block) {
|
||||
auto read_size = std::min<std::size_t>(count - index, BLOCK_BITS);
|
||||
unpackBits<VectorT, BlockType>(data, index, read_size, block);
|
||||
index += BLOCK_BITS;
|
||||
};
|
||||
|
||||
reader.ReadStreaming<std::uint64_t>(name, boost::make_function_output_iterator(decode));
|
||||
reader.ReadStreaming<BlockType>(name, boost::make_function_output_iterator(decode));
|
||||
}
|
||||
|
||||
template <typename VectorT>
|
||||
@@ -73,19 +90,20 @@ void writeBoolVector(tar::FileWriter &writer, const std::string &name, const Vec
|
||||
writer.WriteElementCount64(name, count);
|
||||
std::uint64_t index = 0;
|
||||
|
||||
constexpr std::uint64_t WORD_BITS = CHAR_BIT * sizeof(std::uint64_t);
|
||||
using BlockType = std::uint64_t;
|
||||
constexpr std::uint64_t BLOCK_BITS = CHAR_BIT * sizeof(BlockType);
|
||||
|
||||
// FIXME on old boost version the function_input_iterator does not work with lambdas
|
||||
// so we need to wrap it in a function here.
|
||||
const std::function<std::uint64_t()> encode_function = [&]() -> std::uint64_t {
|
||||
auto write_size = std::min<std::size_t>(count - index, WORD_BITS);
|
||||
auto packed = packBits<VectorT, std::uint64_t>(data, index, write_size);
|
||||
index += WORD_BITS;
|
||||
const std::function<BlockType()> encode_function = [&]() -> BlockType {
|
||||
auto write_size = std::min<std::size_t>(count - index, BLOCK_BITS);
|
||||
auto packed = packBits<VectorT, BlockType>(data, index, write_size);
|
||||
index += BLOCK_BITS;
|
||||
return packed;
|
||||
};
|
||||
|
||||
std::uint64_t number_of_blocks = (count + WORD_BITS - 1) / WORD_BITS;
|
||||
writer.WriteStreaming<std::uint64_t>(
|
||||
std::uint64_t number_of_blocks = (count + BLOCK_BITS - 1) / BLOCK_BITS;
|
||||
writer.WriteStreaming<BlockType>(
|
||||
name,
|
||||
boost::make_function_input_iterator(encode_function, boost::infinite()),
|
||||
number_of_blocks);
|
||||
@@ -266,9 +284,9 @@ template <typename K, typename V> void write(io::BufferWriter &writer, const std
|
||||
}
|
||||
}
|
||||
|
||||
inline void read(io::BufferReader &reader, DataLayout &layout) { read(reader, layout.blocks); }
|
||||
inline void read(io::BufferReader &reader, BaseDataLayout &layout) { read(reader, layout.blocks); }
|
||||
|
||||
inline void write(io::BufferWriter &writer, const DataLayout &layout)
|
||||
inline void write(io::BufferWriter &writer, const BaseDataLayout &layout)
|
||||
{
|
||||
write(writer, layout.blocks);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace osrm
|
||||
@@ -19,8 +20,8 @@ class SharedDataIndex
|
||||
public:
|
||||
struct AllocatedRegion
|
||||
{
|
||||
char *memory_ptr;
|
||||
DataLayout layout;
|
||||
void *memory_ptr;
|
||||
std::unique_ptr<BaseDataLayout> layout;
|
||||
};
|
||||
|
||||
SharedDataIndex() = default;
|
||||
@@ -29,10 +30,10 @@ class SharedDataIndex
|
||||
// Build mapping from block name to region
|
||||
for (auto index : util::irange<std::uint32_t>(0, regions.size()))
|
||||
{
|
||||
regions[index].layout.List("",
|
||||
boost::make_function_output_iterator([&](const auto &name) {
|
||||
block_to_region[name] = index;
|
||||
}));
|
||||
regions[index].layout->List("",
|
||||
boost::make_function_output_iterator([&](const auto &name) {
|
||||
block_to_region[name] = index;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,39 +41,57 @@ class SharedDataIndex
|
||||
{
|
||||
for (const auto ®ion : regions)
|
||||
{
|
||||
region.layout.List(name_prefix, out);
|
||||
region.layout->List(name_prefix, out);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> auto GetBlockPtr(const std::string &name) const
|
||||
{
|
||||
const auto index_iter = block_to_region.find(name);
|
||||
const auto ®ion = regions[index_iter->second];
|
||||
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||
// is_tivially_copyable only exists in GCC >=5
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Block-based data must be a trivially copyable type");
|
||||
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
|
||||
#endif
|
||||
const auto ®ion = GetBlockRegion(name);
|
||||
return reinterpret_cast<T *>(region.layout->GetBlockPtr(region.memory_ptr, name));
|
||||
}
|
||||
|
||||
template <typename T> auto GetBlockPtr(const std::string &name)
|
||||
{
|
||||
const auto index_iter = block_to_region.find(name);
|
||||
const auto ®ion = regions[index_iter->second];
|
||||
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||
// is_tivially_copyable only exists in GCC >=5
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Block-based data must be a trivially copyable type");
|
||||
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
|
||||
#endif
|
||||
const auto ®ion = GetBlockRegion(name);
|
||||
return reinterpret_cast<T *>(region.layout->GetBlockPtr(region.memory_ptr, name));
|
||||
}
|
||||
|
||||
std::size_t GetBlockEntries(const std::string &name) const
|
||||
{
|
||||
const auto index_iter = block_to_region.find(name);
|
||||
const auto ®ion = regions[index_iter->second];
|
||||
return region.layout.GetBlockEntries(name);
|
||||
const auto ®ion = GetBlockRegion(name);
|
||||
return region.layout->GetBlockEntries(name);
|
||||
}
|
||||
|
||||
std::size_t GetBlockSize(const std::string &name) const
|
||||
{
|
||||
const auto index_iter = block_to_region.find(name);
|
||||
const auto ®ion = regions[index_iter->second];
|
||||
return region.layout.GetBlockSize(name);
|
||||
const auto ®ion = GetBlockRegion(name);
|
||||
return region.layout->GetBlockSize(name);
|
||||
}
|
||||
|
||||
private:
|
||||
const AllocatedRegion &GetBlockRegion(const std::string &name) const
|
||||
{
|
||||
const auto index_iter = block_to_region.find(name);
|
||||
if (index_iter == block_to_region.end())
|
||||
{
|
||||
throw util::exception("data block " + name + " not found " + SOURCE_REF);
|
||||
}
|
||||
return regions[index_iter->second];
|
||||
}
|
||||
|
||||
std::vector<AllocatedRegion> regions;
|
||||
std::unordered_map<std::string, std::uint32_t> block_to_region;
|
||||
};
|
||||
|
||||
@@ -20,13 +20,13 @@ namespace osrm
|
||||
namespace storage
|
||||
{
|
||||
|
||||
class DataLayout;
|
||||
class BaseDataLayout;
|
||||
namespace serialization
|
||||
{
|
||||
inline void read(io::BufferReader &reader, DataLayout &layout);
|
||||
inline void read(io::BufferReader &reader, BaseDataLayout &layout);
|
||||
|
||||
inline void write(io::BufferWriter &writer, const DataLayout &layout);
|
||||
}
|
||||
inline void write(io::BufferWriter &writer, const BaseDataLayout &layout);
|
||||
} // namespace serialization
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -52,46 +52,30 @@ inline std::string trimName(const std::string &name_prefix, const std::string &n
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
class DataLayout
|
||||
class BaseDataLayout
|
||||
{
|
||||
public:
|
||||
DataLayout() : blocks{} {}
|
||||
virtual ~BaseDataLayout() = default;
|
||||
|
||||
inline void SetBlock(const std::string &name, Block block) { blocks[name] = std::move(block); }
|
||||
|
||||
inline uint64_t GetBlockEntries(const std::string &name) const
|
||||
inline std::uint64_t GetBlockEntries(const std::string &name) const
|
||||
{
|
||||
return GetBlock(name).num_entries;
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockSize(const std::string &name) const { return GetBlock(name).byte_size; }
|
||||
inline std::uint64_t GetBlockSize(const std::string &name) const
|
||||
{
|
||||
return GetBlock(name).byte_size;
|
||||
}
|
||||
|
||||
inline bool HasBlock(const std::string &name) const
|
||||
{
|
||||
return blocks.find(name) != blocks.end();
|
||||
}
|
||||
|
||||
inline uint64_t GetSizeOfLayout() const
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (const auto &name_and_block : blocks)
|
||||
{
|
||||
result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T> inline T *GetBlockPtr(char *shared_memory, const std::string &name) const
|
||||
{
|
||||
static_assert(BLOCK_ALIGNMENT % std::alignment_of<T>::value == 0,
|
||||
"Datatype does not fit alignment constraints.");
|
||||
|
||||
char *ptr = (char *)GetAlignedBlockPtr(shared_memory, name);
|
||||
return (T *)ptr;
|
||||
}
|
||||
|
||||
// Depending on the name prefix this function either lists all blocks with the same prefix
|
||||
// or all entries in the sub-directory.
|
||||
// '/ch/edge' -> '/ch/edge_filter/0/blocks', '/ch/edge_filter/1/blocks'
|
||||
@@ -115,10 +99,10 @@ class DataLayout
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
friend void serialization::read(io::BufferReader &reader, DataLayout &layout);
|
||||
friend void serialization::write(io::BufferWriter &writer, const DataLayout &layout);
|
||||
virtual inline void *GetBlockPtr(void *base_ptr, const std::string &name) const = 0;
|
||||
virtual inline std::uint64_t GetSizeOfLayout() const = 0;
|
||||
|
||||
protected:
|
||||
const Block &GetBlock(const std::string &name) const
|
||||
{
|
||||
auto iter = blocks.find(name);
|
||||
@@ -130,10 +114,42 @@ class DataLayout
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout);
|
||||
friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout);
|
||||
|
||||
std::map<std::string, Block> blocks;
|
||||
};
|
||||
|
||||
class ContiguousDataLayout final : public BaseDataLayout
|
||||
{
|
||||
public:
|
||||
inline std::uint64_t GetSizeOfLayout() const override final
|
||||
{
|
||||
std::uint64_t result = 0;
|
||||
for (const auto &name_and_block : blocks)
|
||||
{
|
||||
result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final
|
||||
{
|
||||
// TODO: re-enable this alignment checking somehow
|
||||
// static_assert(BLOCK_ALIGNMENT % std::alignment_of<T>::value == 0,
|
||||
// "Datatype does not fit alignment constraints.");
|
||||
|
||||
return GetAlignedBlockPtr(base_ptr, name);
|
||||
}
|
||||
|
||||
private:
|
||||
friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout);
|
||||
friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout);
|
||||
|
||||
// Fit aligned storage in buffer to 64 bytes to conform with AVX 512 types
|
||||
inline void *align(void *&ptr) const noexcept
|
||||
{
|
||||
const auto intptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
const auto intptr = reinterpret_cast<std::uintptr_t>(ptr);
|
||||
const auto aligned = (intptr - 1u + BLOCK_ALIGNMENT) & -BLOCK_ALIGNMENT;
|
||||
return ptr = reinterpret_cast<void *>(aligned);
|
||||
}
|
||||
@@ -157,7 +173,27 @@ class DataLayout
|
||||
}
|
||||
|
||||
static constexpr std::size_t BLOCK_ALIGNMENT = 64;
|
||||
std::map<std::string, Block> blocks;
|
||||
};
|
||||
|
||||
class TarDataLayout final : public BaseDataLayout
|
||||
{
|
||||
public:
|
||||
inline std::uint64_t GetSizeOfLayout() const override final
|
||||
{
|
||||
std::uint64_t result = 0;
|
||||
for (const auto &name_and_block : blocks)
|
||||
{
|
||||
result += GetBlockSize(name_and_block.first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final
|
||||
{
|
||||
auto offset = GetBlock(name).offset;
|
||||
const auto offset_address = reinterpret_cast<std::uintptr_t>(base_ptr) + offset;
|
||||
return reinterpret_cast<void *>(offset_address);
|
||||
}
|
||||
};
|
||||
|
||||
struct SharedRegion
|
||||
@@ -165,7 +201,7 @@ struct SharedRegion
|
||||
static constexpr const int MAX_NAME_LENGTH = 254;
|
||||
|
||||
SharedRegion() : name{0}, timestamp{0} {}
|
||||
SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint8_t shm_key)
|
||||
SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint16_t shm_key)
|
||||
: name{0}, timestamp{timestamp}, shm_key{shm_key}
|
||||
{
|
||||
std::copy_n(name_.begin(), std::min<std::size_t>(MAX_NAME_LENGTH, name_.size()), name);
|
||||
@@ -175,14 +211,14 @@ struct SharedRegion
|
||||
|
||||
char name[MAX_NAME_LENGTH + 1];
|
||||
std::uint64_t timestamp;
|
||||
std::uint8_t shm_key;
|
||||
std::uint16_t shm_key;
|
||||
};
|
||||
|
||||
// Keeps a list of all shared regions in a fixed-sized struct
|
||||
// for fast access and deserialization.
|
||||
struct SharedRegionRegister
|
||||
{
|
||||
using RegionID = std::uint8_t;
|
||||
using RegionID = std::uint16_t;
|
||||
static constexpr const RegionID INVALID_REGION_ID = std::numeric_limits<RegionID>::max();
|
||||
using ShmKey = decltype(SharedRegion::shm_key);
|
||||
|
||||
@@ -250,12 +286,11 @@ struct SharedRegionRegister
|
||||
|
||||
void ReleaseKey(ShmKey key) { shm_key_in_use[key] = false; }
|
||||
|
||||
static constexpr const std::uint8_t MAX_SHARED_REGIONS =
|
||||
std::numeric_limits<RegionID>::max() - 1;
|
||||
static constexpr const std::size_t MAX_SHARED_REGIONS = 512;
|
||||
static_assert(MAX_SHARED_REGIONS < std::numeric_limits<RegionID>::max(),
|
||||
"Number of shared memory regions needs to be less than the region id size.");
|
||||
|
||||
static constexpr const std::uint8_t MAX_SHM_KEYS = std::numeric_limits<std::uint8_t>::max() - 1;
|
||||
static constexpr const std::size_t MAX_SHM_KEYS = MAX_SHARED_REGIONS * 2;
|
||||
|
||||
static constexpr const char *name = "osrm-region";
|
||||
|
||||
@@ -263,7 +298,7 @@ struct SharedRegionRegister
|
||||
std::array<SharedRegion, MAX_SHARED_REGIONS> regions;
|
||||
std::array<bool, MAX_SHM_KEYS> shm_key_in_use;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace storage
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* SHARED_DATA_TYPE_HPP */
|
||||
|
||||
@@ -34,10 +34,10 @@ namespace storage
|
||||
|
||||
struct OSRMLockFile
|
||||
{
|
||||
boost::filesystem::path operator()()
|
||||
template <typename IdentifierT> boost::filesystem::path operator()(const IdentifierT &id)
|
||||
{
|
||||
boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::path lock_file = temp_dir / "osrm.lock";
|
||||
boost::filesystem::path lock_file = temp_dir / ("osrm-" + std::to_string(id) + ".lock");
|
||||
return lock_file;
|
||||
}
|
||||
};
|
||||
@@ -93,7 +93,7 @@ class SharedMemory
|
||||
try
|
||||
{
|
||||
OSRMLockFile lock_file;
|
||||
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
|
||||
boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id);
|
||||
result = RegionExists(key);
|
||||
}
|
||||
catch (...)
|
||||
@@ -106,7 +106,7 @@ class SharedMemory
|
||||
template <typename IdentifierT> static bool Remove(const IdentifierT id)
|
||||
{
|
||||
OSRMLockFile lock_file;
|
||||
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
|
||||
boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id);
|
||||
return Remove(key);
|
||||
}
|
||||
|
||||
@@ -287,10 +287,11 @@ class SharedMemory
|
||||
template <typename IdentifierT, typename LockFileT = OSRMLockFile>
|
||||
std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint64_t size = 0)
|
||||
{
|
||||
static_assert(sizeof(id) == sizeof(std::uint16_t), "Key type is not 16 bits");
|
||||
try
|
||||
{
|
||||
LockFileT lock_file;
|
||||
if (!boost::filesystem::exists(lock_file()))
|
||||
if (!boost::filesystem::exists(lock_file(id)))
|
||||
{
|
||||
if (0 == size)
|
||||
{
|
||||
@@ -298,10 +299,10 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::filesystem::ofstream ofs(lock_file());
|
||||
boost::filesystem::ofstream ofs(lock_file(id));
|
||||
}
|
||||
}
|
||||
return std::make_unique<SharedMemory>(lock_file(), id, size);
|
||||
return std::make_unique<SharedMemory>(lock_file(id), id, size);
|
||||
}
|
||||
catch (const boost::interprocess::interprocess_exception &e)
|
||||
{
|
||||
@@ -310,7 +311,7 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint
|
||||
throw util::exception(e.what() + SOURCE_REF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace storage
|
||||
} // namespace osrm
|
||||
|
||||
#endif // SHARED_MEMORY_HPP
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user