diff --git a/.babelrc b/.babelrc index fd234626a..21e2dd7fd 100644 --- a/.babelrc +++ b/.babelrc @@ -1,8 +1,7 @@ { "plugins": ["transform-class-properties"], "presets": [ - "stage-0", - "es2015", - "react" + "@babel/preset-env", + "@babel/preset-react" ] } diff --git a/.clang-tidy b/.clang-tidy index de4303bf8..1c87f8702 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,4 +1,87 @@ --- -Checks: '-clang-analyzer-*,google-*,llvm-*,misc-*,readability-*,-google-build-explicit-make-pair,-google-explicit-constructor,-google-readability-braces-around-statements,-google-readability-casting,-google-readability-namespace-comments,-google-readability-function,-google-readability-todo,-google-runtime-int,-llvm-namespace-comment,-llvm-header-guard,-llvm-twine-local,-misc-argument-comment,-readability-braces-around-statements,-readability-identifier-naming' -... +Checks: > + bugprone-*, + -bugprone-narrowing-conversions, + -bugprone-easily-swappable-parameters, + -bugprone-branch-clone, + -bugprone-misplaced-widening-cast, + -bugprone-exception-escape, + -bugprone-implicit-widening-of-multiplication-result, + -bugprone-integer-division, + -bugprone-reserved-identifier, + -bugprone-unhandled-self-assignment, + -bugprone-forward-declaration-namespace, + -bugprone-sizeof-expression, + -bugprone-throw-keyword-missing, + -clang-analyzer-*, + -clang-diagnostic-deprecated-declarations, + -clang-diagnostic-constant-conversion, + cppcoreguidelines-avoid-goto, + cppcoreguidelines-no-malloc, + cppcoreguidelines-virtual-class-destructor, + google-*, + -google-build-explicit-make-pair, + -google-build-using-namespace, + -google-explicit-constructor, + -google-default-arguments, + -google-readability-braces-around-statements, + -google-readability-casting, + -google-readability-namespace-comments, + -google-readability-function, + -google-readability-todo, + -google-runtime-int, + -google-build-namespaces, + -google-runtime-references, + -google-readability-function-size, + llvm-*, + -llvm-namespace-comment, + -llvm-qualified-auto, + -llvm-include-order, + -llvm-else-after-return, + -llvm-header-guard, + -llvm-twine-local, + misc-*, + -misc-argument-comment, + -misc-non-private-member-variables-in-classes, + -misc-unconventional-assign-operator, + -misc-no-recursion, + -misc-misplaced-const, + -misc-definitions-in-headers, + -misc-unused-parameters, + performance-*, + -performance-noexcept-move-constructor, + -performance-no-int-to-ptr, + readability-*, + -readability-avoid-const-params-in-decls, + -readability-braces-around-statements, + -readability-container-size-empty, + -readability-convert-member-functions-to-static, + -readability-const-return-type, + -readability-function-cognitive-complexity, + -readability-function-size, + -readability-identifier-naming, + -readability-implicit-bool-conversion, + -readability-magic-numbers, + -readability-else-after-return, + -readability-inconsistent-declaration-parameter-name, + -readability-isolate-declaration, + -readability-identifier-length, + -readability-redundant-declaration, + -readability-uppercase-literal-suffix, + -readability-named-parameter, + -readability-qualified-auto, + -readability-suspicious-call-argument, + -readability-redundant-access-specifiers, + -readability-redundant-member-init, + -readability-static-definition-in-anonymous-namespace, + -readability-use-anyofallof, + -readability-simplify-boolean-expr, + -readability-make-member-function-const, + -readability-redundant-string-init, + -readability-non-const-parameter, + -readability-static-accessed-through-instance + +WarningsAsErrors: '*' +HeaderFilterRegex: '.*' + diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..77c25935a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +test +build diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..a8458e8f9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,30 @@ +# EditorConfig is awesome: http://EditorConfig.org +# +# NOTE: Keep settings in sync with the master .clang-format file +# +# top-most EditorConfig file +root = true + +# CMake configuration files +[{CMakeLists.txt,CMakeSettings.json,*.cmake}] +indent_size = 2 +indent_style = space +trim_trailing_whitespace = true + +# CI configuration files +[{.travis.yml,appveyor.yml}] +indent_size = 2 +indent_style = space +trim_trailing_whitespace = true + +# Unix shell scripts +[*.sh] +end_of_line = lf +indent_style = space +trim_trailing_whitespace = true + +# Windows shell scripts +[*.bat] +end_of_line = crlf +indent_style = space +trim_trailing_whitespace = true diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..5ec6bad6f --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +features/support/flatbuffers.js +features/support/fbresult_generated.js \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 37ce36f9b..c426721cb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,3 +13,6 @@ # Declare files that will always have LF line endings on checkout. *.sh text eol=lf + +# https://eslint.org/docs/latest/rules/linebreak-style#using-this-rule-with-version-control-systems +*.js text eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..e223dc636 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug Report +about: Report issue with osrm-backend +labels: Bug Report +--- + +# Issue + +Please describe the issue you are seeing with OSRM. +Images are a good way to illustrate your problem. + +**Note**: If your issue relates to the demo site (https://map.project-osrm.org) or routing provided on openstreetmap.org, be aware that they use separate [profile settings](https://github.com/fossgis-routing-server/cbf-routing-profiles) from those provided by default in `osrm-backend`. +If your issue relates to the demo site or openstreetmap.org behaviour, please check these profiles first to see if they explain the behaviour before creating an issue here. + +# Steps to reproduce + +Please provide the steps required to reproduce your problem. +- `osrm-backend` version being used +- OSM extract that was processed +- Processing commands (e.g. CH vs MLD processing) +- Server queries + +If you're reporting an issue with https://map.project-osrm.org, please provide a link to the problematic request. + +# Specifications + +Please provide details of your development environment. +- Library/dependency versions +- Operating system +- Hardware diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md new file mode 100644 index 000000000..ea79a1f90 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -0,0 +1,10 @@ +--- +name: Feature Request +about: Request a new feature in osrm-backend +labels: Feature Request +--- + +# Feature + +Please describe the feature you would like to see in OSRM. +Images are often a good way to illustrate your requested feature. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 000000000..7c7c703b1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,5 @@ +--- +name: Question +about: Ask a question about OSRM +labels: question +--- diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 21f40300f..5643bb9b7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,12 +2,18 @@ What issue is this PR targeting? If there is no issue that addresses the problem, please open a corresponding issue and link it here. +Please read our [documentation](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/releasing.md) on release and version management. +If your PR is still work in progress please attach the relevant label. + ## Tasklist - - [ ] ADD OWN TASKS HERE + + - [ ] CHANGELOG.md entry ([How to write a changelog entry](http://keepachangelog.com/en/1.0.0/#how)) - [ ] update relevant [Wiki pages](https://github.com/Project-OSRM/osrm-backend/wiki) - - [ ] add regression / cucumber cases (see docs/testing.md) + - [ ] add tests (see [testing documentation](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/testing.md)) - [ ] review - [ ] adjust for comments + - [ ] cherry pick to release branch ## Requirements / Relations + Link any requirements here. Other pull requests this PR is based on? diff --git a/.github/workflows/osrm-backend-docker.yml b/.github/workflows/osrm-backend-docker.yml new file mode 100644 index 000000000..e0cf8939d --- /dev/null +++ b/.github/workflows/osrm-backend-docker.yml @@ -0,0 +1,84 @@ +name: build and publish container image +on: + push: + tags: + - 'v*' + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v3 + with: + images: ghcr.io/${{ github.repository }} + + - name: Docker meta - debug + id: metadebug + uses: docker/metadata-action@v3 + with: + images: ghcr.io/${{ github.repository }} + flavor: | + latest=true + suffix=-debug,onlatest=true + + - name: Docker meta - assertions + id: metaassertions + uses: docker/metadata-action@v3 + with: + images: ghcr.io/${{ github.repository }} + flavor: | + latest=true + suffix=-assertions,onlatest=true + + - name: Log in to GitHub Docker Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build container image - debug + uses: docker/build-push-action@v2 + with: + push: true + platforms: linux/amd64,linux/arm64 + file: ./docker/Dockerfile + tags: ${{ steps.metadebug.outputs.tags }} + build-args: | + DOCKER_TAG=${{ join(steps.metadebug.outputs.tags ) }} + + + - name: Build container image - assertions + uses: docker/build-push-action@v2 + with: + push: true + platforms: linux/amd64,linux/arm64 + file: ./docker/Dockerfile + tags: ${{ steps.metaassertions.outputs.tags }} + build-args: | + DOCKER_TAG=${{ join(steps.metaassertions.outputs.tags ) }} + + # build and publish "normal" image as last to get it listed on top + - name: Build container image - normal + uses: docker/build-push-action@v2 + with: + push: true + platforms: linux/amd64,linux/arm64 + file: ./docker/Dockerfile + tags: ${{ steps.meta.outputs.tags }} + build-args: | + DOCKER_TAG=${{ join(steps.meta.outputs.tags ) }} + + + diff --git a/.github/workflows/osrm-backend.yml b/.github/workflows/osrm-backend.yml new file mode 100644 index 000000000..057edd241 --- /dev/null +++ b/.github/workflows/osrm-backend.yml @@ -0,0 +1,762 @@ +name: osrm-backend CI +on: + push: + branches: + - master + tags: + - v[1-9]+.[0-9]+.[0-9]+ + - v[1-9]+.[0-9]+.[0-9]+-[a-zA-Z]+.[0-9]+ + - v[1-9]+.[0-9]+-[0-9a-zA-Z]+ + pull_request: + branches: + - master + +env: + CCACHE_TEMPDIR: /tmp/.ccache-temp + CCACHE_COMPRESS: 1 + CASHER_TIME_OUT: 599 # one second less than 10m to avoid 10m timeout error: https://github.com/Project-OSRM/osrm-backend/issues/2742 + CCACHE_VERSION: 3.3.1 + CMAKE_VERSION: 3.21.2 + ENABLE_NODE_BINDINGS: "ON" + +jobs: + windows: + needs: format-taginfo-docs + runs-on: windows-2022 + continue-on-error: false + env: + BUILD_TYPE: Release + ENABLE_APPLE_SILICON: "OFF" + steps: + - uses: actions/checkout@v3 + - run: pip install conan==1.53.0 + - run: conan --version + - run: cmake --version + - uses: actions/setup-node@v3 + with: + node-version: 16 + - run: node --version + - run: npm --version + - name: Prepare environment + shell: bash + run: | + PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)") + echo PUBLISH=$([[ "${GITHUB_REF:-}" == "refs/tags/v${PACKAGE_JSON_VERSION}" ]] && echo "On" || echo "Off") >> $GITHUB_ENV + - run: npm install --ignore-scripts + - run: npm link --ignore-scripts + - uses: microsoft/setup-msbuild@v1.1 + - name: Build + run: | + .\scripts\ci\windows-build.bat + - name: Run node tests + shell: bash + run: | + ./lib/binding/osrm-datastore.exe test/data/ch/monaco.osrm + node test/nodejs/index.js + - name: Build Node package + shell: bash + run: ./scripts/ci/node_package.sh + - name: Publish Node package + if: ${{ env.PUBLISH == 'On' }} + uses: ncipollo/release-action@v1 + with: + allowUpdates: true + artifactErrorsFailBuild: true + artifacts: build/stage/**/*.tar.gz + omitBody: true + omitBodyDuringUpdate: true + omitName: true + omitNameDuringUpdate: true + replacesArtifacts: true + token: ${{ secrets.GITHUB_TOKEN }} + + format-taginfo-docs: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 12 + - name: Enable Node.js cache + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Prepare environment + run: | + npm ci --ignore-scripts + clang-format-10 --version + - name: Run checks + run: | + ./scripts/check_taginfo.py taginfo.json profiles/car.lua + ./scripts/format.sh && ./scripts/error_on_dirty.sh + node ./scripts/validate_changelog.js + npm run docs && ./scripts/error_on_dirty.sh + + docker-image: + needs: format-taginfo-docs + runs-on: ubuntu-22.04 + continue-on-error: false + steps: + - name: Check out the repo + uses: actions/checkout@v3 + - name: Enable osm.pbf cache + uses: actions/cache@v3 + with: + path: berlin-latest.osm.pbf + key: v1-berlin-osm-pbf + restore-keys: | + v1-berlin-osm-pbf + - name: Docker build + run: | + docker build -t osrm-backend-local -f docker/Dockerfile . + - name: Test Docker image + run: | + if [ ! -f "${PWD}/berlin-latest.osm.pbf" ]; then + wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf + fi + TAG=osrm-backend-local + # when `--memory-swap` value equals `--memory` it means container won't use swap + # see https://docs.docker.com/config/containers/resource_constraints/#--memory-swap-details + MEMORY_ARGS="--memory=1g --memory-swap=1g" + docker run $MEMORY_ARGS -t -v "${PWD}:/data" "${TAG}" osrm-extract --dump-nbg-graph -p /opt/car.lua /data/berlin-latest.osm.pbf + docker run $MEMORY_ARGS -t -v "${PWD}:/data" "${TAG}" osrm-components /data/berlin-latest.osrm.nbg /data/berlin-latest.geojson + if [ ! -s "${PWD}/berlin-latest.geojson" ] + then + >&2 echo "No berlin-latest.geojson found" + exit 1 + fi + + # removing `.osrm.nbg` to check that whole pipeline works without it + rm -rf "${PWD}/berlin-latest.osrm.nbg" + + docker run $MEMORY_ARGS -t -v "${PWD}:/data" "${TAG}" osrm-partition /data/berlin-latest.osrm + docker run $MEMORY_ARGS -t -v "${PWD}:/data" "${TAG}" osrm-customize /data/berlin-latest.osrm + docker run $MEMORY_ARGS --name=osrm-container -t -p 5000:5000 -v "${PWD}:/data" "${TAG}" osrm-routed --algorithm mld /data/berlin-latest.osrm & + curl --retry-delay 3 --retry 10 --retry-all-errors "http://127.0.0.1:5000/route/v1/driving/13.388860,52.517037;13.385983,52.496891?steps=true" + docker stop osrm-container + + build-test-publish: + needs: format-taginfo-docs + strategy: + matrix: + include: + - name: gcc-9-debug-cov + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Debug + CCOMPILER: gcc-9 + CUCUMBER_TIMEOUT: 20000 + CXXCOMPILER: g++-9 + ENABLE_COVERAGE: ON + + - name: gcc-9-debug-asan-ubsan + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Debug + CCOMPILER: gcc-9 + CUCUMBER_TIMEOUT: 20000 + CXXCOMPILER: g++-9 + ENABLE_SANITIZER: ON + TARGET_ARCH: x86_64-asan-ubsan + OSRM_CONNECTION_RETRIES: 10 + OSRM_CONNECTION_EXP_BACKOFF_COEF: 1.5 + + - name: clang-6.0-debug + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Debug + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + CUCUMBER_TIMEOUT: 60000 + + - name: clang-11.0-debug-clang-tidy + continue-on-error: false + node: 12 + runs-on: ubuntu-22.04 + BUILD_TOOLS: ON + BUILD_TYPE: Debug + CCOMPILER: clang-14 + CXXCOMPILER: clang++-14 + CUCUMBER_TIMEOUT: 60000 + ENABLE_CLANG_TIDY: ON + + - name: conan-linux-debug-asan-ubsan + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: clang-11 + CXXCOMPILER: clang++-11 + ENABLE_CONAN: ON + ENABLE_SANITIZER: ON + + - name: conan-linux-release + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + + - name: gcc-11-release + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: gcc-11 + CXXCOMPILER: g++-11 + ENABLE_BENCHMARKS: ON + + - name: gcc-10-release + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: gcc-10 + CXXCOMPILER: g++-10 + + - name: gcc-9-release + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: gcc-9 + CXXCOMPILER: g++-9 + CXXFLAGS: -Wno-cast-function-type + + - name: gcc-9-conan-release-i686 + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: gcc-9 + CFLAGS: "-m32 -msse2 -mfpmath=sse" + CXXCOMPILER: g++-9 + CXXFLAGS: "-m32 -msse2 -mfpmath=sse" + TARGET_ARCH: i686 + ENABLE_CONAN: ON + + - name: gcc-8-release + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: gcc-8 + CXXCOMPILER: g++-8 + CXXFLAGS: -Wno-cast-function-type + + - name: gcc-7-release + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: gcc-7 + CXXCOMPILER: g++-7 + + - name: conan-macos-x64-release-node-12 + build_node_package: true + continue-on-error: false + node: 12 + runs-on: macos-11 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + + - name: conan-macos-x64-release-node-14 + build_node_package: true + continue-on-error: false + node: 14 + runs-on: macos-11 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + + - name: conan-macos-x64-release-node-16 + build_node_package: true + continue-on-error: false + node: 16 + runs-on: macos-11 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + + - name: conan-macos-arm64-release-node-16 + build_node_package: true + continue-on-error: false + node: 16 + runs-on: macos-11 + BUILD_TOOLS: ON + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + ENABLE_APPLE_SILICON: ON + + - name: gcc-7-release-shared + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TOOLS: ON + BUILD_TYPE: Release + BUILD_SHARED_LIBS: ON + CCOMPILER: gcc-7 + CXXCOMPILER: g++-7 + + - name: node-12-conan-linux-release + build_node_package: true + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TYPE: Release + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: node-12-conan-linux-debug + build_node_package: true + continue-on-error: false + node: 12 + runs-on: ubuntu-20.04 + BUILD_TYPE: Debug + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: node-14-conan-linux-release + build_node_package: true + continue-on-error: false + node: 14 + runs-on: ubuntu-20.04 + BUILD_TYPE: Release + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: node-14-conan-linux-debug + build_node_package: true + continue-on-error: false + node: 14 + runs-on: ubuntu-20.04 + BUILD_TYPE: Debug + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + + - name: node-16-conan-linux-release + build_node_package: true + continue-on-error: false + node: 16 + runs-on: ubuntu-20.04 + BUILD_TYPE: Release + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: node-16-conan-linux-debug + build_node_package: true + continue-on-error: false + node: 16 + runs-on: ubuntu-20.04 + BUILD_TYPE: Debug + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: conan-macos-x64-release-node-latest + build_node_package: true + continue-on-error: true + node: latest + runs-on: macos-11 + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + + - name: conan-macos-arm64-release-node-latest + build_node_package: true + continue-on-error: true + node: latest + runs-on: macos-11 + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + ENABLE_APPLE_SILICON: ON + + - name: node-latest-conan-linux-release + build_node_package: true + continue-on-error: true + node: latest + runs-on: ubuntu-20.04 + BUILD_TYPE: Release + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: node-latest-conan-linux-debug + build_node_package: true + continue-on-error: true + node: latest + runs-on: ubuntu-20.04 + BUILD_TYPE: Debug + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: conan-macos-x64-release-node-lts + build_node_package: true + continue-on-error: true + node: "lts/*" + runs-on: macos-11 + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + + - name: conan-macos-arm64-release-node-lts + build_node_package: true + continue-on-error: true + node: "lts/*" + runs-on: macos-11 + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + ENABLE_APPLE_SILICON: ON + + - name: node-lts-conan-linux-release + build_node_package: true + continue-on-error: true + node: "lts/*" + runs-on: ubuntu-20.04 + BUILD_TYPE: Release + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: node-lts-conan-linux-debug + build_node_package: true + continue-on-error: true + node: "lts/*" + runs-on: ubuntu-20.04 + BUILD_TYPE: Debug + CCOMPILER: clang-6.0 + CXXCOMPILER: clang++-6.0 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + name: ${{ matrix.name}} + continue-on-error: ${{ matrix.continue-on-error }} + runs-on: ${{ matrix.runs-on }} + env: + BUILD_TOOLS: ${{ matrix.BUILD_TOOLS }} + BUILD_TYPE: ${{ matrix.BUILD_TYPE }} + BUILD_SHARED_LIBS: ${{ matrix.BUILD_SHARED_LIBS }} + CCOMPILER: ${{ matrix.CCOMPILER }} + CFLAGS: ${{ matrix.CFLAGS }} + CUCUMBER_TIMEOUT: ${{ matrix.CUCUMBER_TIMEOUT }} + CXXCOMPILER: ${{ matrix.CXXCOMPILER }} + CXXFLAGS: ${{ matrix.CXXFLAGS }} + ENABLE_ASSERTIONS: ${{ matrix.ENABLE_ASSERTIONS }} + ENABLE_CLANG_TIDY: ${{ matrix.ENABLE_CLANG_TIDY }} + ENABLE_COVERAGE: ${{ matrix.ENABLE_COVERAGE }} + ENABLE_CONAN: ${{ matrix.ENABLE_CONAN }} + ENABLE_SANITIZER: ${{ matrix.ENABLE_SANITIZER }} + NODE_PACKAGE_TESTS_ONLY: ${{ matrix.NODE_PACKAGE_TESTS_ONLY }} + ENABLE_APPLE_SILICON: ${{ matrix.ENABLE_APPLE_SILICON }} + TARGET_ARCH: ${{ matrix.TARGET_ARCH }} + OSRM_CONNECTION_RETRIES: ${{ matrix.OSRM_CONNECTION_RETRIES }} + OSRM_CONNECTION_EXP_BACKOFF_COEF: ${{ matrix.OSRM_CONNECTION_EXP_BACKOFF_COEF }} + steps: + - uses: actions/checkout@v2 + + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + - name: Enable Node.js cache + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Enable compiler cache + uses: actions/cache@v3 + with: + path: ~/.ccache + key: ccache-${{ matrix.name }}-${{ github.sha }} + restore-keys: | + ccache-${{ matrix.name }}- + - name: Enable Conan cache + uses: actions/cache@v3 + with: + path: ~/.conan + key: v6-conan-${{ matrix.name }}-${{ github.sha }} + restore-keys: | + v6-conan-${{ matrix.name }}- + - name: Enable test cache + uses: actions/cache@v3 + with: + path: ${{github.workspace}}/test/cache + key: v3-test-${{ matrix.name }}-${{ github.sha }} + restore-keys: | + v3-test-${{ matrix.name }}- + + - name: Prepare environment + run: | + PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)") + echo PUBLISH=$([[ "${GITHUB_REF:-}" == "refs/tags/v${PACKAGE_JSON_VERSION}" ]] && echo "On" || echo "Off") >> $GITHUB_ENV + echo "OSRM_INSTALL_DIR=${GITHUB_WORKSPACE}/install-osrm" >> $GITHUB_ENV + echo "OSRM_BUILD_DIR=${GITHUB_WORKSPACE}/build-osrm" >> $GITHUB_ENV + if [[ "$ENABLE_SANITIZER" == 'ON' ]]; then + # We can only set this after checkout once we know the workspace directory + echo "LSAN_OPTIONS=print_suppressions=0:suppressions=${GITHUB_WORKSPACE}/scripts/ci/leaksanitizer.conf" >> $GITHUB_ENV + echo "UBSAN_OPTIONS=symbolize=1:halt_on_error=1:print_stacktrace=1:suppressions=${GITHUB_WORKSPACE}/scripts/ci/undefinedsanitizer.conf" >> $GITHUB_ENV + fi + + if [[ "${RUNNER_OS}" == "Linux" ]]; then + echo "JOBS=$((`nproc` + 1))" >> $GITHUB_ENV + elif [[ "${RUNNER_OS}" == "macOS" ]]; then + echo "JOBS=$((`sysctl -n hw.ncpu` + 1))" >> $GITHUB_ENV + fi + + - name: Install dev dependencies + run: | + python3 -m pip install conan==1.53.0 + + # ccache + if [[ "${RUNNER_OS}" == "Linux" ]]; then + sudo apt-get update -y && sudo apt-get install ccache + elif [[ "${RUNNER_OS}" == "macOS" ]]; then + brew install ccache + fi + + # clang + if [[ "${CCOMPILER}" == "clang-6.0" ]]; then + sudo apt-get update -y && sudo apt-get install clang++-6 + fi + + # Linux dev packages + if [ "${TARGET_ARCH}" != "i686" ] && [ "${ENABLE_CONAN}" != "ON" ]; then + sudo apt-get update -y + sudo apt-get install -y libbz2-dev libxml2-dev libzip-dev liblua5.2-dev libboost-all-dev + if [[ "${CCOMPILER}" != clang-* ]]; then + sudo apt-get install -y ${CXXCOMPILER} + fi + if [[ "${ENABLE_COVERAGE}" == "ON" ]]; then + sudo apt-get install -y lcov + fi + elif [[ $TARGET_ARCH == "i686" ]]; then + source ./scripts/ci/before_install.${TARGET_ARCH}.sh + echo "PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig:${PKG_CONFIG_PATH}" >> $GITHUB_ENV + fi + + # TBB + TBB_VERSION=2021.3.0 + if [[ "${RUNNER_OS}" == "Linux" ]]; then + TBB_URL="https://github.com/oneapi-src/oneTBB/releases/download/v${TBB_VERSION}/oneapi-tbb-${TBB_VERSION}-lin.tgz" + elif [[ "${RUNNER_OS}" == "macOS" ]]; then + TBB_URL="https://github.com/oneapi-src/oneTBB/releases/download/v${TBB_VERSION}/oneapi-tbb-${TBB_VERSION}-mac.tgz" + fi + wget --tries 5 ${TBB_URL} -O onetbb.tgz + tar zxvf onetbb.tgz + sudo cp -a oneapi-tbb-${TBB_VERSION}/lib/. /usr/local/lib/ + sudo cp -a oneapi-tbb-${TBB_VERSION}/include/. /usr/local/include/ + + - name: Prepare build + run: | + mkdir ${OSRM_BUILD_DIR} + ccache --max-size=256M + npm ci --ignore-scripts + if [[ "${ENABLE_COVERAGE}" == "ON" ]]; then + lcov --directory . --zerocounters # clean cached files + fi + echo "CC=${CCOMPILER}" >> $GITHUB_ENV + echo "CXX=${CXXCOMPILER}" >> $GITHUB_ENV + + - name: Build and install OSRM + run: | + echo "Using ${JOBS} jobs" + pushd ${OSRM_BUILD_DIR} + + # handle Apple Silicon cross compilation + if [[ "${ENABLE_APPLE_SILICON}" == "ON" ]]; then + ARCH=arm64 + TARGET="${ARCH}-apple-darwin" + CFLAGS="$CFLAGS --target=$TARGET" + CXXFLAGS="$CXXFLAGS --target=$TARGET" + APPLE_SILICON_FLAGS=(-DCMAKE_C_COMPILER_TARGET="$TARGET" -DCMAKE_CXX_COMPILER_TARGET="$TARGET" -DCMAKE_SYSTEM_PROCESSOR="${ARCH}" -DCMAKE_SYSTEM_NAME="Darwin" -DCMAKE_C_FLAGS="$CFLAGS" -DCMAKE_CXX_FLAGS="$CXXFLAGS") + else + APPLE_SILICON_FLAGS=() + fi + + cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DENABLE_CONAN=${ENABLE_CONAN:-OFF} \ + -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS:-OFF} \ + -DENABLE_CLANG_TIDY=${ENABLE_CLANG_TIDY:-OFF} \ + -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} \ + -DENABLE_COVERAGE=${ENABLE_COVERAGE:-OFF} \ + -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ + -DENABLE_SANITIZER=${ENABLE_SANITIZER:-OFF} \ + -DBUILD_TOOLS=${BUILD_TOOLS:-OFF} \ + -DENABLE_CCACHE=ON \ + -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ + "${APPLE_SILICON_FLAGS[@]}" + + make --jobs=${JOBS} + + if [[ "${NODE_PACKAGE_TESTS_ONLY}" != "ON" && "${ENABLE_APPLE_SILICON}" != "ON" ]]; then + make tests --jobs=${JOBS} + make benchmarks --jobs=${JOBS} + ccache -s + sudo make install + if [[ "${RUNNER_OS}" == "Linux" ]]; then + echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${OSRM_INSTALL_DIR}/lib" >> $GITHUB_ENV + fi + echo "PKG_CONFIG_PATH=${OSRM_INSTALL_DIR}/lib/pkgconfig" >> $GITHUB_ENV + fi + popd + - name: Build example + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY != 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} + run: | + mkdir example/build && pushd example/build + cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} + make --jobs=${JOBS} + popd + - name: Run all tests + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY != 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} + run: | + make -C test/data benchmark + + # macOS SIP strips the linker path. Reset this inside the running shell + export LD_LIBRARY_PATH=${{ env.LD_LIBRARY_PATH }} + ./example/build/osrm-example test/data/mld/monaco.osrm + + # All tests assume to be run from the build directory + pushd ${OSRM_BUILD_DIR} + for i in ./unit_tests/*-tests ; do echo Running $i ; $i ; done + if [ -z "${ENABLE_SANITIZER}" ] && [ "$TARGET_ARCH" != "i686" ]; then + npm run nodejs-tests + fi + popd + npm test + - name: Run benchmarks + if: ${{ matrix.ENABLE_BENCHMARKS == 'ON' }} + run: | + pushd ${OSRM_BUILD_DIR} + make --jobs=${JOBS} benchmarks + ./src/benchmarks/alias-bench + ./src/benchmarks/json-render-bench ../src/benchmarks/portugal_to_korea.json + ./src/benchmarks/match-bench ../test/data/ch/monaco.osrm + ./src/benchmarks/packedvector-bench + ./src/benchmarks/rtree-bench ../test/data/monaco.osrm.ramIndex ../test/data/monaco.osrm.fileIndex ../test/data/monaco.osrm.nbg_nodes + popd + - name: Run Node package tests only + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} + run: | + npm run nodejs-tests + - name: Upload test logs + uses: actions/upload-artifact@v3 + if: failure() + with: + name: logs + path: test/logs/ + + - name: Generate code coverage + if: ${{ matrix.ENABLE_COVERAGE == 'ON' }} + run: | + lcov --directory . --capture --output-file coverage.info # capture coverage info + lcov --remove coverage.info '/usr/*' --output-file coverage.info # filter out system + lcov --list coverage.info #debug info + # Uploading report to CodeCov + - name: Upload code coverage + if: ${{ matrix.ENABLE_COVERAGE == 'ON' }} + uses: codecov/codecov-action@v1 + with: + files: coverage.info + name: codecov-osrm-backend + fail_ci_if_error: true + verbose: true + - name: Check Apple Silicon binary + if: ${{ matrix.ENABLE_APPLE_SILICON == 'ON' }} + run: | + ARCH=$(file ./lib/binding/node_osrm.node | awk '{printf $NF}') + if [[ "$ARCH" != "arm64" ]]; then + file ./lib/binding/node_osrm.node + >&2 echo "Wrong architecture!" + exit 1 + fi + - name: Build Node package + if: ${{ matrix.build_node_package }} + run: ./scripts/ci/node_package.sh + - name: Publish Node package + if: ${{ matrix.build_node_package && env.PUBLISH == 'On' }} + uses: ncipollo/release-action@v1 + with: + allowUpdates: true + artifactErrorsFailBuild: true + artifacts: build/stage/**/*.tar.gz + omitBody: true + omitBodyDuringUpdate: true + omitName: true + omitNameDuringUpdate: true + replacesArtifacts: true + token: ${{ secrets.GITHUB_TOKEN }} + + ci-complete: + runs-on: ubuntu-22.04 + needs: [build-test-publish, docker-image, windows] + steps: + - run: echo "CI complete" diff --git a/.gitignore b/.gitignore index 4cb581217..3b443d06d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ -# mason # -######### -/.mason -/mason_packages - # pre compiled dependencies # ############################# osrm-deps @@ -49,7 +44,7 @@ Thumbs.db /_build* /build/ /example/build/ -/test/data/monaco* +/test/data/monaco.osrm* /test/data/ch /test/data/corech /test/data/mld @@ -66,12 +61,12 @@ Thumbs.db ###################################### /.vs* /*.local.bat +/CMakeSettings.json +/.cache -# stxxl related files # -####################### -.stxxl -stxxl.log -stxxl.errlog +# Jetbrains related files # +########################### +.idea/ # Compiled Binary Files # #################################### diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 94816029a..000000000 --- a/.travis.yml +++ /dev/null @@ -1,379 +0,0 @@ -language: cpp - -git: - depth: 10 - -# sudo:required is needed for trusty images -sudo: required -dist: trusty - -notifications: - email: false - -branches: - only: - - master - # enable building tags - - /^v\d+\.\d+(\.\d+)?(-\S*)?$/ - -cache: - yarn: true - ccache: true - apt: true - directories: - - test/cache - -env: - global: - - secure: "hk+32aXXF5t1ApaM2Wjqooz3dx1si907L87WRMkO47WlpJmUUU/Ye+MJk9sViH8MdhOcceocVAmdYl5/WFWOIbDWNlBya9QvXDZyIu2KIre/0QyOCTZbrsif8paBXKIO5O/R4OTvIZ8rvWZsadBdmAT9GSbDhih6FzqXAEgeIYQ=" - - secure: "VE+cFkseFwW4jK6XwkP0yW3h4DixPJ8+Eb3yKcchGZ5iIJxlZ/8i1vKHYxadgPRwSYwPSB14tF70xj2OmiT2keGzZUfphmPXinBaLEhYk+Bde+GZZkoSl5ND109I/LcyNr0nG9dDgtV6pkvFchgchpyP9JnVOOS0+crEZlAz0RE=" - - CCACHE_TEMPDIR=/tmp/.ccache-temp - - CCACHE_COMPRESS=1 - - CASHER_TIME_OUT=599 # one second less than 10m to avoid 10m timeout error: https://github.com/Project-OSRM/osrm-backend/issues/2742 - - CCACHE_VERSION=3.3.1 - - CMAKE_VERSION=3.7.2 - - MASON="$(pwd)/scripts/mason.sh" - - ENABLE_NODE_BINDINGS=On - - NODE="4" - -matrix: - fast_finish: true - - # We override the compiler names here to yield better ccache behavior, which uses this as key - include: - - # Debug Builds - - os: linux - compiler: "format-taginfo-docs" - env: NODE=6 - sudo: false - before_install: - install: - - source $NVM_DIR/nvm.sh - - nvm install $NODE - - nvm use $NODE - - npm --version - - npm install --ignore-scripts - - npm link --ignore-scripts - script: - - ./scripts/check_taginfo.py taginfo.json profiles/car.lua - - ${MASON} install clang-format 3.8.1 - - PATH=$(${MASON} prefix clang-format 3.8.1)/bin:${PATH} ./scripts/format.sh && ./scripts/error_on_dirty.sh - # See issue 4043 - #- npm run docs && ./scripts/error_on_dirty.sh - after_success: - - - os: linux - compiler: "gcc-6-debug-cov" - addons: &gcc6 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' ENABLE_COVERAGE=ON CUCUMBER_TIMEOUT=20000 - after_success: - - bash <(curl -s https://codecov.io/bash) - - - os: linux - compiler: "gcc-6-debug-asan" - addons: &gcc6 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Debug' TARGET_ARCH='x86_64-asan' ENABLE_SANITIZER=ON CUCUMBER_TIMEOUT=20000 - - - os: linux - compiler: "clang-4.0-debug" - addons: &clang40 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-5-dev', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev'] - env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' CUCUMBER_TIMEOUT=60000 - - - os: linux - compiler: "mason-linux-debug-asan" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-5-dev'] - env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_SANITIZER=ON - - # Release Builds - - os: linux - compiler: "mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-5-dev'] - env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON RUN_CLANG_FORMAT=ON ENABLE_LTO=ON - - - os: linux - compiler: "gcc-6-release" - addons: &gcc6 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' - - - os: linux - compiler: "gcc-6-release-i686" - env: > - TARGET_ARCH='i686' CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' - CFLAGS='-m32 -msse2 -mfpmath=sse' CXXFLAGS='-m32 -msse2 -mfpmath=sse' - - - os: linux - compiler: "gcc-6-stxxl" - addons: &gcc6 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-6', 'libbz2-dev', 'libstxxl-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' ENABLE_STXXL=On - - - os: linux - compiler: "gcc-4.9-release" - addons: &gcc49 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-4.9', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev', 'ccache'] - env: CCOMPILER='gcc-4.9' CXXCOMPILER='g++-4.9' BUILD_TYPE='Release' - - - os: osx - osx_image: xcode8.2 - compiler: "mason-osx-release" - # we use the xcode provides clang and don't install our own - env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="4" - after_success: - - ./scripts/travis/publish.sh - - - os: osx - osx_image: xcode8.2 - compiler: "mason-osx-release" - # we use the xcode provides clang and don't install our own - env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="6" - after_success: - - ./scripts/travis/publish.sh - - # Disabled because of CI slowness - #- os: linux - #- compiler: clang - #- addons: &clang40 - #- apt: - #- sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test'] - #- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev'] - #- env: CCOMPILER='clang-4.0' CXXCOMPILER='clang++-4.0' BUILD_TYPE='Release' - - # Shared Library - - os: linux - compiler: "gcc-6-release-shared" - addons: &gcc6 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON - - # Disabled because CI slowness - #- os: linux - #- compiler: clang - #- addons: &clang40 - #- apt: - #- sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test'] - #- packages: ['clang-4.0', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libgdal-dev', 'libboost-all-dev'] - #- env: CCOMPILER='clang-4.0' CXXCOMPILER='clang++-4.0' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON - - # 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++-5-dev'] - env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 - 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} - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-4-mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-5-dev'] - env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 - 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} - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-6-mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-5-dev'] - env: CLANG_VERSION='4.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="6" - 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} - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-6-mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-5-dev'] - env: CLANG_VERSION='4.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="6" - 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} - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - -before_install: - - source $NVM_DIR/nvm.sh - - nvm install $NODE - - nvm use $NODE - - node --version - - if [[ ! -z $TARGET_ARCH ]] ; then source ./scripts/travis/before_install.$TARGET_ARCH.sh ; fi - - | - if [[ -z $JOBS ]]; then - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then - export JOBS=$((`nproc` + 1)) - elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - export JOBS=$((`sysctl -n hw.ncpu` + 1)) - fi - fi - - | - 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 - # 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}" - - mkdir -p ${CMAKE_DIR} - - travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${CMAKE_DIR} || travis_terminate 1 - - export PATH=${CMAKE_DIR}/bin:${PATH} - - ${MASON} install tbb 2017_U7 && export LD_LIBRARY_PATH=$(${MASON} prefix tbb 2017_U7)/lib/:${LD_LIBRARY_PATH} - - ${MASON} install ccache ${CCACHE_VERSION} && export PATH=$(${MASON} prefix ccache ${CCACHE_VERSION})/bin:${PATH} - - | - if [[ ! -z ${CLANG_VERSION} ]]; then - export CCOMPILER='clang' - export CXXCOMPILER='clang++' - ${MASON} install clang++ ${CLANG_VERSION} && export PATH=$(${MASON} prefix clang++ ${CLANG_VERSION})/bin:${PATH} || travis_terminate 1 - # we only enable lto for release builds - # and therefore don't need to us ld.gold or llvm tools for linking - # for debug builds - if [[ ${BUILD_TYPE} == 'Release' ]]; then - ${MASON} install binutils 2.27 && export PATH=$(${MASON} prefix binutils 2.27)/bin:${PATH} || travis_terminate 1 - fi - fi - - ccache --max-size=256M # limiting the cache's size to roughly the previous job's object sizes - - export OSRM_INSTALL_DIR="$(pwd)/install-osrm" - - export OSRM_BUILD_DIR="$(pwd)/build-osrm" - - export CC=${CCOMPILER} CXX=${CXXCOMPILER} - - mkdir ${OSRM_BUILD_DIR} - -install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS:-OFF} \ - -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} \ - -DENABLE_COVERAGE=${ENABLE_COVERAGE:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_SANITIZER=${ENABLE_SANITIZER:-OFF} \ - -DENABLE_STXXL=${ENABLE_STXXL:-OFF} \ - -DBUILD_TOOLS=ON \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} - - echo "travis_fold:start:MAKE" - - make --jobs=${JOBS} - - make tests --jobs=${JOBS} - - make benchmarks --jobs=${JOBS} - - echo "travis_fold:end:MAKE" - - ccache -s - - sudo make install - - | - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${OSRM_INSTALL_DIR}/lib - fi - - popd - - mkdir example/build && pushd example/build - - export PKG_CONFIG_PATH=${OSRM_INSTALL_DIR}/lib/pkgconfig - - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} - - make --jobs=${JOBS} - - popd - -script: - - if [[ $TARGET_ARCH == armhf ]] ; then echo "Skip tests for $TARGET_ARCH" && exit 0 ; fi - - make -C test/data benchmark - - ./example/build/osrm-example test/data/ch/monaco.osrm - # All tests assume to be run from the build directory - - pushd ${OSRM_BUILD_DIR} - - ./unit_tests/library-tests - - ./unit_tests/extractor-tests - - ./unit_tests/contractor-tests - - ./unit_tests/engine-tests - - ./unit_tests/util-tests - - ./unit_tests/server-tests - - ./unit_tests/partition-tests - - | - if [ -z "${ENABLE_SANITIZER}" ] && [ "$TARGET_ARCH" != "i686" ]; then - npm run nodejs-tests - fi - - | - - popd - - yarn test diff --git a/CHANGELOG.md b/CHANGELOG.md index 31ec1d632..2a90bbf74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,422 @@ -# UNRELEASED +# Unreleased + - Changes from 5.27.1 + - Build: + - CHANGED: Update actions/cache to v3. [#6420](https://github.com/Project-OSRM/osrm-backend/pull/6420) + - Misc: + - FIXED: Handle snapping parameter for all plugins in NodeJs bindings, but not for Route only. [#6417](https://github.com/Project-OSRM/osrm-backend/pull/6417) + - FIXED: Fix annotations=true handling in NodeJS bindings & libosrm. [#6415](https://github.com/Project-OSRM/osrm-backend/pull/6415/) + - FIXED: Fix bindings compilation issue on the latest Node. Update NAN to 2.17.0. [#6416](https://github.com/Project-OSRM/osrm-backend/pull/6416) + - Routing: + - FIXED: Fix adding traffic signal penalties during compression [#6419](https://github.com/Project-OSRM/osrm-backend/pull/6419) +# 5.27.1 + - Changes from 5.27.0 + - Misc: + - FIXED: Revert back to using custom HTTP parser instead of Boost.Beast. [#6407](https://github.com/Project-OSRM/osrm-backend/pull/6407) + - FIXED: Fix bug with large HTTP requests leading to Bad Request in osrm-routed. [#6403](https://github.com/Project-OSRM/osrm-backend/pull/6403) + - Routing: + - CHANGED: Add support for surface=metal,grass_paver,woodchips in bicyle profile. [#6395](https://github.com/Project-OSRM/osrm-backend/pull/6395) + +# 5.27.0 + - Changes from 5.26.0 + - API: + - ADDED: Add Flatbuffers support to NodeJS bindings. [#6338](https://github.com/Project-OSRM/osrm-backend/pull/6338) + - CHANGED: Add `data_version` field to responses of all services. [#5387](https://github.com/Project-OSRM/osrm-backend/pull/5387) + - FIXED: Use Boost.Beast to parse HTTP request. [#6294](https://github.com/Project-OSRM/osrm-backend/pull/6294) + - FIXED: Fix inefficient osrm-routed connection handling [#6113](https://github.com/Project-OSRM/osrm-backend/pull/6113) + - FIXED: Fix HTTP compression precedence [#6113](https://github.com/Project-OSRM/osrm-backend/pull/6113) + - NodeJS: + - FIXED: Support `skip_waypoints` in Node bindings [#6060](https://github.com/Project-OSRM/osrm-backend/pull/6060) + - Misc: + - ADDED: conanbuildinfo.json for easy reading of dependencies [#6388](https://github.com/Project-OSRM/osrm-backend/pull/6388) + - CHANGED: Improve performance of JSON rendering. Fix undefined behaviour in JSON numbers formatting. [#6380](https://github.com/Project-OSRM/osrm-backend/pull/6380) + - ADDED: Add timestamps for logs. [#6375](https://github.com/Project-OSRM/osrm-backend/pull/6375) + - CHANGED: Improve performance of map matching via getPathDistance optimization. [#6378](https://github.com/Project-OSRM/osrm-backend/pull/6378) + - CHANGED: Optimize RestrictionParser performance. [#6344](https://github.com/Project-OSRM/osrm-backend/pull/6344) + - ADDED: Support floats for speed value in traffic updates CSV. [#6327](https://github.com/Project-OSRM/osrm-backend/pull/6327) + - CHANGED: Use Lua 5.4 in Docker image. [#6346](https://github.com/Project-OSRM/osrm-backend/pull/6346) + - CHANGED: Remove redundant nullptr check. [#6326](https://github.com/Project-OSRM/osrm-backend/pull/6326) + - CHANGED: missing files list is included in exception message. [#5360](https://github.com/Project-OSRM/osrm-backend/pull/5360) + - CHANGED: Do not use deprecated Callback::Call overload in Node bindings. [#6318](https://github.com/Project-OSRM/osrm-backend/pull/6318) + - FIXED: Fix distance calculation consistency. [#6315](https://github.com/Project-OSRM/osrm-backend/pull/6315) + - FIXED: Fix performance issue after migration to sol2 3.3.0. [#6304](https://github.com/Project-OSRM/osrm-backend/pull/6304) + - CHANGED: Pass osm_node_ids by reference in osrm::updater::Updater class. [#6298](https://github.com/Project-OSRM/osrm-backend/pull/6298) + - FIXED: Fix bug with reading Set values from Lua scripts. [#6285](https://github.com/Project-OSRM/osrm-backend/pull/6285) + - FIXED: Bug in bicycle profile that caused exceptions if there is a highway=bicycle in the data. [#6296](https://github.com/Project-OSRM/osrm-backend/pull/6296) + - FIXED: Internal refactoring of identifier types used in data facade [#6044](https://github.com/Project-OSRM/osrm-backend/pull/6044) + - CHANGED: Update docs to reflect recent build and dependency changes [#6383](https://github.com/Project-OSRM/osrm-backend/issues/6383) + - Build: + - REMOVED: Get rid of Mason. [#6387](https://github.com/Project-OSRM/osrm-backend/pull/6387) + - CHANGED: Use clang-format from CI base image. [#6391](https://github.com/Project-OSRM/osrm-backend/pull/6391) + - ADDED: Build Node bindings on Windows. [#6334](https://github.com/Project-OSRM/osrm-backend/pull/6334) + - ADDED: Configure cross-compilation for Apple Silicon. [#6360](https://github.com/Project-OSRM/osrm-backend/pull/6360) + - CHANGED: Use apt-get to install Clang on CI. [#6345](https://github.com/Project-OSRM/osrm-backend/pull/6345) + - CHANGED: Fix TBB in case of Conan + NodeJS build. [#6333](https://github.com/Project-OSRM/osrm-backend/pull/6333) + - CHANGED: Migrate to modern TBB version. [#6300](https://github.com/Project-OSRM/osrm-backend/pull/6300) + - CHANGED: Enable performance-move-const-arg clang-tidy check. [#6319](https://github.com/Project-OSRM/osrm-backend/pull/6319) + - CHANGED: Use the latest node on CI. [#6317](https://github.com/Project-OSRM/osrm-backend/pull/6317) + - CHANGED: Migrate Windows CI to GitHub Actions. [#6312](https://github.com/Project-OSRM/osrm-backend/pull/6312) + - ADDED: Add smoke test for Docker image. [#6313](https://github.com/Project-OSRM/osrm-backend/pull/6313) + - CHANGED: Update libosmium to version 2.18.0. [#6303](https://github.com/Project-OSRM/osrm-backend/pull/6303) + - CHANGED: Remove EXACT from find_package if using Conan. [#6299](https://github.com/Project-OSRM/osrm-backend/pull/6299) + - CHANGED: Configure Undefined Behaviour Sanitizer. [#6290](https://github.com/Project-OSRM/osrm-backend/pull/6290) + - CHANGED: Use Conan instead of Mason to install code dependencies. [#6284](https://github.com/Project-OSRM/osrm-backend/pull/6284) + - CHANGED: Migrate to C++17. Update sol2 to 3.3.0. [#6279](https://github.com/Project-OSRM/osrm-backend/pull/6279) + - CHANGED: Update macOS CI image to macos-11. [#6286](https://github.com/Project-OSRM/osrm-backend/pull/6286) + - CHANGED: Enable even more clang-tidy checks. [#6273](https://github.com/Project-OSRM/osrm-backend/pull/6273) + - CHANGED: Configure CMake to not build flatbuffers tests and samples. [#6274](https://github.com/Project-OSRM/osrm-backend/pull/6274) + - CHANGED: Enable more clang-tidy checks. [#6270](https://github.com/Project-OSRM/osrm-backend/pull/6270) + - CHANGED: Configure clang-tidy job on CI. [#6261](https://github.com/Project-OSRM/osrm-backend/pull/6261) + - CHANGED: Use Github Actions for building container images [#6138](https://github.com/Project-OSRM/osrm-backend/pull/6138) + - CHANGED: Upgrade Boost dependency to 1.70 [#6113](https://github.com/Project-OSRM/osrm-backend/pull/6113) + - CHANGED: Upgrade Ubuntu CI builds to 20.04 [#6119](https://github.com/Project-OSRM/osrm-backend/pull/6119) + - CHANGED: Make building osrm-routed optional [#6144](https://github.com/Project-OSRM/osrm-backend/pull/6144) + - FIXED: Run all unit tests in CI [#5248](https://github.com/Project-OSRM/osrm-backend/pull/5248) + - FIXED: Fix installation of Mason CMake and 32 bit CI build [#6170](https://github.com/Project-OSRM/osrm-backend/pull/6170) + - FIXED: Fixed Node docs generation check in CI. [#6058](https://github.com/Project-OSRM/osrm-backend/pull/6058) + - CHANGED: Docker build, enabled arm64 build layer [#6172](https://github.com/Project-OSRM/osrm-backend/pull/6172) + - CHANGED: Docker build, enabled apt-get update/install caching in separate layer for build phase [#6175](https://github.com/Project-OSRM/osrm-backend/pull/6175) + - FIXED: Bump CI complete meta job to ubuntu-20.04 [#6323](https://github.com/Project-OSRM/osrm-backend/pull/6323) + - CHANGED: Node packages are now scoped by @project-osrm [#6386](https://github.com/Project-OSRM/osrm-backend/issues/6386) + - Routing: + - CHANGED: Lazily generate optional route path data [#6045](https://github.com/Project-OSRM/osrm-backend/pull/6045) + - FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988) + - ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050) + - FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125) + - ADDED: Support snapping to multiple ways at an input location. [#5953](https://github.com/Project-OSRM/osrm-backend/pull/5953) + - FIXED: Fix snapping target locations to ways used in turn restrictions. [#6339](https://github.com/Project-OSRM/osrm-backend/pull/6339) + - ADDED: Support OSM traffic signal directions. [#6153](https://github.com/Project-OSRM/osrm-backend/pull/6153) + - FIXED: Ensure u-turn exists in intersection view. [#6376](https://github.com/Project-OSRM/osrm-backend/pull/6376) + - FIXED: Gracefully handle no-turn intersections in guidance processing. [#6382](https://github.com/Project-OSRM/osrm-backend/issues/6382) - Profile: - - New function to support relations: `process_relation`. Read more in profiles documentation. + - CHANGED: Bicycle surface speeds [#6212](https://github.com/Project-OSRM/osrm-backend/pull/6212) + - Tools: + - CHANGED: Do not generate intermediate .osrm file in osrm-extract. [#6354](https://github.com/Project-OSRM/osrm-backend/pull/6354) + +# 5.26.0 + - Changes from 5.25.0 + - API: + - FIXED: Allow for special characters in the profile/method as part of the HTTP URL. [#6090](https://github.com/Project-OSRM/osrm-backend/pull/6090) + - FIXED: Set osrm-routed to immediately close bad connections [#6112](https://github.com/Project-OSRM/osrm-backend/pull/6112) + - Build: + - CHANGED: Replace Travis with Github Actions for CI builds [#6071](https://github.com/Project-OSRM/osrm-backend/pull/6071) + - FIXED: Fixed Boost link flags in pkg-config file. [#6083](https://github.com/Project-OSRM/osrm-backend/pull/6083) + - FIXED: Fixed test cache to consider MLD executable changes. [#6129](https://github.com/Project-OSRM/osrm-backend/pull/6129) + - Routing: + - FIXED: Fix generation of inefficient MLD partitions [#6084](https://github.com/Project-OSRM/osrm-backend/pull/6084) + - FIXED: Fix MLD level mask generation to support 64-bit masks. [#6123](https://github.com/Project-OSRM/osrm-backend/pull/6123) + - FIXED: Fix metric offset overflow for large MLD partitions. This breaks the **data format** [#6124](https://github.com/Project-OSRM/osrm-backend/pull/6124) + +# 5.25.0 + - Changes from 5.24.0 + - Build: + - CHANGED: Node binaries now use Github Releases for hosting [#6030](https://github.com/Project-OSRM/osrm-backend/pull/6030) + - Misc: + - FIXED: Upgrade to @mapbox/node-pre-gyp fix various bugs with Node 12/14 [#5991](https://github.com/Project-OSRM/osrm-backend/pull/5991) + - FIXED: `valid` type in documentation examples [#5990](https://github.com/Project-OSRM/osrm-backend/issues/5990) + - FIXED: Remove redundant loading of .osrm.cell_metrics [#6019](https://github.com/Project-OSRM/osrm-backend/issues/6019) + - CHANGED: Increase PackedOSMIDs size to 34 bits. This breaks the **data format** [#6020](https://github.com/Project-OSRM/osrm-backend/issues/6020) + - Profile: + - FIXED: Add kerb barrier exception to default car profile. [#5999](https://github.com/Project-OSRM/osrm-backend/pull/5999) + +# 5.24.0 + - Changes from 5.23.0 + - Features + - ADDED: Added support for multiple via-way restrictions. [#5907](https://github.com/Project-OSRM/osrm-backend/pull/5907) + - ADDED: Add node bindings support for Node 12, 14, and publish binaries [#5918](https://github.com/Project-OSRM/osrm-backend/pull/5918) + - REMOVED: we no longer publish Node 8 binary modules (they are still buildable from source) [#5918](https://github.com/Project-OSRM/osrm-backend/pull/5918) + - Routing: + - FIXED: Avoid copying ManyToMany table results [#5923](https://github.com/Project-OSRM/osrm-backend/pull/5923) + - FIXED: Reduce copying in API parameter constructors [#5925](https://github.com/Project-OSRM/osrm-backend/pull/5925) + - Misc: + - CHANGED: Cleanup NodeJS dependencies [#5945](https://github.com/Project-OSRM/osrm-backend/pull/5945) + - CHANGED: Unify `.osrm.turn_penalites_index` dump processing same with `.osrm.turn_weight_penalties` and `.osrm.turn_duration_penalties` [#5868](https://github.com/Project-OSRM/osrm-backend/pull/5868) + - FIXED: Properly validate source/destination validation in NodeJS table service [#5595](https://github.com/Project-OSRM/osrm-backend/pull/5595/files) + - FIXED: turn.roads_on_the_left not containing incoming roads and turn.roads_on_the_right not containing outgoing roads on two-way roads [#5128](https://github.com/Project-OSRM/osrm-backend/issues/5128) + - Profile: + - ADDED: Profile debug script which fetches a way from OSM then outputs the result of the profile. [#5908](https://github.com/Project-OSRM/osrm-backend/pull/5908) + - Infrastructure + - CHANGED: Bundled protozero updated to v1.7.0. [#5858](https://github.com/Project-OSRM/osrm-backend/pull/5858) + - Windows: + - FIXED: Fix bit-shift overflow in MLD partition step. [#5878](https://github.com/Project-OSRM/osrm-backend/pull/5878) + - FIXED: Fix vector bool permutation in graph contraction step [#5882](https://github.com/Project-OSRM/osrm-backend/pull/5882) + - API: + - FIXED: Undo libosrm API break by adding old interface as method overload [#5861](https://github.com/Project-OSRM/osrm-backend/pull/5861) + - FIXED: Fixed validation of sources/destinations when accessed via node bindings [#5595](https://github.com/Project-OSRM/osrm-backend/pull/5595) + +# 5.23.0 + - Changes from 5.22.0 + - Build: + - FIXED: pessimistic calls to std::move [#5560](https://github.com/Project-OSRM/osrm-backend/pull/5561) + - Features: + - ADDED: new API parameter - `snapping=any|default` to allow snapping to previously unsnappable edges [#5361](https://github.com/Project-OSRM/osrm-backend/pull/5361) + - ADDED: keepalive support to the osrm-routed HTTP server [#5518](https://github.com/Project-OSRM/osrm-backend/pull/5518) + - ADDED: flatbuffers output format support [#5513](https://github.com/Project-OSRM/osrm-backend/pull/5513) + - ADDED: Global 'skip_waypoints' option [#5556](https://github.com/Project-OSRM/osrm-backend/pull/5556) + - FIXED: Install the libosrm_guidance library correctly [#5604](https://github.com/Project-OSRM/osrm-backend/pull/5604) + - FIXED: Http Handler can now deal witch optional whitespace between header-key and -value [#5606](https://github.com/Project-OSRM/osrm-backend/issues/5606) + - Routing: + - CHANGED: allow routing past `barrier=arch` [#5352](https://github.com/Project-OSRM/osrm-backend/pull/5352) + - CHANGED: default car weight was reduced to 2000 kg. [#5371](https://github.com/Project-OSRM/osrm-backend/pull/5371) + - CHANGED: default car height was reduced to 2 meters. [#5389](https://github.com/Project-OSRM/osrm-backend/pull/5389) + - FIXED: treat `bicycle=use_sidepath` as no access on the tagged way. [#5622](https://github.com/Project-OSRM/osrm-backend/pull/5622) + - FIXED: fix table result when source and destination on same one-way segment. [#5828](https://github.com/Project-OSRM/osrm-backend/pull/5828) + - FIXED: fix occasional segfault when swapping data with osrm-datastore and using `exclude=` [#5844](https://github.com/Project-OSRM/osrm-backend/pull/5844) + - FIXED: fix crash in MLD alternative search if source or target are invalid [#5851](https://github.com/Project-OSRM/osrm-backend/pull/5851) + - Misc: + - CHANGED: Reduce memory usage for raster source handling. [#5572](https://github.com/Project-OSRM/osrm-backend/pull/5572) + - CHANGED: Add cmake option `ENABLE_DEBUG_LOGGING` to control whether output debug logging. [#3427](https://github.com/Project-OSRM/osrm-backend/issues/3427) + - CHANGED: updated extent of Hong Kong as left hand drive country. [#5535](https://github.com/Project-OSRM/osrm-backend/issues/5535) + - FIXED: corrected error message when failing to snap input coordinates [#5846](https://github.com/Project-OSRM/osrm-backend/pull/5846) + - Infrastructure + - REMOVED: STXXL support removed as STXXL became abandonware. [#5760](https://github.com/Project-OSRM/osrm-backend/pull/5760) + +# 5.22.0 + - 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.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) + +# 5.17.0 + - Changes from 5.16.0: + - Bugfixes: + - FIXED: deduplication of route steps when waypoints are used [#4909](https://github.com/Project-OSRM/osrm-backend/issues/4909) + - FIXED: Use smaller range for U-turn angles in map-matching [#4920](https://github.com/Project-OSRM/osrm-backend/pull/4920) + - FIXED: Remove the last short annotation segment in `trimShortSegments` [#4946](https://github.com/Project-OSRM/osrm-backend/pull/4946) + - FIXED: Properly calculate annotations for speeds, durations and distances when waypoints are used with mapmatching [#4949](https://github.com/Project-OSRM/osrm-backend/pull/4949) + - FIXED: Don't apply unimplemented SH and PH conditions in OpeningHours and add inversed date ranges [#4992](https://github.com/Project-OSRM/osrm-backend/issues/4992) + - FIXED: integer overflow in `DynamicGraph::Renumber` [#5021](https://github.com/Project-OSRM/osrm-backend/pull/5021) + - Profile: + - CHANGED: Handle oneways in get_forward_backward_by_key [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929) + - FIXED: Do not route against oneway road if there is a cycleway in the wrong direction; also review bike profile [#4943](https://github.com/Project-OSRM/osrm-backend/issues/4943) + - CHANGED: Make cyclability weighting of the bike profile prefer safer routes more strongly [#5015](https://github.com/Project-OSRM/osrm-backend/issues/5015) + - Guidance: + - CHANGED: Don't use obviousness for links bifurcations [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929) + - FIXED: Adjust Straight direction modifiers of side roads in driveway handler [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929) + - CHANGED: Added post process logic to collapse segregated turn instructions [#4925](https://github.com/Project-OSRM/osrm-backend/pull/4925) + - ADDED: Maneuver relation now supports `straight` as a direction [#4995](https://github.com/Project-OSRM/osrm-backend/pull/4995) + - FIXED: Support spelling maneuver relation with British spelling [#4950](https://github.com/Project-OSRM/osrm-backend/issues/4950) + - Tools: + - ADDED: `osrm-routed` accepts a new property `--memory_file` to store memory in a file on disk. [#4881](https://github.com/Project-OSRM/osrm-backend/pull/4881) + - ADDED: `osrm-datastore` accepts a new parameter `--dataset-name` to select the name of the dataset. [#4982](https://github.com/Project-OSRM/osrm-backend/pull/4982) + - ADDED: `osrm-datastore` accepts a new parameter `--list` to list all datasets loaded into memory. [#4982](https://github.com/Project-OSRM/osrm-backend/pull/4982) + - ADDED: `osrm-datastore` accepts a new parameter `--only-metric` to only reload the data that can be updated by a weight update (reduces memory for traffic updates). [#5002](https://github.com/Project-OSRM/osrm-backend/pull/5002) + - ADDED: `osrm-routed` accepts a new parameter `--dataset-name` to select the shared-memory dataset to use. [#4982](https://github.com/Project-OSRM/osrm-backend/pull/4982) + - NodeJS: + - ADDED: `OSRM` object accepts a new option `memory_file` that stores the memory in a file on disk. [#4881](https://github.com/Project-OSRM/osrm-backend/pull/4881) + - ADDED: `OSRM` object accepts a new option `dataset_name` to select the shared-memory dataset. [#4982](https://github.com/Project-OSRM/osrm-backend/pull/4982) + - Internals + - CHANGED: Updated segregated intersection identification [#4845](https://github.com/Project-OSRM/osrm-backend/pull/4845) [#4968](https://github.com/Project-OSRM/osrm-backend/pull/4968) + - REMOVED: Remove `.timestamp` file since it was unused [#4960](https://github.com/Project-OSRM/osrm-backend/pull/4960) + - Documentation: + - ADDED: Add documentation about OSM node ids in nearest service response [#4436](https://github.com/Project-OSRM/osrm-backend/pull/4436) + - Performance + - FIXED: Speed up response time when lots of legs exist and geojson is used with `steps=true` [#4936](https://github.com/Project-OSRM/osrm-backend/pull/4936) + - FIXED: Return iterators instead of vectors in datafacade_base functions [#4969](https://github.com/Project-OSRM/osrm-backend/issues/4969) + - Misc: + - ADDED: expose name for datasource annotations as metadata [#4973](https://github.com/Project-OSRM/osrm-backend/pull/4973) + +# 5.16.0 + - Changes from 5.15.2: + - Guidance + - ADDED #4676: Support for maneuver override relation, allowing data-driven overrides for turn-by-turn instructions [#4676](https://github.com/Project-OSRM/osrm-backend/pull/4676) + - CHANGED #4830: Announce reference change if names are empty + - CHANGED #4835: MAXIMAL_ALLOWED_SEPARATION_WIDTH increased to 12 meters + - CHANGED #4842: Lower priority links from a motorway now are used as motorway links [#4842](https://github.com/Project-OSRM/osrm-backend/pull/4842) + - CHANGED #4895: Use ramp bifurcations as fork intersections [#4895](https://github.com/Project-OSRM/osrm-backend/issues/4895) + - CHANGED #4893: Handle motorway forks with links as normal motorway intersections[#4893](https://github.com/Project-OSRM/osrm-backend/issues/4893) + - FIXED #4905: Check required tags of `maneuver` relations [#4905](https://github.com/Project-OSRM/osrm-backend/pull/4905) + - Profile: + - FIXED: `highway=service` will now be used for restricted access, `access=private` is still disabled for snapping. + - ADDED #4775: Exposes more information to the turn function, now being able to set turn weights with highway and access information of the turn as well as other roads at the intersection [#4775](https://github.com/Project-OSRM/osrm-backend/issues/4775) + - FIXED #4763: Add support for non-numerical units in car profile for maxheight [#4763](https://github.com/Project-OSRM/osrm-backend/issues/4763) + - ADDED #4872: Handling of `barrier=height_restrictor` nodes [#4872](https://github.com/Project-OSRM/osrm-backend/pull/4872) + +# 5.15.2 + - Changes from 5.15.1: + - Features: + - ADDED: Exposed the waypoints parameter in the node bindings interface + - Bugfixes: + - FIXED: Segfault causing bug in leg collapsing map matching when traversing edges in reverse + +# 5.15.1 + - Changes from 5.15.0: + - Bugfixes: + - FIXED: Segfault in map matching when RouteLeg collapsing code is run on a match with multiple submatches + - Guidance: + - Set type of trivial intersections where classes change to Suppressed instead of NoTurn + +# 5.15.0 + - Changes from 5.14.3: + - Bugfixes: + - FIXED #4704: Fixed regression in bearings reordering introduced in 5.13 [#4704](https://github.com/Project-OSRM/osrm-backend/issues/4704) + - FIXED #4781: Fixed overflow exceptions in percent-encoding parsing + - FIXED #4770: Fixed exclude flags for single toll road scenario + - FIXED #4283: Fix overflow on zero duration segments + - FIXED #4804: Ignore no_*_on_red turn restrictions + - Guidance: + - CHANGED #4706: Guidance refactoring step to decouple intersection connectivity analysis and turn instructions generation [#4706](https://github.com/Project-OSRM/osrm-backend/pull/4706) + - CHANGED #3491: Refactor `isThroughStreet`/Intersection options + - Profile: + - ADDED: `tunnel` as a new class in car profile so that sections of the route with tunnel tags will be marked as such + +# 5.14.3 + - Changes from 5.14.2: + - Features: + - Added a `waypoints` parameter to the match service plugin that accepts indices to input coordinates and treats only those points as waypoints in the response format. + - Bugfixes: + - FIXED #4754: U-Turn penalties are applied to straight turns. + - FIXED #4756: Removed too restrictive road name check in the sliproad handler + - FIXED #4731: Use correct weights for edge-based graph duplicated via nodes. + - Profile: + - CHANGED: added Belarus speed limits + - CHANGED: set default urban speed in Ukraine to 50kmh + +# 5.14.2 + - Changes from 5.14.1: + - Bugfixes: + - FIXED #4727: Erroring when a old .core file is present. + - FIXED #4642: Update checks for EMPTY_NAMEID to check for empty name strings + - FIXED #4738: Fix potential segmentation fault + - Node.js Bindings: + - ADDED: Exposed new `max_radiuses_map_matching` option from `EngingConfig` options + - Tools: + - ADDED: New osrm-routed `max_radiuses_map_matching` command line flag to optionally set a maximum radius for map matching + +# 5.14.1 + - Changes from 5.14.0 + - Bugfixes: + - FIXED: don't use removed alternative candidates in `filterPackedPathsByCellSharing` + +# 5.14.0 + - Changes from 5.13 + - API: + - ADDED: new RouteStep property `driving_side` that has either "left" or "right" for that step + - Misc: + - ADDED: Bundles a rough (please improve!) driving-side GeoJSON file for use with `osrm-extract --location-dependent-data data/driving_side.geojson` + - CHANGED: Conditional turn parsing is disabled by default now + - ADDED: Adds a tool to analyze turn instruction generation in a dataset. Useful for tracking turn-by-turn heuristic changes over time. + - CHANGED: Internal refactoring of guidance code as a first step towards a re-runnable guidance pipeline + - ADDED: Now publishing Node 8.x LTS binary modules + - Profile: + - CHANGED: Remove dependency on turn types and turn modifier in the process_turn function in the `car.lua` profile. Guidance instruction types are not used to influence turn penalty anymore so this will break backward compatibility between profile version 3 and 4. + - Guidance: + - ADDED: New internal flag on "segregated intersections" - in the future, will should allow collapsing of instructions across complex intersection geometry where humans only perceive a single maneuver + - CHANGED: Decrease roundabout turn radius threshold from 25m to 15m - adds some "exit the roundabout" instructions for moderately sized roundabouts that were being missed previously + - Docker: + - CHANGED: switch to alpine 3.6, and use a multistage build to reduce image size + - Build: + - FIX: use LUA_LIBRARY_DIRS to propertly detect Lua on all platforms + - Docs: + - FIX: clarify description of roundabout exit instructions + - Bugfixes: + - FIXED: Fix bug where merge instructions got the wrong direction modifier ([PR #4670](https://github.com/Project-OSRM/osrm-backend/pull/4670)) + - FIXED: Properly use the `profile.properties.left_hand_driving` property, there was a typo that meant it had no effect + - FIXED: undefined behaviour when alternative candidate via node is same as source node ([#4691](https://github.com/Project-OSRM/osrm-backend/issues/4691)) + - FIXED: ensure libosrm.pc is pushed to the correct location for pkgconfig to find it on all platforms + - FIXED: don't consider empty names + empty refs as a valid name for u-turns + +# 5.13.0 + - Changes from 5.12: + - Profile: + - Append cardinal directions from route relations to ref fields to improve instructions; off by default see `profile.cardinal_directions` - Support of `distance` weight in foot and bicycle profiles + - Support of relations processing + - Added `way:get_location_tag(key)` method to get location-dependent tags https://github.com/Project-OSRM/osrm-backend/wiki/Using-location-dependent-data-in-profiles + - Added `forward_ref` and `backward_ref` support + - Left-side driving mode is specified by a local Boolean flag `is_left_hand_driving` in `ExtractionWay` and `ExtractionTurn` + - Support literal values for maxspeeds in NO, PL and ZA - Infrastructure: - Lua 5.1 support is removed due to lack of support in sol2 https://github.com/ThePhD/sol2/issues/302 - - Node.js Bindings: - - Exposes `use_threads_number=Number` parameter of `EngineConfig` to limit a number of threads in a TBB internal pool + - Fixed pkg-config version of OSRM + - Removed `.osrm.core` file since CoreCH is deprecated now. + - Tools: + - Because of boost/program_options#32 with boost 1.65+ we needed to change the behavior of the following flags to not accept `={true|false}` anymore: + - `--use-locations-cache=false` becomes `--disable-location-cache` + - `--parse-conditional-restrictions=true` becomes `--parse-conditional-restrictions` + - The deprecated options `--use-level-cache` and `--generate-edge-lookup` + - Bugfixes: + - Fixed #4348: Some cases of sliproads pre-processing were broken + - Fixed #4331: Correctly compute left/right modifiers of forks in case the fork is curved. + - Fixed #4472: Correctly count the number of lanes using the delimter in `turn:lanes` tag. + - Fixed #4214: Multiple runs of `osrm-partition` lead to crash. + - Fixed #4348: Fix assorted problems around slip roads. + - Fixed #4420: A bug that would result in unnecessary instructions, due to problems in suffix/prefix detection + - Algorithm + - Deprecate CoreCH functionality. Usage of CoreCH specific options will fall back to using CH with core_factor of 1.0 + - MLD uses a unidirectional Dijkstra for 1-to-N and N-to-1 matrices which yields speedup. # 5.12.0 + - Changes from 5.11: - Guidance - now announcing turning onto oneways at the end of a road (e.g. onto dual carriageways) - Adds new instruction types at the exit of roundabouts and rotaries `exit roundabout` and `exit rotary`. @@ -70,7 +479,7 @@ - Bugfixes - Properly save/retrieve datasource annotations for road segments ([#4346](https://github.com/Project-OSRM/osrm-backend/issues/4346) - Fix conditional restriction grammer parsing so it works for single-day-of-week restrictions ([#4357](https://github.com/Project-OSRM/osrm-backend/pull/4357)) - - Algorithm) + - Algorithm - BREAKING: the file format requires re-processing due to the changes on via-ways - Added support for via-way restrictions diff --git a/CMakeLists.txt b/CMakeLists.txt index b7fb38bf8..86adcd678 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,8 @@ -cmake_minimum_required(VERSION 2.8.11) -# we depend on 2.8.11 introducing target_include_directories +cmake_minimum_required(VERSION 3.2) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR AND NOT MSVC_IDE) message(FATAL_ERROR "In-source builds are not allowed. @@ -19,52 +22,73 @@ if (NOT WIN32 AND NOT DEFINED ENV{OSRM_BUILD_DIR}) set(ENV{OSRM_BUILD_DIR} ${CMAKE_CURRENT_BINARY_DIR}) endif() -option(ENABLE_MASON "Use mason for dependencies" OFF) +option(ENABLE_CONAN "Use conan for dependencies" OFF) option(ENABLE_CCACHE "Speed up incremental rebuilds via ccache" ON) option(BUILD_TOOLS "Build OSRM tools" OFF) option(BUILD_PACKAGE "Build OSRM package" OFF) +option(BUILD_ROUTED "Build osrm-routed HTTP server" ON) option(ENABLE_ASSERTIONS "Use assertions in release mode" OFF) +option(ENABLE_DEBUG_LOGGING "Use debug logging in release mode" OFF) option(ENABLE_COVERAGE "Build with coverage instrumentalisation" OFF) option(ENABLE_SANITIZER "Use memory sanitizer for Debug build" OFF) -option(ENABLE_STXXL "Use STXXL library" OFF) option(ENABLE_LTO "Use LTO if available" OFF) option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF) option(ENABLE_GOLD_LINKER "Use GNU gold linker if available" ON) option(ENABLE_NODE_BINDINGS "Build NodeJs bindings" OFF) +option(ENABLE_CLANG_TIDY "Enables clang-tidy checks" OFF) + +if (ENABLE_CLANG_TIDY) + find_program(CLANG_TIDY_COMMAND NAMES clang-tidy) + if(NOT CLANG_TIDY_COMMAND) + message(FATAL_ERROR "ENABLE_CLANG_TIDY is ON but clang-tidy is not found!") + else() + message(STATUS "Found clang-tidy at ${CLANG_TIDY_COMMAND}") + set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND};--warnings-as-errors=*") + endif() +endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -if(ENABLE_MASON) - # versions in use - set(MASON_BOOST_VERSION "1.63.0") - set(MASON_STXXL_VERSION "1.4.1-1") - set(MASON_EXPAT_VERSION "2.2.0") - set(MASON_LUA_VERSION "5.2.4") - set(MASON_BZIP2_VERSION "1.0.6") - set(MASON_TBB_VERSION "2017_U7") - set(MASON_LIBSHP_VERSION "1.3.0") - - message(STATUS "Enabling mason") - - find_program(CURL_FOUND curl) - if(NOT CURL_FOUND) - message(FATAL_ERROR "curl command required with -DENABLE_MASON") - endif() - - include(mason) -endif() - # be compatible with version handling before cmake 3.x if (POLICY CMP0048) cmake_policy(SET CMP0048 OLD) endif() +if (POLICY CMP0057) + cmake_policy(SET CMP0057 NEW) +endif() +if (POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif() project(OSRM C CXX) -set(OSRM_VERSION_MAJOR 5) -set(OSRM_VERSION_MINOR 12) -set(OSRM_VERSION_PATCH 0) -set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}") -add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}") +# add @loader_path/$ORIGIN to rpath to make binaries relocatable +if (APPLE) + set(CMAKE_BUILD_RPATH "@loader_path") +else() + set(CMAKE_BUILD_RPATH "\$ORIGIN") + # https://stackoverflow.com/questions/6324131/rpath-origin-not-having-desired-effect + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,origin") +endif() + +include(JSONParser) +file(READ "package.json" packagejsonraw) +sbeParseJson(packagejson packagejsonraw) + +if (packagejson.version MATCHES "^([0-9]+)\.([0-9]+)\.([0-9]+)") + set(OSRM_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(OSRM_VERSION_MINOR ${CMAKE_MATCH_2}) + set(OSRM_VERSION_PATCH ${CMAKE_MATCH_3}) + + set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}") +else() + message(FATAL_ERROR "Version from package.json cannot be parsed, expected semver compatible X.Y.Z, but found ${packagejson.version}") +endif() + +if (MSVC) + add_definitions("-DOSRM_PROJECT_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"") +else() + add_definitions(-DOSRM_PROJECT_DIR="${CMAKE_CURRENT_SOURCE_DIR}") +endif() # these two functions build up custom variables: # DEPENDENCIES_INCLUDE_DIRS and OSRM_DEFINES @@ -101,10 +125,10 @@ if(WIN32 AND MSVC_VERSION LESS 1900) message(FATAL_ERROR "Building with Microsoft compiler needs Latest Visual Studio 2015 (Community or better)") endif() -# Strictly require GCC>=4.9 and Clang>=3.4 - GCC 4.8 is already too old for C++14. +# Strictly require GCC>=5.0 and Clang>=3.4 - GCC 4.8 is already too old for C++14. if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) - message(FATAL_ERROR "GCC>=4.9 required. In case you are on Ubuntu upgrade via ppa:ubuntu-toolchain-r/test") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) + message(FATAL_ERROR "GCC>=5.0 required. In case you are on Ubuntu upgrade via ppa:ubuntu-toolchain-r/test") endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) @@ -114,7 +138,7 @@ endif() include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/) -include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/sol2/) +include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/sol2-3.3.0/include) include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/variant/include) set(BOOST_COMPONENTS date_time chrono filesystem iostreams program_options regex system thread unit_test_framework) @@ -125,7 +149,8 @@ configure_file( ) file(GLOB UtilGlob src/util/*.cpp src/util/*/*.cpp) file(GLOB ExtractorGlob src/extractor/*.cpp src/extractor/*/*.cpp) -file(GLOB PartitionerGlob src/partition/*.cpp) +file(GLOB GuidanceGlob src/guidance/*.cpp src/extractor/intersection/*.cpp) +file(GLOB PartitionerGlob src/partitioner/*.cpp) file(GLOB CustomizerGlob src/customize/*.cpp) file(GLOB ContractorGlob src/contractor/*.cpp) file(GLOB UpdaterGlob src/updater/*.cpp) @@ -136,13 +161,18 @@ file(GLOB ErrorcodesGlob src/osrm/errorcodes.cpp) add_library(UTIL OBJECT ${UtilGlob}) add_library(EXTRACTOR OBJECT ${ExtractorGlob}) +add_library(GUIDANCE OBJECT ${GuidanceGlob}) add_library(PARTITIONER OBJECT ${PartitionerGlob}) add_library(CUSTOMIZER OBJECT ${CustomizerGlob}) add_library(CONTRACTOR OBJECT ${ContractorGlob}) add_library(UPDATER OBJECT ${UpdaterGlob}) add_library(STORAGE OBJECT ${StorageGlob}) add_library(ENGINE OBJECT ${EngineGlob}) -add_library(SERVER OBJECT ${ServerGlob}) + +if (BUILD_ROUTED) + add_library(SERVER OBJECT ${ServerGlob}) + add_executable(osrm-routed src/tools/routed.cpp $ $) +endif() set_target_properties(UTIL PROPERTIES LINKER_LANGUAGE CXX) @@ -150,21 +180,21 @@ add_executable(osrm-extract src/tools/extract.cpp) add_executable(osrm-partition src/tools/partition.cpp) add_executable(osrm-customize src/tools/customize.cpp) add_executable(osrm-contract src/tools/contract.cpp) -add_executable(osrm-routed src/tools/routed.cpp $ $) -add_executable(osrm-datastore src/tools/store.cpp $) -add_library(osrm src/osrm/osrm.cpp $ $ $) +add_executable(osrm-datastore src/tools/store.cpp $ $) +add_library(osrm src/osrm/osrm.cpp $ $ $ $) add_library(osrm_contract src/osrm/contractor.cpp $ $) -add_library(osrm_extract src/osrm/extractor.cpp $ $) -add_library(osrm_partition $ $) -add_library(osrm_customize $ $) -add_library(osrm_update $ $) -add_library(osrm_store $ $) +add_library(osrm_extract src/osrm/extractor.cpp $ $ $) +add_library(osrm_guidance $ $) +add_library(osrm_partition src/osrm/partitioner.cpp $ $ $) +add_library(osrm_customize src/osrm/customizer.cpp $ $ $) +add_library(osrm_update $ $ $) +add_library(osrm_store $ $ $) if(ENABLE_GOLD_LINKER) execute_process(COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) if("${LD_VERSION}" MATCHES "GNU gold") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags") set(OSRM_LDFLAGS "${OSRM_LDFLAGS} -fuse-ld=gold -Wl,--disable-new-dtags") message(STATUS "Using GNU gold as linker.") @@ -180,13 +210,6 @@ if(ENABLE_GOLD_LINKER) endif() endif() -# Disable LTO when mason+gcc is detected before testing for / setting any flags. -# Mason builds libraries with Clang, mixing does not work in the context of lto. -if(ENABLE_MASON AND CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND ENABLE_LTO) - set(ENABLE_LTO OFF) - message(WARNING "Mason and GCC's LTO not work together. Disabling LTO.") -endif() - # Explicitly set the build type to Release if no other type is specified # on the command line. Without this, cmake defaults to an unoptimized, # non-debug build, which almost nobody wants. @@ -211,19 +234,20 @@ endif() if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) message(STATUS "Configuring debug mode flags") set(ENABLE_ASSERTIONS ON) - if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline -fno-omit-frame-pointer") - if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - if (CMAKE_BUILD_TYPE MATCHES Debug) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og -ggdb") - else() - # Don't override the -O parameter for RelWithDebInfo, we want an optimized build - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") - endif() - endif() - endif() + set(ENABLE_DEBUG_LOGGING ON) endif() +if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fno-inline -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-inline -fno-omit-frame-pointer") +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ggdb") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -ggdb") +endif() + + if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) message(STATUS "Configuring release mode optimizations") # Check if LTO is available @@ -255,8 +279,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM endif() # Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools - if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND - NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0" AND NOT MINGW) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT MINGW) find_program(GCC_AR gcc-ar) find_program(GCC_RANLIB gcc-ranlib) if ("${GCC_AR}" STREQUAL "GCC_AR-NOTFOUND" OR "${GCC_RANLIB}" STREQUAL "GCC_RANLIB-NOTFOUND") @@ -284,18 +307,12 @@ if(CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CM set(CMAKE_RANLIB ${LLVM_RANLIB}) endif() endif() - - if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0") - message(STATUS "Disabling LTO on GCC < 4.9.0 since it is broken, see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57038") - set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}") - set(ENABLE_LTO Off) - endif() endif() endif() -if(UNIX AND NOT APPLE AND ENABLE_MASON AND (LTO_WORKS OR ENABLE_GOLD_LINKER)) - message(WARNING "ENABLE_MASON and ENABLE_LTO/ENABLE_GOLD_LINKER may not work on all linux systems currently") - message(WARNING "For more details see: https://github.com/Project-OSRM/osrm-backend/issues/3202") +# TODO: this was added for Mason, we are not sure if it is true after migration to Conan +if(UNIX AND NOT APPLE AND ENABLE_CONAN AND (LTO_WORKS OR ENABLE_GOLD_LINKER)) + message(WARNING "ENABLE_CONAN and ENABLE_LTO/ENABLE_GOLD_LINKER may not work on all linux systems currently") endif() set(MAYBE_COVERAGE_LIBRARIES "") @@ -303,20 +320,25 @@ if (ENABLE_COVERAGE) if (NOT CMAKE_BUILD_TYPE MATCHES "Debug") message(ERROR "ENABLE_COVERAGE=ON only make sense with a Debug build") endif() - message(INFO "Enabling coverage") + message(STATUS "Enabling coverage") set(MAYBE_COVERAGE_LIBRARIES "-lgcov") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ftest-coverage -fprofile-arcs") endif() + + if (ENABLE_SANITIZER) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") - set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -fsanitize=address") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") + set(SANITIZER_FLAGS "-g -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=undefined -fno-omit-frame-pointer") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZER_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS}") + set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} ${SANITIZER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${SANITIZER_FLAGS}") endif() # Configuring compilers +include(cmake/warnings.cmake) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC -fcolor-diagnostics -ftemplate-depth=1024 -Wno-unused-command-line-argument") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC -fcolor-diagnostics -ftemplate-depth=1024") elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(COLOR_FLAG "-fdiagnostics-color=auto") check_cxx_compiler_flag("-fdiagnostics-color=auto" HAS_COLOR_FLAG) @@ -324,7 +346,8 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(COLOR_FLAG "") endif() # using GCC - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=1 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 ${COLOR_FLAG} -fPIC -ftemplate-depth=1024") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 ${COLOR_FLAG} -fPIC -ftemplate-depth=1024") + if(WIN32) # using mingw add_dependency_defines(-DWIN32) set(OPTIONAL_SOCKET_LIBS ws2_32 wsock32) @@ -342,7 +365,6 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC") elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") # using Visual Studio C++ - set(BOOST_COMPONENTS ${BOOST_COMPONENTS} zlib) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") # avoid compiler error C1128 from scripting_environment_lua.cpp set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /DWIN32_LEAN_AND_MEAN") # avoid compiler error C2011 from dual #include of winsock.h and winsock2.h add_dependency_defines(-DBOOST_LIB_DIAGNOSTIC) @@ -379,16 +401,13 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") # Activate C++1y if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") - set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++14") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") + set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -std=c++17") endif() # Configuring other platform dependencies if(APPLE) - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.10") execute_process(COMMAND xcrun --sdk macosx --show-sdk-path OUTPUT_VARIABLE CMAKE_OSX_SYSROOT OUTPUT_STRIP_TRAILING_WHITESPACE) - set(CMAKE_OSX_ARCHITECTURES "x86_64") - message(STATUS "Set Architecture to x64 on OS X") exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION) string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION}) if(OSXLIBSTD) @@ -404,127 +423,156 @@ if(UNIX AND NOT APPLE) set(MAYBE_RT_LIBRARY -lrt) endif() -# Disallow deprecated protozero APIs -add_definitions(-DPROTOZERO_STRICT_API) - find_package(Threads REQUIRED) -# if mason is enabled no find_package calls are made -# to ensure that we are only compiling and linking against -# fully portable mason packages -if(ENABLE_MASON) - message(STATUS "Installing dependencies via mason") +# 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-2778eb8/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) +target_no_warning(MICROTAR unused-variable) +target_no_warning(MICROTAR format) + +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}) + +set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "Disable the build of Flatbuffers tests and samples.") +set(FLATBUFFERS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/flatbuffers") +set(FLATBUFFERS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/flatbuffers/include") +include_directories(SYSTEM ${FLATBUFFERS_INCLUDE_DIR}) +add_subdirectory(${FLATBUFFERS_SRC_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build + EXCLUDE_FROM_ALL) + +set(FMT_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/fmt-9.1.0/include") +add_compile_definitions(FMT_HEADER_ONLY) +include_directories(SYSTEM ${FMT_INCLUDE_DIR}) + + +# see https://stackoverflow.com/questions/70898030/boost-link-error-using-conan-find-package +if (MSVC) + add_definitions(-DBOOST_ALL_NO_LIB) +endif() + +if(ENABLE_CONAN) + message(STATUS "Installing dependencies via Conan") + + # Conan will generate Find*.cmake files to build directory, so we use them with the highest priority + list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_BINARY_DIR}) + list(INSERT CMAKE_PREFIX_PATH 0 ${CMAKE_BINARY_DIR}) + + include(${CMAKE_CURRENT_LIST_DIR}/cmake/conan.cmake) + + set(CONAN_BOOST_VERSION "1.79.0#96e4902111a2e343a8ba0aa95391bb58") + set(CONAN_BZIP2_VERSION "1.0.8#d1b2d5816f25865acf978501dff1f897") + set(CONAN_EXPAT_VERSION "2.2.10#916908d4a570ad839edd25322c3268cd") + set(CONAN_LUA_VERSION "5.4.4#3ec62efc37cd0a5d80b9e5cb35277360") + set(CONAN_TBB_VERSION "2021.3.0#507ec17cbd51a84167e143b20d170eea") + + set(CONAN_SYSTEM_INCLUDES ON) + + # TODO: + # if we link TBB dynamically osrm-extract.exe finishes on the first access to any TBB symbol + # with exit code = -1073741515, which means that program cannot load required DLL. + if (MSVC) + set(TBB_SHARED False) + else() + set(TBB_SHARED True) + endif() + + set(CONAN_ARGS + REQUIRES + "boost/${CONAN_BOOST_VERSION}" + "bzip2/${CONAN_BZIP2_VERSION}" + "expat/${CONAN_EXPAT_VERSION}" + "lua/${CONAN_LUA_VERSION}" + "onetbb/${CONAN_TBB_VERSION}" + BASIC_SETUP + GENERATORS cmake_find_package json # json generator generates a conanbuildinfo.json in the build folder so (non-CMake) projects can easily parse OSRM's dependencies + KEEP_RPATHS + NO_OUTPUT_DIRS + OPTIONS boost:filesystem_version=3 # https://stackoverflow.com/questions/73392648/error-with-boost-filesystem-version-in-cmake + onetbb:shared=${TBB_SHARED} + boost:without_stacktrace=True # Apple Silicon cross-compilation fails without it + BUILD missing + ) + # explicitly say Conan to use x86 dependencies if build for x86 platforms (https://github.com/conan-io/cmake-conan/issues/141) + if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + conan_cmake_run("${CONAN_ARGS};ARCH;x86") + # cross-compilation for Apple Silicon + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") + conan_cmake_run("${CONAN_ARGS};ARCH;armv8") + else() + conan_cmake_run("${CONAN_ARGS}") + endif() + + add_dependency_includes(${CONAN_INCLUDE_DIRS_BOOST}) + add_dependency_includes(${CONAN_INCLUDE_DIRS_BZIP2}) + add_dependency_includes(${CONAN_INCLUDE_DIRS_EXPAT}) + add_dependency_includes(${CONAN_INCLUDE_DIRS_LUA}) + add_dependency_includes(${CONAN_INCLUDE_DIRS_TBB}) set(Boost_USE_STATIC_LIBS ON) - mason_use(boost VERSION ${MASON_BOOST_VERSION} HEADER_ONLY) - add_dependency_includes(${MASON_PACKAGE_boost_INCLUDE_DIRS}) - mason_use(boost_libfilesystem VERSION ${MASON_BOOST_VERSION}) - set(Boost_FILESYSTEM_LIBRARY ${MASON_PACKAGE_boost_libfilesystem_STATIC_LIBS}) - mason_use(boost_libiostreams VERSION ${MASON_BOOST_VERSION}) - set(Boost_IOSTREAMS_LIBRARY ${MASON_PACKAGE_boost_libiostreams_STATIC_LIBS}) - mason_use(boost_libprogram_options VERSION ${MASON_BOOST_VERSION}) - set(Boost_PROGRAM_OPTIONS_LIBRARY ${MASON_PACKAGE_boost_libprogram_options_STATIC_LIBS}) - mason_use(boost_libregex VERSION ${MASON_BOOST_VERSION}) - set(Boost_REGEX_LIBRARY ${MASON_PACKAGE_boost_libregex_STATIC_LIBS}) - mason_use(boost_libtest VERSION ${MASON_BOOST_VERSION}) - set(Boost_UNIT_TEST_FRAMEWORK_LIBRARY ${MASON_PACKAGE_boost_libtest_STATIC_LIBS}) - mason_use(boost_libdate_time VERSION ${MASON_BOOST_VERSION}) - set(Boost_DATE_TIME_LIBRARY ${MASON_PACKAGE_boost_libdate_time_STATIC_LIBS}) - mason_use(boost_libthread VERSION ${MASON_BOOST_VERSION}) - set(Boost_THREAD_LIBRARY ${MASON_PACKAGE_boost_libthread_STATIC_LIBS}) - mason_use(boost_libsystem VERSION ${MASON_BOOST_VERSION}) - set(Boost_SYSTEM_LIBRARY ${MASON_PACKAGE_boost_libsystem_STATIC_LIBS}) + find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) + set(Boost_DATE_TIME_LIBRARY "${Boost_date_time_LIB_TARGETS}") + set(Boost_CHRONO_LIBRARY "${Boost_chrono_LIB_TARGETS}") + set(Boost_PROGRAM_OPTIONS_LIBRARY "${Boost_program_options_LIB_TARGETS}") + set(Boost_FILESYSTEM_LIBRARY "${Boost_filesystem_LIB_TARGETS}") + set(Boost_IOSTREAMS_LIBRARY "${Boost_iostreams_LIB_TARGETS}") + set(Boost_THREAD_LIBRARY "${Boost_thread_LIB_TARGETS}") + set(Boost_SYSTEM_LIBRARY "${Boost_system_LIB_TARGETS}") + set(Boost_ZLIB_LIBRARY "${Boost_zlib_LIB_TARGETS}") + set(Boost_REGEX_LIBRARY "${Boost_regex_LIB_TARGETS}") + set(Boost_UNIT_TEST_FRAMEWORK_LIBRARY "${Boost_unit_test_framework_LIB_TARGETS}") + - if (ENABLE_STXXL) - mason_use(stxxl VERSION ${MASON_STXXL_VERSION}) - add_dependency_includes(${MASON_PACKAGE_stxxl_INCLUDE_DIRS}) - set(MAYBE_STXXL_LIBRARY ${MASON_PACKAGE_stxxl_STATIC_LIBS}) - add_definitions(-DUSE_STXXL_LIBRARY) - endif() + find_package(BZip2 REQUIRED) + find_package(EXPAT REQUIRED) + find_package(lua REQUIRED) + set(LUA_LIBRARIES ${lua_LIBRARIES}) - mason_use(expat VERSION ${MASON_EXPAT_VERSION}) - add_dependency_includes(${MASON_PACKAGE_expat_INCLUDE_DIRS}) - set(EXPAT_LIBRARIES ${MASON_PACKAGE_expat_STATIC_LIBS}) + find_package(TBB REQUIRED) - mason_use(lua VERSION ${MASON_LUA_VERSION}) - add_dependency_includes(${MASON_PACKAGE_lua_INCLUDE_DIRS}) - set(USED_LUA_LIBRARIES ${MASON_PACKAGE_lua_STATIC_LIBS}) - - mason_use(bzip2 VERSION ${MASON_BZIP2_VERSION}) - add_dependency_includes(${MASON_PACKAGE_bzip2_INCLUDE_DIRS}) - set(BZIP2_LIBRARIES ${MASON_PACKAGE_bzip2_STATIC_LIBS}) - - mason_use(tbb VERSION ${MASON_TBB_VERSION}) - add_dependency_includes(${MASON_PACKAGE_tbb_INCLUDE_DIRS}) - set(TBB_LIBRARIES ${MASON_PACKAGE_tbb_LDFLAGS}) - - if(NOT MASON_PACKAGE_tbb_LIBRARY_DIRS) - message(FATAL_ERROR "MASON_PACKAGE_tbb_LIBRARY_DIRS is empty, rpath will not work") - endif() - set(TBB_LINKER_RPATHS "") - foreach(libpath ${MASON_PACKAGE_tbb_LIBRARY_DIRS}) - set(TBB_LINKER_RPATHS "${TBB_LINKER_RPATHS} -Wl,-rpath -Wl,${libpath}") - file(GLOB TBBGlob ${libpath}/*.*) - install(FILES ${TBBGlob} DESTINATION lib) - endforeach() - if(APPLE) - set(LINKER_FLAGS "${TBB_LINKER_RPATHS} -Wl,-rpath -Wl,@loader_path") - elseif(UNIX) - set(LINKER_FLAGS "${TBB_LINKER_RPATHS} '-Wl,-rpath,$ORIGIN' -Wl,-z,origin") - endif() - - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") - - # current mason packages target -D_GLIBCXX_USE_CXX11_ABI=0 - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0") # note: we avoid calling find_package(Osmium ...) here to ensure that the - # expat and bzip2 are used from mason rather than the system + # expat and bzip2 are used from conan rather than the system include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include) - - include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/rapidjson/include) - else() - - find_package(Boost 1.54 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) - add_dependency_includes(${Boost_INCLUDE_DIRS}) - if(WIN32 AND Boost_VERSION VERSION_LESS 106200) - message(FATAL_ERROR "Building with MSVC needs Boost 1.62 with CXX11_CONSTEXPR support") + if (BUILD_ROUTED) + # osrm-routed requires newer boost:asio + find_package(Boost 1.70 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) + else() + find_package(Boost 1.60 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) endif() + add_dependency_includes(${Boost_INCLUDE_DIRS}) find_package(TBB REQUIRED) add_dependency_includes(${TBB_INCLUDE_DIR}) - if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug) - set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES}) - endif() + set(TBB_LIBRARIES TBB::tbb) find_package(EXPAT REQUIRED) add_dependency_includes(${EXPAT_INCLUDE_DIRS}) - if (ENABLE_STXXL) - find_package(STXXL) - if (STXXL_FOUND) - add_dependency_includes(${STXXL_INCLUDE_DIR}) - set(MAYBE_STXXL_LIBRARY ${STXXL_LIBRARY}) - add_definitions(-DUSE_STXXL_LIBRARY) - else() - MESSAGE(STATUS "STXXL was requested but not found, default STL will be used") - endif() - endif() - find_package(BZip2 REQUIRED) add_dependency_includes(${BZIP2_INCLUDE_DIR}) - FIND_PACKAGE(Lua 5.2 EXACT) - IF (LUA_FOUND) - MESSAGE(STATUS "Using Lua ${LUA_VERSION_STRING}") - ELSE() - MESSAGE(FATAL_ERROR "Lua 5.2 was not found.") - ENDIF() + find_package(Lua 5.2 REQUIRED) + if (LUA_FOUND) + message(STATUS "Using Lua ${LUA_VERSION_STRING}") + endif() - set(USED_LUA_LIBRARIES ${LUA_LIBRARIES}) add_dependency_includes(${LUA_INCLUDE_DIR}) # add a target to generate API documentation with Doxygen @@ -545,10 +593,6 @@ else() endif() find_package(Osmium REQUIRED COMPONENTS io) include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR}) - - set(RAPIDJSON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/rapidjson/include") - include_directories(SYSTEM ${RAPIDJSON_INCLUDE_DIR}) - endif() # prefix compilation with ccache by default if available and on clang or gcc @@ -562,32 +606,15 @@ if(ENABLE_CCACHE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILE endif() endif() -# even with mason builds we want to link to system zlib +# even with conan builds we want to link to system zlib # to ensure that osrm binaries play well with other binaries like nodejs find_package(ZLIB REQUIRED) add_dependency_includes(${ZLIB_INCLUDE_DIRS}) -if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS) - add_dependency_defines(-DBOOST_TEST_DYN_LINK) -endif() - -if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS) - add_dependency_defines(-DBOOST_TEST_DYN_LINK) -endif() - add_dependency_defines(-DBOOST_SPIRIT_USE_PHOENIX_V3) add_dependency_defines(-DBOOST_RESULT_OF_USE_DECLTYPE) add_dependency_defines(-DBOOST_FILESYSTEM_NO_DEPRECATED) -if (ENABLE_STXXL) - set(OpenMP_FIND_QUIETLY ON) - find_package(OpenMP) - if(OPENMP_FOUND) - message(STATUS "OpenMP support found. Linking just in case for stxxl") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - endif() -endif() - add_definitions(${OSRM_DEFINES}) include_directories(SYSTEM ${DEPENDENCIES_INCLUDE_DIRS}) @@ -610,7 +637,9 @@ target_link_libraries(osrm-extract osrm_extract ${Boost_PROGRAM_OPTIONS_LIBRARY} target_link_libraries(osrm-partition osrm_partition ${Boost_PROGRAM_OPTIONS_LIBRARY}) target_link_libraries(osrm-customize osrm_customize ${Boost_PROGRAM_OPTIONS_LIBRARY}) target_link_libraries(osrm-contract osrm_contract ${Boost_PROGRAM_OPTIONS_LIBRARY}) -target_link_libraries(osrm-routed osrm ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY}) +if (BUILD_ROUTED) + target_link_libraries(osrm-routed osrm ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY}) +endif() set(EXTRACTOR_LIBRARIES ${BZIP2_LIBRARIES} @@ -618,12 +647,17 @@ set(EXTRACTOR_LIBRARIES ${BOOST_BASE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${EXPAT_LIBRARIES} - ${USED_LUA_LIBRARIES} + ${LUA_LIBRARIES} ${OSMIUM_LIBRARIES} - ${MAYBE_STXXL_LIBRARY} ${TBB_LIBRARIES} ${ZLIB_LIBRARY} ${MAYBE_COVERAGE_LIBRARIES}) +set(GUIDANCE_LIBRARIES + ${BOOST_BASE_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ${LUA_LIBRARIES} + ${TBB_LIBRARIES} + ${MAYBE_COVERAGE_LIBRARIES}) set(PARTITIONER_LIBRARIES ${BOOST_ENGINE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} @@ -647,8 +681,7 @@ set(UPDATER_LIBRARIES set(CONTRACTOR_LIBRARIES ${BOOST_BASE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - ${USED_LUA_LIBRARIES} - ${MAYBE_STXXL_LIBRARY} + ${LUA_LIBRARIES} ${TBB_LIBRARIES} ${MAYBE_RT_LIBRARY} ${MAYBE_COVERAGE_LIBRARIES}) @@ -668,39 +701,30 @@ set(STORAGE_LIBRARIES set(UTIL_LIBRARIES ${BOOST_BASE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - ${MAYBE_STXXL_LIBRARY} ${TBB_LIBRARIES} - ${MAYBE_COVERAGE_LIBRARIES}) + ${MAYBE_COVERAGE_LIBRARIES} + ${ZLIB_LIBRARY}) # Libraries target_link_libraries(osrm ${ENGINE_LIBRARIES}) target_link_libraries(osrm_update ${UPDATER_LIBRARIES}) target_link_libraries(osrm_contract ${CONTRACTOR_LIBRARIES} osrm_update osrm_store) -target_link_libraries(osrm_extract ${EXTRACTOR_LIBRARIES}) +target_link_libraries(osrm_extract osrm_guidance ${EXTRACTOR_LIBRARIES}) target_link_libraries(osrm_partition ${PARTITIONER_LIBRARIES}) target_link_libraries(osrm_customize ${CUSTOMIZER_LIBRARIES} osrm_update osrm_store) target_link_libraries(osrm_store ${STORAGE_LIBRARIES}) # BUILD_COMPONENTS -add_executable(osrm-components src/tools/components.cpp $) +add_executable(osrm-components src/tools/components.cpp $ $) target_link_libraries(osrm-components ${TBB_LIBRARIES} ${BOOST_BASE_LIBRARIES} ${UTIL_LIBRARIES}) install(TARGETS osrm-components DESTINATION bin) if(BUILD_TOOLS) message(STATUS "Activating OSRM internal tools") add_executable(osrm-io-benchmark src/tools/io-benchmark.cpp $) - target_link_libraries(osrm-io-benchmark ${BOOST_BASE_LIBRARIES}) + target_link_libraries(osrm-io-benchmark ${BOOST_BASE_LIBRARIES} ${TBB_LIBRARIES}) install(TARGETS osrm-io-benchmark DESTINATION bin) - - find_package(Shapefile) - if(SHAPEFILE_FOUND AND (Boost_VERSION VERSION_GREATER 106000 OR ENABLE_MASON)) - add_executable(osrm-extract-conditionals src/tools/extract-conditionals.cpp $) - target_include_directories(osrm-extract-conditionals PRIVATE ${LIBSHAPEFILE_INCLUDE_DIR}) - target_link_libraries(osrm-extract-conditionals ${OSMIUM_LIBRARIES} ${BOOST_BASE_LIBRARIES} ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${UTIL_LIBRARIES} ${BZIP2_LIBRARIES} ${ZLIB_LIBRARY} ${EXPAT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) - install(TARGETS osrm-extract-conditionals DESTINATION bin) - endif() endif() if (ENABLE_ASSERTIONS) @@ -708,6 +732,11 @@ if (ENABLE_ASSERTIONS) add_definitions(-DBOOST_ENABLE_ASSERT_HANDLER) endif() +if (ENABLE_DEBUG_LOGGING) + message(STATUS "Enabling debug logging") + add_definitions(-DENABLE_DEBUG_LOGGING) +endif() + # Add RPATH info to executables so that when they are run after being installed # (i.e., from /usr/local/bin/) the linker can find library dependencies. For # more info see http://www.cmake.org/Wiki/CMake_RPATH_handling @@ -715,32 +744,40 @@ set_property(TARGET osrm-extract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET osrm-partition PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) -set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) +if (BUILD_ROUTED) + set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) +endif() file(GLOB VariantGlob third_party/variant/include/mapbox/*.hpp) +file(GLOB FlatbuffersGlob third_party/flatbuffers/include/flatbuffers/*.h) file(GLOB LibraryGlob include/osrm/*.hpp) file(GLOB ParametersGlob include/engine/api/*_parameters.hpp) +set(ApiHeader include/engine/api/base_result.hpp) set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/approach.hpp include/engine/phantom_node.hpp) set(UtilHeader include/util/coordinate.hpp include/util/json_container.hpp include/util/typedefs.hpp include/util/alias.hpp include/util/exception.hpp include/util/bearing.hpp) set(ExtractorHeader include/extractor/extractor.hpp include/storage/io_config.hpp include/extractor/extractor_config.hpp include/extractor/travel_mode.hpp) -set(PartitionerHeader include/partition/partitioner.hpp include/partition/partition_config.hpp) +set(PartitionerHeader include/partitioner/partitioner.hpp include/partitioner/partitioner_config.hpp) set(ContractorHeader include/contractor/contractor.hpp include/contractor/contractor_config.hpp) set(StorageHeader include/storage/storage.hpp include/storage/io_config.hpp include/storage/storage_config.hpp) install(FILES ${EngineHeader} DESTINATION include/osrm/engine) install(FILES ${UtilHeader} DESTINATION include/osrm/util) install(FILES ${StorageHeader} DESTINATION include/osrm/storage) install(FILES ${ExtractorHeader} DESTINATION include/osrm/extractor) -install(FILES ${PartitionerHeader} DESTINATION include/osrm/partition) +install(FILES ${PartitionerHeader} DESTINATION include/osrm/partitioner) install(FILES ${ContractorHeader} DESTINATION include/osrm/contractor) install(FILES ${LibraryGlob} DESTINATION include/osrm) install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api) +install(FILES ${ApiHeader} DESTINATION include/osrm/engine/api) install(FILES ${VariantGlob} DESTINATION include/mapbox) +install(FILES ${FlatbuffersGlob} DESTINATION include/flatbuffers) install(TARGETS osrm-extract DESTINATION bin) install(TARGETS osrm-partition DESTINATION bin) install(TARGETS osrm-customize DESTINATION bin) install(TARGETS osrm-contract DESTINATION bin) install(TARGETS osrm-datastore DESTINATION bin) -install(TARGETS osrm-routed DESTINATION bin) +if (BUILD_ROUTED) + install(TARGETS osrm-routed DESTINATION bin) +endif() install(TARGETS osrm DESTINATION lib) install(TARGETS osrm_extract DESTINATION lib) install(TARGETS osrm_partition DESTINATION lib) @@ -748,6 +785,7 @@ install(TARGETS osrm_customize DESTINATION lib) install(TARGETS osrm_update DESTINATION lib) install(TARGETS osrm_contract DESTINATION lib) install(TARGETS osrm_store DESTINATION lib) +install(TARGETS osrm_guidance DESTINATION lib) # Install profiles and support library to /usr/local/share/osrm/profiles by default @@ -793,10 +831,27 @@ set(PKGCONFIG_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include") list(APPEND DEPENDENCIES_INCLUDE_DIRS "${PKGCONFIG_INCLUDE_DIR}") list(APPEND DEPENDENCIES_INCLUDE_DIRS "${PKGCONFIG_INCLUDE_DIR}/osrm") JOIN("-I${DEPENDENCIES_INCLUDE_DIRS}" " -I" PKGCONFIG_OSRM_INCLUDE_FLAGS) -JOIN("${ENGINE_LIBRARIES}" " " PKGCONFIG_OSRM_DEPENDENT_LIBRARIES) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY) -install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +# Boost uses imported targets, we need to use a generator expression to extract +# the link libraries to be written to the pkg-config file. +# Conan & TBB define dependencies as CMake targets too, that's why we do the same for them. +foreach(engine_lib ${ENGINE_LIBRARIES}) + if("${engine_lib}" MATCHES "^Boost.*" OR "${engine_lib}" MATCHES "^CONAN_LIB.*" OR "${engine_lib}" MATCHES "^TBB.*") + list(APPEND PKGCONFIG_DEPENDENT_LIBRARIES "$") + else() + list(APPEND PKGCONFIG_DEPENDENT_LIBRARIES "${engine_lib}") + endif() +endforeach(engine_lib) +JOIN("${PKGCONFIG_DEPENDENT_LIBRARIES}" " " PKGCONFIG_OSRM_DEPENDENT_LIBRARIES) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in pkgconfig.configured @ONLY) +file(GENERATE + OUTPUT + ${PROJECT_BINARY_DIR}/libosrm.pc + INPUT + ${PROJECT_BINARY_DIR}/pkgconfig.configured) + +install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION ${PKGCONFIG_LIBRARY_DIR}/pkgconfig) # uninstall target configure_file( @@ -831,22 +886,23 @@ if (ENABLE_FUZZING) add_subdirectory(fuzz) endif () +# add headers sanity check target that includes all headers independently +set(check_headers_dir "${PROJECT_BINARY_DIR}/check-headers") +file(GLOB_RECURSE headers_to_check + ${PROJECT_BINARY_DIR}/*.hpp + ${PROJECT_SOURCE_DIR}/include/*.hpp) +foreach(header ${headers_to_check}) + if ("${header}" MATCHES ".*/include/nodejs/.*") + # we do not check NodeJS bindings headers + continue() + endif() + get_filename_component(filename ${header} NAME_WE) + set(filename "${check_headers_dir}/${filename}.cpp") + if (NOT EXISTS ${filename}) + file(WRITE ${filename} "#include \"${header}\"\n") + endif() + list(APPEND sources ${filename}) +endforeach() +add_library(check-headers STATIC EXCLUDE_FROM_ALL ${sources}) +set_target_properties(check-headers PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${check_headers_dir}) -# add headers sanity check target that includes all headers independently -# make sure we have all deps for the nodejs sub project's includes (nan, node) -if (ENABLE_NODE_BINDINGS) - set(check_headers_dir "${PROJECT_BINARY_DIR}/check-headers") - file(GLOB_RECURSE headers_to_check - ${PROJECT_BINARY_DIR}/*.hpp - ${PROJECT_SOURCE_DIR}/include/*.hpp) - foreach(header ${headers_to_check}) - get_filename_component(filename ${header} NAME_WE) - set(filename "${check_headers_dir}/${filename}.cpp") - if (NOT EXISTS ${filename}) - file(WRITE ${filename} "#include \"${header}\"\n") - endif() - list(APPEND sources ${filename}) - endforeach() - add_library(check-headers STATIC EXCLUDE_FROM_ALL ${sources}) - set_target_properties(check-headers PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${check_headers_dir}) -endif() diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md new file mode 100644 index 000000000..9d0614931 --- /dev/null +++ b/CODE-OF-CONDUCT.md @@ -0,0 +1,3 @@ +# Code of conduct + +Everyone is invited to participate in Project OSRM’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Project-OSRM organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2745a654b..30b697e55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,12 @@ +# Everyone + +Please take some time to review our [code of conduct](CODE-OF-CONDUCT.md) to help guide your interactions with others on this project. + # User Before you open a new issue, please search for older ones that cover the same issue. In general "me too" comments/issues are frowned upon. -You can add a :+1: emoji to the issue if you want to express interest in this. +You can add a :+1: emoji reaction to the issue if you want to express interest in this. # Developer diff --git a/LICENCE.TXT b/LICENSE.TXT similarity index 96% rename from LICENCE.TXT rename to LICENSE.TXT index 143580ec6..779b5db50 100644 --- a/LICENCE.TXT +++ b/LICENSE.TXT @@ -1,4 +1,4 @@ -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/README.md b/README.md index ec6a84816..91f6037fb 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ ## Open Source Routing Machine -| Linux / macOS | Windows | Code Coverage | -| ------------- | ------- | ------------- | -| [![Travis](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=master)](https://travis-ci.org/Project-OSRM/osrm-backend) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/4iuo3s9gxprmcjjh)](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) | [![Codecov](https://codecov.io/gh/Project-OSRM/osrm-backend/branch/master/graph/badge.svg)](https://codecov.io/gh/Project-OSRM/osrm-backend) | +| Linux / macOS / Windows | Code Coverage | +| ----------------------- | ------------- | +| [![osrm-backend CI](https://github.com/Project-OSRM/osrm-backend/actions/workflows/osrm-backend.yml/badge.svg)](https://github.com/Project-OSRM/osrm-backend/actions/workflows/osrm-backend.yml) | [![Codecov](https://codecov.io/gh/Project-OSRM/osrm-backend/branch/master/graph/badge.svg)](https://codecov.io/gh/Project-OSRM/osrm-backend) | High performance routing engine written in C++14 designed to run on OpenStreetMap data. 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 @@ -19,7 +19,6 @@ To quickly try OSRM use our [demo server](http://map.project-osrm.org) which com For a quick introduction about how the road network is represented in OpenStreetMap and how to map specific road network features have a look at [this guide about mapping for navigation](https://www.mapbox.com/mapping/mapping-for-navigation/). Related [Project-OSRM](https://github.com/Project-OSRM) repositories: -- [node-osrm](https://www.npmjs.com/package/osrm) - Production-ready NodeJs bindings for the routing engine - [osrm-frontend](https://github.com/Project-OSRM/osrm-frontend) - User-facing frontend with map. The demo server runs this on top of the backend - [osrm-text-instructions](https://github.com/Project-OSRM/osrm-text-instructions) - Text instructions from OSRM route response - [osrm-backend-docker](https://hub.docker.com/r/osrm/osrm-backend/) - Ready to use Docker images @@ -41,9 +40,17 @@ Related [Project-OSRM](https://github.com/Project-OSRM) repositories: The easiest and quickest way to setup your own routing engine is to use Docker images we provide. +There are two pre-processing pipelines available: +- Contraction Hierarchies (CH) +- Multi-Level Dijkstra (MLD) + +we recommend using MLD by default except for special use-cases such as very large distance matrices where CH is still a better fit for the time being. +In the following we explain the MLD pipeline. +If you want to use the CH pipeline instead replace `osrm-partition` and `osrm-customize` with a single `osrm-contract` and change the algorithm option for `osrm-routed` to `--algorithm ch`. + ### 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://github.com/Project-OSRM/osrm-backend/pkgs/container/osrm-backend), [frontend](https://hub.docker.com/r/osrm/osrm-frontend/)) on Debian and make sure they are as lightweight as possible. Older backend versions can be found on [Docker Hub](https://hub.docker.com/r/osrm/osrm-backend/). Download OpenStreetMap extracts for example from [Geofabrik](http://download.geofabrik.de/) @@ -51,10 +58,16 @@ Download OpenStreetMap extracts for example from [Geofabrik](http://download.geo Pre-process the extract with the car profile and start a routing engine HTTP server on port 5000 - docker run -t -v $(pwd):/data osrm/osrm-backend osrm-extract -p /opt/car.lua /data/berlin-latest.osm.pbf - docker run -t -v $(pwd):/data osrm/osrm-backend osrm-contract /data/berlin-latest.osrm + docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-extract -p /opt/car.lua /data/berlin-latest.osm.pbf - docker run -t -i -p 5000:5000 -v $(pwd):/data osrm/osrm-backend osrm-routed /data/berlin-latest.osrm +The flag `-v "${PWD}:/data"` creates the directory `/data` inside the docker container and makes the current working directory `"${PWD}"` available there. The file `/data/berlin-latest.osm.pbf` inside the container is referring to `"${PWD}/berlin-latest.osm.pbf"` on the host. + + docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-partition /data/berlin-latest.osrm + docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-customize /data/berlin-latest.osrm + +Note there is no `berlin-latest.osrm` file, but multiple `berlin-latest.osrm.*` files, i.e. `berlin-latest.osrm` is not file path, but "base" path referring to set of files and there is an option to omit this `.osrm` suffix completely(e.g. `osrm-partition /data/berlin-latest`). + + docker run -t -i -p 5000:5000 -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-routed --algorithm mld /data/berlin-latest.osrm Make requests against the HTTP server @@ -71,7 +84,7 @@ In case Docker complains about not being able to connect to the Docker daemon ma After adding yourself to the `docker` group make sure to log out and back in again with your terminal. -We support the following images on Docker Cloud: +We support the following images in the Container Registry: Name | Description -----|------ @@ -83,15 +96,15 @@ Name | Description ### Building from Source -The following targets Ubuntu 16.04. +The following targets Ubuntu 22.04. For instructions how to build on different distributions, macOS or Windows see our [Wiki](https://github.com/Project-OSRM/osrm-backend/wiki). Install dependencies ```bash sudo apt install build-essential git cmake pkg-config \ -libbz2-dev libstxxl-dev libstxxl1v5 libxml2-dev \ -libzip-dev libboost-all-dev lua5.2 liblua5.2-dev libtbb-dev +libbz2-dev libxml2-dev libzip-dev libboost-all-dev \ +lua5.2 liblua5.2-dev libtbb-dev ``` Compile and install OSRM binaries @@ -104,29 +117,10 @@ cmake --build . sudo cmake --build . --target install ``` -Grab a `.osm.pbf` extract from [Geofabrik](http://download.geofabrik.de/index.html) or [Mapzen's Metro Extracts](https://mapzen.com/data/metro-extracts/) - -```bash -wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf -``` - -Pre-process the extract and start the HTTP server - -``` -osrm-extract berlin-latest.osm.pbf -p profiles/car.lua -osrm-contract berlin-latest.osrm -osrm-routed berlin-latest.osrm -``` - -Running Queries - -``` -curl "http://127.0.0.1:5000/route/v1/driving/13.388860,52.517037;13.385983,52.496891?steps=true" -``` - ### Request Against the Demo Server -Read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Api-usage-policy). +Read the [API usage policy](https://github.com/Project-OSRM/osrm-backend/wiki/Demo-server). + Simple query with instructions and alternatives on Berlin: ``` @@ -138,16 +132,16 @@ curl "https://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.38 The Node.js bindings provide read-only access to the routing engine. We provide API documentation and examples [here](docs/nodejs/api.md). -You will need a modern `libstdc++` toolchain (`>= GLIBCXX_3.4.20`) for binary compatibility if you want to use the pre-built binaries. +You will need a modern `libstdc++` toolchain (`>= GLIBCXX_3.4.26`) for binary compatibility if you want to use the pre-built binaries. For older Ubuntu systems you can upgrade your standard library for example with: ``` sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update -y -sudo apt-get install -y libstdc++-5-dev +sudo apt-get install -y libstdc++-9-dev ``` -You can install the Node.js bindings via `npm install osrm` or from this repository either via +You can install the Node.js bindings via `npm install @project-osrm/osrm` or from this repository either via npm install @@ -157,8 +151,21 @@ which will check and use pre-built binaries if they're available for this releas to always force building the Node.js bindings from source. +#### Unscoped packages + +Prior to v5.27.0, the `osrm` Node package was unscoped. If you are upgrading from an old package, you will need to do the following: + +``` +npm uninstall osrm --save +npm install @project-osrm/osrm --save +``` + +#### Package docs + For usage details have a look [these API docs](docs/nodejs/api.md). +An exemplary implementation by a 3rd party with Docker and Node.js can be found [here](https://github.com/door2door-io/osrm-express-server-demo). + ## References in publications diff --git a/appveyor-build.bat b/appveyor-build.bat deleted file mode 100644 index aba8f23c7..000000000 --- a/appveyor-build.bat +++ /dev/null @@ -1,195 +0,0 @@ -@ECHO OFF -SETLOCAL -SET EL=0 - -ECHO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -SET PROJECT_DIR=%CD% -ECHO PROJECT_DIR^: %PROJECT_DIR% -ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS% - - -:: Check CMake version -SET CMAKE_VERSION=3.9.2 -SET PATH=%PROJECT_DIR%\cmake-%CMAKE_VERSION%-win32-x86\bin;%PATH% -ECHO cmake^: && cmake --version -IF %ERRORLEVEL% NEQ 0 ECHO CMAKE not found && GOTO CMAKE_NOT_OK - -cmake --version | findstr /C:%CMAKE_VERSION% && GOTO CMAKE_OK - -:CMAKE_NOT_OK -ECHO CMAKE NOT OK - downloading new CMake %CMAKE_VERSION% -powershell Invoke-WebRequest https://cmake.org/files/v3.9/cmake-%CMAKE_VERSION%-win32-x86.zip -OutFile $env:PROJECT_DIR\cm.zip -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -IF NOT EXIST cmake-%CMAKE_VERSION%-win32-x86 7z -y x cm.zip | %windir%\system32\FIND "ing archive" -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -:CMAKE_OK -ECHO CMAKE_OK -cmake --version - -ECHO activating VS command prompt ... -SET PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH% -CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 - -ECHO platform^: %platform% - -ECHO cl.exe version -cl -ECHO msbuild version -msbuild /version - -:: HARDCODE "x64" as it is uppercase on AppVeyor and download from S3 is case sensitive -SET DEPSPKG=osrm-deps-win-x64-14.0.7z - -:: local development -ECHO. -ECHO LOCAL_DEV^: %LOCAL_DEV% -IF NOT DEFINED LOCAL_DEV SET LOCAL_DEV=0 -IF DEFINED LOCAL_DEV IF %LOCAL_DEV% EQU 1 IF EXIST %DEPSPKG% ECHO skipping deps download && GOTO SKIPDL - -IF EXIST %DEPSPKG% DEL %DEPSPKG% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO downloading %DEPSPKG% -powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/$env:DEPSPKG -OutFile $env:PROJECT_DIR\$env:DEPSPKG -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -:SKIPDL - -IF EXIST osrm-deps ECHO deleting osrm-deps... && RD /S /Q osrm-deps -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -IF EXIST build ECHO deleting build dir... && RD /S /Q build -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -7z -y x %DEPSPKG% | %windir%\system32\FIND "ing archive" -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -::tree osrm-deps - -MKDIR build -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -cd build -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET OSRMDEPSDIR=%PROJECT_DIR%/osrm-deps -set PREFIX=%OSRMDEPSDIR%/libs -set BOOST_ROOT=%OSRMDEPSDIR%/boost -set BOOST_LIBRARYDIR=%BOOST_ROOT%/lib -set TBB_INSTALL_DIR=%OSRMDEPSDIR%/tbb -set TBB_ARCH_PLATFORM=intel64/vc14 - -ECHO OSRMDEPSDIR ^: %OSRMDEPSDIR% -ECHO PREFIX ^: %PREFIX% -ECHO BOOST_ROOT ^: %BOOST_ROOT% -ECHO BOOST_LIBRARYDIR ^: %BOOST_LIBRARYDIR% -ECHO TBB_INSTALL_DIR ^: %TBB_INSTALL_DIR% -ECHO TBB_ARCH_PLATFORM ^: %TBB_ARCH_PLATFORM% - - -ECHO calling cmake .... -cmake .. ^ --G "Visual Studio 14 2015 Win64" ^ --DBOOST_ROOT=%BOOST_ROOT% ^ --DBOOST_LIBRARYDIR=%BOOST_LIBRARYDIR% ^ --DBoost_ADDITIONAL_VERSIONS=1.58 ^ --DBoost_USE_MULTITHREADED=ON ^ --DBoost_USE_STATIC_LIBS=ON ^ --DCMAKE_BUILD_TYPE=%CONFIGURATION% ^ --DCMAKE_INSTALL_PREFIX=%PREFIX% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO building ... -msbuild OSRM.sln ^ -/p:Configuration=%Configuration% ^ -/p:Platform=x64 ^ -/t:rebuild ^ -/p:BuildInParallel=true ^ -/m:%NUMBER_OF_PROCESSORS% ^ -/toolsversion:14.0 ^ -/p:PlatformToolset=v140 ^ -/clp:Verbosity=normal ^ -/nologo ^ -/flp1:logfile=build_errors.txt;errorsonly ^ -/flp2:logfile=build_warnings.txt;warningsonly -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -CD %PROJECT_DIR%\build -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET PATH=%PROJECT_DIR%\osrm-deps\libs\bin;%PATH% - -ECHO running extractor-tests.exe ... -unit_tests\%Configuration%\extractor-tests.exe -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO running engine-tests.exe ... -unit_tests\%Configuration%\engine-tests.exe -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO running util-tests.exe ... -unit_tests\%Configuration%\util-tests.exe -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO running server-tests.exe ... -unit_tests\%Configuration%\server-tests.exe -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO running library-tests.exe ... -SET test_region=monaco -SET test_region_ch=ch\monaco -SET test_region_corech=corech\monaco -SET test_region_mld=mld\monaco -SET test_osm=%test_region%.osm.pbf -IF NOT EXIST %test_osm% powershell Invoke-WebRequest https://s3.amazonaws.com/mapbox/osrm/testing/monaco.osm.pbf -OutFile %test_osm% -%Configuration%\osrm-extract.exe -p ../profiles/car.lua %test_osm% -MKDIR ch -XCOPY %test_region%.osrm.* ch\ -XCOPY %test_region%.osrm ch\ -MKDIR corech -XCOPY %test_region%.osrm.* corech\ -XCOPY %test_region%.osrm corech\ -MKDIR mld -XCOPY %test_region%.osrm.* mld\ -XCOPY %test_region%.osrm mld\ -%Configuration%\osrm-contract.exe %test_region_ch%.osrm -%Configuration%\osrm-contract.exe --core 0.8 %test_region_corech%.osrm -%Configuration%\osrm-partition.exe %test_region_mld%.osrm -%Configuration%\osrm-customize.exe %test_region_mld%.osrm -XCOPY /Y ch\*.* ..\test\data\ch\ -XCOPY /Y corech\*.* ..\test\data\corech\ -XCOPY /Y mld\*.* ..\test\data\mld\ -unit_tests\%Configuration%\library-tests.exe - -IF NOT "%APPVEYOR_REPO_BRANCH%"=="master" GOTO DONE -ECHO ========= CREATING PACKAGES ========== - -CD %PROJECT_DIR%\build\%Configuration% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET P=%PROJECT_DIR% -SET ZIP= %P%\osrm_%Configuration%.zip -IF EXIST %ZIP% ECHO deleting %ZIP% && DEL /F /Q %ZIP% -IF %ERRORLEVEL% NEQ 0 ECHO deleting %ZIP% FAILED && GOTO ERROR - -7z a %ZIP% *.lib *.exe *.pdb %P%/osrm-deps/libs/bin/*.dll -tzip -mx9 | %windir%\system32\FIND "ing archive" -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -CD ..\..\profiles -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ECHO disk=c:\temp\stxxl,10000,wincall > .stxxl.txt -7z a %ZIP% * -tzip -mx9 | %windir%\system32\FIND "ing archive" -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -GOTO DONE - -:ERROR -ECHO ~~~~~~~~~~~~~~~~~~~~~~ ERROR %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -ECHO ERRORLEVEL^: %ERRORLEVEL% -SET EL=%ERRORLEVEL% - -:DONE -ECHO ~~~~~~~~~~~~~~~~~~~~~~ DONE %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -EXIT /b %EL% diff --git a/appveyor.yml b/appveyor.yml index db8d3d854..a1849a9e7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,52 +1,15 @@ -environment: - matrix: - - configuration: Release -# - configuration: Debug - -install: - - ps: Install-Product node 6 - -# scripts that are called at very beginning, before repo cloning -init: - - git config --global core.autocrlf input - -os: Visual Studio 2015 +os: Visual Studio 2019 # clone directory clone_folder: c:\projects\osrm platform: x64 +# no-op for the time being until someone with access to GitHub checks settings will remove integration with AppVeyor +# https://github.com/Project-OSRM/osrm-backend/pull/6312#issuecomment-1217237055 build_script: - - CALL appveyor-build.bat - -before_test: - - node --version - - npm --version - - npm install --ignore-scripts - - npm link --ignore-scripts - - SET PATH=%CD%\osrm-deps\libs\bin;%PATH% - - SET OSRM_BUILD_DIR=build\%Configuration% - - npm test - -artifacts: - - path: osrm_Release.zip - name: osrm_Release.zip -# - path: osrm_Debug.zip -# name: osrm_Debug.zip + - EXIT 0 branches: only: - master - -deploy: - provider: FTP - server: - secure: ef7oiQTTXFGt8NdNiOHm/uRFVrUttzyFbIlnaeHhQvw= - username: - secure: Bw+Se2GTJxA6+GtRkEc//tQSBHOuFIuJHBjFwR9cD+8= - password: - secure: eqwESZqxMXC/j5mOCpaXuw== - folder: / - enable_ssl: true - active_mode: false diff --git a/build-local.bat b/build-local.bat index 8598230f3..dad1d25c5 100644 --- a/build-local.bat +++ b/build-local.bat @@ -11,7 +11,6 @@ SET CONFIGURATION=Release FOR /F "tokens=*" %%i in ('git rev-parse --abbrev-ref HEAD') do SET APPVEYOR_REPO_BRANCH=%%i ECHO APPVEYOR_REPO_BRANCH^: %APPVEYOR_REPO_BRANCH% -SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.7.0-rc2-win32-x86\bin;%PATH% SET PATH=C:\Program Files\7-Zip;%PATH% powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force diff --git a/cmake/CPackConfig.cmake b/cmake/CPackConfig.cmake index c05dc2201..6ce8def8e 100644 --- a/cmake/CPackConfig.cmake +++ b/cmake/CPackConfig.cmake @@ -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 ") -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/*) diff --git a/cmake/FindLua.cmake b/cmake/FindLua.cmake index 49b6ae304..237dca8e6 100644 --- a/cmake/FindLua.cmake +++ b/cmake/FindLua.cmake @@ -36,13 +36,15 @@ # This is because, the lua location is not standardized and may exist in # locations other than lua/ +include(FindPkgConfig) + unset(_lua_include_subdirs) unset(_lua_library_names) unset(_lua_append_versions) # this is a function only to have all the variables inside go away automatically function(_lua_set_version_vars) - set(LUA_VERSIONS5 5.3 5.2 5.1 5.0) + set(LUA_VERSIONS5 5.4 5.3 5.2 5.1 5.0) if (Lua_FIND_VERSION_EXACT) if (Lua_FIND_VERSION_COUNT GREATER 1) @@ -81,11 +83,16 @@ function(_lua_set_version_vars) lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2} lua.${CMAKE_MATCH_1}.${CMAKE_MATCH_2} ) + pkg_check_modules(LUA QUIET "lua${ver}") + list(APPEND _lua_include_subdirs ${LUA_INCLUDE_DIRS}) + list(APPEND _lua_library_names ${LUA_LIBRARIES}) + list(APPEND _lua_library_dirs ${LUA_LIBRARY_DIRS}) endforeach () set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE) set(_lua_library_names "${_lua_library_names}" PARENT_SCOPE) set(_lua_append_versions "${_lua_append_versions}" PARENT_SCOPE) + set(_lua_library_dirs "${_lua_library_dirs}" PARENT_SCOPE) endfunction(_lua_set_version_vars) function(_lua_check_header_version _hdr_file) @@ -158,6 +165,7 @@ find_library(LUA_LIBRARY ENV LUA_DIR PATH_SUFFIXES lib PATHS + ${_lua_library_dirs} ~/Library/Frameworks /Library/Frameworks /sw diff --git a/cmake/FindSTXXL.cmake b/cmake/FindSTXXL.cmake deleted file mode 100644 index 473fb6a29..000000000 --- a/cmake/FindSTXXL.cmake +++ /dev/null @@ -1,51 +0,0 @@ -# Locate STXXL library -# This module defines -# STXXL_FOUND, if false, do not try to link to libstxxl -# STXXL_LIBRARY -# STXXL_INCLUDE_DIR, where to find stxxl.h -# - - -IF( NOT STXXL_FIND_QUIETLY ) - MESSAGE(STATUS "Looking for STXXL...") -ENDIF() - -FIND_PATH(STXXL_INCLUDE_DIR stxxl.h - HINTS - $ENV{STXXL_DIR} - PATH_SUFFIXES stxxl include/stxxl/stxxl include/stxxl include - PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /opt/local # DarwinPorts - /opt -) - -FIND_LIBRARY(STXXL_LIBRARY - NAMES stxxl stxxl_debug - HINTS - $ENV{STXXL_DIR} - PATH_SUFFIXES lib64 lib - PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /opt/local - /opt -) - -INCLUDE(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set STXXL_FOUND to TRUE if -# all listed variables are TRUE -FIND_PACKAGE_HANDLE_STANDARD_ARGS(STXXL DEFAULT_MSG STXXL_LIBRARY STXXL_INCLUDE_DIR) - -IF( NOT STXXL_FIND_QUIETLY ) - IF( STXXL_FOUND ) - MESSAGE(STATUS "Found STXXL: ${STXXL_LIBRARY}" ) - ENDIF() -ENDIF() - -MARK_AS_ADVANCED(STXXL_INCLUDE_DIR STXXL_LIBRARY) diff --git a/cmake/FindShapefile.cmake b/cmake/FindShapefile.cmake deleted file mode 100644 index 5b90ec622..000000000 --- a/cmake/FindShapefile.cmake +++ /dev/null @@ -1,21 +0,0 @@ -# - Try to find Shapefile C Library -# http://shapelib.maptools.org/ -# -# Exports: -# Shapefile_FOUND -# LIBSHAPEFILE_INCLUDE_DIR -# LIBSHAPEFILE_LIBRARY -# Hints: -# LIBSHAPEFILE_LIBRARY_DIR - -find_path(LIBSHAPEFILE_INCLUDE_DIR - shapefil.h) - -find_library(LIBSHAPEFILE_LIBRARY - NAMES shp - HINTS "${LIBSHAPEFILE_LIBRARY_DIR}") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Shapefile DEFAULT_MSG - LIBSHAPEFILE_LIBRARY LIBSHAPEFILE_INCLUDE_DIR) -mark_as_advanced(LIBSHAPEFILE_INCLUDE_DIR LIBSHAPEFILE_LIBRARY) diff --git a/cmake/FindTBB.cmake b/cmake/FindTBB.cmake index 09ba16555..ca5a792ae 100644 --- a/cmake/FindTBB.cmake +++ b/cmake/FindTBB.cmake @@ -1,286 +1,456 @@ -# Locate Intel Threading Building Blocks include paths and libraries -# FindTBB.cmake can be found at https://code.google.com/p/findtbb/ -# Written by Hannes Hofmann -# Improvements by Gino van den Bergen , -# Florian Uhlig , -# Jiri Marsik - -# The MIT License +# - Find ThreadingBuildingBlocks include dirs and libraries +# Use this module by invoking find_package with the form: +# find_package(TBB +# [REQUIRED] # Fail with error if TBB is not found +# ) # +# Once done, this will define # -# Copyright (c) 2011 Hannes Hofmann +# TBB_FOUND - system has TBB +# TBB_INCLUDE_DIRS - the TBB include directories +# TBB_LIBRARIES - TBB libraries to be lined, doesn't include malloc or +# malloc proxy +# TBB::tbb - imported target for the TBB library # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: +# TBB_VERSION_MAJOR - Major Product Version Number +# TBB_VERSION_MINOR - Minor Product Version Number +# TBB_INTERFACE_VERSION - Engineering Focused Version Number +# TBB_COMPATIBLE_INTERFACE_VERSION - The oldest major interface version +# still supported. This uses the engineering +# focused interface version numbers. # -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. +# TBB_MALLOC_FOUND - system has TBB malloc library +# TBB_MALLOC_INCLUDE_DIRS - the TBB malloc include directories +# TBB_MALLOC_LIBRARIES - The TBB malloc libraries to be lined +# TBB::malloc - imported target for the TBB malloc library # -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler. -# e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21" -# TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found -# in the TBB installation directory (TBB_INSTALL_DIR). +# TBB_MALLOC_PROXY_FOUND - system has TBB malloc proxy library +# TBB_MALLOC_PROXY_INCLUDE_DIRS = the TBB malloc proxy include directories +# TBB_MALLOC_PROXY_LIBRARIES - The TBB malloc proxy libraries to be lined +# TBB::malloc_proxy - imported target for the TBB malloc proxy library # -# GvdB: Mac OS X distribution places libraries directly in lib directory. # -# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER. -# TBB_ARCHITECTURE [ ia32 | em64t | itanium ] -# which architecture to use -# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9 -# which compiler to use (detected automatically on Windows) - -# This module respects -# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR} - -# This module defines -# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc. -# TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc -# TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug -# TBB_INSTALL_DIR, the base TBB install directory -# TBB_LIBRARIES, the libraries to link against to use TBB. -# TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols. -# TBB_FOUND, If false, don't try to use TBB. -# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h +# This module reads hints about search locations from variables: +# ENV TBB_ARCH_PLATFORM - for eg. set it to "mic" for Xeon Phi builds +# ENV TBB_ROOT or just TBB_ROOT - root directory of tbb installation +# ENV TBB_BUILD_PREFIX - specifies the build prefix for user built tbb +# libraries. Should be specified with ENV TBB_ROOT +# and optionally... +# ENV TBB_BUILD_DIR - if build directory is different than ${TBB_ROOT}/build +# +# +# Modified by Robert Maynard from the original OGRE source +# +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- +# +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# Copyright 2012 Rolf Eike Beer +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) -if (WIN32) - # has em64t/vc8 em64t/vc9 - # has ia32/vc7.1 ia32/vc8 ia32/vc9 - set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB") - set(_TBB_LIB_NAME "tbb") - set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") - set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") - set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") - if (MSVC71) - set (_TBB_COMPILER "vc7.1") - endif(MSVC71) - if (MSVC80) - set(_TBB_COMPILER "vc8") - endif(MSVC80) - if (MSVC90) - set(_TBB_COMPILER "vc9") - endif(MSVC90) - if(MSVC10) - set(_TBB_COMPILER "vc10") - endif(MSVC10) - # Todo: add other Windows compilers such as ICL. - set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) -endif (WIN32) +#============================================================================= +# FindTBB helper functions and macros +# -if (UNIX) - if (APPLE) - # MAC - set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions") - # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug - set(_TBB_LIB_NAME "tbb") - set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") - set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") - set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") - # default flavor on apple: ia32/cc4.0.1_os10.4.9 - # Jiri: There is no reason to presume there is only one flavor and - # that user's setting of variables should be ignored. - if(NOT TBB_COMPILER) - set(_TBB_COMPILER "cc4.0.1_os10.4.9") - elseif (NOT TBB_COMPILER) - set(_TBB_COMPILER ${TBB_COMPILER}) - endif(NOT TBB_COMPILER) - if(NOT TBB_ARCHITECTURE) - set(_TBB_ARCHITECTURE "ia32") - elseif(NOT TBB_ARCHITECTURE) - set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) - endif(NOT TBB_ARCHITECTURE) - else (APPLE) - # LINUX - set(_TBB_DEFAULT_INSTALL_DIR "/usr") - set(_TBB_LIB_NAME "tbb") - set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") - set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") - set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") - # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21 - # has ia32/* - # has itanium/* - set(_TBB_COMPILER ${TBB_COMPILER}) - set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) - endif (APPLE) -endif (UNIX) - -if (CMAKE_SYSTEM MATCHES "SunOS.*") -# SUN -# not yet supported -# has em64t/cc3.4.3_kernel5.10 -# has ia32/* -endif (CMAKE_SYSTEM MATCHES "SunOS.*") - - -#-- Clear the public variables -set (TBB_FOUND "NO") - - -#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR} -# first: use CMake variable TBB_INSTALL_DIR -if (TBB_INSTALL_DIR) - set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR}) -endif (TBB_INSTALL_DIR) -# second: use environment variable -if (NOT _TBB_INSTALL_DIR) - if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") - set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR}) - endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") - # Intel recommends setting TBB21_INSTALL_DIR - if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") - set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR}) - endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") - if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") - set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR}) - endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") - if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") - set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR}) - endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") -endif (NOT _TBB_INSTALL_DIR) -# third: try to find path automatically -if (NOT _TBB_INSTALL_DIR) - if (_TBB_DEFAULT_INSTALL_DIR) - set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR}) - endif (_TBB_DEFAULT_INSTALL_DIR) -endif (NOT _TBB_INSTALL_DIR) -# sanity check -if (NOT _TBB_INSTALL_DIR) - message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}") -else (NOT _TBB_INSTALL_DIR) -# finally: set the cached CMake variable TBB_INSTALL_DIR -if (NOT TBB_INSTALL_DIR) - set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory") - mark_as_advanced(TBB_INSTALL_DIR) -endif (NOT TBB_INSTALL_DIR) - - -#-- A macro to rewrite the paths of the library. This is necessary, because -# find_library() always found the em64t/vc9 version of the TBB libs -macro(TBB_CORRECT_LIB_DIR var_name) -# if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") - string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) -# endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") - string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) - string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) - string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) - string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) - string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) -endmacro(TBB_CORRECT_LIB_DIR var_content) - - -#-- Look for include directory and set ${TBB_INCLUDE_DIR} -set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include) -# Jiri: tbbvars now sets the CPATH environment variable to the directory -# containing the headers. -find_path(TBB_INCLUDE_DIR - tbb/task_scheduler_init.h - HINTS ${TBB_INC_SEARCH_DIR} ENV CPATH -) -mark_as_advanced(TBB_INCLUDE_DIR) - -#-- Look for libraries -# GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh] -if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") - set (_TBB_LIBRARY_DIR - ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM} - ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib - ) -endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") -# Jiri: This block isn't mutually exclusive with the previous one -# (hence no else), instead I test if the user really specified -# the variables in question. -if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) - # HH: deprecated - message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).") - # Jiri: It doesn't hurt to look in more places, so I store the hints from - # ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER - # variables and search them both. - set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR}) -endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) - -# GvdB: Mac OS X distribution places libraries directly in lib directory. -list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib) - -if(EXISTS ${_TBB_INSTALL_DIR}/build) - file(GLOB _TBB_BUILD_DIR_RELEASE ${_TBB_INSTALL_DIR}/build/*_release) - file(GLOB _TBB_BUILD_DIR_DEBUG ${_TBB_INSTALL_DIR}/build/*_debug) -endif() - -# Jiri: No reason not to check the default paths. From recent versions, -# tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH -# variables, which now point to the directories of the lib files. -# It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS -# argument instead of the implicit PATHS as it isn't hard-coded -# but computed by system introspection. Searching the LIBRARY_PATH -# and LD_LIBRARY_PATH environment variables is now even more important -# that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates -# the use of TBB built from sources. -find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_BUILD_DIR_RELEASE} ${_TBB_LIBRARY_DIR}) -find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_BUILD_DIR_RELEASE} ${_TBB_LIBRARY_DIR}) - -#Extract path from TBB_LIBRARY name -get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH) - -#TBB_CORRECT_LIB_DIR(TBB_LIBRARY) -#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY) -mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY) - -#-- Look for debug libraries -# Jiri: Changed the same way as for the release libraries. -find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_BUILD_DIR_DEBUG} ${_TBB_LIBRARY_DIR} - PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) -find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_BUILD_DIR_DEBUG} ${_TBB_LIBRARY_DIR} - PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) - -# Jiri: Self-built TBB stores the debug libraries in a separate directory. -# Extract path from TBB_LIBRARY_DEBUG name -get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH) - -#TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG) -#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG) -mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG) - - -if (TBB_INCLUDE_DIR) - if (TBB_LIBRARY) - set (TBB_FOUND "YES") - set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES}) - set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES}) - set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE) - set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE) - # Jiri: Self-built TBB stores the debug libraries in a separate directory. - set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE) - mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES) - message(STATUS "Found Intel TBB") - endif (TBB_LIBRARY) -endif (TBB_INCLUDE_DIR) - -if (NOT TBB_FOUND) - message("ERROR: Intel TBB NOT found!") - message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}") - # do only throw fatal, if this pkg is REQUIRED - if (TBB_FIND_REQUIRED) - message(FATAL_ERROR "Could NOT find TBB library.") - endif (TBB_FIND_REQUIRED) -endif (NOT TBB_FOUND) - -endif (NOT _TBB_INSTALL_DIR) +# Use TBBConfig.cmake if possible. +set(_tbb_find_quiet) +if (TBB_FIND_QUIETLY) + set(_tbb_find_quiet QUIET) +endif () +set(_tbb_find_components) +set(_tbb_find_optional_components) +foreach (_tbb_find_component IN LISTS TBB_FIND_COMPONENTS) + if (TBB_FIND_REQUIRED_${_tbb_find_component}) + list(APPEND _tbb_find_components "${_tbb_find_component}") + else () + list(APPEND _tbb_find_optional_components "${_tbb_find_component}") + endif () +endforeach () +unset(_tbb_find_component) +find_package(TBB CONFIG ${_tbb_find_quiet} + COMPONENTS ${_tbb_find_components} + OPTIONAL_COMPONENTS ${_tbb_find_optional_components}) +unset(_tbb_find_quiet) +unset(_tbb_find_components) +unset(_tbb_find_optional_components) if (TBB_FOUND) - set(TBB_INTERFACE_VERSION 0) - FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS) - STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}") - set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}") - message(STATUS "TBB interface version: ${TBB_INTERFACE_VERSION}") -endif (TBB_FOUND) + return () +endif () + +#==================================================== +# Fix the library path in case it is a linker script +#==================================================== +function(tbb_extract_real_library library real_library) + if(NOT UNIX OR NOT EXISTS ${library}) + set(${real_library} "${library}" PARENT_SCOPE) + return() + endif() + + #Read in the first 4 bytes and see if they are the ELF magic number + set(_elf_magic "7f454c46") + file(READ ${library} _hex_data OFFSET 0 LIMIT 4 HEX) + if(_hex_data STREQUAL _elf_magic) + #we have opened a elf binary so this is what + #we should link to + set(${real_library} "${library}" PARENT_SCOPE) + return() + endif() + + file(READ ${library} _data OFFSET 0 LIMIT 1024) + if("${_data}" MATCHES "INPUT \\(([^(]+)\\)") + #extract out the .so name from REGEX MATCH command + set(_proper_so_name "${CMAKE_MATCH_1}") + + #construct path to the real .so which is presumed to be in the same directory + #as the input file + get_filename_component(_so_dir "${library}" DIRECTORY) + set(${real_library} "${_so_dir}/${_proper_so_name}" PARENT_SCOPE) + else() + #unable to determine what this library is so just hope everything works + #and pass it unmodified. + set(${real_library} "${library}" PARENT_SCOPE) + endif() +endfunction() + +#=============================================== +# Do the final processing for the package find. +#=============================================== +macro(findpkg_finish PREFIX TARGET_NAME) + if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) + set(${PREFIX}_FOUND TRUE) + set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) + set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) + else () + if (${PREFIX}_FIND_REQUIRED AND NOT ${PREFIX}_FIND_QUIETLY) + message(FATAL_ERROR "Required library ${PREFIX} not found.") + endif () + endif () + + if (NOT TARGET "TBB::${TARGET_NAME}") + if (${PREFIX}_LIBRARY_RELEASE) + tbb_extract_real_library(${${PREFIX}_LIBRARY_RELEASE} real_release) + endif () + if (${PREFIX}_LIBRARY_DEBUG) + tbb_extract_real_library(${${PREFIX}_LIBRARY_DEBUG} real_debug) + endif () + add_library(TBB::${TARGET_NAME} UNKNOWN IMPORTED) + set_target_properties(TBB::${TARGET_NAME} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${${PREFIX}_INCLUDE_DIR}") + if (${PREFIX}_LIBRARY_DEBUG AND ${PREFIX}_LIBRARY_RELEASE) + set_target_properties(TBB::${TARGET_NAME} PROPERTIES + IMPORTED_LOCATION "${real_release}" + IMPORTED_LOCATION_DEBUG "${real_debug}" + IMPORTED_LOCATION_RELEASE "${real_release}") + elseif (${PREFIX}_LIBRARY_RELEASE) + set_target_properties(TBB::${TARGET_NAME} PROPERTIES + IMPORTED_LOCATION "${real_release}") + elseif (${PREFIX}_LIBRARY_DEBUG) + set_target_properties(TBB::${TARGET_NAME} PROPERTIES + IMPORTED_LOCATION "${real_debug}") + endif () + endif () + + #mark the following variables as internal variables + mark_as_advanced(${PREFIX}_INCLUDE_DIR + ${PREFIX}_LIBRARY + ${PREFIX}_LIBRARY_DEBUG + ${PREFIX}_LIBRARY_RELEASE) +endmacro() + +#=============================================== +# Generate debug names from given release names +#=============================================== +macro(get_debug_names PREFIX) + foreach(i ${${PREFIX}}) + set(${PREFIX}_DEBUG ${${PREFIX}_DEBUG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i}) + endforeach() +endmacro() + +#=============================================== +# See if we have env vars to help us find tbb +#=============================================== +macro(getenv_path VAR) + set(ENV_${VAR} $ENV{${VAR}}) + # replace won't work if var is blank + if (ENV_${VAR}) + string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} ) + endif () +endmacro() + +#=============================================== +# Couple a set of release AND debug libraries +#=============================================== +macro(make_library_set PREFIX) + if (${PREFIX}_RELEASE AND ${PREFIX}_DEBUG) + set(${PREFIX} optimized ${${PREFIX}_RELEASE} debug ${${PREFIX}_DEBUG}) + elseif (${PREFIX}_RELEASE) + set(${PREFIX} ${${PREFIX}_RELEASE}) + elseif (${PREFIX}_DEBUG) + set(${PREFIX} ${${PREFIX}_DEBUG}) + endif () +endmacro() + + +#============================================================================= +# Now to actually find TBB +# + +# Get path, convert backslashes as ${ENV_${var}} +getenv_path(TBB_ROOT) + +# initialize search paths +set(TBB_PREFIX_PATH ${TBB_ROOT} ${ENV_TBB_ROOT}) +set(TBB_INC_SEARCH_PATH "") +set(TBB_LIB_SEARCH_PATH "") + + +# If user built from sources +set(TBB_BUILD_PREFIX $ENV{TBB_BUILD_PREFIX}) +if (TBB_BUILD_PREFIX AND ENV_TBB_ROOT) + getenv_path(TBB_BUILD_DIR) + if (NOT ENV_TBB_BUILD_DIR) + set(ENV_TBB_BUILD_DIR ${ENV_TBB_ROOT}/build) + endif () + + # include directory under ${ENV_TBB_ROOT}/include + list(APPEND TBB_LIB_SEARCH_PATH + ${ENV_TBB_BUILD_DIR}/${TBB_BUILD_PREFIX}_release + ${ENV_TBB_BUILD_DIR}/${TBB_BUILD_PREFIX}_debug) +endif () + + +# For Windows, let's assume that the user might be using the precompiled +# TBB packages from the main website. These use a rather awkward directory +# structure (at least for automatically finding the right files) depending +# on platform and compiler, but we'll do our best to accommodate it. +# Not adding the same effort for the precompiled linux builds, though. Those +# have different versions for CC compiler versions and linux kernels which +# will never adequately match the user's setup, so there is no feasible way +# to detect the "best" version to use. The user will have to manually +# select the right files. (Chances are the distributions are shipping their +# custom version of tbb, anyway, so the problem is probably nonexistent.) +if (WIN32 AND MSVC) + set(COMPILER_PREFIX "vc7.1") + if (MSVC_VERSION EQUAL 1400) + set(COMPILER_PREFIX "vc8") + elseif(MSVC_VERSION EQUAL 1500) + set(COMPILER_PREFIX "vc9") + elseif(MSVC_VERSION EQUAL 1600) + set(COMPILER_PREFIX "vc10") + elseif(MSVC_VERSION EQUAL 1700) + set(COMPILER_PREFIX "vc11") + elseif(MSVC_VERSION EQUAL 1800) + set(COMPILER_PREFIX "vc12") + elseif(MSVC_VERSION GREATER_EQUAL 1900) + set(COMPILER_PREFIX "vc14") + endif () + + # for each prefix path, add ia32/64\${COMPILER_PREFIX}\lib to the lib search path + foreach (dir IN LISTS TBB_PREFIX_PATH) + if (CMAKE_CL_64) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia64/${COMPILER_PREFIX}/lib) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia64/${COMPILER_PREFIX}) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${COMPILER_PREFIX}/lib) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64/${COMPILER_PREFIX}) + else () + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${COMPILER_PREFIX}/lib) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32/${COMPILER_PREFIX}) + endif () + endforeach () +endif () + +# For OS X binary distribution, choose libc++ based libraries for Mavericks (10.9) +# and above and AppleClang +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND + NOT CMAKE_SYSTEM_VERSION VERSION_LESS 13.0) + set (USE_LIBCXX OFF) + cmake_policy(GET CMP0025 POLICY_VAR) + + if (POLICY_VAR STREQUAL "NEW") + if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + set (USE_LIBCXX ON) + endif () + else () + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set (USE_LIBCXX ON) + endif () + endif () + + if (USE_LIBCXX) + foreach (dir IN LISTS TBB_PREFIX_PATH) + list (APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/libc++ ${dir}/libc++/lib) + endforeach () + endif () +endif () + +# check compiler ABI +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(COMPILER_PREFIX) + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) + list(APPEND COMPILER_PREFIX "gcc4.8") + endif() + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) + list(APPEND COMPILER_PREFIX "gcc4.7") + endif() + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4) + list(APPEND COMPILER_PREFIX "gcc4.4") + endif() + list(APPEND COMPILER_PREFIX "gcc4.1") +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(COMPILER_PREFIX) + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0) # Complete guess + list(APPEND COMPILER_PREFIX "gcc4.8") + endif() + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.6) + list(APPEND COMPILER_PREFIX "gcc4.7") + endif() + list(APPEND COMPILER_PREFIX "gcc4.4") +else() # Assume compatibility with 4.4 for other compilers + list(APPEND COMPILER_PREFIX "gcc4.4") +endif () + +# if platform architecture is explicitly specified +set(TBB_ARCH_PLATFORM $ENV{TBB_ARCH_PLATFORM}) +if (TBB_ARCH_PLATFORM) + foreach (dir IN LISTS TBB_PREFIX_PATH) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/${TBB_ARCH_PLATFORM}/lib) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/${TBB_ARCH_PLATFORM}) + endforeach () +endif () + +foreach (dir IN LISTS TBB_PREFIX_PATH) + foreach (prefix IN LISTS COMPILER_PREFIX) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64/${prefix}) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/lib) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${prefix}/lib) + else () + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32/${prefix}) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/lib) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${prefix}/lib) + endif () + endforeach() +endforeach () + +# add general search paths +foreach (dir IN LISTS TBB_PREFIX_PATH) + list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib ${dir}/Lib ${dir}/lib/tbb + ${dir}/Libs) + list(APPEND TBB_INC_SEARCH_PATH ${dir}/include ${dir}/Include + ${dir}/include/tbb) +endforeach () + +set(TBB_LIBRARY_NAMES tbb) +get_debug_names(TBB_LIBRARY_NAMES) + + +find_path(TBB_INCLUDE_DIR + NAMES tbb/tbb.h + PATHS ${TBB_INC_SEARCH_PATH}) + +find_library(TBB_LIBRARY_RELEASE + NAMES ${TBB_LIBRARY_NAMES} + PATHS ${TBB_LIB_SEARCH_PATH}) +find_library(TBB_LIBRARY_DEBUG + NAMES ${TBB_LIBRARY_NAMES_DEBUG} + PATHS ${TBB_LIB_SEARCH_PATH}) +make_library_set(TBB_LIBRARY) + +findpkg_finish(TBB tbb) + +#if we haven't found TBB no point on going any further +if (NOT TBB_FOUND) + return() +endif () + +#============================================================================= +# Look for TBB's malloc package +set(TBB_MALLOC_LIBRARY_NAMES tbbmalloc) +get_debug_names(TBB_MALLOC_LIBRARY_NAMES) + +find_path(TBB_MALLOC_INCLUDE_DIR + NAMES tbb/tbb.h + PATHS ${TBB_INC_SEARCH_PATH}) + +find_library(TBB_MALLOC_LIBRARY_RELEASE + NAMES ${TBB_MALLOC_LIBRARY_NAMES} + PATHS ${TBB_LIB_SEARCH_PATH}) +find_library(TBB_MALLOC_LIBRARY_DEBUG + NAMES ${TBB_MALLOC_LIBRARY_NAMES_DEBUG} + PATHS ${TBB_LIB_SEARCH_PATH}) +make_library_set(TBB_MALLOC_LIBRARY) + +findpkg_finish(TBB_MALLOC tbbmalloc) + +#============================================================================= +# Look for TBB's malloc proxy package +set(TBB_MALLOC_PROXY_LIBRARY_NAMES tbbmalloc_proxy) +get_debug_names(TBB_MALLOC_PROXY_LIBRARY_NAMES) + +find_path(TBB_MALLOC_PROXY_INCLUDE_DIR + NAMES tbb/tbbmalloc_proxy.h + PATHS ${TBB_INC_SEARCH_PATH}) + +find_library(TBB_MALLOC_PROXY_LIBRARY_RELEASE + NAMES ${TBB_MALLOC_PROXY_LIBRARY_NAMES} + PATHS ${TBB_LIB_SEARCH_PATH}) +find_library(TBB_MALLOC_PROXY_LIBRARY_DEBUG + NAMES ${TBB_MALLOC_PROXY_LIBRARY_NAMES_DEBUG} + PATHS ${TBB_LIB_SEARCH_PATH}) +make_library_set(TBB_MALLOC_PROXY_LIBRARY) + +findpkg_finish(TBB_MALLOC_PROXY tbbmalloc_proxy) + + +#============================================================================= +#parse all the version numbers from tbb +if(NOT TBB_VERSION) + if (EXISTS "${TBB_INCLUDE_DIR}/oneapi/tbb/version.h") + file(STRINGS + "${TBB_INCLUDE_DIR}/oneapi/tbb/version.h" + TBB_VERSION_CONTENTS + REGEX "VERSION") + else() + #only read the start of the file + file(STRINGS + "${TBB_INCLUDE_DIR}/tbb/tbb_stddef.h" + TBB_VERSION_CONTENTS + REGEX "VERSION") + endif() + + string(REGEX REPLACE + ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" + TBB_VERSION_MAJOR "${TBB_VERSION_CONTENTS}") + + string(REGEX REPLACE + ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" + TBB_VERSION_MINOR "${TBB_VERSION_CONTENTS}") + + string(REGEX REPLACE + ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" + TBB_INTERFACE_VERSION "${TBB_VERSION_CONTENTS}") + + string(REGEX REPLACE + ".*#define TBB_COMPATIBLE_INTERFACE_VERSION ([0-9]+).*" "\\1" + TBB_COMPATIBLE_INTERFACE_VERSION "${TBB_VERSION_CONTENTS}") + +endif() \ No newline at end of file diff --git a/cmake/JSONParser.cmake b/cmake/JSONParser.cmake new file mode 100644 index 000000000..e1be64e0d --- /dev/null +++ b/cmake/JSONParser.cmake @@ -0,0 +1,290 @@ +# https://github.com/sbellus/json-cmake/blob/9913da8800b95322d393894d3525d634568f305e/JSONParser.cmake +# MIT Licensed - https://github.com/sbellus/json-cmake/blob/master/LICENSE + +cmake_minimum_required(VERSION 3.1) + +if (DEFINED JSonParserGuard) + return() +endif() + +set(JSonParserGuard yes) + +macro(sbeParseJson prefix jsonString) + cmake_policy(PUSH) + + set(json_string "${${jsonString}}") + string(LENGTH "${json_string}" json_jsonLen) + set(json_index 0) + set(json_AllVariables ${prefix}) + set(json_ArrayNestingLevel 0) + set(json_MaxArrayNestingLevel 0) + + _sbeParse(${prefix}) + + unset(json_index) + unset(json_AllVariables) + unset(json_jsonLen) + unset(json_string) + unset(json_value) + unset(json_inValue) + unset(json_name) + unset(json_inName) + unset(json_newPrefix) + unset(json_reservedWord) + unset(json_arrayIndex) + unset(json_char) + unset(json_end) + unset(json_ArrayNestingLevel) + foreach(json_nestingLevel RANGE ${json_MaxArrayNestingLevel}) + unset(json_${json_nestingLevel}_arrayIndex) + endforeach() + unset(json_nestingLevel) + unset(json_MaxArrayNestingLevel) + + cmake_policy(POP) +endmacro() + +macro(sbeClearJson prefix) + foreach(json_var ${${prefix}}) + unset(${json_var}) + endforeach() + + unset(${prefix}) + unset(json_var) +endmacro() + +macro(sbePrintJson prefix) + foreach(json_var ${${prefix}}) + message("${json_var} = ${${json_var}}") + endforeach() +endmacro() + +macro(_sbeParse prefix) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + _sbeParseNameValue(${prefix}) + elseif("{" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseObject(${prefix}) + elseif("[" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseArray(${prefix}) + endif() + + if(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + else() + break() + endif() + + if ("}" STREQUAL "${json_char}" OR "]" STREQUAL "${json_char}") + break() + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() +endmacro() + +macro(_sbeParseNameValue prefix) + set(json_name "") + set(json_inName no) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + # check if name ends + if("\"" STREQUAL "${json_char}" AND json_inName) + set(json_inName no) + _sbeMoveToNextNonEmptyCharacter() + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + set(json_newPrefix ${prefix}.${json_name}) + set(json_name "") + + if(":" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + _sbeParseValue(${json_newPrefix}) + break() + elseif("{" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseObject(${json_newPrefix}) + break() + elseif("[" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseArray(${json_newPrefix}) + break() + else() + # reserved word starts + _sbeParseReservedWord(${json_newPrefix}) + break() + endif() + else() + # name without value + list(APPEND ${json_AllVariables} ${json_newPrefix}) + set(${json_newPrefix} "") + break() + endif() + endif() + + if(json_inName) + # remove escapes + if("\\" STREQUAL "${json_char}") + math(EXPR json_index "${json_index} + 1") + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + endif() + + set(json_name "${json_name}${json_char}") + endif() + + # check if name starts + if("\"" STREQUAL "${json_char}" AND NOT json_inName) + set(json_inName yes) + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() +endmacro() + +macro(_sbeParseReservedWord prefix) + set(json_reservedWord "") + set(json_end no) + while(${json_index} LESS ${json_jsonLen} AND NOT json_end) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("," STREQUAL "${json_char}" OR "}" STREQUAL "${json_char}" OR "]" STREQUAL "${json_char}") + set(json_end yes) + else() + set(json_reservedWord "${json_reservedWord}${json_char}") + math(EXPR json_index "${json_index} + 1") + endif() + endwhile() + + list(APPEND ${json_AllVariables} ${prefix}) + string(STRIP "${json_reservedWord}" json_reservedWord) + set(${prefix} ${json_reservedWord}) +endmacro() + +macro(_sbeParseValue prefix) + cmake_policy(SET CMP0054 NEW) # turn off implicit expansions in if statement + + set(json_value "") + set(json_inValue no) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + # check if json_value ends, it is ended by " + if("\"" STREQUAL "${json_char}" AND json_inValue) + set(json_inValue no) + + set(${prefix} ${json_value}) + list(APPEND ${json_AllVariables} ${prefix}) + _sbeMoveToNextNonEmptyCharacter() + break() + endif() + + if(json_inValue) + # if " is escaped consume + if("\\" STREQUAL "${json_char}") + math(EXPR json_index "${json_index} + 1") + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + if(NOT "\"" STREQUAL "${json_char}") + # if it is not " then copy also escape character + set(json_char "\\${json_char}") + endif() + endif() + + _sbeAddEscapedCharacter("${json_char}") + endif() + + # check if value starts + if("\"" STREQUAL "${json_char}" AND NOT json_inValue) + set(json_inValue yes) + endif() + + math(EXPR json_index "${json_index} + 1") + endwhile() +endmacro() + +macro(_sbeAddEscapedCharacter char) + string(CONCAT json_value "${json_value}" "${char}") +endmacro() + +macro(_sbeParseObject prefix) + _sbeParse(${prefix}) + _sbeMoveToNextNonEmptyCharacter() +endmacro() + +macro(_sbeParseArray prefix) + math(EXPR json_ArrayNestingLevel "${json_ArrayNestingLevel} + 1") + set(json_${json_ArrayNestingLevel}_arrayIndex 0) + + set(${prefix} "") + list(APPEND ${json_AllVariables} ${prefix}) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + # simple value + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseValue(${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + elseif("{" STREQUAL "${json_char}") + # object + _sbeMoveToNextNonEmptyCharacter() + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseObject(${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + else() + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseReservedWord(${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + endif() + + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("]" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + break() + elseif("," STREQUAL "${json_char}") + math(EXPR json_${json_ArrayNestingLevel}_arrayIndex "${json_${json_ArrayNestingLevel}_arrayIndex} + 1") + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() + + if(${json_MaxArrayNestingLevel} LESS ${json_ArrayNestingLevel}) + set(json_MaxArrayNestingLevel ${json_ArrayNestingLevel}) + endif() + math(EXPR json_ArrayNestingLevel "${json_ArrayNestingLevel} - 1") +endmacro() + +macro(_sbeMoveToNextNonEmptyCharacter) + math(EXPR json_index "${json_index} + 1") + if(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + while(${json_char} MATCHES "[ \t\n\r]" AND ${json_index} LESS ${json_jsonLen}) + math(EXPR json_index "${json_index} + 1") + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + endwhile() + endif() +endmacro() diff --git a/cmake/conan.cmake b/cmake/conan.cmake new file mode 100644 index 000000000..4f5f67e74 --- /dev/null +++ b/cmake/conan.cmake @@ -0,0 +1,1026 @@ +# The MIT License (MIT) + +# Copyright (c) 2018 JFrog + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + + +# This file comes from: https://github.com/conan-io/cmake-conan. Please refer +# to this repository for issues and documentation. + +# Its purpose is to wrap and launch Conan C/C++ Package Manager when cmake is called. +# It will take CMake current settings (os, compiler, compiler version, architecture) +# and translate them to conan settings for installing and retrieving dependencies. + +# It is intended to facilitate developers building projects that have conan dependencies, +# but it is only necessary on the end-user side. It is not necessary to create conan +# packages, in fact it shouldn't be use for that. Check the project documentation. + +# version: 0.18.1 + +include(CMakeParseArguments) + +function(_get_msvc_ide_version result) + set(${result} "" PARENT_SCOPE) + if(NOT MSVC_VERSION VERSION_LESS 1400 AND MSVC_VERSION VERSION_LESS 1500) + set(${result} 8 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1500 AND MSVC_VERSION VERSION_LESS 1600) + set(${result} 9 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1600 AND MSVC_VERSION VERSION_LESS 1700) + set(${result} 10 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1700 AND MSVC_VERSION VERSION_LESS 1800) + set(${result} 11 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1800 AND MSVC_VERSION VERSION_LESS 1900) + set(${result} 12 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1900 AND MSVC_VERSION VERSION_LESS 1910) + set(${result} 14 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1910 AND MSVC_VERSION VERSION_LESS 1920) + set(${result} 15 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1920 AND MSVC_VERSION VERSION_LESS 1930) + set(${result} 16 PARENT_SCOPE) + elseif(NOT MSVC_VERSION VERSION_LESS 1930 AND MSVC_VERSION VERSION_LESS 1940) + set(${result} 17 PARENT_SCOPE) + else() + message(FATAL_ERROR "Conan: Unknown MSVC compiler version [${MSVC_VERSION}]") + endif() +endfunction() + +macro(_conan_detect_build_type) + conan_parse_arguments(${ARGV}) + + if(ARGUMENTS_BUILD_TYPE) + set(_CONAN_SETTING_BUILD_TYPE ${ARGUMENTS_BUILD_TYPE}) + elseif(CMAKE_BUILD_TYPE) + set(_CONAN_SETTING_BUILD_TYPE ${CMAKE_BUILD_TYPE}) + else() + message(FATAL_ERROR "Please specify in command line CMAKE_BUILD_TYPE (-DCMAKE_BUILD_TYPE=Release)") + endif() + + string(TOUPPER ${_CONAN_SETTING_BUILD_TYPE} _CONAN_SETTING_BUILD_TYPE_UPPER) + if (_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "DEBUG") + set(_CONAN_SETTING_BUILD_TYPE "Debug") + elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "RELEASE") + set(_CONAN_SETTING_BUILD_TYPE "Release") + elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "RELWITHDEBINFO") + set(_CONAN_SETTING_BUILD_TYPE "RelWithDebInfo") + elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "MINSIZEREL") + set(_CONAN_SETTING_BUILD_TYPE "MinSizeRel") + endif() +endmacro() + +macro(_conan_check_system_name) + #handle -s os setting + if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic") + #use default conan os setting if CMAKE_SYSTEM_NAME is not defined + set(CONAN_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}) + if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(CONAN_SYSTEM_NAME Macos) + endif() + if(${CMAKE_SYSTEM_NAME} STREQUAL "QNX") + set(CONAN_SYSTEM_NAME Neutrino) + endif() + set(CONAN_SUPPORTED_PLATFORMS Windows Linux Macos Android iOS FreeBSD WindowsStore WindowsCE watchOS tvOS FreeBSD SunOS AIX Arduino Emscripten Neutrino) + list (FIND CONAN_SUPPORTED_PLATFORMS "${CONAN_SYSTEM_NAME}" _index) + if (${_index} GREATER -1) + #check if the cmake system is a conan supported one + set(_CONAN_SETTING_OS ${CONAN_SYSTEM_NAME}) + else() + message(FATAL_ERROR "cmake system ${CONAN_SYSTEM_NAME} is not supported by conan. Use one of ${CONAN_SUPPORTED_PLATFORMS}") + endif() + endif() +endmacro() + +macro(_conan_check_language) + get_property(_languages GLOBAL PROPERTY ENABLED_LANGUAGES) + if (";${_languages};" MATCHES ";CXX;") + set(LANGUAGE CXX) + set(USING_CXX 1) + elseif (";${_languages};" MATCHES ";C;") + set(LANGUAGE C) + set(USING_CXX 0) + else () + message(FATAL_ERROR "Conan: Neither C or C++ was detected as a language for the project. Unabled to detect compiler version.") + endif() +endmacro() + +macro(_conan_detect_compiler) + + conan_parse_arguments(${ARGV}) + + if(ARGUMENTS_ARCH) + set(_CONAN_SETTING_ARCH ${ARGUMENTS_ARCH}) + endif() + + if(USING_CXX) + set(_CONAN_SETTING_COMPILER_CPPSTD ${CMAKE_CXX_STANDARD}) + endif() + + if (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL GNU) + # using GCC + # TODO: Handle other params + string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) + list(GET VERSION_LIST 0 MAJOR) + list(GET VERSION_LIST 1 MINOR) + set(COMPILER_VERSION ${MAJOR}.${MINOR}) + if(${MAJOR} GREATER 4) + set(COMPILER_VERSION ${MAJOR}) + endif() + set(_CONAN_SETTING_COMPILER gcc) + set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) + if (USING_CXX) + conan_cmake_detect_unix_libcxx(_LIBCXX) + set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) + endif () + elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Intel) + string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) + list(GET VERSION_LIST 0 MAJOR) + list(GET VERSION_LIST 1 MINOR) + set(COMPILER_VERSION ${MAJOR}.${MINOR}) + set(_CONAN_SETTING_COMPILER intel) + set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) + if (USING_CXX) + conan_cmake_detect_unix_libcxx(_LIBCXX) + set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) + endif () + elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL AppleClang) + # using AppleClang + string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) + list(GET VERSION_LIST 0 MAJOR) + list(GET VERSION_LIST 1 MINOR) + set(_CONAN_SETTING_COMPILER apple-clang) + set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR}) + if (USING_CXX) + conan_cmake_detect_unix_libcxx(_LIBCXX) + set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) + endif () + elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Clang + AND NOT "${CMAKE_${LANGUAGE}_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC" + AND NOT "${CMAKE_${LANGUAGE}_SIMULATE_ID}" STREQUAL "MSVC") + + string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) + list(GET VERSION_LIST 0 MAJOR) + list(GET VERSION_LIST 1 MINOR) + set(_CONAN_SETTING_COMPILER clang) + set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR}) + if(APPLE) + cmake_policy(GET CMP0025 APPLE_CLANG_POLICY) + if(NOT APPLE_CLANG_POLICY STREQUAL NEW) + message(STATUS "Conan: APPLE and Clang detected. Assuming apple-clang compiler. Set CMP0025 to avoid it") + set(_CONAN_SETTING_COMPILER apple-clang) + endif() + endif() + if(${_CONAN_SETTING_COMPILER} STREQUAL clang AND ${MAJOR} GREATER 7) + set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}) + endif() + if (USING_CXX) + conan_cmake_detect_unix_libcxx(_LIBCXX) + set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) + endif () + elseif(${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL MSVC + OR (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Clang + AND "${CMAKE_${LANGUAGE}_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC" + AND "${CMAKE_${LANGUAGE}_SIMULATE_ID}" STREQUAL "MSVC")) + + set(_VISUAL "Visual Studio") + _get_msvc_ide_version(_VISUAL_VERSION) + if("${_VISUAL_VERSION}" STREQUAL "") + message(FATAL_ERROR "Conan: Visual Studio not recognized") + else() + set(_CONAN_SETTING_COMPILER ${_VISUAL}) + set(_CONAN_SETTING_COMPILER_VERSION ${_VISUAL_VERSION}) + endif() + + if(NOT _CONAN_SETTING_ARCH) + if (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "64") + set(_CONAN_SETTING_ARCH x86_64) + elseif (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "^ARM") + message(STATUS "Conan: Using default ARM architecture from MSVC") + set(_CONAN_SETTING_ARCH armv6) + elseif (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "86") + set(_CONAN_SETTING_ARCH x86) + else () + message(FATAL_ERROR "Conan: Unknown MSVC architecture [${MSVC_${LANGUAGE}_ARCHITECTURE_ID}]") + endif() + endif() + + conan_cmake_detect_vs_runtime(_vs_runtime ${ARGV}) + message(STATUS "Conan: Detected VS runtime: ${_vs_runtime}") + set(_CONAN_SETTING_COMPILER_RUNTIME ${_vs_runtime}) + + if (CMAKE_GENERATOR_TOOLSET) + set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET}) + elseif(CMAKE_VS_PLATFORM_TOOLSET AND (CMAKE_GENERATOR STREQUAL "Ninja")) + set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET}) + endif() + else() + message(FATAL_ERROR "Conan: compiler setup not recognized") + endif() + +endmacro() + +function(conan_cmake_settings result) + #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER}) + #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER_ID}) + #message(STATUS "VERSION " ${CMAKE_CXX_COMPILER_VERSION}) + #message(STATUS "FLAGS " ${CMAKE_LANG_FLAGS}) + #message(STATUS "LIB ARCH " ${CMAKE_CXX_LIBRARY_ARCHITECTURE}) + #message(STATUS "BUILD TYPE " ${CMAKE_BUILD_TYPE}) + #message(STATUS "GENERATOR " ${CMAKE_GENERATOR}) + #message(STATUS "GENERATOR WIN64 " ${CMAKE_CL_64}) + + message(STATUS "Conan: Automatic detection of conan settings from cmake") + + conan_parse_arguments(${ARGV}) + + _conan_detect_build_type(${ARGV}) + + _conan_check_system_name() + + _conan_check_language() + + _conan_detect_compiler(${ARGV}) + + # If profile is defined it is used + if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND ARGUMENTS_DEBUG_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_DEBUG_PROFILE}) + elseif(CMAKE_BUILD_TYPE STREQUAL "Release" AND ARGUMENTS_RELEASE_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_RELEASE_PROFILE}) + elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" AND ARGUMENTS_RELWITHDEBINFO_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_RELWITHDEBINFO_PROFILE}) + elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" AND ARGUMENTS_MINSIZEREL_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_MINSIZEREL_PROFILE}) + elseif(ARGUMENTS_PROFILE) + set(_APPLIED_PROFILES ${ARGUMENTS_PROFILE}) + endif() + + foreach(ARG ${_APPLIED_PROFILES}) + set(_SETTINGS ${_SETTINGS} -pr=${ARG}) + endforeach() + foreach(ARG ${ARGUMENTS_PROFILE_BUILD}) + conan_check(VERSION 1.24.0 REQUIRED DETECT_QUIET) + set(_SETTINGS ${_SETTINGS} -pr:b=${ARG}) + endforeach() + + if(NOT _SETTINGS OR ARGUMENTS_PROFILE_AUTO STREQUAL "ALL") + set(ARGUMENTS_PROFILE_AUTO arch build_type compiler compiler.version + compiler.runtime compiler.libcxx compiler.toolset) + endif() + + # remove any manually specified settings from the autodetected settings + foreach(ARG ${ARGUMENTS_SETTINGS}) + string(REGEX MATCH "[^=]*" MANUAL_SETTING "${ARG}") + message(STATUS "Conan: ${MANUAL_SETTING} was added as an argument. Not using the autodetected one.") + list(REMOVE_ITEM ARGUMENTS_PROFILE_AUTO "${MANUAL_SETTING}") + endforeach() + + # Automatic from CMake + foreach(ARG ${ARGUMENTS_PROFILE_AUTO}) + string(TOUPPER ${ARG} _arg_name) + string(REPLACE "." "_" _arg_name ${_arg_name}) + if(_CONAN_SETTING_${_arg_name}) + set(_SETTINGS ${_SETTINGS} -s ${ARG}=${_CONAN_SETTING_${_arg_name}}) + endif() + endforeach() + + foreach(ARG ${ARGUMENTS_SETTINGS}) + set(_SETTINGS ${_SETTINGS} -s ${ARG}) + endforeach() + + message(STATUS "Conan: Settings= ${_SETTINGS}") + + set(${result} ${_SETTINGS} PARENT_SCOPE) +endfunction() + + +function(conan_cmake_detect_unix_libcxx result) + # Take into account any -stdlib in compile options + get_directory_property(compile_options DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) + string(GENEX_STRIP "${compile_options}" compile_options) + + # Take into account any _GLIBCXX_USE_CXX11_ABI in compile definitions + get_directory_property(defines DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) + string(GENEX_STRIP "${defines}" defines) + + foreach(define ${defines}) + if(define MATCHES "_GLIBCXX_USE_CXX11_ABI") + if(define MATCHES "^-D") + set(compile_options ${compile_options} "${define}") + else() + set(compile_options ${compile_options} "-D${define}") + endif() + endif() + endforeach() + + # add additional compiler options ala cmRulePlaceholderExpander::ExpandRuleVariable + set(EXPAND_CXX_COMPILER ${CMAKE_CXX_COMPILER}) + if(CMAKE_CXX_COMPILER_ARG1) + # CMake splits CXX="foo bar baz" into CMAKE_CXX_COMPILER="foo", CMAKE_CXX_COMPILER_ARG1="bar baz" + # without this, ccache, winegcc, or other wrappers might lose all their arguments + separate_arguments(SPLIT_CXX_COMPILER_ARG1 NATIVE_COMMAND ${CMAKE_CXX_COMPILER_ARG1}) + list(APPEND EXPAND_CXX_COMPILER ${SPLIT_CXX_COMPILER_ARG1}) + endif() + + if(CMAKE_CXX_COMPILE_OPTIONS_TARGET AND CMAKE_CXX_COMPILER_TARGET) + # without --target= we may be calling the wrong underlying GCC + list(APPEND EXPAND_CXX_COMPILER "${CMAKE_CXX_COMPILE_OPTIONS_TARGET}${CMAKE_CXX_COMPILER_TARGET}") + endif() + + if(CMAKE_CXX_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN AND CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN) + list(APPEND EXPAND_CXX_COMPILER "${CMAKE_CXX_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN}${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}") + endif() + + if(CMAKE_CXX_COMPILE_OPTIONS_SYSROOT) + # without --sysroot= we may find the wrong #include + if(CMAKE_SYSROOT_COMPILE) + list(APPEND EXPAND_CXX_COMPILER "${CMAKE_CXX_COMPILE_OPTIONS_SYSROOT}${CMAKE_SYSROOT_COMPILE}") + elseif(CMAKE_SYSROOT) + list(APPEND EXPAND_CXX_COMPILER "${CMAKE_CXX_COMPILE_OPTIONS_SYSROOT}${CMAKE_SYSROOT}") + endif() + endif() + + separate_arguments(SPLIT_CXX_FLAGS NATIVE_COMMAND ${CMAKE_CXX_FLAGS}) + + if(CMAKE_OSX_SYSROOT) + set(xcode_sysroot_option "--sysroot=${CMAKE_OSX_SYSROOT}") + endif() + + execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "#include " + COMMAND ${EXPAND_CXX_COMPILER} ${SPLIT_CXX_FLAGS} -x c++ ${xcode_sysroot_option} ${compile_options} -E -dM - + OUTPUT_VARIABLE string_defines + ) + + if(string_defines MATCHES "#define __GLIBCXX__") + # Allow -D_GLIBCXX_USE_CXX11_ABI=ON/OFF as argument to cmake + if(DEFINED _GLIBCXX_USE_CXX11_ABI) + if(_GLIBCXX_USE_CXX11_ABI) + set(${result} libstdc++11 PARENT_SCOPE) + return() + else() + set(${result} libstdc++ PARENT_SCOPE) + return() + endif() + endif() + + if(string_defines MATCHES "#define _GLIBCXX_USE_CXX11_ABI 1\n") + set(${result} libstdc++11 PARENT_SCOPE) + else() + # Either the compiler is missing the define because it is old, and so + # it can't use the new abi, or the compiler was configured to use the + # old abi by the user or distro (e.g. devtoolset on RHEL/CentOS) + set(${result} libstdc++ PARENT_SCOPE) + endif() + else() + set(${result} libc++ PARENT_SCOPE) + endif() +endfunction() + +function(conan_cmake_detect_vs_runtime result) + + conan_parse_arguments(${ARGV}) + if(ARGUMENTS_BUILD_TYPE) + set(build_type "${ARGUMENTS_BUILD_TYPE}") + elseif(CMAKE_BUILD_TYPE) + set(build_type "${CMAKE_BUILD_TYPE}") + else() + message(FATAL_ERROR "Please specify in command line CMAKE_BUILD_TYPE (-DCMAKE_BUILD_TYPE=Release)") + endif() + + if(build_type) + string(TOUPPER "${build_type}" build_type) + endif() + set(variables CMAKE_CXX_FLAGS_${build_type} CMAKE_C_FLAGS_${build_type} CMAKE_CXX_FLAGS CMAKE_C_FLAGS) + foreach(variable ${variables}) + if(NOT "${${variable}}" STREQUAL "") + string(REPLACE " " ";" flags "${${variable}}") + foreach (flag ${flags}) + if("${flag}" STREQUAL "/MD" OR "${flag}" STREQUAL "/MDd" OR "${flag}" STREQUAL "/MT" OR "${flag}" STREQUAL "/MTd") + string(SUBSTRING "${flag}" 1 -1 runtime) + set(${result} "${runtime}" PARENT_SCOPE) + return() + endif() + endforeach() + endif() + endforeach() + if("${build_type}" STREQUAL "DEBUG") + set(${result} "MDd" PARENT_SCOPE) + else() + set(${result} "MD" PARENT_SCOPE) + endif() +endfunction() + +function(_collect_settings result) + set(ARGUMENTS_PROFILE_AUTO arch build_type compiler compiler.version + compiler.runtime compiler.libcxx compiler.toolset + compiler.cppstd) + foreach(ARG ${ARGUMENTS_PROFILE_AUTO}) + string(TOUPPER ${ARG} _arg_name) + string(REPLACE "." "_" _arg_name ${_arg_name}) + if(_CONAN_SETTING_${_arg_name}) + set(detected_setings ${detected_setings} ${ARG}=${_CONAN_SETTING_${_arg_name}}) + endif() + endforeach() + set(${result} ${detected_setings} PARENT_SCOPE) +endfunction() + +function(conan_cmake_autodetect detected_settings) + _conan_detect_build_type(${ARGV}) + _conan_check_system_name() + _conan_check_language() + _conan_detect_compiler(${ARGV}) + _collect_settings(collected_settings) + set(${detected_settings} ${collected_settings} PARENT_SCOPE) +endfunction() + +macro(conan_parse_arguments) + set(options BASIC_SETUP CMAKE_TARGETS UPDATE KEEP_RPATHS NO_LOAD NO_OUTPUT_DIRS OUTPUT_QUIET NO_IMPORTS SKIP_STD) + set(oneValueArgs CONANFILE ARCH BUILD_TYPE INSTALL_FOLDER OUTPUT_FOLDER CONAN_COMMAND) + set(multiValueArgs DEBUG_PROFILE RELEASE_PROFILE RELWITHDEBINFO_PROFILE MINSIZEREL_PROFILE + PROFILE REQUIRES OPTIONS IMPORTS SETTINGS BUILD ENV GENERATORS PROFILE_AUTO + INSTALL_ARGS CONFIGURATION_TYPES PROFILE_BUILD BUILD_REQUIRES) + cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) +endmacro() + +function(old_conan_cmake_install) + # Calls "conan install" + # Argument BUILD is equivalant to --build={missing, PkgName,...} or + # --build when argument is 'BUILD all' (which builds all packages from source) + # Argument CONAN_COMMAND, to specify the conan path, e.g. in case of running from source + # cmake does not identify conan as command, even if it is +x and it is in the path + conan_parse_arguments(${ARGV}) + + if(CONAN_CMAKE_MULTI) + set(ARGUMENTS_GENERATORS ${ARGUMENTS_GENERATORS} cmake_multi) + else() + set(ARGUMENTS_GENERATORS ${ARGUMENTS_GENERATORS} cmake) + endif() + + set(CONAN_BUILD_POLICY "") + foreach(ARG ${ARGUMENTS_BUILD}) + if(${ARG} STREQUAL "all") + set(CONAN_BUILD_POLICY ${CONAN_BUILD_POLICY} --build) + break() + else() + set(CONAN_BUILD_POLICY ${CONAN_BUILD_POLICY} --build=${ARG}) + endif() + endforeach() + if(ARGUMENTS_CONAN_COMMAND) + set(CONAN_CMD ${ARGUMENTS_CONAN_COMMAND}) + else() + conan_check(REQUIRED) + endif() + set(CONAN_OPTIONS "") + if(ARGUMENTS_CONANFILE) + if(IS_ABSOLUTE ${ARGUMENTS_CONANFILE}) + set(CONANFILE ${ARGUMENTS_CONANFILE}) + else() + set(CONANFILE ${CMAKE_CURRENT_SOURCE_DIR}/${ARGUMENTS_CONANFILE}) + endif() + else() + set(CONANFILE ".") + endif() + foreach(ARG ${ARGUMENTS_OPTIONS}) + set(CONAN_OPTIONS ${CONAN_OPTIONS} -o=${ARG}) + endforeach() + if(ARGUMENTS_UPDATE) + set(CONAN_INSTALL_UPDATE --update) + endif() + if(ARGUMENTS_NO_IMPORTS) + set(CONAN_INSTALL_NO_IMPORTS --no-imports) + endif() + set(CONAN_INSTALL_FOLDER "") + if(ARGUMENTS_INSTALL_FOLDER) + set(CONAN_INSTALL_FOLDER -if=${ARGUMENTS_INSTALL_FOLDER}) + endif() + set(CONAN_OUTPUT_FOLDER "") + if(ARGUMENTS_OUTPUT_FOLDER) + set(CONAN_OUTPUT_FOLDER -of=${ARGUMENTS_OUTPUT_FOLDER}) + endif() + foreach(ARG ${ARGUMENTS_GENERATORS}) + set(CONAN_GENERATORS ${CONAN_GENERATORS} -g=${ARG}) + endforeach() + foreach(ARG ${ARGUMENTS_ENV}) + set(CONAN_ENV_VARS ${CONAN_ENV_VARS} -e=${ARG}) + endforeach() + set(conan_args install ${CONANFILE} ${settings} ${CONAN_ENV_VARS} ${CONAN_GENERATORS} ${CONAN_BUILD_POLICY} ${CONAN_INSTALL_UPDATE} ${CONAN_INSTALL_NO_IMPORTS} ${CONAN_OPTIONS} ${CONAN_INSTALL_FOLDER} ${ARGUMENTS_INSTALL_ARGS}) + + string (REPLACE ";" " " _conan_args "${conan_args}") + message(STATUS "Conan executing: ${CONAN_CMD} ${_conan_args}") + + if(ARGUMENTS_OUTPUT_QUIET) + execute_process(COMMAND ${CONAN_CMD} ${conan_args} + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_output + ERROR_VARIABLE conan_output + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + else() + execute_process(COMMAND ${CONAN_CMD} ${conan_args} + RESULT_VARIABLE return_code + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() + + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan install failed='${return_code}'") + endif() + +endfunction() + +function(conan_cmake_install) + if(DEFINED CONAN_COMMAND) + set(CONAN_CMD ${CONAN_COMMAND}) + else() + conan_check(REQUIRED) + endif() + + set(installOptions UPDATE NO_IMPORTS OUTPUT_QUIET ERROR_QUIET) + set(installOneValueArgs PATH_OR_REFERENCE REFERENCE REMOTE LOCKFILE LOCKFILE_OUT LOCKFILE_NODE_ID INSTALL_FOLDER OUTPUT_FOLDER) + set(installMultiValueArgs GENERATOR BUILD ENV ENV_HOST ENV_BUILD OPTIONS_HOST OPTIONS OPTIONS_BUILD PROFILE + PROFILE_HOST PROFILE_BUILD SETTINGS SETTINGS_HOST SETTINGS_BUILD) + cmake_parse_arguments(ARGS "${installOptions}" "${installOneValueArgs}" "${installMultiValueArgs}" ${ARGN}) + foreach(arg ${installOptions}) + if(ARGS_${arg}) + set(${arg} ${${arg}} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${installOneValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "REMOTE") + set(flag "--remote") + elseif("${arg}" STREQUAL "LOCKFILE") + set(flag "--lockfile") + elseif("${arg}" STREQUAL "LOCKFILE_OUT") + set(flag "--lockfile-out") + elseif("${arg}" STREQUAL "LOCKFILE_NODE_ID") + set(flag "--lockfile-node-id") + elseif("${arg}" STREQUAL "INSTALL_FOLDER") + set(flag "--install-folder") + elseif("${arg}" STREQUAL "OUTPUT_FOLDER") + set(flag "--output-folder") + endif() + set(${arg} ${${arg}} ${flag} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${installMultiValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "GENERATOR") + set(flag "--generator") + elseif("${arg}" STREQUAL "BUILD") + set(flag "--build") + elseif("${arg}" STREQUAL "ENV") + set(flag "--env") + elseif("${arg}" STREQUAL "ENV_HOST") + set(flag "--env:host") + elseif("${arg}" STREQUAL "ENV_BUILD") + set(flag "--env:build") + elseif("${arg}" STREQUAL "OPTIONS") + set(flag "--options") + elseif("${arg}" STREQUAL "OPTIONS_HOST") + set(flag "--options:host") + elseif("${arg}" STREQUAL "OPTIONS_BUILD") + set(flag "--options:build") + elseif("${arg}" STREQUAL "PROFILE") + set(flag "--profile") + elseif("${arg}" STREQUAL "PROFILE_HOST") + set(flag "--profile:host") + elseif("${arg}" STREQUAL "PROFILE_BUILD") + set(flag "--profile:build") + elseif("${arg}" STREQUAL "SETTINGS") + set(flag "--settings") + elseif("${arg}" STREQUAL "SETTINGS_HOST") + set(flag "--settings:host") + elseif("${arg}" STREQUAL "SETTINGS_BUILD") + set(flag "--settings:build") + endif() + list(LENGTH ARGS_${arg} numargs) + foreach(item ${ARGS_${arg}}) + if(${item} STREQUAL "all" AND ${arg} STREQUAL "BUILD") + set(${arg} "--build") + break() + endif() + set(${arg} ${${arg}} ${flag} ${item}) + endforeach() + endif() + endforeach() + if(DEFINED UPDATE) + set(UPDATE --update) + endif() + if(DEFINED NO_IMPORTS) + set(NO_IMPORTS --no-imports) + endif() + set(install_args install ${PATH_OR_REFERENCE} ${REFERENCE} ${UPDATE} ${NO_IMPORTS} ${REMOTE} ${LOCKFILE} ${LOCKFILE_OUT} ${LOCKFILE_NODE_ID} ${INSTALL_FOLDER} ${OUTPUT_FOLDER} + ${GENERATOR} ${BUILD} ${ENV} ${ENV_HOST} ${ENV_BUILD} ${OPTIONS} ${OPTIONS_HOST} ${OPTIONS_BUILD} + ${PROFILE} ${PROFILE_HOST} ${PROFILE_BUILD} ${SETTINGS} ${SETTINGS_HOST} ${SETTINGS_BUILD}) + + string(REPLACE ";" " " _install_args "${install_args}") + message(STATUS "Conan executing: ${CONAN_CMD} ${_install_args}") + + if(ARGS_OUTPUT_QUIET) + set(OUTPUT_OPT OUTPUT_QUIET) + endif() + if(ARGS_ERROR_QUIET) + set(ERROR_OPT ERROR_QUIET) + endif() + + execute_process(COMMAND ${CONAN_CMD} ${install_args} + RESULT_VARIABLE return_code + ${OUTPUT_OPT} + ${ERROR_OPT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + if(NOT "${return_code}" STREQUAL "0") + if (ARGS_ERROR_QUIET) + message(WARNING "Conan install failed='${return_code}'") + else() + message(FATAL_ERROR "Conan install failed='${return_code}'") + endif() + endif() + +endfunction() + +function(conan_cmake_lock_create) + if(DEFINED CONAN_COMMAND) + set(CONAN_CMD ${CONAN_COMMAND}) + else() + conan_check(REQUIRED) + endif() + + set(lockCreateOptions UPDATE BASE OUTPUT_QUIET ERROR_QUIET) + set(lockCreateOneValueArgs PATH REFERENCE REMOTE LOCKFILE LOCKFILE_OUT) + set(lockCreateMultiValueArgs BUILD ENV ENV_HOST ENV_BUILD OPTIONS_HOST OPTIONS OPTIONS_BUILD PROFILE + PROFILE_HOST PROFILE_BUILD SETTINGS SETTINGS_HOST SETTINGS_BUILD) + cmake_parse_arguments(ARGS "${lockCreateOptions}" "${lockCreateOneValueArgs}" "${lockCreateMultiValueArgs}" ${ARGN}) + foreach(arg ${lockCreateOptions}) + if(ARGS_${arg}) + set(${arg} ${${arg}} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${lockCreateOneValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "REMOTE") + set(flag "--remote") + elseif("${arg}" STREQUAL "LOCKFILE") + set(flag "--lockfile") + elseif("${arg}" STREQUAL "LOCKFILE_OUT") + set(flag "--lockfile-out") + endif() + set(${arg} ${${arg}} ${flag} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${lockCreateMultiValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "BUILD") + set(flag "--build") + elseif("${arg}" STREQUAL "ENV") + set(flag "--env") + elseif("${arg}" STREQUAL "ENV_HOST") + set(flag "--env:host") + elseif("${arg}" STREQUAL "ENV_BUILD") + set(flag "--env:build") + elseif("${arg}" STREQUAL "OPTIONS") + set(flag "--options") + elseif("${arg}" STREQUAL "OPTIONS_HOST") + set(flag "--options:host") + elseif("${arg}" STREQUAL "OPTIONS_BUILD") + set(flag "--options:build") + elseif("${arg}" STREQUAL "PROFILE") + set(flag "--profile") + elseif("${arg}" STREQUAL "PROFILE_HOST") + set(flag "--profile:host") + elseif("${arg}" STREQUAL "PROFILE_BUILD") + set(flag "--profile:build") + elseif("${arg}" STREQUAL "SETTINGS") + set(flag "--settings") + elseif("${arg}" STREQUAL "SETTINGS_HOST") + set(flag "--settings:host") + elseif("${arg}" STREQUAL "SETTINGS_BUILD") + set(flag "--settings:build") + endif() + list(LENGTH ARGS_${arg} numargs) + foreach(item ${ARGS_${arg}}) + if(${item} STREQUAL "all" AND ${arg} STREQUAL "BUILD") + set(${arg} "--build") + break() + endif() + set(${arg} ${${arg}} ${flag} ${item}) + endforeach() + endif() + endforeach() + if(DEFINED UPDATE) + set(UPDATE --update) + endif() + if(DEFINED BASE) + set(BASE --base) + endif() + set(lock_create_Args lock create ${PATH} ${REFERENCE} ${UPDATE} ${BASE} ${REMOTE} ${LOCKFILE} ${LOCKFILE_OUT} ${LOCKFILE_NODE_ID} ${INSTALL_FOLDER} + ${GENERATOR} ${BUILD} ${ENV} ${ENV_HOST} ${ENV_BUILD} ${OPTIONS} ${OPTIONS_HOST} ${OPTIONS_BUILD} + ${PROFILE} ${PROFILE_HOST} ${PROFILE_BUILD} ${SETTINGS} ${SETTINGS_HOST} ${SETTINGS_BUILD}) + + string(REPLACE ";" " " _lock_create_Args "${lock_create_Args}") + message(STATUS "Conan executing: ${CONAN_CMD} ${_lock_create_Args}") + + if(ARGS_OUTPUT_QUIET) + set(OUTPUT_OPT OUTPUT_QUIET) + endif() + if(ARGS_ERROR_QUIET) + set(ERROR_OPT ERROR_QUIET) + endif() + + execute_process(COMMAND ${CONAN_CMD} ${lock_create_Args} + RESULT_VARIABLE return_code + ${OUTPUT_OPT} + ${ERROR_OPT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + if(NOT "${return_code}" STREQUAL "0") + if (ARGS_ERROR_QUIET) + message(WARNING "Conan lock create failed='${return_code}'") + else() + message(FATAL_ERROR "Conan lock create failed='${return_code}'") + endif() + endif() +endfunction() + +function(conan_cmake_setup_conanfile) + conan_parse_arguments(${ARGV}) + if(ARGUMENTS_CONANFILE) + get_filename_component(_CONANFILE_NAME ${ARGUMENTS_CONANFILE} NAME) + # configure_file will make sure cmake re-runs when conanfile is updated + configure_file(${ARGUMENTS_CONANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk COPYONLY) + file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk) + else() + conan_cmake_generate_conanfile(ON ${ARGV}) + endif() +endfunction() + +function(conan_cmake_configure) + conan_cmake_generate_conanfile(OFF ${ARGV}) +endfunction() + +# Generate, writing in disk a conanfile.txt with the requires, options, and imports +# specified as arguments +# This will be considered as temporary file, generated in CMAKE_CURRENT_BINARY_DIR) +function(conan_cmake_generate_conanfile DEFAULT_GENERATOR) + + conan_parse_arguments(${ARGV}) + + set(_FN "${CMAKE_CURRENT_BINARY_DIR}/conanfile.txt") + file(WRITE ${_FN} "") + + if(DEFINED ARGUMENTS_REQUIRES) + file(APPEND ${_FN} "[requires]\n") + foreach(REQUIRE ${ARGUMENTS_REQUIRES}) + file(APPEND ${_FN} ${REQUIRE} "\n") + endforeach() + endif() + + if (DEFAULT_GENERATOR OR DEFINED ARGUMENTS_GENERATORS) + file(APPEND ${_FN} "[generators]\n") + if (DEFAULT_GENERATOR) + file(APPEND ${_FN} "cmake\n") + endif() + if (DEFINED ARGUMENTS_GENERATORS) + foreach(GENERATOR ${ARGUMENTS_GENERATORS}) + file(APPEND ${_FN} ${GENERATOR} "\n") + endforeach() + endif() + endif() + + if(DEFINED ARGUMENTS_BUILD_REQUIRES) + file(APPEND ${_FN} "[build_requires]\n") + foreach(BUILD_REQUIRE ${ARGUMENTS_BUILD_REQUIRES}) + file(APPEND ${_FN} ${BUILD_REQUIRE} "\n") + endforeach() + endif() + + if(DEFINED ARGUMENTS_IMPORTS) + file(APPEND ${_FN} "[imports]\n") + foreach(IMPORTS ${ARGUMENTS_IMPORTS}) + file(APPEND ${_FN} ${IMPORTS} "\n") + endforeach() + endif() + + if(DEFINED ARGUMENTS_OPTIONS) + file(APPEND ${_FN} "[options]\n") + foreach(OPTION ${ARGUMENTS_OPTIONS}) + file(APPEND ${_FN} ${OPTION} "\n") + endforeach() + endif() + +endfunction() + + +macro(conan_load_buildinfo) + if(CONAN_CMAKE_MULTI) + set(_CONANBUILDINFO conanbuildinfo_multi.cmake) + else() + set(_CONANBUILDINFO conanbuildinfo.cmake) + endif() + if(ARGUMENTS_INSTALL_FOLDER) + set(_CONANBUILDINFOFOLDER ${ARGUMENTS_INSTALL_FOLDER}) + else() + set(_CONANBUILDINFOFOLDER ${CMAKE_CURRENT_BINARY_DIR}) + endif() + # Checks for the existence of conanbuildinfo.cmake, and loads it + # important that it is macro, so variables defined at parent scope + if(EXISTS "${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}") + message(STATUS "Conan: Loading ${_CONANBUILDINFO}") + include(${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}) + else() + message(FATAL_ERROR "${_CONANBUILDINFO} doesn't exist in ${CMAKE_CURRENT_BINARY_DIR}") + endif() +endmacro() + + +macro(conan_cmake_run) + conan_parse_arguments(${ARGV}) + + if(ARGUMENTS_CONFIGURATION_TYPES AND NOT CMAKE_CONFIGURATION_TYPES) + message(WARNING "CONFIGURATION_TYPES should only be specified for multi-configuration generators") + elseif(ARGUMENTS_CONFIGURATION_TYPES AND ARGUMENTS_BUILD_TYPE) + message(WARNING "CONFIGURATION_TYPES and BUILD_TYPE arguments should not be defined at the same time.") + endif() + + if(CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE AND NOT CONAN_EXPORTED + AND NOT ARGUMENTS_BUILD_TYPE) + set(CONAN_CMAKE_MULTI ON) + if (NOT ARGUMENTS_CONFIGURATION_TYPES) + set(ARGUMENTS_CONFIGURATION_TYPES "Release;Debug") + endif() + message(STATUS "Conan: Using cmake-multi generator") + else() + set(CONAN_CMAKE_MULTI OFF) + endif() + + if(NOT CONAN_EXPORTED) + conan_cmake_setup_conanfile(${ARGV}) + if(CONAN_CMAKE_MULTI) + foreach(CMAKE_BUILD_TYPE ${ARGUMENTS_CONFIGURATION_TYPES}) + set(ENV{CONAN_IMPORT_PATH} ${CMAKE_BUILD_TYPE}) + conan_cmake_settings(settings ${ARGV}) + old_conan_cmake_install(SETTINGS ${settings} ${ARGV}) + endforeach() + set(CMAKE_BUILD_TYPE) + else() + conan_cmake_settings(settings ${ARGV}) + old_conan_cmake_install(SETTINGS ${settings} ${ARGV}) + endif() + endif() + + if (NOT ARGUMENTS_NO_LOAD) + conan_load_buildinfo() + endif() + + if(ARGUMENTS_BASIC_SETUP) + foreach(_option CMAKE_TARGETS KEEP_RPATHS NO_OUTPUT_DIRS SKIP_STD) + if(ARGUMENTS_${_option}) + if(${_option} STREQUAL "CMAKE_TARGETS") + list(APPEND _setup_options "TARGETS") + else() + list(APPEND _setup_options ${_option}) + endif() + endif() + endforeach() + conan_basic_setup(${_setup_options}) + endif() +endmacro() + +macro(conan_check) + # Checks conan availability in PATH + # Arguments REQUIRED, DETECT_QUIET and VERSION are optional + # Example usage: + # conan_check(VERSION 1.0.0 REQUIRED) + set(options REQUIRED DETECT_QUIET) + set(oneValueArgs VERSION) + cmake_parse_arguments(CONAN "${options}" "${oneValueArgs}" "" ${ARGN}) + if(NOT CONAN_DETECT_QUIET) + message(STATUS "Conan: checking conan executable") + endif() + + find_program(CONAN_CMD conan) + if(NOT CONAN_CMD AND CONAN_REQUIRED) + message(FATAL_ERROR "Conan executable not found! Please install conan.") + endif() + if(NOT CONAN_DETECT_QUIET) + message(STATUS "Conan: Found program ${CONAN_CMD}") + endif() + execute_process(COMMAND ${CONAN_CMD} --version + RESULT_VARIABLE return_code + OUTPUT_VARIABLE CONAN_VERSION_OUTPUT + ERROR_VARIABLE CONAN_VERSION_OUTPUT) + + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan --version failed='${return_code}'") + endif() + + if(NOT CONAN_DETECT_QUIET) + string(STRIP "${CONAN_VERSION_OUTPUT}" _CONAN_VERSION_OUTPUT) + message(STATUS "Conan: Version found ${_CONAN_VERSION_OUTPUT}") + endif() + + if(DEFINED CONAN_VERSION) + string(REGEX MATCH ".*Conan version ([0-9]+\\.[0-9]+\\.[0-9]+)" FOO + "${CONAN_VERSION_OUTPUT}") + if(${CMAKE_MATCH_1} VERSION_LESS ${CONAN_VERSION}) + message(FATAL_ERROR "Conan outdated. Installed: ${CMAKE_MATCH_1}, \ + required: ${CONAN_VERSION}. Consider updating via 'pip \ + install conan==${CONAN_VERSION}'.") + endif() + endif() +endmacro() + +function(conan_add_remote) + # Adds a remote + # Arguments URL and NAME are required, INDEX, COMMAND and VERIFY_SSL are optional + # Example usage: + # conan_add_remote(NAME bincrafters INDEX 1 + # URL https://api.bintray.com/conan/bincrafters/public-conan + # VERIFY_SSL True) + set(oneValueArgs URL NAME INDEX COMMAND VERIFY_SSL) + cmake_parse_arguments(CONAN "" "${oneValueArgs}" "" ${ARGN}) + + if(DEFINED CONAN_INDEX) + set(CONAN_INDEX_ARG "-i ${CONAN_INDEX}") + endif() + if(DEFINED CONAN_COMMAND) + set(CONAN_CMD ${CONAN_COMMAND}) + else() + conan_check(REQUIRED DETECT_QUIET) + endif() + set(CONAN_VERIFY_SSL_ARG "True") + if(DEFINED CONAN_VERIFY_SSL) + set(CONAN_VERIFY_SSL_ARG ${CONAN_VERIFY_SSL}) + endif() + message(STATUS "Conan: Adding ${CONAN_NAME} remote repository (${CONAN_URL}) verify ssl (${CONAN_VERIFY_SSL_ARG})") + execute_process(COMMAND ${CONAN_CMD} remote add ${CONAN_NAME} ${CONAN_INDEX_ARG} -f ${CONAN_URL} ${CONAN_VERIFY_SSL_ARG} + RESULT_VARIABLE return_code) + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan remote failed='${return_code}'") + endif() +endfunction() + +macro(conan_config_install) + # install a full configuration from a local or remote zip file + # Argument ITEM is required, arguments TYPE, SOURCE, TARGET and VERIFY_SSL are optional + # Example usage: + # conan_config_install(ITEM https://github.com/conan-io/cmake-conan.git + # TYPE git SOURCE source-folder TARGET target-folder VERIFY_SSL false) + set(oneValueArgs ITEM TYPE SOURCE TARGET VERIFY_SSL) + set(multiValueArgs ARGS) + cmake_parse_arguments(CONAN "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(DEFINED CONAN_COMMAND) + set(CONAN_CMD ${CONAN_COMMAND}) + else() + conan_check(REQUIRED) + endif() + + if(DEFINED CONAN_VERIFY_SSL) + set(CONAN_VERIFY_SSL_ARG "--verify-ssl=${CONAN_VERIFY_SSL}") + endif() + + if(DEFINED CONAN_TYPE) + set(CONAN_TYPE_ARG "--type=${CONAN_TYPE}") + endif() + + if(DEFINED CONAN_ARGS) + set(CONAN_ARGS_ARGS "--args=\"${CONAN_ARGS}\"") + endif() + + if(DEFINED CONAN_SOURCE) + set(CONAN_SOURCE_ARGS "--source-folder=${CONAN_SOURCE}") + endif() + + if(DEFINED CONAN_TARGET) + set(CONAN_TARGET_ARGS "--target-folder=${CONAN_TARGET}") + endif() + + set (CONAN_CONFIG_INSTALL_ARGS ${CONAN_VERIFY_SSL_ARG} + ${CONAN_TYPE_ARG} + ${CONAN_ARGS_ARGS} + ${CONAN_SOURCE_ARGS} + ${CONAN_TARGET_ARGS}) + + message(STATUS "Conan: Installing config from ${CONAN_ITEM}") + execute_process(COMMAND ${CONAN_CMD} config install ${CONAN_ITEM} ${CONAN_CONFIG_INSTALL_ARGS} + RESULT_VARIABLE return_code) + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan config failed='${return_code}'") + endif() +endmacro() diff --git a/cmake/pkgconfig.in b/cmake/pkgconfig.in index baeb394dd..15d1aae3b 100644 --- a/cmake/pkgconfig.in +++ b/cmake/pkgconfig.in @@ -4,7 +4,7 @@ libdir=@PKGCONFIG_LIBRARY_DIR@ Name: libOSRM Description: Project OSRM library -Version: v@OSRM_VERSION@ +Version: @OSRM_VERSION@ Requires: Libs: -L${libdir} -losrm @PKGCONFIG_OSRM_LDFLAGS@ Libs.private: @PKGCONFIG_OSRM_DEPENDENT_LIBRARIES@ diff --git a/cmake/warnings.cmake b/cmake/warnings.cmake new file mode 100644 index 000000000..ad9cfb086 --- /dev/null +++ b/cmake/warnings.cmake @@ -0,0 +1,93 @@ +include (CheckCXXCompilerFlag) +include (CheckCCompilerFlag) + +# Try to add -Wflag if compiler supports it +macro (add_warning flag) + string(REPLACE "-" "_" underscored_flag ${flag}) + string(REPLACE "+" "x" underscored_flag ${underscored_flag}) + + check_cxx_compiler_flag("-W${flag}" SUPPORTS_CXXFLAG_${underscored_flag}) + check_c_compiler_flag("-W${flag}" SUPPORTS_CFLAG_${underscored_flag}) + + if (SUPPORTS_CXXFLAG_${underscored_flag}) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W${flag}") + else() + message (STATUS "Flag -W${flag} is unsupported") + endif() + + if (SUPPORTS_CFLAG_${underscored_flag}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W${flag}") + else() + message(STATUS "Flag -W${flag} is unsupported") + endif() +endmacro() + +# Try to add -Wno flag if compiler supports it +macro (no_warning flag) + add_warning(no-${flag}) +endmacro () + + +# The same but only for specified target. +macro (target_add_warning target flag) + string (REPLACE "-" "_" underscored_flag ${flag}) + string (REPLACE "+" "x" underscored_flag ${underscored_flag}) + + check_cxx_compiler_flag("-W${flag}" SUPPORTS_CXXFLAG_${underscored_flag}) + + if (SUPPORTS_CXXFLAG_${underscored_flag}) + target_compile_options (${target} PRIVATE "-W${flag}") + else () + message (STATUS "Flag -W${flag} is unsupported") + endif () +endmacro () + +macro (target_no_warning target flag) + target_add_warning(${target} no-${flag}) +endmacro () + +add_warning(all) +add_warning(extra) +add_warning(pedantic) +add_warning(error) # treat all warnings as errors +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_warning(strict-overflow=2) +elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + add_warning(strict-overflow=1) +endif() +add_warning(suggest-override) +add_warning(suggest-destructor-override) +add_warning(unused) +add_warning(unreachable-code) +add_warning(delete-incomplete) +add_warning(duplicated-cond) +add_warning(disabled-optimization) +add_warning(init-self) +add_warning(bool-compare) +add_warning(logical-not-parentheses) +add_warning(logical-op) +add_warning(maybe-uninitialized) +add_warning(misleading-indentation) +# `no-` prefix is part of warning name(i.e. doesn't mean we are disabling it) +add_warning(no-return-local-addr) +add_warning(odr) +add_warning(pointer-arith) +add_warning(redundant-decls) +add_warning(reorder) +add_warning(shift-negative-value) +add_warning(sizeof-array-argument) +add_warning(switch-bool) +add_warning(tautological-compare) +add_warning(trampolines) +no_warning(c++17-extensions) +# TODO: these warnings are not enabled by default, but we consider them as useful and good to enable in the future +no_warning(implicit-int-conversion) +no_warning(implicit-float-conversion) +no_warning(unused-member-function) +no_warning(old-style-cast) +no_warning(non-virtual-dtor) +no_warning(float-conversion) +no_warning(sign-conversion) +no_warning(shorten-64-to-32) +no_warning(padded) +no_warning(missing-noreturn) \ No newline at end of file diff --git a/cucumber.js b/cucumber.js index ccd5d0319..288e3ba5a 100644 --- a/cucumber.js +++ b/cucumber.js @@ -1,7 +1,7 @@ module.exports = { - default: '--strict --tags ~@stress --tags ~@mld --tags ~@todo --require features/support --require features/step_definitions', - verify: '--strict --tags ~@stress --tags ~@mld --tags ~@todo -f progress --require features/support --require features/step_definitions', + default: '--strict --tags ~@stress --tags ~@todo --tags ~@mld-only --require features/support --require features/step_definitions', + 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 --tags ~@alternative --tags ~@ch --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' }; diff --git a/data/driving_side.geojson b/data/driving_side.geojson new file mode 100644 index 000000000..9dc8e7652 --- /dev/null +++ b/data/driving_side.geojson @@ -0,0 +1,3160 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 113.573, + 22.186 + ], + [ + 114, + 22.5 + ], + [ + 114.05534, + 22.503 + ], + [ + 114.0595, + 22.51422 + ], + [ + 114.07345, + 22.51934 + ], + [ + 114.0786, + 22.53012 + ], + [ + 114.08512, + 22.53228 + ], + [ + 114.09034, + 22.53717 + ], + [ + 114.09611, + 22.53486 + ], + [ + 114.10602, + 22.53472 + ], + [ + 114.1115, + 22.52929 + ], + [ + 114.11522, + 22.5308 + ], + [ + 114.11649, + 22.53418 + ], + [ + 114.11979, + 22.53511 + ], + [ + 114.1244, + 22.5393 + ], + [ + 114.12729, + 22.53947 + ], + [ + 114.13018, + 22.54132 + ], + [ + 114.13807, + 22.5432 + ], + [ + 114.14429, + 22.54176 + ], + [ + 114.14441, + 22.54114 + ], + [ + 114.14846, + 22.54179 + ], + [ + 114.14855, + 22.54397 + ], + [ + 114.15042, + 22.54593 + ], + [ + 114.14964, + 22.54954 + ], + [ + 114.15166, + 22.55168 + ], + [ + 114.15192, + 22.55438 + ], + [ + 114.15642, + 22.55495 + ], + [ + 114.15841, + 22.55909 + ], + [ + 114.16032, + 22.56153 + ], + [ + 114.16162, + 22.56187 + ], + [ + 114.1634, + 22.55931 + ], + [ + 114.16553, + 22.5593 + ], + [ + 114.16733, + 22.56119 + ], + [ + 114.16934, + 22.56093 + ], + [ + 114.17061, + 22.5597 + ], + [ + 114.17702, + 22.56 + ], + [ + 114.17798, + 22.55546 + ], + [ + 114.18401, + 22.5552 + ], + [ + 114.18673, + 22.55468 + ], + [ + 114.1878, + 22.55545 + ], + [ + 114.18979, + 22.55446 + ], + [ + 114.1955, + 22.55564 + ], + [ + 114.19674, + 22.55691 + ], + [ + 114.20005, + 22.55717 + ], + [ + 114.20376, + 22.55623 + ], + [ + 114.20884, + 22.55672 + ], + [ + 114.22438, + 22.55055 + ], + [ + 114.2264, + 22.5476 + ], + [ + 114.22545, + 22.54528 + ], + [ + 114.22661, + 22.54339 + ], + [ + 114.32, + 22.576 + ], + [ + 114.45, + 22.43 + ], + [ + 114.45, + 22.14 + ], + [ + 113.9, + 22.14 + ], + [ + 113.75, + 22.22 + ], + [ + 113.553, + 22.095 + ], + [ + 113.54678, + 22.1207 + ], + [ + 113.5456, + 22.1207 + ], + [ + 113.54076, + 22.12373 + ], + [ + 113.54016, + 22.13618 + ], + [ + 113.54701, + 22.13651 + ], + [ + 113.5475, + 22.14583 + ], + [ + 113.52456, + 22.17978 + ], + [ + 113.53623, + 22.20191 + ], + [ + 113.53299, + 22.21232 + ], + [ + 113.53497, + 22.21351 + ], + [ + 113.53735, + 22.21377 + ], + [ + 113.54156, + 22.21315 + ], + [ + 113.54385, + 22.21709 + ], + [ + 113.55849, + 22.21565 + ], + [ + 113.573, + 22.186 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -75, + 18 + ], + [ + -80, + 20.5 + ], + [ + -83, + 19 + ], + [ + -77, + 16 + ], + [ + -75, + 18 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -64.33594, + 32.86113 + ], + [ + -79.39819, + 27.21067 + ], + [ + -80.63965, + 23.71998 + ], + [ + -73.39966, + 20.40642 + ], + [ + -65.1709, + 19.20743 + ], + [ + -65.09399, + 16.23577 + ], + [ + -59.13391, + 16.80454 + ], + [ + -62.64404, + 15.16228 + ], + [ + -59.43054, + 14.85985 + ], + [ + -62.83081, + 13.64599 + ], + [ + -61.80359, + 10.73752 + ], + [ + -62.08649, + 10.04729 + ], + [ + -61.06201, + 9.85522 + ], + [ + -59.81369, + 8.31274 + ], + [ + -59.8027, + 8.27469 + ], + [ + -59.83498, + 8.22712 + ], + [ + -59.94141, + 8.21149 + ], + [ + -59.99771, + 8.15576 + ], + [ + -59.97986, + 8.13265 + ], + [ + -59.99771, + 8.12041 + ], + [ + -60.00183, + 8.07147 + ], + [ + -60.05127, + 8.02524 + ], + [ + -60.09933, + 8.03747 + ], + [ + -60.12268, + 8.02388 + ], + [ + -60.14053, + 7.98988 + ], + [ + -60.36163, + 7.83345 + ], + [ + -60.53467, + 7.81713 + ], + [ + -60.5896, + 7.6375 + ], + [ + -60.72144, + 7.54493 + ], + [ + -60.5896, + 7.31888 + ], + [ + -60.63904, + 7.24532 + ], + [ + -60.54703, + 7.12542 + ], + [ + -60.46875, + 7.20309 + ], + [ + -60.37262, + 7.18401 + ], + [ + -60.29984, + 7.1445 + ], + [ + -60.2916, + 7.06819 + ], + [ + -60.39871, + 6.95097 + ], + [ + -60.66513, + 6.83235 + ], + [ + -60.71869, + 6.75053 + ], + [ + -60.91232, + 6.81735 + ], + [ + -60.94254, + 6.72053 + ], + [ + -61.14441, + 6.72326 + ], + [ + -61.23093, + 6.5773 + ], + [ + -61.1554, + 6.45314 + ], + [ + -61.14441, + 6.20199 + ], + [ + -61.39709, + 5.95619 + ], + [ + -60.71045, + 5.20036 + ], + [ + -60.21606, + 5.23319 + ], + [ + -59.99634, + 5.06906 + ], + [ + -60.13916, + 4.51071 + ], + [ + -59.69971, + 4.40118 + ], + [ + -59.5459, + 3.93002 + ], + [ + -59.87549, + 3.56825 + ], + [ + -59.7876, + 3.37086 + ], + [ + -60.01831, + 2.83332 + ], + [ + -59.90845, + 2.38335 + ], + [ + -59.69971, + 2.2626 + ], + [ + -59.77661, + 1.87833 + ], + [ + -59.65302, + 1.85087 + ], + [ + -59.69147, + 1.75754 + ], + [ + -59.61456, + 1.71361 + ], + [ + -59.55139, + 1.73283 + ], + [ + -59.36188, + 1.49123 + ], + [ + -59.26575, + 1.39238 + ], + [ + -58.92242, + 1.30726 + ], + [ + -58.83728, + 1.17271 + ], + [ + -58.71918, + 1.23037 + ], + [ + -58.71094, + 1.29902 + ], + [ + -58.49121, + 1.26058 + ], + [ + -58.461, + 1.37591 + ], + [ + -58.50494, + 1.38689 + ], + [ + -58.51044, + 1.46102 + ], + [ + -58.38135, + 1.4775 + ], + [ + -58.32642, + 1.57359 + ], + [ + -58.00507, + 1.49946 + ], + [ + -57.99133, + 1.65321 + ], + [ + -57.79907, + 1.69165 + ], + [ + -57.70844, + 1.71087 + ], + [ + -57.54364, + 1.68341 + ], + [ + -57.41455, + 1.94421 + ], + [ + -57.10693, + 1.97715 + ], + [ + -56.8103, + 1.85636 + ], + [ + -56.48071, + 1.92225 + ], + [ + -55.90942, + 1.81244 + ], + [ + -55.90942, + 2.04302 + ], + [ + -56.14014, + 2.26534 + ], + [ + -55.94788, + 2.53701 + ], + [ + -55.70892, + 2.39981 + ], + [ + -55.37933, + 2.43274 + ], + [ + -55.19257, + 2.53976 + ], + [ + -54.98108, + 2.57268 + ], + [ + -54.88495, + 2.43548 + ], + [ + -54.71191, + 2.46293 + ], + [ + -54.69543, + 2.34767 + ], + [ + -54.58832, + 2.32846 + ], + [ + -54.43451, + 2.43548 + ], + [ + -54.20654, + 2.76748 + ], + [ + -54.17358, + 3.12955 + ], + [ + -53.96484, + 3.57921 + ], + [ + -54.33838, + 4.00674 + ], + [ + -54.44412, + 4.52577 + ], + [ + -54.46884, + 4.91036 + ], + [ + -54.36653, + 5.13061 + ], + [ + -54.27727, + 5.26191 + ], + [ + -54.19968, + 5.3084 + ], + [ + -54.01222, + 5.54457 + ], + [ + -54.0239, + 5.64605 + ], + [ + -53.86322, + 5.94936 + ], + [ + -64.33594, + 32.86113 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -14.5, + -6 + ], + [ + 11.79657, + -17.27197 + ], + [ + 12.03415, + -17.14866 + ], + [ + 12.38159, + -17.22213 + ], + [ + 12.58484, + -17.22476 + ], + [ + 13.01193, + -16.97405 + ], + [ + 13.24951, + -17.00098 + ], + [ + 13.38135, + -16.98522 + ], + [ + 13.93341, + -17.38734 + ], + [ + 18.42476, + -17.38996 + ], + [ + 18.47763, + -17.46857 + ], + [ + 18.62663, + -17.64599 + ], + [ + 18.79211, + -17.76177 + ], + [ + 18.92944, + -17.82061 + ], + [ + 19.33044, + -17.84806 + ], + [ + 19.66278, + -17.8644 + ], + [ + 19.74792, + -17.90557 + ], + [ + 19.85161, + -17.87486 + ], + [ + 20.10361, + -17.90296 + ], + [ + 20.18394, + -17.88401 + ], + [ + 20.34737, + -17.88466 + ], + [ + 20.44693, + -17.91733 + ], + [ + 20.51697, + -17.96698 + ], + [ + 20.83008, + -18.03032 + ], + [ + 20.95711, + -17.97285 + ], + [ + 21.16997, + -17.93497 + ], + [ + 21.42677, + -18.0264 + ], + [ + 23.45032, + -17.63879 + ], + [ + 22.00012, + -16.38866 + ], + [ + 21.99944, + -13.00523 + ], + [ + 24.03809, + -12.99118 + ], + [ + 24.03809, + -10.91962 + ], + [ + 24.43359, + -11.09217 + ], + [ + 24.45557, + -11.48002 + ], + [ + 25.37842, + -11.19996 + ], + [ + 25.42236, + -11.60919 + ], + [ + 26.96045, + -11.97484 + ], + [ + 27.18018, + -11.60919 + ], + [ + 28.125, + -12.42048 + ], + [ + 29.11377, + -13.36824 + ], + [ + 29.1687, + -13.43771 + ], + [ + 29.55872, + -13.19716 + ], + [ + 29.68506, + -13.2239 + ], + [ + 29.62463, + -13.41099 + ], + [ + 29.80591, + -13.44305 + ], + [ + 29.81415, + -12.14809 + ], + [ + 29.31152, + -12.55456 + ], + [ + 28.41064, + -11.78133 + ], + [ + 28.63037, + -10.70379 + ], + [ + 28.65234, + -9.73071 + ], + [ + 28.37219, + -9.24309 + ], + [ + 28.89748, + -8.47916 + ], + [ + 30.78644, + -8.26857 + ], + [ + 29.39941, + -6.05316 + ], + [ + 29.4873, + -4.45595 + ], + [ + 29.75922, + -4.46759 + ], + [ + 29.81415, + -4.36421 + ], + [ + 29.88007, + -4.36832 + ], + [ + 30.04074, + -4.26699 + ], + [ + 30.07919, + -4.1629 + ], + [ + 30.18356, + -4.08311 + ], + [ + 30.1918, + -4.05126 + ], + [ + 30.21566, + -4.04595 + ], + [ + 30.22923, + -4.01136 + ], + [ + 30.21326, + -3.99612 + ], + [ + 30.25978, + -3.88755 + ], + [ + 30.29274, + -3.86288 + ], + [ + 30.34424, + -3.77245 + ], + [ + 30.39848, + -3.79095 + ], + [ + 30.40878, + -3.76765 + ], + [ + 30.39548, + -3.7304 + ], + [ + 30.39054, + -3.72821 + ], + [ + 30.3896, + -3.71918 + ], + [ + 30.39093, + -3.7101 + ], + [ + 30.39514, + -3.70444 + ], + [ + 30.42028, + -3.64963 + ], + [ + 30.46886, + -3.53501 + ], + [ + 30.67108, + -3.41335 + ], + [ + 30.63297, + -3.34892 + ], + [ + 30.84206, + -3.25535 + ], + [ + 30.84549, + -3.16108 + ], + [ + 30.83485, + -3.09698 + ], + [ + 30.7933, + -3.06235 + ], + [ + 30.82111, + -3.02258 + ], + [ + 30.84515, + -2.9739 + ], + [ + 30.74764, + -2.99618 + ], + [ + 30.7037, + -2.97013 + ], + [ + 30.66422, + -2.98967 + ], + [ + 30.57632, + -2.90738 + ], + [ + 30.49393, + -2.94441 + ], + [ + 30.41016, + -2.87172 + ], + [ + 30.52002, + -2.39432 + ], + [ + 30.77545, + -2.38883 + ], + [ + 30.8606, + -2.31199 + ], + [ + 30.84961, + -2.19398 + ], + [ + 30.89081, + -2.07322 + ], + [ + 30.81116, + -1.96068 + ], + [ + 30.83862, + -1.6587 + ], + [ + 30.73425, + -1.4418 + ], + [ + 30.56259, + -1.33884 + ], + [ + 30.4541, + -1.05737 + ], + [ + 30.35797, + -1.06287 + ], + [ + 30.34149, + -1.13152 + ], + [ + 30.16571, + -1.34296 + ], + [ + 29.91852, + -1.48024 + ], + [ + 29.83887, + -1.31824 + ], + [ + 29.58344, + -1.39238 + ], + [ + 29.729, + 0.05493 + ], + [ + 29.96796, + 0.5136 + ], + [ + 29.9707, + 0.8569 + ], + [ + 30.22339, + 0.92281 + ], + [ + 30.24536, + 1.15349 + ], + [ + 30.47745, + 1.20772 + ], + [ + 31.30966, + 2.15693 + ], + [ + 31.20255, + 2.22211 + ], + [ + 31.20255, + 2.29278 + ], + [ + 31.16409, + 2.27906 + ], + [ + 31.13937, + 2.28318 + ], + [ + 31.13113, + 2.26534 + ], + [ + 31.07826, + 2.30033 + ], + [ + 31.0714, + 2.34767 + ], + [ + 31.00479, + 2.4005 + ], + [ + 30.97183, + 2.40461 + ], + [ + 30.94711, + 2.38746 + ], + [ + 30.94849, + 2.36276 + ], + [ + 30.9375, + 2.33532 + ], + [ + 30.88531, + 2.34012 + ], + [ + 30.83038, + 2.42176 + ], + [ + 30.74112, + 2.43274 + ], + [ + 30.76035, + 2.5864 + ], + [ + 30.90179, + 2.88132 + ], + [ + 30.76447, + 3.04178 + ], + [ + 30.93613, + 3.40239 + ], + [ + 30.94059, + 3.50588 + ], + [ + 30.85236, + 3.48601 + ], + [ + 30.90866, + 3.5936 + ], + [ + 30.95055, + 3.63918 + ], + [ + 30.94677, + 3.65391 + ], + [ + 30.9866, + 3.70187 + ], + [ + 31.00582, + 3.70701 + ], + [ + 31.02058, + 3.69708 + ], + [ + 31.16547, + 3.7954 + ], + [ + 31.28838, + 3.79643 + ], + [ + 31.52699, + 3.66282 + ], + [ + 31.7038, + 3.72449 + ], + [ + 31.82671, + 3.82794 + ], + [ + 31.96198, + 3.65596 + ], + [ + 31.95854, + 3.57099 + ], + [ + 32.04987, + 3.59155 + ], + [ + 32.07733, + 3.57099 + ], + [ + 32.0842, + 3.53672 + ], + [ + 32.20093, + 3.50657 + ], + [ + 32.21672, + 3.56448 + ], + [ + 32.19578, + 3.59977 + ], + [ + 32.41516, + 3.74504 + ], + [ + 32.72055, + 3.76782 + ], + [ + 32.89307, + 3.81219 + ], + [ + 33.02782, + 3.89371 + ], + [ + 33.18146, + 3.7793 + ], + [ + 33.51173, + 3.75258 + ], + [ + 33.98758, + 4.23309 + ], + [ + 34.05762, + 4.28342 + ], + [ + 34.38721, + 4.61065 + ], + [ + 35.94452, + 4.62023 + ], + [ + 35.95688, + 4.53467 + ], + [ + 36.04134, + 4.44568 + ], + [ + 36.89621, + 4.4491 + ], + [ + 38.14728, + 3.62992 + ], + [ + 38.55927, + 3.62033 + ], + [ + 38.92181, + 3.51068 + ], + [ + 39.56039, + 3.43392 + ], + [ + 39.87076, + 3.87522 + ], + [ + 40.76752, + 4.28753 + ], + [ + 41.16371, + 3.94372 + ], + [ + 41.89774, + 3.97797 + ], + [ + 41.31271, + 3.14463 + ], + [ + 40.98896, + 2.82869 + ], + [ + 40.99548, + -0.84042 + ], + [ + 41.7, + -1.8 + ], + [ + 41.7, + -49 + ], + [ + -27, + -60 + ], + [ + -65.7, + -52.5 + ], + [ + -14.5, + -6 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 31.33301, + 35.47856 + ], + [ + 33.0249, + 33.75175 + ], + [ + 35.44189, + 36.02245 + ], + [ + 31.33301, + 35.47856 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 14, + 36.5 + ], + [ + 15, + 36 + ], + [ + 14, + 35 + ], + [ + 14, + 36.5 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 0, + 62 + ], + [ + 2.5, + 51.3 + ], + [ + -2, + 50 + ], + [ + -1.9, + 49 + ], + [ + -20, + 53 + ], + [ + 0, + 62 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 180, + -35 + ], + [ + 161, + -19 + ], + [ + 167, + -12 + ], + [ + 180, + -22 + ], + [ + 180, + 4 + ], + [ + 170, + 3.7 + ], + [ + 127, + 5.7 + ], + [ + 118, + 2.7 + ], + [ + 119.5, + 5.4 + ], + [ + 117.2, + 7.5 + ], + [ + 102.6, + 8 + ], + [ + 102.9158, + 11.74099 + ], + [ + 102.76268, + 12.07357 + ], + [ + 102.70226, + 12.17158 + ], + [ + 102.74139, + 12.46474 + ], + [ + 102.53128, + 12.68857 + ], + [ + 102.49557, + 12.9256 + ], + [ + 102.49763, + 13.0064 + ], + [ + 102.4597, + 13.08199 + ], + [ + 102.43412, + 13.09026 + ], + [ + 102.39155, + 13.16407 + ], + [ + 102.35481, + 13.29341 + ], + [ + 102.35893, + 13.30945 + ], + [ + 102.34503, + 13.34837 + ], + [ + 102.35928, + 13.39797 + ], + [ + 102.3567, + 13.48095 + ], + [ + 102.36168, + 13.50582 + ], + [ + 102.33559, + 13.53787 + ], + [ + 102.33971, + 13.56023 + ], + [ + 102.35498, + 13.5649 + ], + [ + 102.36511, + 13.5785 + ], + [ + 102.40047, + 13.5679 + ], + [ + 102.42537, + 13.56891 + ], + [ + 102.44614, + 13.56123 + ], + [ + 102.48047, + 13.57091 + ], + [ + 102.53849, + 13.56757 + ], + [ + 102.5699, + 13.58526 + ], + [ + 102.57806, + 13.60486 + ], + [ + 102.62501, + 13.60845 + ], + [ + 102.62132, + 13.61295 + ], + [ + 102.60767, + 13.61562 + ], + [ + 102.57231, + 13.63331 + ], + [ + 102.56922, + 13.64082 + ], + [ + 102.54879, + 13.658 + ], + [ + 102.56252, + 13.68552 + ], + [ + 102.5972, + 13.70803 + ], + [ + 102.67084, + 13.74472 + ], + [ + 102.68818, + 13.75172 + ], + [ + 102.7014, + 13.7684 + ], + [ + 102.73161, + 13.77082 + ], + [ + 102.76543, + 13.85541 + ], + [ + 102.78397, + 13.93207 + ], + [ + 102.80388, + 13.94406 + ], + [ + 102.81607, + 13.96639 + ], + [ + 102.90705, + 14.02119 + ], + [ + 102.89726, + 14.0535 + ], + [ + 102.90095, + 14.0838 + ], + [ + 102.92421, + 14.10744 + ], + [ + 102.92378, + 14.12838 + ], + [ + 102.94147, + 14.15035 + ], + [ + 102.92953, + 14.17952 + ], + [ + 103.17535, + 14.33774 + ], + [ + 103.19939, + 14.32992 + ], + [ + 103.68553, + 14.44 + ], + [ + 103.94508, + 14.34157 + ], + [ + 104.05756, + 14.34589 + ], + [ + 104.06636, + 14.3419 + ], + [ + 104.26025, + 14.37749 + ], + [ + 104.50058, + 14.36984 + ], + [ + 104.57817, + 14.36019 + ], + [ + 104.6422, + 14.42387 + ], + [ + 104.66632, + 14.40234 + ], + [ + 104.68357, + 14.39877 + ], + [ + 104.71138, + 14.43169 + ], + [ + 104.72305, + 14.42188 + ], + [ + 104.71687, + 14.40043 + ], + [ + 104.75344, + 14.40459 + ], + [ + 104.80408, + 14.43867 + ], + [ + 104.83429, + 14.41573 + ], + [ + 104.99239, + 14.3838 + ], + [ + 105.05402, + 14.19783 + ], + [ + 105.47905, + 14.49186 + ], + [ + 105.60883, + 15.0005 + ], + [ + 105.46703, + 15.13005 + ], + [ + 105.48866, + 15.20237 + ], + [ + 105.59269, + 15.2716 + ], + [ + 105.58617, + 15.32823 + ], + [ + 105.50308, + 15.31912 + ], + [ + 105.46703, + 15.33948 + ], + [ + 105.49175, + 15.37921 + ], + [ + 105.59372, + 15.42869 + ], + [ + 105.59372, + 15.50927 + ], + [ + 105.60986, + 15.54871 + ], + [ + 105.62616, + 15.56492 + ], + [ + 105.62702, + 15.59129 + ], + [ + 105.63518, + 15.62742 + ], + [ + 105.63612, + 15.66056 + ], + [ + 105.5975, + 15.72088 + ], + [ + 105.49965, + 15.76681 + ], + [ + 105.46291, + 15.74517 + ], + [ + 105.43819, + 15.75459 + ], + [ + 105.40489, + 15.79424 + ], + [ + 105.34241, + 15.92039 + ], + [ + 105.37811, + 15.98344 + ], + [ + 105.39167, + 15.99136 + ], + [ + 105.41931, + 15.98608 + ], + [ + 105.42652, + 15.99764 + ], + [ + 105.41468, + 16.01661 + ], + [ + 105.21263, + 16.05076 + ], + [ + 105.04955, + 16.10552 + ], + [ + 105.01316, + 16.24401 + ], + [ + 104.88235, + 16.37812 + ], + [ + 104.8391, + 16.45782 + ], + [ + 104.77936, + 16.49041 + ], + [ + 104.73919, + 16.53287 + ], + [ + 104.74228, + 16.62205 + ], + [ + 104.76391, + 16.70953 + ], + [ + 104.73953, + 16.80323 + ], + [ + 104.76425, + 16.85088 + ], + [ + 104.73782, + 16.90968 + ], + [ + 104.744, + 17.0128 + ], + [ + 104.81266, + 17.21853 + ], + [ + 104.79841, + 17.39274 + ], + [ + 104.70348, + 17.52833 + ], + [ + 104.46384, + 17.65515 + ], + [ + 104.34368, + 17.83564 + ], + [ + 104.27776, + 17.8559 + ], + [ + 104.22661, + 17.98069 + ], + [ + 104.1116, + 18.10735 + ], + [ + 104.06525, + 18.21174 + ], + [ + 103.97392, + 18.33823 + ], + [ + 103.9286, + 18.33237 + ], + [ + 103.88809, + 18.29456 + ], + [ + 103.85582, + 18.28673 + ], + [ + 103.83659, + 18.32715 + ], + [ + 103.79128, + 18.3467 + ], + [ + 103.70201, + 18.34214 + ], + [ + 103.60931, + 18.40405 + ], + [ + 103.57292, + 18.40437 + ], + [ + 103.51593, + 18.42978 + ], + [ + 103.45963, + 18.42587 + ], + [ + 103.41568, + 18.44802 + ], + [ + 103.30479, + 18.43206 + ], + [ + 103.24265, + 18.37082 + ], + [ + 103.24333, + 18.34133 + ], + [ + 103.29123, + 18.32357 + ], + [ + 103.28899, + 18.29521 + ], + [ + 103.23595, + 18.28299 + ], + [ + 103.16608, + 18.25511 + ], + [ + 103.02429, + 17.98135 + ], + [ + 102.6535, + 17.83237 + ], + [ + 102.40631, + 17.99963 + ], + [ + 102.10968, + 18.22413 + ], + [ + 101.548, + 17.81538 + ], + [ + 101.30493, + 17.64991 + ], + [ + 101.14563, + 17.46595 + ], + [ + 100.95886, + 17.61654 + ], + [ + 101.01757, + 17.88858 + ], + [ + 101.18752, + 18.05121 + ], + [ + 101.16863, + 18.10409 + ], + [ + 101.18134, + 18.33595 + ], + [ + 101.08727, + 18.38287 + ], + [ + 101.05499, + 18.43988 + ], + [ + 101.23215, + 18.73015 + ], + [ + 101.35265, + 19.04524 + ], + [ + 101.25927, + 19.12733 + ], + [ + 101.2373, + 19.32637 + ], + [ + 101.25824, + 19.58438 + ], + [ + 101.11954, + 19.56836 + ], + [ + 101.08898, + 19.58777 + ], + [ + 101.08624, + 19.59715 + ], + [ + 101.03165, + 19.6185 + ], + [ + 100.89844, + 19.62125 + ], + [ + 100.77827, + 19.49249 + ], + [ + 100.63751, + 19.56432 + ], + [ + 100.58258, + 19.49313 + ], + [ + 100.47478, + 19.5944 + ], + [ + 100.42929, + 19.67152 + ], + [ + 100.43341, + 19.7024 + ], + [ + 100.4147, + 19.7255 + ], + [ + 100.40525, + 19.7646 + ], + [ + 100.43907, + 19.80345 + ], + [ + 100.45555, + 19.84843 + ], + [ + 100.50636, + 19.87264 + ], + [ + 100.51709, + 19.93027 + ], + [ + 100.58653, + 20.1599 + ], + [ + 100.56576, + 20.1757 + ], + [ + 100.54945, + 20.17473 + ], + [ + 100.52731, + 20.14379 + ], + [ + 100.51065, + 20.14895 + ], + [ + 100.48697, + 20.17956 + ], + [ + 100.46774, + 20.196 + ], + [ + 100.45246, + 20.20147 + ], + [ + 100.45521, + 20.22129 + ], + [ + 100.44783, + 20.23546 + ], + [ + 100.41607, + 20.25286 + ], + [ + 100.40594, + 20.28184 + ], + [ + 100.38397, + 20.31082 + ], + [ + 100.37556, + 20.35187 + ], + [ + 100.36165, + 20.35638 + ], + [ + 100.35736, + 20.37408 + ], + [ + 100.33195, + 20.39902 + ], + [ + 100.27805, + 20.40224 + ], + [ + 100.25917, + 20.39677 + ], + [ + 100.2475, + 20.37263 + ], + [ + 100.22535, + 20.35509 + ], + [ + 100.22346, + 20.31839 + ], + [ + 100.16579, + 20.29988 + ], + [ + 100.17162, + 20.24545 + ], + [ + 100.10845, + 20.25221 + ], + [ + 100.09266, + 20.2696 + ], + [ + 100.09798, + 20.31485 + ], + [ + 100.07961, + 20.3678 + ], + [ + 99.9567, + 20.46417 + ], + [ + 99.91636, + 20.44925 + ], + [ + 99.90765, + 20.44977 + ], + [ + 99.89121, + 20.44511 + ], + [ + 99.87276, + 20.44406 + ], + [ + 99.86212, + 20.44326 + ], + [ + 99.80186, + 20.33948 + ], + [ + 99.46472, + 20.3884 + ], + [ + 99.56085, + 20.20035 + ], + [ + 99.43691, + 20.08882 + ], + [ + 99.27727, + 20.11623 + ], + [ + 99.06921, + 20.1101 + ], + [ + 98.97789, + 19.74538 + ], + [ + 98.24387, + 19.68656 + ], + [ + 97.85934, + 19.57014 + ], + [ + 97.76733, + 18.57336 + ], + [ + 97.39655, + 18.47179 + ], + [ + 97.62451, + 18.30238 + ], + [ + 97.73849, + 17.97743 + ], + [ + 97.66502, + 17.87943 + ], + [ + 97.90947, + 17.56745 + ], + [ + 98.52951, + 16.82557 + ], + [ + 98.51303, + 16.69276 + ], + [ + 98.69293, + 16.26873 + ], + [ + 98.87421, + 16.43609 + ], + [ + 98.93394, + 16.3353 + ], + [ + 98.84743, + 16.13356 + ], + [ + 98.74512, + 16.12037 + ], + [ + 98.58307, + 16.07287 + ], + [ + 98.5762, + 15.79754 + ], + [ + 98.54736, + 15.37557 + ], + [ + 98.17383, + 15.15167 + ], + [ + 98.3606, + 14.63674 + ], + [ + 99.08295, + 13.89208 + ], + [ + 99.16534, + 13.72204 + ], + [ + 99.18182, + 13.00723 + ], + [ + 99.39331, + 12.56797 + ], + [ + 99.64153, + 11.78973 + ], + [ + 99.32156, + 11.30266 + ], + [ + 98.77859, + 10.67849 + ], + [ + 98.80597, + 10.47642 + ], + [ + 98.76657, + 10.40459 + ], + [ + 98.74924, + 10.34194 + ], + [ + 96.85547, + 6.40265 + ], + [ + 92.42523, + 20.54794 + ], + [ + 92.2728, + 20.96272 + ], + [ + 92.187, + 21.16 + ], + [ + 92.26, + 21.36 + ], + [ + 92.27, + 21.4328 + ], + [ + 92.62, + 21.43 + ], + [ + 92.6, + 22 + ], + [ + 93.22, + 22.25 + ], + [ + 93.4, + 23.7 + ], + [ + 93.34, + 23.95 + ], + [ + 94.155, + 23.847 + ], + [ + 94.17, + 23.92 + ], + [ + 94.25171, + 24.07405 + ], + [ + 94.28, + 24.23 + ], + [ + 94.30175, + 24.2371 + ], + [ + 94.3256, + 24.2731 + ], + [ + 94.6, + 24.7 + ], + [ + 94.78, + 25.47 + ], + [ + 95.2, + 26 + ], + [ + 95.1, + 26.6 + ], + [ + 97.3, + 27.9 + ], + [ + 96.14, + 29.38 + ], + [ + 95.4, + 29.1 + ], + [ + 94.8, + 29.2 + ], + [ + 92.5, + 27.8 + ], + [ + 91.64, + 27.76 + ], + [ + 91.4, + 28 + ], + [ + 89.58, + 28.18 + ], + [ + 88.9, + 27.32 + ], + [ + 88.74, + 27.47 + ], + [ + 88.9, + 27.86 + ], + [ + 88.7, + 28.1 + ], + [ + 88.1, + 27.87 + ], + [ + 85.93, + 27.942 + ], + [ + 81.6, + 30.5 + ], + [ + 81.2, + 30 + ], + [ + 78.73, + 31.5 + ], + [ + 78.77, + 31.99 + ], + [ + 78.4, + 32.5 + ], + [ + 79.3, + 32.5 + ], + [ + 79, + 34.3 + ], + [ + 78.3, + 34.6 + ], + [ + 78, + 35.5 + ], + [ + 76.1, + 35.8 + ], + [ + 76, + 36.55 + ], + [ + 75.15, + 37 + ], + [ + 72.5, + 36.9 + ], + [ + 71.1, + 36.1 + ], + [ + 71.65, + 35.44 + ], + [ + 71.45, + 35 + ], + [ + 70.985, + 34.54 + ], + [ + 71.18, + 34.36 + ], + [ + 71.092, + 34.118 + ], + [ + 70.88, + 33.97 + ], + [ + 70.5, + 33.94 + ], + [ + 69.908, + 34.04 + ], + [ + 69.869, + 33.96 + ], + [ + 70, + 33.75 + ], + [ + 70.13, + 33.73 + ], + [ + 70.34, + 33.34 + ], + [ + 70.013, + 33.14 + ], + [ + 69.57, + 33.09 + ], + [ + 69.24, + 32.45 + ], + [ + 69.3, + 31.9 + ], + [ + 68.1, + 31.6 + ], + [ + 66.393, + 30.934 + ], + [ + 66.2, + 29.8 + ], + [ + 62.5, + 29.4 + ], + [ + 60.87, + 29.86 + ], + [ + 61.53, + 29.0165 + ], + [ + 61.66, + 28.77 + ], + [ + 61.96, + 28.54 + ], + [ + 62.43, + 28.42 + ], + [ + 62.6, + 28.25 + ], + [ + 62.795, + 28.28 + ], + [ + 62.86, + 27.25 + ], + [ + 63.24, + 27.25 + ], + [ + 63.327, + 27.13 + ], + [ + 63.25, + 27.1 + ], + [ + 63.25, + 26.84 + ], + [ + 63.18, + 26.83 + ], + [ + 63.18, + 26.65 + ], + [ + 62.3, + 26.5 + ], + [ + 62.2, + 26.28 + ], + [ + 61.85, + 26.22 + ], + [ + 61.84, + 25.75 + ], + [ + 61.68, + 25.67 + ], + [ + 58.49, + -1.62 + ], + [ + 49.26, + -1.62 + ], + [ + 49.30, + -8.23 + ], + [ + 57.78, + -8.27 + ], + [ + 56.5, + -21 + ], + [ + 180, + -65 + ], + [ + 180, + -35 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 138.7, + 46.7 + ], + [ + 145.5, + 44.5 + ], + [ + 145.2, + 43.7 + ], + [ + 146, + 43.3 + ], + [ + 142, + 18 + ], + [ + 122, + 24.3 + ], + [ + 138.7, + 46.7 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -180, + 7 + ], + [ + -148, + 7 + ], + [ + -151, + -12 + ], + [ + -171.5, + -10.75 + ], + [ + -171, + -16 + ], + [ + -152, + -19 + ], + [ + -180, + -55 + ], + [ + -180, + 7 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -130.21, + -25.16 + ], + [ + -129.99, + -25.16 + ], + [ + -129.99, + -24.98 + ], + [ + -130.21, + -24.98 + ], + [ + -130.21, + -25.16 + ] + ] + ] + } + } + ] +} diff --git a/data/maxheight.geojson b/data/maxheight.geojson new file mode 100644 index 000000000..4799740cf --- /dev/null +++ b/data/maxheight.geojson @@ -0,0 +1,5573 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "source": "https://tunnels.piarc.org/en/operational-safety-requirements-geometry/vertical-clearance", + "maxheight": 4.60 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 11.53568658203126, + 58.863759696945536 + ], + [ + 11.451946582031237, + 58.87852151409769 + ], + [ + 11.449226582031242, + 58.987954993959185 + ], + [ + 11.341756582031264, + 59.10011882620849 + ], + [ + 11.161736582031267, + 59.06461444598701 + ], + [ + 11.12776658203125, + 59.004647051425295 + ], + [ + 11.072656582031259, + 58.963772013799435 + ], + [ + 10.64905658203124, + 58.87919159659029 + ], + [ + 10.597926582031263, + 58.747215360494565 + ], + [ + 12.911682128906252, + 55.607832700383256 + ], + [ + 12.749633789062502, + 55.372868141151756 + ], + [ + 13.145141601562502, + 55.21649013168979 + ], + [ + 14.897460937500002, + 55.36662484928637 + ], + [ + 15.424804687500002, + 55.01227627898974 + ], + [ + 12.079467773437502, + 54.5529515605619 + ], + [ + 11.1016845703125, + 54.56569261911194 + ], + [ + 10.681457519531252, + 54.49078187790844 + ], + [ + 9.953613281250002, + 54.79751835965958 + ], + [ + 9.670715332031252, + 54.83233630197071 + ], + [ + 9.596557617187502, + 54.8813470246203 + ], + [ + 9.440002441406252, + 54.81651368485388 + ], + [ + 9.401550292968752, + 54.837081878208025 + ], + [ + 9.346618652343752, + 54.795935012800115 + ], + [ + 9.250488281250002, + 54.80385112692083 + ], + [ + 9.247741699218752, + 54.84182689655073 + ], + [ + 9.154357910156252, + 54.865543621010204 + ], + [ + 9.043121337890627, + 54.86791452655591 + ], + [ + 8.940124511718752, + 54.89714423283808 + ], + [ + 8.863220214843752, + 54.88766665128539 + ], + [ + 8.833007812500002, + 54.898723612960424 + ], + [ + 8.735504150390627, + 54.88766665128539 + ], + [ + 8.643493652343752, + 54.90661958449141 + ], + [ + 8.462219238281252, + 55.05477583937859 + ], + [ + 8.033752441406252, + 55.14905799760122 + ], + [ + 4.970446582031261, + 57.65868231876128 + ], + [ + -11.365263417968754, + 71.33876369092192 + ], + [ + 9.554470582031263, + 81.00254147223497 + ], + [ + 35.52985658203126, + 81.0506683082062 + ], + [ + 33.49891658203127, + 70.87198018361804 + ], + [ + 31.588446582031263, + 70.13124977442264 + ], + [ + 31.11151658203125, + 69.96743763157777 + ], + [ + 30.83578658203124, + 69.79002367617007 + ], + [ + 30.900966582031252, + 69.7417371609734 + ], + [ + 30.901666582031257, + 69.71115303536982 + ], + [ + 30.956666582031257, + 69.68478947974779 + ], + [ + 30.94425658203123, + 69.66093626321357 + ], + [ + 30.963946582031248, + 69.63941336134145 + ], + [ + 30.965156582031245, + 69.60979936923155 + ], + [ + 30.95519658203125, + 69.57040405974075 + ], + [ + 30.92699658203127, + 69.54127013409932 + ], + [ + 30.800286582031248, + 69.51741692055988 + ], + [ + 30.517146582031238, + 69.52766830157962 + ], + [ + 30.41660658203127, + 69.5777950557564 + ], + [ + 30.239846582031266, + 69.63596289616261 + ], + [ + 30.15399658203124, + 69.65635564558814 + ], + [ + 30.112786582031262, + 69.65025482301466 + ], + [ + 30.147236582031265, + 69.6481145344475 + ], + [ + 30.20080658203125, + 69.56388318102248 + ], + [ + 30.18676658203125, + 69.52676818031561 + ], + [ + 30.131436582031245, + 69.5059453752746 + ], + [ + 30.122426582031235, + 69.45655872392044 + ], + [ + 29.996976582031273, + 69.39930101518704 + ], + [ + 29.945006582031258, + 69.3923000728333 + ], + [ + 29.86503658203126, + 69.41117261324928 + ], + [ + 29.730296582031265, + 69.37703801865143 + ], + [ + 29.701476582031255, + 69.35123454612557 + ], + [ + 29.56999658203125, + 69.30413820961301 + ], + [ + 29.39517658203125, + 69.30939891731039 + ], + [ + 29.297636582031256, + 69.28480560910381 + ], + [ + 29.291486582031233, + 69.25509161279619 + ], + [ + 29.326416582031225, + 69.2278779534536 + ], + [ + 29.301516582031265, + 69.17200044183178 + ], + [ + 29.254916582031242, + 69.13395532901575 + ], + [ + 29.252926582031257, + 69.10405131117487 + ], + [ + 29.04485658203125, + 68.99789705498348 + ], + [ + 28.85418658203125, + 69.06419595753779 + ], + [ + 28.798366582031267, + 69.11016213214663 + ], + [ + 28.82859658203127, + 69.2296581928171 + ], + [ + 29.21716658203125, + 69.40349157927409 + ], + [ + 29.323546582031252, + 69.47678144724102 + ], + [ + 29.166356582031252, + 69.62896195235317 + ], + [ + 29.130706582031237, + 69.68328927743538 + ], + [ + 28.403126582031245, + 69.80634587894737 + ], + [ + 28.326056582031264, + 69.83938033784818 + ], + [ + 28.33365658203123, + 69.8708945924355 + ], + [ + 28.158836582031228, + 69.90929977849386 + ], + [ + 27.982166582031237, + 70.00241235725733 + ], + [ + 27.955706582031254, + 70.07935275690416 + ], + [ + 27.747366582031255, + 70.0514889901135 + ], + [ + 27.623546582031228, + 70.06194040292007 + ], + [ + 27.56238658203126, + 70.04719841014615 + ], + [ + 27.53021658203125, + 70.01054345605728 + ], + [ + 27.435126582031256, + 70.00677294652054 + ], + [ + 27.30168658203127, + 69.97351845312465 + ], + [ + 27.31763658203123, + 69.95584606559208 + ], + [ + 27.302436582031255, + 69.94126409577623 + ], + [ + 27.044636582031245, + 69.89766820768617 + ], + [ + 26.97136658203125, + 69.92531194107731 + ], + [ + 26.873686582031265, + 69.921441418309 + ], + [ + 26.849126582031257, + 69.9470348753044 + ], + [ + 26.717516582031244, + 69.9324729083007 + ], + [ + 26.679686582031234, + 69.95180551975382 + ], + [ + 26.472656582031235, + 69.92714218828242 + ], + [ + 26.388476582031256, + 69.8408205322633 + ], + [ + 26.258406582031245, + 69.80551576691337 + ], + [ + 26.25411658203124, + 69.78405287043235 + ], + [ + 26.132266582031267, + 69.72250456652414 + ], + [ + 26.00203658203125, + 69.70455214505874 + ], + [ + 25.91916658203123, + 69.66387665969032 + ], + [ + 25.96450658203124, + 69.65076489178574 + ], + [ + 25.987436582031233, + 69.60233836357239 + ], + [ + 25.943326582031276, + 69.56084277132611 + ], + [ + 25.87015658203124, + 69.54161017991426 + ], + [ + 25.889426582031245, + 69.52493793374765 + ], + [ + 25.86616658203124, + 69.49131340442895 + ], + [ + 25.87558658203124, + 69.46876036702824 + ], + [ + 25.82347658203123, + 69.42733478907569 + ], + [ + 25.85842658203124, + 69.3864792893658 + ], + [ + 25.82688658203124, + 69.3491742688873 + ], + [ + 25.792516582031258, + 69.34327347487616 + ], + [ + 25.756436582031238, + 69.31007900880164 + ], + [ + 25.759586582031236, + 69.27858477238357 + ], + [ + 25.720826582031258, + 69.2437800916887 + ], + [ + 25.72581658203126, + 69.20633505710977 + ], + [ + 25.712156582031245, + 69.19483351094847 + ], + [ + 25.755706582031266, + 69.14174637593561 + ], + [ + 25.743366582031236, + 69.0753874607114 + ], + [ + 25.764546582031237, + 69.05892524964784 + ], + [ + 25.761556582031247, + 69.03712232163883 + ], + [ + 25.78774658203127, + 69.02398055698063 + ], + [ + 25.785356582031245, + 69.00449794116723 + ], + [ + 25.733726582031263, + 68.97951458730232 + ], + [ + 25.66467658203127, + 68.89630342075985 + ], + [ + 25.62945658203126, + 68.8790511063634 + ], + [ + 25.544186582031227, + 68.87337034434861 + ], + [ + 25.48418658203123, + 68.89205285052122 + ], + [ + 25.41300658203126, + 68.8797912056423 + ], + [ + 25.16670658203125, + 68.78809890958908 + ], + [ + 25.13700658203125, + 68.74506314106843 + ], + [ + 25.14408658203124, + 68.713598924666 + ], + [ + 25.125926582031276, + 68.69581654211404 + ], + [ + 25.125876582031257, + 68.62916761480164 + ], + [ + 25.073396582031247, + 68.60696464171826 + ], + [ + 24.928186582031266, + 68.59398290361123 + ], + [ + 24.90827658203123, + 68.54186592729485 + ], + [ + 24.854406582031242, + 68.55084712933024 + ], + [ + 24.781056582031262, + 68.62423695452388 + ], + [ + 24.609236582031237, + 68.66906295810915 + ], + [ + 24.251846582031245, + 68.71431902115354 + ], + [ + 24.150546582031257, + 68.74204273627615 + ], + [ + 24.149406582031258, + 68.7752571881068 + ], + [ + 24.077546582031257, + 68.76701608343382 + ], + [ + 23.983276582031245, + 68.8143624307819 + ], + [ + 23.874696582031227, + 68.82346365114338 + ], + [ + 23.784176582031257, + 68.80682141968232 + ], + [ + 23.741186582031244, + 68.74102259955994 + ], + [ + 23.678836582031256, + 68.69286614683655 + ], + [ + 23.444756582031257, + 68.679234320624 + ], + [ + 23.170916582031232, + 68.61553578938202 + ], + [ + 23.046356582031244, + 68.67633393208997 + ], + [ + 22.80161658203125, + 68.6747437190694 + ], + [ + 22.537706582031248, + 68.73130129678412 + ], + [ + 22.37485658203124, + 68.70396763419272 + ], + [ + 22.335126582031258, + 68.81767287466295 + ], + [ + 22.187756582031255, + 68.90853506179616 + ], + [ + 22.170546582031236, + 68.94656016422906 + ], + [ + 21.626456582031256, + 69.26395280447741 + ], + [ + 21.28240658203126, + 69.29882749521371 + ], + [ + 21.01326658203126, + 69.21158576300492 + ], + [ + 21.00278658203125, + 69.19133304040106 + ], + [ + 21.06543658203124, + 69.12729443400268 + ], + [ + 21.120986582031268, + 69.1039112923638 + ], + [ + 21.061786582031235, + 69.02345048580666 + ], + [ + 20.72060658203126, + 69.106411628273 + ], + [ + 20.556946582031255, + 69.0473036888853 + ], + [ + 20.10322658203126, + 69.03394189456102 + ], + [ + 20.316236582031248, + 68.93029798191368 + ], + [ + 20.34848658203124, + 68.79778020750358 + ], + [ + 20.21137658203123, + 68.6548510544982 + ], + [ + 20.059336582031243, + 68.57909090993239 + ], + [ + 19.975206582031248, + 68.55463763667012 + ], + [ + 20.231126582031262, + 68.49759000253091 + ], + [ + 20.236186582031262, + 68.48066773856169 + ], + [ + 19.927526582031234, + 68.34355940506279 + ], + [ + 18.985746582031233, + 68.50390084690395 + ], + [ + 18.622226582031235, + 68.49405953017987 + ], + [ + 18.40761658203124, + 68.56858950416982 + ], + [ + 18.137216582031265, + 68.52474363586904 + ], + [ + 18.11402658203126, + 68.4031673734345 + ], + [ + 18.164896582031233, + 68.19220918742295 + ], + [ + 17.905836582031245, + 67.9567977832248 + ], + [ + 17.665096582031236, + 68.02568696775687 + ], + [ + 17.28661658203125, + 68.10510756189967 + ], + [ + 17.185536582031244, + 68.03781858564555 + ], + [ + 16.747106582031247, + 67.9026005606139 + ], + [ + 16.566516582031248, + 67.63819536444701 + ], + [ + 16.504606582031254, + 67.58318805053749 + ], + [ + 16.41286658203126, + 67.52109979860793 + ], + [ + 16.164556582031246, + 67.5066078730695 + ], + [ + 16.10744658203124, + 67.43406823777906 + ], + [ + 16.414396582031234, + 67.20823827376161 + ], + [ + 16.398326582031252, + 67.03613547173899 + ], + [ + 16.046956582031232, + 66.90067754520484 + ], + [ + 15.634736582031234, + 66.59467711568443 + ], + [ + 15.393686582031235, + 66.47731163377327 + ], + [ + 15.493596582031236, + 66.27124448446456 + ], + [ + 15.038816582031233, + 66.14023724655831 + ], + [ + 14.532636582031246, + 66.11975455302213 + ], + [ + 14.63674658203124, + 65.81074396910465 + ], + [ + 14.541776582031261, + 65.67536622012108 + ], + [ + 14.50956658203126, + 65.51327499373848 + ], + [ + 14.516996582031235, + 65.30135728365617 + ], + [ + 14.389556582031247, + 65.2372789141067 + ], + [ + 14.33572658203125, + 65.10867212925918 + ], + [ + 14.024556582031252, + 64.87886217964262 + ], + [ + 13.676586582031254, + 64.58120347144276 + ], + [ + 13.867506582031243, + 64.51871535743416 + ], + [ + 14.092276582031234, + 64.48451091781249 + ], + [ + 14.127456582031247, + 64.46253806647697 + ], + [ + 14.17035658203125, + 64.17997144554522 + ], + [ + 13.991836582031263, + 64.00273852044663 + ], + [ + 13.213786582031261, + 64.08150870512621 + ], + [ + 12.931876582031265, + 64.04444391194332 + ], + [ + 12.693136582031268, + 63.96103313086357 + ], + [ + 12.350066582031262, + 63.715891490057416 + ], + [ + 12.305666582031252, + 63.66110442771649 + ], + [ + 12.173416582031244, + 63.59134544025311 + ], + [ + 12.204946582031255, + 63.566922294957855 + ], + [ + 12.25093658203125, + 63.4766806791202 + ], + [ + 11.99225658203125, + 63.26437338711429 + ], + [ + 12.230886582031255, + 62.99996946929797 + ], + [ + 12.088836582031266, + 62.89418592161703 + ], + [ + 12.149076582031253, + 62.74298657976717 + ], + [ + 12.070786582031246, + 62.60856940679589 + ], + [ + 12.312126582031262, + 62.26256529792048 + ], + [ + 12.152336582031241, + 61.72434696391711 + ], + [ + 12.424656582031243, + 61.56913732168368 + ], + [ + 12.574936582031253, + 61.573617888310054 + ], + [ + 12.883456582031252, + 61.35084974548805 + ], + [ + 12.84453658203126, + 61.24842682617029 + ], + [ + 12.800046582031237, + 61.18588894405436 + ], + [ + 12.718636582031234, + 61.132872265670684 + ], + [ + 12.689216582031266, + 61.046771427013255 + ], + [ + 12.612956582031236, + 61.03243962375226 + ], + [ + 12.451476582031235, + 61.03721022397256 + ], + [ + 12.243756582031255, + 61.0047961462904 + ], + [ + 12.343996582031266, + 60.891571912749406 + ], + [ + 12.347136582031238, + 60.85080679195039 + ], + [ + 12.405786582031244, + 60.73653244796702 + ], + [ + 12.52138658203124, + 60.646341138249504 + ], + [ + 12.53022658203125, + 60.60176555229897 + ], + [ + 12.591976582031238, + 60.55384955047661 + ], + [ + 12.618836582031259, + 60.51242436395807 + ], + [ + 12.617936582031254, + 60.39794004131724 + ], + [ + 12.512376582031235, + 60.313879535209885 + ], + [ + 12.554386582031258, + 60.1869936933159 + ], + [ + 12.490536582031261, + 60.06204811329414 + ], + [ + 12.34899658203126, + 59.95295452591262 + ], + [ + 12.23821658203127, + 59.91440972881 + ], + [ + 12.178816582031239, + 59.8758449310888 + ], + [ + 12.054456582031257, + 59.87195444719017 + ], + [ + 11.985556582031244, + 59.88570615771369 + ], + [ + 11.871416582031264, + 59.83480982810166 + ], + [ + 11.937466582031234, + 59.79494487266291 + ], + [ + 11.956086582031254, + 59.68919173668039 + ], + [ + 11.896116582031267, + 59.679300508778404 + ], + [ + 11.862056582031233, + 59.63493500274752 + ], + [ + 11.727906582031254, + 59.61225218863626 + ], + [ + 11.704746582031254, + 59.58588891873496 + ], + [ + 11.765386582031244, + 59.47851561008659 + ], + [ + 11.791886582031259, + 59.38711429270137 + ], + [ + 11.828776582031232, + 59.34229874750251 + ], + [ + 11.84243658203125, + 59.23619562920893 + ], + [ + 11.79565658203124, + 59.19849097098797 + ], + [ + 11.779356582031252, + 59.11489064910603 + ], + [ + 11.793506582031243, + 59.09189781182659 + ], + [ + 11.721666582031261, + 59.02230922886059 + ], + [ + 11.700516582031263, + 58.94764002621434 + ], + [ + 11.661926582031237, + 58.895003543338625 + ], + [ + 11.575666582031266, + 58.87365091450484 + ], + [ + 11.557456582031238, + 58.883352108796316 + ], + [ + 11.53568658203126, + 58.863759696945536 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "source": "https://tunnels.piarc.org/en/operational-safety-requirements-geometry/vertical-clearance", + "maxheight": 4.70 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 15.96205, + 48.802 + ], + [ + 16.0949, + 48.75043 + ], + [ + 16.34018, + 48.74916 + ], + [ + 16.39895, + 48.74517 + ], + [ + 16.45823, + 48.81096 + ], + [ + 16.51004, + 48.80534 + ], + [ + 16.54021, + 48.81873 + ], + [ + 16.61968, + 48.7888 + ], + [ + 16.66113, + 48.78688 + ], + [ + 16.73632, + 48.74051 + ], + [ + 16.77557, + 48.71796 + ], + [ + 16.91582, + 48.72533 + ], + [ + 16.94161, + 48.62055 + ], + [ + 16.95876, + 48.54549 + ], + [ + 16.95003, + 48.52128 + ], + [ + 16.92148, + 48.49319 + ], + [ + 16.86818, + 48.45311 + ], + [ + 16.86356, + 48.40326 + ], + [ + 16.84929, + 48.38014 + ], + [ + 16.8385, + 48.38292 + ], + [ + 16.83555, + 48.38072 + ], + [ + 16.91133, + 48.32528 + ], + [ + 16.90019, + 48.31199 + ], + [ + 16.92493, + 48.27645 + ], + [ + 16.95956, + 48.26423 + ], + [ + 16.95327, + 48.24222 + ], + [ + 16.96545, + 48.21421 + ], + [ + 17.00929, + 48.15746 + ], + [ + 17.05958, + 48.14571 + ], + [ + 17.07828, + 48.11644 + ], + [ + 17.09714, + 48.09903 + ], + [ + 17.09633, + 48.08961 + ], + [ + 17.08301, + 48.07855 + ], + [ + 17.09149, + 48.04724 + ], + [ + 17.14412, + 48.02304 + ], + [ + 17.16273, + 48.00808 + ], + [ + 17.10844, + 47.96939 + ], + [ + 17.12187, + 47.96152 + ], + [ + 17.11977, + 47.92778 + ], + [ + 17.09039, + 47.87319 + ], + [ + 17.03491, + 47.86025 + ], + [ + 17.08072, + 47.80555 + ], + [ + 17.06007, + 47.7935 + ], + [ + 17.10251, + 47.70674 + ], + [ + 16.83115, + 47.67714 + ], + [ + 16.75232, + 47.67924 + ], + [ + 16.60737, + 47.75624 + ], + [ + 16.54661, + 47.7339 + ], + [ + 16.55935, + 47.7209 + ], + [ + 16.47544, + 47.6777 + ], + [ + 16.43008, + 47.66502 + ], + [ + 16.51868, + 47.65056 + ], + [ + 16.58626, + 47.62199 + ], + [ + 16.62446, + 47.63161 + ], + [ + 16.65174, + 47.62709 + ], + [ + 16.67509, + 47.60663 + ], + [ + 16.68071, + 47.56934 + ], + [ + 16.71825, + 47.54049 + ], + [ + 16.70715, + 47.51267 + ], + [ + 16.66098, + 47.49821 + ], + [ + 16.67819, + 47.48318 + ], + [ + 16.6669, + 47.4547 + ], + [ + 16.5787, + 47.4034 + ], + [ + 16.5233, + 47.40482 + ], + [ + 16.49769, + 47.38692 + ], + [ + 16.45216, + 47.40554 + ], + [ + 16.46789, + 47.38408 + ], + [ + 16.45907, + 47.35651 + ], + [ + 16.43828, + 47.35205 + ], + [ + 16.46705, + 47.33745 + ], + [ + 16.49272, + 47.28394 + ], + [ + 16.48174, + 47.25831 + ], + [ + 16.44606, + 47.24606 + ], + [ + 16.44102, + 47.20929 + ], + [ + 16.42423, + 47.20387 + ], + [ + 16.45549, + 47.19132 + ], + [ + 16.46869, + 47.16935 + ], + [ + 16.45949, + 47.14623 + ], + [ + 16.51683, + 47.15459 + ], + [ + 16.53892, + 47.12719 + ], + [ + 16.47158, + 47.09483 + ], + [ + 16.53238, + 47.05695 + ], + [ + 16.47186, + 47.03437 + ], + [ + 16.51872, + 47.00027 + ], + [ + 16.48594, + 46.99213 + ], + [ + 16.43599, + 46.9907 + ], + [ + 16.28949, + 46.99671 + ], + [ + 16.279, + 46.96034 + ], + [ + 16.25423, + 46.95977 + ], + [ + 16.25255, + 46.94802 + ], + [ + 16.22149, + 46.93398 + ], + [ + 16.20302, + 46.93713 + ], + [ + 16.18371, + 46.90588 + ], + [ + 16.15013, + 46.88322 + ], + [ + 16.06073, + 46.83529 + ], + [ + 16.00043, + 46.8256 + ], + [ + 15.9965, + 46.73613 + ], + [ + 16.0326, + 46.71484 + ], + [ + 16.04729, + 46.68893 + ], + [ + 16.04347, + 46.65197 + ], + [ + 15.84539, + 46.71858 + ], + [ + 15.77307, + 46.69654 + ], + [ + 15.70939, + 46.69411 + ], + [ + 15.6565, + 46.70419 + ], + [ + 15.65818, + 46.69008 + ], + [ + 15.63048, + 46.67741 + ], + [ + 15.59438, + 46.68144 + ], + [ + 15.56297, + 46.6699 + ], + [ + 15.54569, + 46.62641 + ], + [ + 15.50707, + 46.612 + ], + [ + 15.47504, + 46.60907 + ], + [ + 15.4122, + 46.64976 + ], + [ + 15.22835, + 46.63708 + ], + [ + 15.15615, + 46.65235 + ], + [ + 15.08186, + 46.64313 + ], + [ + 15.0403, + 46.64659 + ], + [ + 14.98064, + 46.59783 + ], + [ + 14.95597, + 46.62892 + ], + [ + 14.93074, + 46.60017 + ], + [ + 14.8754, + 46.60386 + ], + [ + 14.84469, + 46.56699 + ], + [ + 14.81998, + 46.50874 + ], + [ + 14.78677, + 46.49769 + ], + [ + 14.72632, + 46.48873 + ], + [ + 14.71667, + 46.49249 + ], + [ + 14.70534, + 46.46561 + ], + [ + 14.6663, + 46.44363 + ], + [ + 14.59022, + 46.42758 + ], + [ + 14.59284, + 46.39936 + ], + [ + 14.58067, + 46.37272 + ], + [ + 14.56271, + 46.36851 + ], + [ + 14.52904, + 46.41528 + ], + [ + 14.48874, + 46.40949 + ], + [ + 14.30825, + 46.42974 + ], + [ + 14.2825, + 46.43865 + ], + [ + 14.23815, + 46.42859 + ], + [ + 14.15407, + 46.42856 + ], + [ + 14.00138, + 46.4794 + ], + [ + 13.74518, + 46.51044 + ], + [ + 13.68029, + 46.51936 + ], + [ + 13.62425, + 46.5323 + ], + [ + 13.4956, + 46.5465 + ], + [ + 13.38185, + 46.56036 + ], + [ + 13.32098, + 46.55025 + ], + [ + 13.27649, + 46.55718 + ], + [ + 13.23278, + 46.5471 + ], + [ + 12.53678, + 46.65018 + ], + [ + 12.37941, + 46.71289 + ], + [ + 12.3497, + 46.77174 + ], + [ + 12.27869, + 46.78018 + ], + [ + 12.27914, + 46.81664 + ], + [ + 12.29428, + 46.8401 + ], + [ + 12.2613, + 46.88123 + ], + [ + 12.21461, + 46.87155 + ], + [ + 12.19257, + 46.88984 + ], + [ + 12.18995, + 46.90222 + ], + [ + 12.138, + 46.91242 + ], + [ + 12.11847, + 47.01369 + ], + [ + 12.23347, + 47.0735 + ], + [ + 12.1868, + 47.08527 + ], + [ + 11.74395, + 46.96545 + ], + [ + 11.67574, + 46.98907 + ], + [ + 11.62118, + 47.00267 + ], + [ + 11.53932, + 46.98191 + ], + [ + 11.50469, + 47.00339 + ], + [ + 11.48161, + 47.00589 + ], + [ + 11.46482, + 46.97869 + ], + [ + 11.40395, + 46.96151 + ], + [ + 11.31843, + 46.98227 + ], + [ + 11.17309, + 46.94142 + ], + [ + 11.10435, + 46.90095 + ], + [ + 11.08809, + 46.82023 + ], + [ + 11.0277, + 46.76278 + ], + [ + 10.88618, + 46.76019 + ], + [ + 10.72762, + 46.78539 + ], + [ + 10.7208, + 46.79832 + ], + [ + 10.74861, + 46.82526 + ], + [ + 10.70401, + 46.84069 + ], + [ + 10.66931, + 46.86781 + ], + [ + 10.55132, + 46.83351 + ], + [ + 10.4644, + 46.8522 + ], + [ + 10.45976, + 46.88503 + ], + [ + 10.48203, + 46.93464 + ], + [ + 10.42068, + 46.95649 + ], + [ + 10.38916, + 46.99593 + ], + [ + 10.31154, + 46.91565 + ], + [ + 10.25077, + 46.92534 + ], + [ + 10.23878, + 46.86318 + ], + [ + 10.11058, + 46.8371 + ], + [ + 9.864168, + 46.93453 + ], + [ + 9.871334, + 47.00204 + ], + [ + 9.670363, + 47.05382 + ], + [ + 9.624504, + 47.05046 + ], + [ + 9.603802, + 47.05961 + ], + [ + 9.60736, + 47.08034 + ], + [ + 9.630754, + 47.08638 + ], + [ + 9.601922, + 47.14683 + ], + [ + 9.561625, + 47.1704 + ], + [ + 9.577475, + 47.20636 + ], + [ + 9.54873, + 47.22297 + ], + [ + 9.563506, + 47.24139 + ], + [ + 9.52678, + 47.27044 + ], + [ + 9.546581, + 47.28223 + ], + [ + 9.555715, + 47.29954 + ], + [ + 9.580161, + 47.31211 + ], + [ + 9.587146, + 47.31885 + ], + [ + 9.598429, + 47.34853 + ], + [ + 9.623682, + 47.36836 + ], + [ + 9.64974, + 47.37 + ], + [ + 9.668545, + 47.37909 + ], + [ + 9.670188, + 47.38933 + ], + [ + 9.650585, + 47.40376 + ], + [ + 9.643626, + 47.43845 + ], + [ + 9.652597, + 47.44515 + ], + [ + 9.657001, + 47.45192 + ], + [ + 9.642144, + 47.45491 + ], + [ + 9.622475, + 47.45612 + ], + [ + 9.614635, + 47.46217 + ], + [ + 9.609683, + 47.46933 + ], + [ + 9.604731, + 47.46031 + ], + [ + 9.593577, + 47.46229 + ], + [ + 9.581624, + 47.4789 + ], + [ + 9.557769, + 47.49771 + ], + [ + 9.548319, + 47.53856 + ], + [ + 9.733247, + 47.53553 + ], + [ + 9.734075, + 47.54719 + ], + [ + 9.740522, + 47.55778 + ], + [ + 9.747315, + 47.57102 + ], + [ + 9.761369, + 47.58736 + ], + [ + 9.775602, + 47.59688 + ], + [ + 9.788018, + 47.59533 + ], + [ + 9.806501, + 47.59848 + ], + [ + 9.827778, + 47.58678 + ], + [ + 9.828852, + 47.57692 + ], + [ + 9.828637, + 47.56039 + ], + [ + 9.823188, + 47.5504 + ], + [ + 9.852278, + 47.54241 + ], + [ + 9.871835, + 47.5324 + ], + [ + 9.874199, + 47.54415 + ], + [ + 9.879787, + 47.54966 + ], + [ + 9.906651, + 47.54603 + ], + [ + 9.92191, + 47.53356 + ], + [ + 9.969675, + 47.5492 + ], + [ + 10.00798, + 47.48769 + ], + [ + 10.04269, + 47.49132 + ], + [ + 10.09487, + 47.46272 + ], + [ + 10.11286, + 47.42786 + ], + [ + 10.08323, + 47.40833 + ], + [ + 10.09866, + 47.37182 + ], + [ + 10.17924, + 47.39571 + ], + [ + 10.22584, + 47.39201 + ], + [ + 10.24739, + 47.38713 + ], + [ + 10.20708, + 47.27987 + ], + [ + 10.33014, + 47.31402 + ], + [ + 10.41269, + 47.39916 + ], + [ + 10.46696, + 47.43529 + ], + [ + 10.4619, + 47.47773 + ], + [ + 10.44007, + 47.48312 + ], + [ + 10.42832, + 47.5024 + ], + [ + 10.45098, + 47.55427 + ], + [ + 10.43042, + 47.56758 + ], + [ + 10.42781, + 47.57908 + ], + [ + 10.43387, + 47.5853 + ], + [ + 10.47398, + 47.58865 + ], + [ + 10.48562, + 47.58565 + ], + [ + 10.47616, + 47.5693 + ], + [ + 10.45848, + 47.55557 + ], + [ + 10.56881, + 47.53863 + ], + [ + 10.57848, + 47.55658 + ], + [ + 10.59567, + 47.57126 + ], + [ + 10.69507, + 47.55821 + ], + [ + 10.7934, + 47.52393 + ], + [ + 10.85277, + 47.53572 + ], + [ + 10.89233, + 47.53786 + ], + [ + 10.92111, + 47.51998 + ], + [ + 10.92153, + 47.51119 + ], + [ + 10.87536, + 47.48709 + ], + [ + 10.91397, + 47.49077 + ], + [ + 10.94126, + 47.48226 + ], + [ + 10.9379, + 47.46921 + ], + [ + 10.99183, + 47.42552 + ], + [ + 10.9754, + 47.40061 + ], + [ + 11.10775, + 47.40086 + ], + [ + 11.11877, + 47.41293 + ], + [ + 11.2043, + 47.43636 + ], + [ + 11.25152, + 47.43601 + ], + [ + 11.26071, + 47.43081 + ], + [ + 11.23473, + 47.40335 + ], + [ + 11.27503, + 47.40022 + ], + [ + 11.28848, + 47.42908 + ], + [ + 11.33281, + 47.4502 + ], + [ + 11.40736, + 47.45225 + ], + [ + 11.37881, + 47.47245 + ], + [ + 11.40568, + 47.49878 + ], + [ + 11.44462, + 47.52157 + ], + [ + 11.53158, + 47.5124 + ], + [ + 11.57358, + 47.52168 + ], + [ + 11.58029, + 47.55048 + ], + [ + 11.60514, + 47.58288 + ], + [ + 11.63478, + 47.59578 + ], + [ + 11.8439, + 47.59035 + ], + [ + 11.85498, + 47.60462 + ], + [ + 11.91106, + 47.61458 + ], + [ + 12.00811, + 47.62635 + ], + [ + 12.02423, + 47.6182 + ], + [ + 12.06318, + 47.62046 + ], + [ + 12.13068, + 47.60915 + ], + [ + 12.18062, + 47.61739 + ], + [ + 12.18371, + 47.60597 + ], + [ + 12.20403, + 47.60835 + ], + [ + 12.20249, + 47.62557 + ], + [ + 12.18809, + 47.65337 + ], + [ + 12.16617, + 47.68102 + ], + [ + 12.15913, + 47.70162 + ], + [ + 12.25269, + 47.74609 + ], + [ + 12.27644, + 47.74362 + ], + [ + 12.25773, + 47.69616 + ], + [ + 12.44206, + 47.70194 + ], + [ + 12.51121, + 47.6268 + ], + [ + 12.62362, + 47.68957 + ], + [ + 12.78759, + 47.68198 + ], + [ + 12.83877, + 47.6183 + ], + [ + 12.82647, + 47.55859 + ], + [ + 13.00502, + 47.48139 + ], + [ + 13.03279, + 47.55524 + ], + [ + 13.03136, + 47.58101 + ], + [ + 13.08234, + 47.63644 + ], + [ + 13.06733, + 47.68431 + ], + [ + 13.03764, + 47.70612 + ], + [ + 12.99187, + 47.70445 + ], + [ + 12.92438, + 47.70807 + ], + [ + 12.901, + 47.72516 + ], + [ + 12.91707, + 47.7445 + ], + [ + 12.93233, + 47.75013 + ], + [ + 12.94136, + 47.76415 + ], + [ + 12.9405, + 47.76935 + ], + [ + 12.92481, + 47.76906 + ], + [ + 12.9362, + 47.78495 + ], + [ + 12.96049, + 47.79924 + ], + [ + 12.98176, + 47.8271 + ], + [ + 13.0023, + 47.84879 + ], + [ + 12.96608, + 47.89415 + ], + [ + 12.93078, + 47.93129 + ], + [ + 12.87254, + 47.9594 + ], + [ + 12.84473, + 48.01138 + ], + [ + 12.75554, + 48.07242 + ], + [ + 12.74356, + 48.0972 + ], + [ + 12.74938, + 48.12599 + ], + [ + 12.82794, + 48.16035 + ], + [ + 12.8652, + 48.20303 + ], + [ + 12.9523, + 48.21282 + ], + [ + 13.01211, + 48.2586 + ], + [ + 13.07298, + 48.27816 + ], + [ + 13.17529, + 48.29771 + ], + [ + 13.27341, + 48.30225 + ], + [ + 13.33952, + 48.33784 + ], + [ + 13.41322, + 48.39928 + ], + [ + 13.43693, + 48.43378 + ], + [ + 13.4251, + 48.45659 + ], + [ + 13.43527, + 48.47611 + ], + [ + 13.45398, + 48.5112 + ], + [ + 13.44325, + 48.52296 + ], + [ + 13.44009, + 48.54407 + ], + [ + 13.43569, + 48.55155 + ], + [ + 13.43651, + 48.55811 + ], + [ + 13.45109, + 48.56503 + ], + [ + 13.46416, + 48.55574 + ], + [ + 13.47214, + 48.55729 + ], + [ + 13.47269, + 48.56284 + ], + [ + 13.47888, + 48.56575 + ], + [ + 13.4874, + 48.56412 + ], + [ + 13.48988, + 48.56976 + ], + [ + 13.50542, + 48.57604 + ], + [ + 13.4991, + 48.58359 + ], + [ + 13.51053, + 48.59392 + ], + [ + 13.52759, + 48.58871 + ], + [ + 13.57561, + 48.56161 + ], + [ + 13.58535, + 48.57094 + ], + [ + 13.60348, + 48.57072 + ], + [ + 13.62631, + 48.5565 + ], + [ + 13.65049, + 48.55138 + ], + [ + 13.72544, + 48.51595 + ], + [ + 13.73176, + 48.52604 + ], + [ + 13.74552, + 48.53382 + ], + [ + 13.74116, + 48.54183 + ], + [ + 13.74385, + 48.55583 + ], + [ + 13.75761, + 48.56828 + ], + [ + 13.7697, + 48.55827 + ], + [ + 13.79933, + 48.57673 + ], + [ + 13.79791, + 48.59782 + ], + [ + 13.8194, + 48.6218 + ], + [ + 13.81, + 48.64954 + ], + [ + 13.81403, + 48.67327 + ], + [ + 13.79246, + 48.71483 + ], + [ + 13.8147, + 48.73577 + ], + [ + 13.81772, + 48.75569 + ], + [ + 13.83754, + 48.77495 + ], + [ + 13.86474, + 48.77473 + ], + [ + 13.89081, + 48.7612 + ], + [ + 14.00913, + 48.70763 + ], + [ + 14.06286, + 48.67505 + ], + [ + 14.05969, + 48.65359 + ], + [ + 14.01788, + 48.63921 + ], + [ + 14.05749, + 48.62535 + ], + [ + 14.11155, + 48.59316 + ], + [ + 14.12834, + 48.60049 + ], + [ + 14.19248, + 48.59471 + ], + [ + 14.2724, + 48.58272 + ], + [ + 14.32815, + 48.56516 + ], + [ + 14.33285, + 48.55472 + ], + [ + 14.35626, + 48.57654 + ], + [ + 14.3902, + 48.57679 + ], + [ + 14.38147, + 48.59588 + ], + [ + 14.42922, + 48.59427 + ], + [ + 14.44911, + 48.62737 + ], + [ + 14.43659, + 48.64515 + ], + [ + 14.4697, + 48.65237 + ], + [ + 14.56203, + 48.61427 + ], + [ + 14.6104, + 48.63486 + ], + [ + 14.69151, + 48.58724 + ], + [ + 14.70828, + 48.651 + ], + [ + 14.72246, + 48.69528 + ], + [ + 14.75577, + 48.71117 + ], + [ + 14.79295, + 48.73173 + ], + [ + 14.80595, + 48.78141 + ], + [ + 14.83099, + 48.78769 + ], + [ + 14.87763, + 48.78344 + ], + [ + 14.9565, + 48.76347 + ], + [ + 14.97563, + 48.77254 + ], + [ + 14.97477, + 48.77976 + ], + [ + 14.94724, + 48.79161 + ], + [ + 14.96848, + 48.84614 + ], + [ + 14.97335, + 48.96965 + ], + [ + 14.99015, + 49.02403 + ], + [ + 15.05992, + 49.01914 + ], + [ + 15.16145, + 48.99495 + ], + [ + 15.18257, + 48.95889 + ], + [ + 15.25275, + 48.96449 + ], + [ + 15.27767, + 48.99806 + ], + [ + 15.3708, + 48.98343 + ], + [ + 15.46918, + 48.95501 + ], + [ + 15.5774, + 48.90072 + ], + [ + 15.61741, + 48.90201 + ], + [ + 15.74858, + 48.85715 + ], + [ + 15.76957, + 48.87743 + ], + [ + 15.84434, + 48.87959 + ], + [ + 15.96303, + 48.82584 + ], + [ + 15.96205, + 48.802 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "source": "https://tunnels.piarc.org/en/operational-safety-requirements-geometry/vertical-clearance", + "maxheight": 4.90 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + -124.94750976562501, + 48.531157010976735 + ], + [ + -123.58520507812501, + 48.22467264956519 + ], + [ + -123.10180664062501, + 48.42920055556841 + ], + [ + -123.24462890625001, + 48.67645370777654 + ], + [ + -122.99194335937501, + 48.84302835299519 + ], + [ + -123.32153320312501, + 49.009050809382074 + ], + [ + -95.18554687500001, + 48.99463598353408 + ], + [ + -95.14160156250001, + 49.41812070066643 + ], + [ + -94.82299804687501, + 49.33944093715549 + ], + [ + -94.59228515625001, + 48.71271258145237 + ], + [ + -93.438720703125, + 48.60385760823255 + ], + [ + -93.1201171875, + 48.669198799260066 + ], + [ + -91.38427734375001, + 48.06339653776214 + ], + [ + -90.85693359375001, + 48.26125565204099 + ], + [ + -89.3408203125, + 47.989921667414194 + ], + [ + -88.37402343750001, + 48.31242790407178 + ], + [ + -84.79248046875001, + 46.882723010671945 + ], + [ + -84.57275390625, + 46.4605655457854 + ], + [ + -84.13330078125001, + 46.543749602738565 + ], + [ + -83.9794921875, + 46.03510927947337 + ], + [ + -83.64990234375001, + 46.13417004624326 + ], + [ + -83.45214843750001, + 46.01222384063236 + ], + [ + -83.57299804687501, + 45.81348649679973 + ], + [ + -82.47436523437501, + 45.31352900692261 + ], + [ + -82.408447265625, + 43.02071359427862 + ], + [ + -82.50732421875001, + 42.56926437219384 + ], + [ + -83.16650390625001, + 42.147114459221015 + ], + [ + -83.13354492187501, + 41.88592102814744 + ], + [ + -78.87084960937501, + 42.88401467044253 + ], + [ + -79.22241210937501, + 43.492782808225 + ], + [ + -75.87158203125001, + 44.41808794374849 + ], + [ + -74.93774414062501, + 45.042478050891546 + ], + [ + -71.51000976562501, + 45.02695045318546 + ], + [ + -71.31225585937501, + 45.31352900692261 + ], + [ + -70.65307617187501, + 45.42929873257377 + ], + [ + -70.00488281250001, + 46.68713141244413 + ], + [ + -69.22485351562501, + 47.46523622438362 + ], + [ + -68.90625000000001, + 47.17477833929906 + ], + [ + -68.30200195312501, + 47.368594345213374 + ], + [ + -67.77465820312501, + 47.07012182383309 + ], + [ + -67.78564453125001, + 45.66780526567164 + ], + [ + -67.41210937500001, + 45.590978249451936 + ], + [ + -67.43408203125001, + 45.390735154248894 + ], + [ + -67.48901367187501, + 45.26715476332794 + ], + [ + -67.34619140625001, + 45.120052841530544 + ], + [ + -67.28027343750001, + 45.19752230305685 + ], + [ + -66.88476562500001, + 44.86365630540613 + ], + [ + -81.10107421875001, + 23.40276490540795 + ], + [ + -97.49267578125001, + 25.878994400196202 + ], + [ + -97.80029296875001, + 26.05678288577881 + ], + [ + -98.23974609375001, + 26.07652055985697 + ], + [ + -99.12963867187501, + 26.401710528707707 + ], + [ + -99.459228515625, + 27.039556602163195 + ], + [ + -99.53613281250001, + 27.595934774495056 + ], + [ + -100.37109375, + 28.362401735238237 + ], + [ + -100.92041015625001, + 29.32472016151103 + ], + [ + -101.49169921875001, + 29.754839972510933 + ], + [ + -102.66723632812501, + 29.76437737516313 + ], + [ + -103.13964843750001, + 28.950475674848008 + ], + [ + -104.51293945312501, + 29.602118211647333 + ], + [ + -104.996337890625, + 30.637912028341123 + ], + [ + -106.46850585937501, + 31.662732913235317 + ], + [ + -108.21533203125001, + 31.784216884487385 + ], + [ + -108.21533203125001, + 31.31610138349565 + ], + [ + -111.104736328125, + 31.306715155075167 + ], + [ + -114.82910156250001, + 32.491230287947594 + ], + [ + -114.74121093750001, + 32.704111144407406 + ], + [ + -117.14721679687501, + 32.52828936482526 + ], + [ + -125.46386718750001, + 33.284619968887675 + ], + [ + -124.94750976562501, + 48.531157010976735 + ] + ] + ], + [ + [ + [ + -141.50390625000003, + 72.20867825343294 + ], + [ + -140.99853515625003, + 60.326947742998414 + ], + [ + -137.43896484375003, + 58.97266715450153 + ], + [ + -135.48339843750003, + 59.81168490365651 + ], + [ + -133.39599609375003, + 58.436233157945246 + ], + [ + -131.77001953125003, + 56.607885465009254 + ], + [ + -130.01220703125003, + 56.07203547180089 + ], + [ + -129.96826171875003, + 55.25407706707272 + ], + [ + -130.69335937500003, + 54.635697306063854 + ], + [ + -180.21972656250003, + 50.88917404890332 + ], + [ + -172.44140625000003, + 63.99523519297698 + ], + [ + -169.0191650390625, + 65.68769190893039 + ], + [ + -165.32226562500003, + 71.04552881933586 + ], + [ + -141.50390625000003, + 72.20867825343294 + ] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "source": "https://tunnels.piarc.org/en/operational-safety-requirements-geometry/vertical-clearance", + "maxheight": 5.00 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -1.818554, + 35.89823 + ], + [ + -2.159529, + 35.7798 + ], + [ + -2.912861, + 35.28711 + ], + [ + -2.929856, + 35.26917 + ], + [ + -2.949118, + 35.26393 + ], + [ + -2.952387, + 35.26424 + ], + [ + -2.972404, + 35.2854 + ], + [ + -2.972424, + 35.28546 + ], + [ + -2.970666, + 35.29861 + ], + [ + -2.964749, + 35.31337 + ], + [ + -2.95959, + 35.31872 + ], + [ + -2.946335, + 35.32466 + ], + [ + -2.914235, + 35.3535 + ], + [ + -2.922474, + 35.47214 + ], + [ + -2.974415, + 35.46091 + ], + [ + -3.128324, + 35.64784 + ], + [ + -5.011109, + 35.73553 + ], + [ + -5.254818, + 35.76327 + ], + [ + -5.342838, + 35.86857 + ], + [ + -5.355773, + 35.87211 + ], + [ + -5.373401, + 35.87996 + ], + [ + -5.398531, + 35.93988 + ], + [ + -5.630473, + 35.91539 + ], + [ + -7.24104, + 35.99849 + ], + [ + -7.409518, + 37.18382 + ], + [ + -7.418941, + 37.2344 + ], + [ + -7.435973, + 37.248 + ], + [ + -7.429025, + 37.27275 + ], + [ + -7.443071, + 37.31069 + ], + [ + -7.447286, + 37.34549 + ], + [ + -7.438652, + 37.35778 + ], + [ + -7.442216, + 37.39151 + ], + [ + -7.464218, + 37.40871 + ], + [ + -7.458467, + 37.42509 + ], + [ + -7.475205, + 37.48907 + ], + [ + -7.492704, + 37.50539 + ], + [ + -7.492083, + 37.51954 + ], + [ + -7.511516, + 37.52181 + ], + [ + -7.52466, + 37.55333 + ], + [ + -7.505928, + 37.60388 + ], + [ + -7.458483, + 37.66085 + ], + [ + -7.44883, + 37.69644 + ], + [ + -7.426996, + 37.74979 + ], + [ + -7.334776, + 37.81999 + ], + [ + -7.295428, + 37.85576 + ], + [ + -7.288272, + 37.89969 + ], + [ + -7.257528, + 37.92893 + ], + [ + -7.265678, + 37.98547 + ], + [ + -7.208883, + 38.00409 + ], + [ + -7.126276, + 38.00631 + ], + [ + -7.149093, + 38.03754 + ], + [ + -7.10563, + 38.0478 + ], + [ + -7.058503, + 38.02424 + ], + [ + -7.009676, + 38.02608 + ], + [ + -7.001054, + 38.04773 + ], + [ + -6.96579, + 38.13198 + ], + [ + -6.971, + 38.1718 + ], + [ + -6.941072, + 38.20297 + ], + [ + -7.004829, + 38.1998 + ], + [ + -7.021836, + 38.1827 + ], + [ + -7.092493, + 38.16507 + ], + [ + -7.144944, + 38.23924 + ], + [ + -7.144371, + 38.25259 + ], + [ + -7.172138, + 38.27751 + ], + [ + -7.230131, + 38.35325 + ], + [ + -7.263894, + 38.38191 + ], + [ + -7.289613, + 38.42548 + ], + [ + -7.333373, + 38.44314 + ], + [ + -7.308567, + 38.4683 + ], + [ + -7.323689, + 38.47703 + ], + [ + -7.314707, + 38.51229 + ], + [ + -7.303838, + 38.54285 + ], + [ + -7.257271, + 38.61414 + ], + [ + -7.272166, + 38.6362 + ], + [ + -7.266327, + 38.7032 + ], + [ + -7.256955, + 38.72873 + ], + [ + -7.161649, + 38.7852 + ], + [ + -7.130998, + 38.81736 + ], + [ + -7.094854, + 38.821 + ], + [ + -7.068198, + 38.85579 + ], + [ + -7.036684, + 38.8765 + ], + [ + -7.051758, + 38.90804 + ], + [ + -7.027884, + 38.92185 + ], + [ + -7.02214, + 38.93947 + ], + [ + -6.955925, + 39.02731 + ], + [ + -6.975859, + 39.03869 + ], + [ + -6.974794, + 39.07525 + ], + [ + -7.033652, + 39.11515 + ], + [ + -7.111249, + 39.09436 + ], + [ + -7.152532, + 39.11232 + ], + [ + -7.135309, + 39.16798 + ], + [ + -7.207901, + 39.18443 + ], + [ + -7.241946, + 39.20291 + ], + [ + -7.250007, + 39.25687 + ], + [ + -7.23709, + 39.27669 + ], + [ + -7.309119, + 39.33414 + ], + [ + -7.325055, + 39.3816 + ], + [ + -7.305234, + 39.41759 + ], + [ + -7.311043, + 39.43591 + ], + [ + -7.300163, + 39.46043 + ], + [ + -7.363802, + 39.48042 + ], + [ + -7.389969, + 39.49233 + ], + [ + -7.394287, + 39.52668 + ], + [ + -7.438688, + 39.53429 + ], + [ + -7.462762, + 39.57122 + ], + [ + -7.497387, + 39.58432 + ], + [ + -7.524867, + 39.62766 + ], + [ + -7.54369, + 39.66918 + ], + [ + -7.425393, + 39.66114 + ], + [ + -7.357485, + 39.64975 + ], + [ + -7.311708, + 39.66345 + ], + [ + -7.268826, + 39.66884 + ], + [ + -7.163162, + 39.66336 + ], + [ + -7.114347, + 39.66608 + ], + [ + -7.064255, + 39.66157 + ], + [ + -7.020435, + 39.67235 + ], + [ + -6.995676, + 39.72512 + ], + [ + -6.989638, + 39.80901 + ], + [ + -6.981901, + 39.82359 + ], + [ + -6.951758, + 39.83019 + ], + [ + -6.935609, + 39.84957 + ], + [ + -6.906468, + 39.87141 + ], + [ + -6.904938, + 39.90689 + ], + [ + -6.874505, + 40.01954 + ], + [ + -6.883362, + 40.03869 + ], + [ + -6.94143, + 40.11268 + ], + [ + -7.018514, + 40.12549 + ], + [ + -7.017838, + 40.22379 + ], + [ + -6.99709, + 40.2488 + ], + [ + -6.944708, + 40.26155 + ], + [ + -6.93333, + 40.27792 + ], + [ + -6.865942, + 40.28403 + ], + [ + -6.865469, + 40.30181 + ], + [ + -6.820871, + 40.32719 + ], + [ + -6.79671, + 40.33083 + ], + [ + -6.793289, + 40.36878 + ], + [ + -6.83655, + 40.40632 + ], + [ + -6.851932, + 40.45361 + ], + [ + -6.820193, + 40.49855 + ], + [ + -6.80452, + 40.51169 + ], + [ + -6.807519, + 40.5514 + ], + [ + -6.846561, + 40.56506 + ], + [ + -6.840079, + 40.59333 + ], + [ + -6.80314, + 40.65403 + ], + [ + -6.811622, + 40.69742 + ], + [ + -6.831865, + 40.74223 + ], + [ + -6.831341, + 40.77023 + ], + [ + -6.820956, + 40.80142 + ], + [ + -6.828272, + 40.84586 + ], + [ + -6.803395, + 40.84824 + ], + [ + -6.810547, + 40.88045 + ], + [ + -6.830377, + 40.87994 + ], + [ + -6.850531, + 40.90085 + ], + [ + -6.860021, + 40.94147 + ], + [ + -6.933364, + 41.01432 + ], + [ + -6.930643, + 41.03147 + ], + [ + -6.91555, + 41.04085 + ], + [ + -6.865731, + 41.02923 + ], + [ + -6.818519, + 41.03571 + ], + [ + -6.780447, + 41.07355 + ], + [ + -6.758287, + 41.10478 + ], + [ + -6.776736, + 41.1285 + ], + [ + -6.702551, + 41.18846 + ], + [ + -6.693919, + 41.20909 + ], + [ + -6.649343, + 41.24942 + ], + [ + -6.590002, + 41.25803 + ], + [ + -6.572309, + 41.24112 + ], + [ + -6.522519, + 41.27795 + ], + [ + -6.493552, + 41.28732 + ], + [ + -6.397614, + 41.36369 + ], + [ + -6.393228, + 41.38594 + ], + [ + -6.366379, + 41.39698 + ], + [ + -6.334733, + 41.38723 + ], + [ + -6.334772, + 41.41522 + ], + [ + -6.297736, + 41.4363 + ], + [ + -6.307896, + 41.4487 + ], + [ + -6.258245, + 41.51488 + ], + [ + -6.246205, + 41.5172 + ], + [ + -6.196614, + 41.58026 + ], + [ + -6.19801, + 41.58996 + ], + [ + -6.23457, + 41.60482 + ], + [ + -6.285455, + 41.65226 + ], + [ + -6.349487, + 41.6738 + ], + [ + -6.374641, + 41.67264 + ], + [ + -6.439706, + 41.68 + ], + [ + -6.456095, + 41.66667 + ], + [ + -6.498993, + 41.65298 + ], + [ + -6.547404, + 41.68064 + ], + [ + -6.556521, + 41.6968 + ], + [ + -6.556168, + 41.72065 + ], + [ + -6.571633, + 41.74422 + ], + [ + -6.556137, + 41.76815 + ], + [ + -6.547637, + 41.79538 + ], + [ + -6.523529, + 41.87339 + ], + [ + -6.574293, + 41.88182 + ], + [ + -6.548705, + 41.93965 + ], + [ + -6.585526, + 41.96432 + ], + [ + -6.59895, + 41.94696 + ], + [ + -6.617454, + 41.93895 + ], + [ + -6.670349, + 41.93623 + ], + [ + -6.696975, + 41.93063 + ], + [ + -6.750448, + 41.94124 + ], + [ + -6.779019, + 41.98692 + ], + [ + -6.803122, + 41.98357 + ], + [ + -6.821389, + 41.94297 + ], + [ + -6.892903, + 41.9384 + ], + [ + -6.943012, + 41.94185 + ], + [ + -6.96766, + 41.97109 + ], + [ + -7.009467, + 41.9474 + ], + [ + -7.070791, + 41.94686 + ], + [ + -7.140343, + 41.98889 + ], + [ + -7.157407, + 41.97496 + ], + [ + -7.176346, + 41.97776 + ], + [ + -7.184385, + 41.96931 + ], + [ + -7.180775, + 41.95157 + ], + [ + -7.182549, + 41.9408 + ], + [ + -7.1719, + 41.91911 + ], + [ + -7.18261, + 41.8978 + ], + [ + -7.19575, + 41.87838 + ], + [ + -7.231034, + 41.86564 + ], + [ + -7.253169, + 41.86227 + ], + [ + -7.308816, + 41.84212 + ], + [ + -7.356211, + 41.83808 + ], + [ + -7.383649, + 41.84035 + ], + [ + -7.395982, + 41.82119 + ], + [ + -7.427711, + 41.80443 + ], + [ + -7.44617, + 41.83703 + ], + [ + -7.452914, + 41.86243 + ], + [ + -7.485302, + 41.85973 + ], + [ + -7.492484, + 41.86885 + ], + [ + -7.509791, + 41.86342 + ], + [ + -7.503777, + 41.8492 + ], + [ + -7.540135, + 41.83039 + ], + [ + -7.61696, + 41.82602 + ], + [ + -7.614216, + 41.84606 + ], + [ + -7.60408, + 41.8664 + ], + [ + -7.589016, + 41.87769 + ], + [ + -7.608166, + 41.87799 + ], + [ + -7.61732, + 41.88218 + ], + [ + -7.628218, + 41.87786 + ], + [ + -7.659008, + 41.88081 + ], + [ + -7.699954, + 41.90597 + ], + [ + -7.728164, + 41.89519 + ], + [ + -7.742938, + 41.89155 + ], + [ + -7.759747, + 41.89725 + ], + [ + -7.783253, + 41.8828 + ], + [ + -7.836983, + 41.8778 + ], + [ + -7.844844, + 41.86234 + ], + [ + -7.876202, + 41.84818 + ], + [ + -7.893359, + 41.85782 + ], + [ + -7.885557, + 41.88348 + ], + [ + -7.888482, + 41.9054 + ], + [ + -7.886263, + 41.92446 + ], + [ + -7.902097, + 41.92475 + ], + [ + -7.918194, + 41.87878 + ], + [ + -7.945466, + 41.86967 + ], + [ + -7.979411, + 41.87092 + ], + [ + -8.011658, + 41.82768 + ], + [ + -8.032384, + 41.82772 + ], + [ + -8.055235, + 41.81432 + ], + [ + -8.092522, + 41.80708 + ], + [ + -8.121925, + 41.80559 + ], + [ + -8.166208, + 41.81538 + ], + [ + -8.163151, + 41.84809 + ], + [ + -8.170953, + 41.87479 + ], + [ + -8.200421, + 41.87304 + ], + [ + -8.204429, + 41.88911 + ], + [ + -8.215463, + 41.89563 + ], + [ + -8.218676, + 41.91185 + ], + [ + -8.200837, + 41.93898 + ], + [ + -8.178815, + 41.95567 + ], + [ + -8.165175, + 41.98401 + ], + [ + -8.141554, + 41.99046 + ], + [ + -8.131392, + 42.0058 + ], + [ + -8.087552, + 42.01714 + ], + [ + -8.087117, + 42.04741 + ], + [ + -8.098351, + 42.06801 + ], + [ + -8.12067, + 42.07929 + ], + [ + -8.171158, + 42.06441 + ], + [ + -8.187058, + 42.06623 + ], + [ + -8.197219, + 42.14451 + ], + [ + -8.229789, + 42.12874 + ], + [ + -8.240965, + 42.1364 + ], + [ + -8.258106, + 42.11996 + ], + [ + -8.315034, + 42.09756 + ], + [ + -8.332577, + 42.0822 + ], + [ + -8.361762, + 42.08588 + ], + [ + -8.386772, + 42.07302 + ], + [ + -8.402614, + 42.07887 + ], + [ + -8.418031, + 42.07165 + ], + [ + -8.429879, + 42.07022 + ], + [ + -8.446635, + 42.08132 + ], + [ + -8.525221, + 42.07546 + ], + [ + -8.523042, + 42.06443 + ], + [ + -8.534481, + 42.05632 + ], + [ + -8.556676, + 42.04984 + ], + [ + -8.571732, + 42.04918 + ], + [ + -8.592822, + 42.05361 + ], + [ + -8.633125, + 42.04498 + ], + [ + -8.653943, + 42.02721 + ], + [ + -8.659507, + 42.00363 + ], + [ + -8.678779, + 41.98933 + ], + [ + -8.719833, + 41.97415 + ], + [ + -8.738811, + 41.95841 + ], + [ + -8.747477, + 41.93935 + ], + [ + -8.764076, + 41.92557 + ], + [ + -8.785824, + 41.91344 + ], + [ + -8.8106, + 41.90503 + ], + [ + -8.829854, + 41.89206 + ], + [ + -8.845999, + 41.86375 + ], + [ + -9.498331, + 41.83423 + ], + [ + -9.779014, + 44.14855 + ], + [ + -1.792107, + 43.59992 + ], + [ + -1.772577, + 43.38897 + ], + [ + -1.789457, + 43.37277 + ], + [ + -1.778506, + 43.36299 + ], + [ + -1.786696, + 43.35398 + ], + [ + -1.774529, + 43.34685 + ], + [ + -1.755642, + 43.34497 + ], + [ + -1.736611, + 43.33042 + ], + [ + -1.73545, + 43.31262 + ], + [ + -1.726584, + 43.29936 + ], + [ + -1.698654, + 43.31224 + ], + [ + -1.667835, + 43.31655 + ], + [ + -1.621838, + 43.30707 + ], + [ + -1.623173, + 43.272 + ], + [ + -1.613853, + 43.25738 + ], + [ + -1.577177, + 43.25438 + ], + [ + -1.565446, + 43.26425 + ], + [ + -1.565568, + 43.29008 + ], + [ + -1.535998, + 43.29558 + ], + [ + -1.506227, + 43.2946 + ], + [ + -1.440086, + 43.26861 + ], + [ + -1.408404, + 43.27522 + ], + [ + -1.377843, + 43.25158 + ], + [ + -1.375143, + 43.23416 + ], + [ + -1.382005, + 43.18872 + ], + [ + -1.401346, + 43.15601 + ], + [ + -1.413043, + 43.12741 + ], + [ + -1.425645, + 43.11482 + ], + [ + -1.468428, + 43.09227 + ], + [ + -1.466093, + 43.07671 + ], + [ + -1.439523, + 43.04731 + ], + [ + -1.355446, + 43.03014 + ], + [ + -1.344981, + 43.05251 + ], + [ + -1.347241, + 43.09268 + ], + [ + -1.328052, + 43.11526 + ], + [ + -1.26689, + 43.12027 + ], + [ + -1.305566, + 43.07442 + ], + [ + -1.25296, + 43.04671 + ], + [ + -1.227127, + 43.05675 + ], + [ + -1.164062, + 43.03628 + ], + [ + -1.134337, + 43.02228 + ], + [ + -1.113169, + 43.02584 + ], + [ + -1.085716, + 43.0118 + ], + [ + -1.084175, + 43.00342 + ], + [ + -1.011938, + 42.99397 + ], + [ + -0.946467, + 42.95466 + ], + [ + -0.927226, + 42.95646 + ], + [ + -0.924265, + 42.96289 + ], + [ + -0.899058, + 42.96293 + ], + [ + -0.827676, + 42.95245 + ], + [ + -0.771521, + 42.97019 + ], + [ + -0.747595, + 42.9689 + ], + [ + -0.722264, + 42.93222 + ], + [ + -0.73039, + 42.89953 + ], + [ + -0.699914, + 42.88009 + ], + [ + -0.67868, + 42.88589 + ], + [ + -0.599915, + 42.82803 + ], + [ + -0.592894, + 42.81232 + ], + [ + -0.567673, + 42.8066 + ], + [ + -0.560704, + 42.79148 + ], + [ + -0.52524, + 42.79667 + ], + [ + -0.527971, + 42.80867 + ], + [ + -0.523062, + 42.81804 + ], + [ + -0.503151, + 42.83012 + ], + [ + -0.445795, + 42.80265 + ], + [ + -0.367787, + 42.81515 + ], + [ + -0.351347, + 42.83844 + ], + [ + -0.334308, + 42.84016 + ], + [ + -0.328082, + 42.83603 + ], + [ + -0.313549, + 42.85068 + ], + [ + -0.242137, + 42.82443 + ], + [ + -0.178017, + 42.78646 + ], + [ + -0.161215, + 42.79884 + ], + [ + -0.157086, + 42.79823 + ], + [ + -0.10362, + 42.72835 + ], + [ + -0.064948, + 42.71773 + ], + [ + -0.056935, + 42.69819 + ], + [ + 0.000665, + 42.68714 + ], + [ + 0.013672, + 42.70322 + ], + [ + 0.064537, + 42.70399 + ], + [ + 0.080973, + 42.71942 + ], + [ + 0.130961, + 42.71505 + ], + [ + 0.135088, + 42.72291 + ], + [ + 0.175668, + 42.73892 + ], + [ + 0.261336, + 42.71815 + ], + [ + 0.277292, + 42.68763 + ], + [ + 0.319069, + 42.68562 + ], + [ + 0.324853, + 42.70565 + ], + [ + 0.360075, + 42.72487 + ], + [ + 0.392605, + 42.71422 + ], + [ + 0.433277, + 42.69262 + ], + [ + 0.475484, + 42.70213 + ], + [ + 0.512661, + 42.69261 + ], + [ + 0.528385, + 42.70462 + ], + [ + 0.587118, + 42.69652 + ], + [ + 0.592356, + 42.70722 + ], + [ + 0.669248, + 42.69249 + ], + [ + 0.681101, + 42.71543 + ], + [ + 0.638433, + 42.75414 + ], + [ + 0.6439, + 42.78326 + ], + [ + 0.663691, + 42.80408 + ], + [ + 0.657726, + 42.83805 + ], + [ + 0.676349, + 42.85575 + ], + [ + 0.714647, + 42.8632 + ], + [ + 0.776876, + 42.83947 + ], + [ + 0.809442, + 42.84145 + ], + [ + 0.831996, + 42.82956 + ], + [ + 0.849593, + 42.83009 + ], + [ + 0.90714, + 42.80513 + ], + [ + 0.921711, + 42.79588 + ], + [ + 0.960095, + 42.80707 + ], + [ + 1.01816, + 42.78832 + ], + [ + 1.079885, + 42.78936 + ], + [ + 1.113731, + 42.77002 + ], + [ + 1.135112, + 42.75069 + ], + [ + 1.132836, + 42.74064 + ], + [ + 1.165316, + 42.71061 + ], + [ + 1.23164, + 42.72871 + ], + [ + 1.259028, + 42.72145 + ], + [ + 1.307865, + 42.71996 + ], + [ + 1.329804, + 42.72572 + ], + [ + 1.35766, + 42.72167 + ], + [ + 1.387885, + 42.69026 + ], + [ + 1.41361, + 42.65762 + ], + [ + 1.422689, + 42.62422 + ], + [ + 1.444097, + 42.60366 + ], + [ + 1.448031, + 42.5689 + ], + [ + 1.426862, + 42.55113 + ], + [ + 1.452642, + 42.53954 + ], + [ + 1.47197, + 42.50955 + ], + [ + 1.431904, + 42.48901 + ], + [ + 1.447408, + 42.4672 + ], + [ + 1.45, + 42.44011 + ], + [ + 1.511736, + 42.43142 + ], + [ + 1.548514, + 42.43528 + ], + [ + 1.558368, + 42.45864 + ], + [ + 1.563078, + 42.46173 + ], + [ + 1.57428, + 42.45577 + ], + [ + 1.596562, + 42.46894 + ], + [ + 1.656383, + 42.4698 + ], + [ + 1.66159, + 42.49384 + ], + [ + 1.669278, + 42.50557 + ], + [ + 1.704487, + 42.49191 + ], + [ + 1.725742, + 42.50555 + ], + [ + 1.762062, + 42.49093 + ], + [ + 1.804881, + 42.491 + ], + [ + 1.824168, + 42.48769 + ], + [ + 1.883093, + 42.45999 + ], + [ + 1.891487, + 42.45025 + ], + [ + 1.936042, + 42.4559 + ], + [ + 1.959234, + 42.42428 + ], + [ + 1.965381, + 42.38767 + ], + [ + 1.980349, + 42.3715 + ], + [ + 1.99787, + 42.35982 + ], + [ + 2.054879, + 42.35935 + ], + [ + 2.090354, + 42.37576 + ], + [ + 2.108178, + 42.38265 + ], + [ + 2.123564, + 42.41409 + ], + [ + 2.167552, + 42.42649 + ], + [ + 2.213249, + 42.4249 + ], + [ + 2.245052, + 42.431 + ], + [ + 2.254165, + 42.43992 + ], + [ + 2.313264, + 42.42901 + ], + [ + 2.345383, + 42.41715 + ], + [ + 2.381219, + 42.40277 + ], + [ + 2.433719, + 42.39425 + ], + [ + 2.441686, + 42.37868 + ], + [ + 2.467081, + 42.36169 + ], + [ + 2.474764, + 42.35113 + ], + [ + 2.540021, + 42.33469 + ], + [ + 2.553768, + 42.3554 + ], + [ + 2.576529, + 42.35984 + ], + [ + 2.650245, + 42.34572 + ], + [ + 2.67266, + 42.34205 + ], + [ + 2.64955, + 42.38615 + ], + [ + 2.67123, + 42.40522 + ], + [ + 2.724517, + 42.42495 + ], + [ + 2.754476, + 42.42688 + ], + [ + 2.774923, + 42.41456 + ], + [ + 2.785584, + 42.41971 + ], + [ + 2.83795, + 42.46027 + ], + [ + 2.869826, + 42.46881 + ], + [ + 2.909506, + 42.46121 + ], + [ + 2.945102, + 42.48326 + ], + [ + 2.971849, + 42.47084 + ], + [ + 2.990752, + 42.47493 + ], + [ + 3.040317, + 42.47583 + ], + [ + 3.082659, + 42.43083 + ], + [ + 3.132676, + 42.44205 + ], + [ + 3.169446, + 42.43686 + ], + [ + 3.485459, + 42.48706 + ], + [ + 4.314623, + 42.36291 + ], + [ + 5.098525, + 39.64927 + ], + [ + -1.357879, + 36.47351 + ], + [ + -1.818554, + 35.89823 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "source": "https://tunnels.piarc.org/en/operational-safety-requirements-geometry/vertical-clearance", + "maxheight": 5.35 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 1.98396, + 51.3377 + ], + [ + 0.058076, + 50.10375 + ], + [ + -1.246113, + 49.89032 + ], + [ + -2.027284, + 49.77612 + ], + [ + -2.0209, + 49.76352 + ], + [ + -2.03199, + 49.76171 + ], + [ + -1.808598, + 49.10263 + ], + [ + -1.835368, + 49.00443 + ], + [ + -3.940324, + 49.15592 + ], + [ + -7.02478, + 49.70097 + ], + [ + -5.441616, + 52.78017 + ], + [ + -3.9331054687500004, + 54.36135760559306 + ], + [ + -4.207763671875001, + 54.5529515605619 + ], + [ + -5.855712890625, + 53.85900655610469 + ], + [ + -6.286926269531251, + 54.1109429427243 + ], + [ + -6.39129638671875, + 54.0577757589617 + ], + [ + -6.451721191406251, + 54.0690593387285 + ], + [ + -6.630249023437501, + 54.03197320632049 + ], + [ + -6.674194335937501, + 54.09322811632353 + ], + [ + -6.641235351562501, + 54.181726602390945 + ], + [ + -6.781311035156251, + 54.194583360162646 + ], + [ + -7.025756835937501, + 54.42851751056349 + ], + [ + -7.190551757812501, + 54.30049911593032 + ], + [ + -7.138366699218751, + 54.24917998455609 + ], + [ + -7.283935546875001, + 54.120602386175754 + ], + [ + -7.586059570312501, + 54.13991452083357 + ], + [ + -7.684936523437501, + 54.20422330473222 + ], + [ + -7.838745117187501, + 54.20743611987478 + ], + [ + -7.893676757812501, + 54.29729354239267 + ], + [ + -8.036499023437502, + 54.36775852406841 + ], + [ + -8.168334960937502, + 54.45407332522336 + ], + [ + -8.052978515625002, + 54.48918653875083 + ], + [ + -8.003540039062502, + 54.54020652089137 + ], + [ + -7.833251953125001, + 54.54020652089137 + ], + [ + -7.701416015625001, + 54.61025498157912 + ], + [ + -7.921142578125001, + 54.65476860921582 + ], + [ + -7.855224609375001, + 54.73413609763888 + ], + [ + -7.558593750000001, + 54.74364976592378 + ], + [ + -7.382812500000001, + 55.02802211299252 + ], + [ + -6.954345703125001, + 55.18200422657057 + ], + [ + -6.730561, + 55.45018 + ], + [ + -9.408655, + 57.73276 + ], + [ + -9.07783, + 58.20977 + ], + [ + -4.158581, + 60.34515 + ], + [ + -1.637515, + 61.13564 + ], + [ + -0.267026, + 61.103 + ], + [ + 0.127846, + 59.76591 + ], + [ + 0.097816, + 59.42198 + ], + [ + 0.799897, + 55.79959 + ], + [ + 1.702395, + 54.43427 + ], + [ + 2.25, + 52.58 + ], + [ + 1.98396, + 51.3377 + ] + ] + ] + } + } + ] +} diff --git a/docker/Dockerfile b/docker/Dockerfile index 0c4ba0215..094bedee7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,34 +1,30 @@ -FROM alpine:3.5 +FROM debian:bullseye-slim as builder +ARG DOCKER_TAG +ARG BUILD_CONCURRENCY +RUN mkdir -p /src && mkdir -p /opt -RUN mkdir /opt -WORKDIR /opt +RUN apt-get update && \ + apt-get -y --no-install-recommends install ca-certificates cmake make git gcc g++ libbz2-dev libxml2-dev wget \ + libzip-dev libboost1.74-all-dev lua5.4 liblua5.4-dev -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 -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.1-dev libtbb@testing libtbb-dev@testing && \ - \ - echo "Building libstxxl" && \ - cd /opt && \ - git clone --depth 1 --branch 1.4.1 https://github.com/stxxl/stxxl.git && \ - cd stxxl && \ +RUN NPROC=${BUILD_CONCURRENCY:-$(nproc)} && \ + ldconfig /usr/local/lib && \ + git clone --branch v2021.3.0 --single-branch https://github.com/oneapi-src/oneTBB.git && \ + cd oneTBB && \ mkdir build && \ cd build && \ - cmake -DCMAKE_BUILD_TYPE=Release .. && \ - make -j${NPROC} && \ - make install + cmake -DTBB_TEST=OFF -DCMAKE_BUILD_TYPE=Release .. && \ + cmake --build . && \ + cmake --install . -ARG DOCKER_TAG -RUN mkdir /src COPY . /src WORKDIR /src -RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \ +RUN NPROC=${BUILD_CONCURRENCY:-$(nproc)} && \ echo "Building OSRM ${DOCKER_TAG}" && \ git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \ echo "Building OSRM gitsha $(cat /opt/OSRM_GITSHA)" && \ - mkdir build && \ + mkdir -p build && \ cd build && \ BUILD_TYPE="Release" && \ ENABLE_ASSERTIONS="Off" && \ @@ -40,14 +36,32 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \ make -j${NPROC} install && \ cd ../profiles && \ cp -r * /opt && \ - \ - echo "Cleaning up" && \ strip /usr/local/bin/* && \ - rm /usr/local/lib/libstxxl* && \ - cd /opt && \ - apk del boost-dev && \ - apk del g++ cmake libc-dev expat-dev zlib-dev bzip2-dev lua5.1-dev git make gcc && \ - apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.1 expat && \ - rm -rf /src /opt/stxxl /usr/local/bin/stxxl_tool /usr/local/lib/libosrm* + 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 debian:bullseye-slim as runstage + +COPY --from=builder /usr/local /usr/local +COPY --from=builder /opt /opt + +RUN apt-get update && \ + apt-get install -y --no-install-recommends libboost-program-options1.74.0 libboost-regex1.74.0 \ + libboost-date-time1.74.0 libboost-chrono1.74.0 libboost-filesystem1.74.0 \ + libboost-iostreams1.74.0 libboost-system1.74.0 libboost-thread1.74.0 \ + expat liblua5.4-0 && \ + rm -rf /var/lib/apt/lists/* && \ +# add /usr/local/lib to ldconfig to allow loading libraries from there + ldconfig /usr/local/lib + +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 diff --git a/docker/hooks/build b/docker/hooks/build index d1eac8ab0..c27c851ad 100644 --- a/docker/hooks/build +++ b/docker/hooks/build @@ -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 .. diff --git a/docs/http.md b/docs/http.md index 9dd4b1204..07acc968a 100644 --- a/docs/http.md +++ b/docs/http.md @@ -1,3 +1,8 @@ +# OSRM HTTP server + +The built-in HTTP server is a basic HTTP/1.0 server that supports a 'keep-alive' extension. Persistent connections are limited to 512 requests per +connection and allow no more than 5 seconds between requests. + ## General options All OSRM HTTP requests use a common structure. @@ -16,22 +21,24 @@ GET /{service}/{version}/{profile}/{coordinates}[.{format}]?option=value&option= | `version` | Version of the protocol implemented by the service. `v1` for all OSRM 5.x installations | | `profile` | Mode of transportation, is determined statically by the Lua profile that is used to prepare the data using `osrm-extract`. Typically `car`, `bike` or `foot` if using one of the supplied profiles. | | `coordinates`| String of format `{longitude},{latitude};{longitude},{latitude}[;{longitude},{latitude} ...]` or `polyline({polyline}) or polyline6({polyline6})`. | -| `format`| Only `json` is supported at the moment. This parameter is optional and defaults to `json`. | +| `format`| `json` or `flatbuffers`. This parameter is optional and defaults to `json`. | Passing any `option=value` is optional. `polyline` follows Google's polyline format with precision 5 by default and can be generated using [this package](https://www.npmjs.com/package/polyline). -To pass parameters to each location some options support an array like encoding: +To pass parameters to each location some options support an array-like encoding: **Request options** -| Option | Values | Description | -|----------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------| -|bearings |`{bearing};{bearing}[;{bearing} ...]` |Limits the search to segments with given bearing in degrees towards true north in clockwise direction. | -|radiuses |`{radius};{radius}[;{radius} ...]` |Limits the search to given radius in meters. | -|generate\_hints |`true` (default), `false` |Adds a Hint to the response which can be used in subsequent requests, see `hints` parameter. | -|hints |`{hint};{hint}[;{hint} ...]` |Hint from previous request to derive position in street network. | -|approaches |`{approach};{approach}[;{approach} ...]` |Keep waypoints on curb side. | -|exclude |`{class}[,{class}]` |Additive list of classes to avoid, order does not matter. | +| Option | Values | Description | +|----------------|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|bearings |`{bearing};{bearing}[;{bearing} ...]` |Limits the search to segments with given bearing in degrees towards true north in a clockwise direction. | +|radiuses |`{radius};{radius}[;{radius} ...]` |Limits the search to given radius in meters. | +|generate\_hints |`true` (default), `false` |Adds a Hint to the response which can be used in subsequent requests, see `hints` parameter. | +|hints |`{hint};{hint}[;{hint} ...]` |Hint from previous request to derive position in street network. | +|approaches |`{approach};{approach}[;{approach} ...]` |Keep waypoints on curbside. | +|exclude |`{class}[,{class}]` |Additive list of classes to avoid, the order does not matter. | +|snapping |`default` (default), `any` |Default snapping avoids is_startpoint (see profile) edges, `any` will snap to any edge in the graph | +|skip_waypoints |`true`, `false` (default) |Removes waypoints from the response. Waypoints are still calculated, but not serialized. Could be useful in case you are interested in some other part of the response and do not want to transfer waste data. | Where the elements follow the following format: @@ -49,7 +56,7 @@ Where the elements follow the following format: The number of elements must match exactly the number of locations (except for `generate_hints` and `exclude`). If you don't want to pass a value but instead use the default you can pass an empty `element`. -Example: 2nd location use the default value for `option`: +Example: 2nd location uses the default value for `option`: ``` {option}={element};;{element} @@ -70,6 +77,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 | @@ -79,20 +88,25 @@ Every response object has a `code` property containing one of the strings below | `InvalidService` | Service name is invalid. | | `InvalidVersion` | Version is not found. | | `InvalidOptions` | Options are invalid. | -| `InvalidQuery` | The query string is synctactically malformed. | +| `InvalidQuery` | The query string is syntactically malformed. | | `InvalidValue` | The successfully parsed query parameters are invalid. | -| `NoSegment` | One of the supplied input coordinates could not snap to street segment. | -| `TooBig` | The request size violates one of the service specific request size restrictions. | +| `NoSegment` | One of the supplied input coordinates could not snap to the street segment. | +| `TooBig` | The request size violates one of the service-specific request size restrictions. | -- `message` is a **optional** human-readable error message. All other status types are service dependent. -- 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`. +- `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` property containing a timestamp from the original OpenStreetMap file. This field is optional. It can be omitted if the data_version parameter was not set on the osrm-extract stage or the 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" } ``` @@ -115,11 +129,14 @@ In addition to the [general options](#general-options) the following options are |------------|------------------------------|----------------------------------------------------| |number |`integer >= 1` (default `1`) |Number of nearest segments that should be returned. | +As `waypoints` is a single thing, returned by that service, using it with the option `skip_waypoints` set to `true` is quite useless, but still +possible. In that case, only the `code` field will be returned. + **Response** - `code` if the request was successful `Ok` otherwise see the service dependent and general status codes. - `waypoints` array of `Waypoint` objects sorted by distance to the input coordinate. Each object has at least the following additional properties: - - `distance`: Distance in meters to the supplied input coordinate. + - `nodes`: Array of OpenStreetMap node ids. #### Example Requests @@ -130,10 +147,14 @@ curl 'http://router.project-osrm.org/nearest/v1/driving/13.388860,52.517037?numb #### Example Response -```json +```JSON { "waypoints" : [ { + "nodes": [ + 2264199819, + 0 + ], "hint" : "KSoKADRYroqUBAEAEAAAABkAAAAGAAAAAAAAABhnCQCLtwAA_0vMAKlYIQM8TMwArVghAwEAAQH1a66g", "distance" : 4.152629, "name" : "Friedrichstraße", @@ -143,6 +164,10 @@ curl 'http://router.project-osrm.org/nearest/v1/driving/13.388860,52.517037?numb ] }, { + "nodes": [ + 2045820592, + 0 + ], "hint" : "KSoKADRYroqUBAEABgAAAAAAAAAAAAAAKQAAABhnCQCLtwAA7kvMAAxZIQM8TMwArVghAwAAAQH1a66g", "distance" : 11.811961, "name" : "Friedrichstraße", @@ -152,6 +177,10 @@ curl 'http://router.project-osrm.org/nearest/v1/driving/13.388860,52.517037?numb ] }, { + "nodes": [ + 0, + 21487242 + ], "hint" : "KioKgDbbDgCUBAEAAAAAABoAAAAAAAAAPAAAABlnCQCLtwAA50vMADJZIQM8TMwArVghAwAAAQH1a66g", "distance" : 15.872438, "name" : "Friedrichstraße", @@ -182,7 +211,8 @@ In addition to the [general options](#general-options) the following options are |annotations |`true`, `false` (default), `nodes`, `distance`, `duration`, `datasources`, `weight`, `speed` |Returns additional metadata for each coordinate along the route geometry. | |geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) | |overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.| -|continue\_straight |`default` (default), `true`, `false` |Forces the route to keep going straight at waypoints constraining uturns there even if it would be faster. Default value depends on the profile. | +|continue\_straight |`default` (default), `true`, `false` |Forces the route to keep going straight at waypoints constraining uturns there even if it would be faster. Default value depends on the profile. | +|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. @@ -209,13 +239,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 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. Durations are in seconds and distances are 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: @@ -223,10 +253,16 @@ 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; +With `skip_waypoints` set to `true`, both `sources` and `destinations` arrays will be skipped. + **Example:** ``` @@ -240,36 +276,148 @@ 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** - `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. + the i-th source to the j-th destination. 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 source to the j-th destination. Values are given in meters. Can be `null` if no route between `i` and `j` can be found. - `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. -Please note the request might result multiple sub-traces. Large jumps in the timestamps (> 60s) or improbable transitions lead to trace splits if a complete matching could not be found. +Please note the request might result in multiple sub-traces. Large jumps in the timestamps (> 60s) or improbable transitions lead to trace splits if a complete matching could not be found. The algorithm might not be able to match all points. Outliers are removed if they can not be matched successfully. ```endpoint @@ -288,6 +436,7 @@ In addition to the [general options](#general-options) the following options are |radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.| |gaps |`split` (default), `ignore` |Allows the input track splitting based on huge timestamp gaps between points. | |tidy |`true`, `false` (default) |Allows the input track modification to obtain better matching quality for noisy tracks. | +|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. | |Parameter |Values | |------------|-----------------------------------| @@ -303,11 +452,11 @@ The area to search is chosen such that the correct candidate should be considere - `code` if the request was successful `Ok` otherwise see the service dependent and general status codes. - `tracepoints`: Array of `Waypoint` objects representing all points of the trace in order. - If the trace point was ommited by map matching because it is an outlier, the entry will be `null`. + If the tracepoint was omitted by map matching because it is an outlier, the entry will be `null`. Each `Waypoint` object has the following additional properties: - `matchings_index`: Index to the `Route` object in `matchings` the sub-trace was matched to. - `waypoint_index`: Index of the waypoint inside the matched route. - - `alternatives_count`: Number of probable alternative matchings for this trace point. A value of zero indicate that this point was matched unambiguously. Split the trace at these points for incremental map matching. + - `alternatives_count`: Number of probable alternative matchings for this tracepoint. A value of zero indicates that this point was matched unambiguously. Split the trace at these points for incremental map matching. - `matchings`: An array of `Route` objects that assemble the trace. Each `Route` object has the following additional properties: - `confidence`: Confidence of the matching. `float` value between 0 and 1. 1 is very confident that the matching is correct. @@ -322,7 +471,7 @@ All other properties might be undefined. ### Trip service The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm) for 10 or more waypoints and uses brute force for less than 10 waypoints. -The returned path does not have to be the fastest path. As TSP is NP-hard it only returns an approximation. +The returned path does not have to be the fastest one. As TSP is NP-hard it only returns an approximation. Note that all input coordinates have to be connected for the trip service to work. ```endpoint @@ -343,12 +492,12 @@ In addition to the [general options](#general-options) the following options are **Fixing Start and End Points** -It is possible to explicitely set the start or end coordinate of the trip. -When source is set to `first`, the first coordinate is used as start coordinate of the trip in the output. When destination is set to `last`, the last coordinate will be used as destination of the trip in the returned output. If you specify `any`, any of the coordinates can be used as the first or last coordinate in the output. +It is possible to explicitly set the start or end coordinate of the trip. +When the source is set to `first`, the first coordinate is used as the start coordinate of the trip in the output. When the destination is set to `last`, the last coordinate will be used as the destination of the trip in the returned output. If you specify `any`, any of the coordinates can be used as the first or last coordinate in the output. However, if `source=any&destination=any` the returned round-trip will still start at the first input coordinate by default. -Currently, not all combinations of `roundtrip`, `source` and `destination` are supported. +Currently, not all combinations of `roundtrip`, `source`, and `destination` are supported. Right now, the following combinations are possible: | roundtrip | source | destination | supported | @@ -358,8 +507,8 @@ Right now, the following combinations are possible: | true | any | last | **yes** | | true | any | any | **yes** | | false | first | last | **yes** | -| false | first | any | no | -| false | any | last | no | +| false | first | any | **yes** | +| false | any | last | **yes** | | false | any | any | no | #### Example Requests @@ -427,7 +576,8 @@ Vector tiles contain two layers: | `duration` | `float` | how long this segment takes to traverse, in seconds. This value is to calculate the total route ETA. | | `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 | +| `rate` | `float` | the value of `length/weight` - analogous 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: @@ -451,13 +601,13 @@ Represents a route through (potentially multiple) waypoints. - `distance`: The distance traveled by the route, in `float` meters. - `duration`: The estimated travel time, in `float` number of seconds. -- `geometry`: The whole geometry of the route value depending on `overview` parameter, format depending on the `geometries` parameter. See `RouteStep`'s `geometry` property for a parameter documentation. +- `geometry`: The whole geometry of the route value depending on `overview` parameter, format depending on the `geometries` parameter. See `RouteStep`'s `geometry` property for the parameter documentation. - `weight`: The calculated weight of the route. -- `weight_name`: The name of the weight profile used during extraction phase. +- `weight_name`: The name of the weight profile used during the extraction phase. | overview | Description | |------------|-----------------------------| -| simplified | Geometry is simplified according to the highest zoom level it can still be displayed on full. | +| simplified | Geometry is simplified according to the highest zoom level it can still be displayed in full. | | full | Geometry is not simplified. | | false | Geometry is not added. | @@ -502,7 +652,7 @@ Represents a route between two waypoints. | summary | | |--------------|-----------------------------------------------------------------------| -| true | Names of the two major roads used. Can be empty if route is too short.| +| true | Names of the two major roads used. Can be empty if the route is too short.| | false | empty `string` | - `steps`: Depends on the `steps` parameter. @@ -512,12 +662,12 @@ Represents a route between two waypoints. | true | array of `RouteStep` objects describing the turn-by-turn instructions | | false | empty array | -- `annotation`: Additional details about each coordinate along the route geometry: +- `annotation`: Additional details about each coordinate along with the route geometry: -| annotations | | -|--------------|-----------------------------------------------------------------------| -| true | An `Annotation` object containing node ids, durations distances and | -| false | weights `undefined` | +| annotations | | +|--------------|-------------------------------------------------------------------------------| +| true | An `Annotation` object containing node ids, durations, distances, and weights. | +| false | `undefined` | #### Example @@ -533,6 +683,7 @@ With `steps=false` and `annotations=true`: "distance": [5,5,10,5,5], "duration": [15,15,40,15,15], "datasources": [1,0,0,0,1], + "metadata": { "datasource_names": ["traffic","lua profile","lua profile","lua profile","traffic"] }, "nodes": [49772551,49772552,49786799,49786800,49786801,49786802], "speed": [0.3, 0.3, 0.3, 0.3, 0.3] } @@ -545,12 +696,14 @@ Annotation of the whole route leg with fine-grained information about each segme **Properties** -- `distance`: The distance, in metres, between each pair of coordinates +- `distance`: The distance, in meters, between each pair of coordinates - `duration`: The duration between each pair of coordinates, in seconds. Does not include the duration of any turns. -- `datasources`: The index of the datasource for the speed between each pair of coordinates. `0` is the default profile, other values are supplied via `--segment-speed-file` to `osrm-contract` +- `datasources`: The index of the data source for the speed between each pair of coordinates. `0` is the default profile, other values are supplied via `--segment-speed-file` to `osrm-contract` or `osrm-customize`. String-like names are in the `metadata.datasource_names` array. - `nodes`: The OSM node ID for each coordinate along the route, excluding the first/last user-supplied coordinates - `weight`: The weights between each pair of coordinates. Does not include any turn costs. - `speed`: Convenience field, calculation of `distance / duration` rounded to one decimal place +- `metadata`: Metadata related to other annotations + - `datasource_names`: The names of the data sources used for the speed between each pair of coordinates. `lua profile` is the default profile, other values are the filenames supplied via `--segment-speed-file` to `osrm-contract` or `osrm-customize` #### Example @@ -559,6 +712,7 @@ Annotation of the whole route leg with fine-grained information about each segme "distance": [5,5,10,5,5], "duration": [15,15,40,15,15], "datasources": [1,0,0,0,1], + "metadata": { "datasource_names": ["traffic","lua profile","lua profile","lua profile","traffic"] }, "nodes": [49772551,49772552,49786799,49786800,49786801,49786802], "weight": [15,15,40,15,15] } @@ -586,7 +740,7 @@ step. - `name`: The name of the way along which travel proceeds. - `ref`: A reference number or code for the way. Optionally included, if ref data is available for the given way. -- `pronunciation`: The pronunciation hint of the way name. Will be `undefined` if there is no pronunciation hit. +- `pronunciation`: A string containing an [IPA](https://en.wikipedia.org/wiki/International_Phonetic_Alphabet) phonetic transcription indicating how to pronounce the name in the `name` property. This property is omitted if pronunciation data is unavailable for the step. - `destinations`: The destinations of the way. Will be `undefined` if there are no destinations. - `exits`: The exit numbers or names of the way. Will be `undefined` if there are no exit numbers or names. - `mode`: A string signifying the mode of transportation. @@ -594,6 +748,7 @@ step. - `intersections`: A list of `Intersection` objects that are passed along the segment, the very first belonging to the StepManeuver - `rotary_name`: The name for the rotary. Optionally included, if the step is a rotary and a rotary name is available. - `rotary_pronunciation`: The pronunciation hint of the rotary name. Optionally included, if the step is a rotary and a rotary pronunciation is available. +- `driving_side`: The legal driving side at the location for this step. Either `left` or `right`. #### Example @@ -607,8 +762,8 @@ step. { "bearings" : [ 10, 92, 184, 270 ], "lanes" : [ { "indications" : [ "left", "straight" ], - "valid" : "false" }, - { "valid" : "true", + "valid" : false }, + { "valid" : true, "indications" : [ "right" ] } ], "out" : 2, @@ -619,9 +774,9 @@ step. { "out" : 1, "lanes" : [ { "indications" : [ "straight" ], - "valid" : "true" }, + "valid" : true }, { "indications" : [ "right" ], - "valid" : "false" } + "valid" : false } ], "bearings" : [ 60, 240, 330 ], "in" : 0, @@ -648,11 +803,11 @@ step. - `bearing_after`: The clockwise angle from true north to the direction of travel immediately after the maneuver. Range 0-359. - `type` A string indicating the type of maneuver. **new identifiers might be introduced without API change** - Types unknown to the client should be handled like the `turn` type, the existence of correct `modifier` values is guranteed. + Types unknown to the client should be handled like the `turn` type, the existence of correct `modifier` values is guaranteed. | `type` | Description | |------------------|--------------------------------------------------------------| -| `turn` | a basic turn into direction of the `modifier` | +| `turn` | a basic turn into the direction of the `modifier` | | `new name` | no turn is taken/possible, but the road name changes. The road can take a turn itself, following `modifier`. | | `depart` | indicates the departure of the leg | | `arrive` | indicates the destination of the leg | @@ -664,11 +819,11 @@ step. | `end of road` | road ends in a T intersection turn in direction of `modifier`| | `use lane` | **Deprecated** replaced by lanes on all intersection entries | | `continue` | Turn in direction of `modifier` to stay on the same road | -| `roundabout` | traverse roundabout, has additional property `exit` with NR if the roundabout is left. The modifier specifies the direction of entering the roundabout. | +| `roundabout` | traverse roundabout, if the route leaves the roundabout there will be an additional property `exit` for exit counting. The modifier specifies the direction of entering the roundabout. | | `rotary` | a traffic circle. While very similar to a larger version of a roundabout, it does not necessarily follow roundabout rules for right of way. It can offer `rotary_name` and/or `rotary_pronunciation` parameters (located in the RouteStep object) in addition to the `exit` parameter (located on the StepManeuver object). | -| `roundabout turn`| Describes a turn at a small roundabout that should be treated as normal turn. The `modifier` indicates the turn direciton. Example instruction: `At the roundabout turn left`. | +| `roundabout turn`| Describes a turn at a small roundabout that should be treated as a normal turn. The `modifier` indicates the turn direction. Example instruction: `At the roundabout turn left`. | | `notification` | not an actual turn but a change in the driving conditions. For example the travel mode or classes. If the road takes a turn itself, the `modifier` describes the direction | -| `exit roundabout`| Describes a maneuver exiting a roundabout (usually preceeded by a `roundabout` instruction) | +| `exit roundabout`| Describes a maneuver exiting a roundabout (usually preceded by a `roundabout` instruction) | | `exit rotary` | Describes the maneuver exiting a rotary (large named roundabout) | Please note that even though there are `new name` and `notification` instructions, the `mode` and `name` can change @@ -678,7 +833,7 @@ step. | `modifier` | Description | |-------------------|-------------------------------------------| -| `uturn` | indicates reversal of direction | +| `uturn` | indicates the reversal of direction | | `sharp right` | a sharp right turn | | `right` | a normal turn to the right | | `slight right` | a slight turn to the right | @@ -696,8 +851,8 @@ step. | `turn` | `modifier` indicates the change in direction accomplished through the turn | | `depart`/`arrive` | `modifier` indicates the position of departure point and arrival point in relation to the current direction of travel | -- `exit` An optional `integer` indicating number of the exit to take. The property exists for the `roundabout` / `rotary` property: - Number of the roundabout exit to take. If exit is `undefined` the destination is on the roundabout. +- `exit` An optional `integer` indicating the number of the exit to take. The property exists for the `roundabout` / `rotary` property: + Number of the roundabout exit to take. If an exit is `undefined` the destination is on the roundabout. New properties (potentially depending on `type`) may be introduced in the future without an API version change. @@ -708,7 +863,7 @@ A `Lane` represents a turn lane at the corresponding turn location. **Properties** -- `indications`: a indication (e.g. marking on the road) specifying the turn lane. A road can have multiple indications (e.g. an arrow pointing straight and left). The indications are given in an array, each containing one of the following types. Further indications might be added on without an API version change. +- `indications`: an indication (e.g. marking on the road) specifying the turn lane. A road can have multiple indications (e.g. an arrow pointing straight and left). The indications are given in an array, each containing one of the following types. Further indications might be added on without an API version change. | `value` | Description | |------------------------|---------------------------------------------------------------------------------------------------------------------------| @@ -729,13 +884,13 @@ A `Lane` represents a turn lane at the corresponding turn location. ```json { "indications": ["left", "straight"], - "valid": "false" + "valid": false } ``` ### Intersection object -An intersection gives a full representation of any cross-way the path passes bay. For every step, the very first intersection (`intersections[0]`) corresponds to the +An intersection gives a full representation of any cross-way the path passes by. For every step, the very first intersection (`intersections[0]`) corresponds to the location of the StepManeuver. Further intersections are listed for every cross-way until the next turn instruction. **Properties** @@ -764,21 +919,22 @@ location of the StepManeuver. Further intersections are listed for every cross-w "classes": ["toll", "restricted"], "lanes":{ "indications": ["left", "straight"], - "valid": "false" + "valid": false } } ``` ### Waypoint object -Object used to describe waypoint on a route. +The object is used to describe the waypoint on a route. **Properties** - `name` Name of the street the coordinate snapped to - `location` Array that contains the `[longitude, latitude]` pair of the snapped coordinate +- `distance` The distance, in meters, 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. + This can be used on subsequent requests 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. #### Example @@ -794,3 +950,175 @@ Object used to describe waypoint on a route. ] } ``` + +## Flatbuffers format + +The default response format is `json`, but OSRM supports binary [`flatbuffers`](https://google.github.io/flatbuffers/) format, which +is much faster in serialization/deserialization, comparing to `json`. + +The format itself is described in message descriptors, located at `include/engine/api/flatbuffers` directory. Those descriptors could +be compiled to provide protocol parsers in Go/Javascript/Typescript/Java/Dart/C#/Python/Lobster/Lua/Rust/PHP/Kotlin. Precompiled +protocol parser for C++ is supplied with OSRM. + +`Flatbuffers` format provides exactly the same data, as `json` format with a slightly different layout, which was optimized to minimize +in-transfer size. + +### Root object + +Root object is the only object, available from a 'raw' `flatbuffers` buffer. It can be constructed with a following call: + + auto osrm = osrm::engine::api::fbresult::GetFBResult(some_input_buffer); + +**Properties** + +- `error`: `bool` Marks response as erroneous. An erroneous response should include the `code` fieldset, all the other fields may not be present. +- `code`: `Error` Error description object, only present, when `error` is `true` +- `waypoints`: `[Waypoint]` Array of `Waypoint` objects. Should present for every service call, unless `skip_waypoints` is set to `true`. Table service will put `sources` array here. +- `routes`: `[RouteObject]` Array of `RouteObject` objects. May be empty or absent. Should present for Route/Trip/Match services call. +- `table`: `Table` Table object, may absent. Should be present in case of Table service call. + +### Error object + +Contains error information. + +**Properties** + +- `code`: `string` Error code +- `message`: `string` Detailed error message + +### Waypoint object + +Almost the same as `json` Waypoint object. The following properties differ: + +- `location`: `Position` Same as `json` location field, but different format. +- `nodes`: `Uint64Pair` Same as `json` nodes field, but different format. + +### RouteObject object + +Almost the same as `json` Route object. The following properties differ: + +- `polyline`: `string` Same as `json` geometry.polyline or geometry.polyline6 fields. One field for both formats. +- `coordinates`: `[Position]` Same as `json` geometry.coordinates field, but different format. +- `legs`: `[Leg]` Array of `Leg` objects. + +### Leg object + +Almost the same as `json` Leg object. The following properties differ: + +- `annotations`: `Annotation` Same as `json` annotation field, but different format. +- `steps`: `[Step]` Same as `step` annotation field, but different format. + +### Step object + +Almost the same as `json` Step object. The following properties differ: + +- `polyline`: `string` Same as `json` geometry.polyline or geometry.polyline6 fields. One field for both formats. +- `coordinates`: `[Position]` Same as `json` geometry.coordinates field, but different format. +- `maneuver`: `StepManeuver` Same as `json` maneuver field, but different format. + +| `type` | Description | +|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `Turn` | a basic turn into the direction of the `modifier` | +| `NewName` | no turn is taken/possible, but the road name changes. The road can take a turn itself, following `modifier`. | +| `Depart` | indicates the departure of the leg | +| `Arrive` | indicates the destination of the leg | +| `Merge` | merge onto a street (e.g. getting on the highway from a ramp, the `modifier specifies the direction of the merge`) | +| `OnRamp` | take a ramp to enter a highway (direction given my `modifier`) | +| `OffRamp` | take a ramp to exit a highway (direction given my `modifier`) | +| `Fork` | take the left/right side at a fork depending on `modifier` | +| `EndOfRoad` | road ends in a T intersection turn in direction of `modifier` | +| `Continue` | Turn in direction of `modifier` to stay on the same road | +| `Roundabout` | traverse roundabout, if the route leaves the roundabout there will be an additional property `exit` for exit counting. The modifier specifies the direction of entering the roundabout. | +| `Rotary` | a traffic circle. While very similar to a larger version of a roundabout, it does not necessarily follow roundabout rules for right of way. It can offer `rotary_name` and/or `rotary_pronunciation` parameters (located in the RouteStep object) in addition to the `exit` parameter (located on the StepManeuver object). | +| `RoundaboutTurn` | Describes a turn at a small roundabout that should be treated as a normal turn. The `modifier` indicates the turn direction. Example instruction: `At the roundabout turn left`. | +| `Notification` | not an actual turn but a change in the driving conditions. For example the travel mode or classes. If the road takes a turn itself, the `modifier` describes the direction | +| `ExitRoundabout` | Describes a maneuver exiting a roundabout (usually preceded by a `roundabout` instruction) | +| `ExitRotary` | Describes the maneuver exiting a rotary (large named roundabout) | + +- `driving_side`: `bool` Ttrue stands for the left side driving. +- `intersections`: `[Intersection]` Same as `json` intersections field, but different format. + +### Intersection object + +Almost the same as `json` Intersection object. The following properties differ: + +- `location`: `Position` Same as `json` location property, but in a different format. +- `lanes`: `[Lane]` Array of `Lane` objects. + +### Lane object + +Almost the same as `json` Lane object. The following properties differ: + +- `indications`: `Turn` Array of `Turn` enum values. + +| `value` | Description | +|------------------------|---------------------------------------------------------------------------------------------------------------------------| +| `None` | No dedicated indication is shown. | +| `UTurn` | An indication signaling the possibility to reverse (i.e. fully bend arrow). | +| `SharpRight` | An indication indicating a sharp right turn (i.e. strongly bend arrow). | +| `Right` | An indication indicating a right turn (i.e. bend arrow). | +| `SlightRight` | An indication indicating a slight right turn (i.e. slightly bend arrow). | +| `Straight` | No dedicated indication is shown (i.e. straight arrow). | +| `SlightLeft` | An indication indicating a slight left turn (i.e. slightly bend arrow). | +| `Left` | An indication indicating a left turn (i.e. bend arrow). | +| `SharpLeft` | An indication indicating a sharp left turn (i.e. strongly bend arrow). | + +### StepManeuver object + +Almost the same as `json` StepManeuver object. The following properties differ: + +- `location`: `Position` Same as `json` location property, but in a different format. +- `type`: `ManeuverType` Type of a maneuver (enum) + +| `type` | Description | +|------------------|--------------------------------------------------------------| +| `Turn` | a basic turn into the direction of the `modifier` | +| `NewName` | no turn is taken/possible, but the road name changes. The road can take a turn itself, following `modifier`. | +| `Depart` | indicates the departure of the leg | +| `Arrive` | indicates the destination of the leg | +| `Merge` | merge onto a street (e.g. getting on the highway from a ramp, the `modifier specifies the direction of the merge`) | +| `OnRamp` | take a ramp to enter a highway (direction given my `modifier`) | +| `OffRamp` | take a ramp to exit a highway (direction given my `modifier`) | +| `Fork` | take the left/right side at a fork depending on `modifier` | +| `EndOfRoad` | road ends in a T intersection turn in direction of `modifier`| +| `Continue` | Turn in direction of `modifier` to stay on the same road | +| `Roundabout` | traverse roundabout, if the route leaves the roundabout there will be an additional property `exit` for exit counting. The modifier specifies the direction of entering the roundabout. | +| `Rotary` | a traffic circle. While very similar to a larger version of a roundabout, it does not necessarily follow roundabout rules for right of way. It can offer `rotary_name` and/or `rotary_pronunciation` parameters (located in the RouteStep object) in addition to the `exit` parameter (located on the StepManeuver object). | +| `RoundaboutTurn` | Describes a turn at a small roundabout that should be treated as a normal turn. The `modifier` indicates the turn direction. Example instruction: `At the roundabout turn left`. | +| `Notification` | not an actual turn but a change in the driving conditions. For example the travel mode or classes. If the road takes a turn itself, the `modifier` describes the direction | +| `ExitRoundabout` | Describes a maneuver exiting a roundabout (usually preceded by a `roundabout` instruction) | +| `ExitRotary` | Describes the maneuver exiting a rotary (large named roundabout) | + +- `modifier`: `Turn` Maneuver turn (enum) + +### Annotation object + +Exactly the same as `json` annotation object. + + +### Position object + +A point on Earth. + +***Properties*** +- `longitute`: `float` Point's longitude +- `latitude`: `float` Point's latitude + +### Uint64Pair + +A pair of long long integers. Used only by `Waypoint` object. + +***Properties*** +- `first`: `uint64` First pair value. +- `second`: `uint64` Second pair value. + +### Table object + +Almost the same as `json` Table object. The main difference is that 'sources' field is absent and the root's object 'waypoints' field is +used instead. All the other differences follow: + +- `durations`: `[float]` Flat representation of a durations matrix. Element at row;col can be addressed as [row * cols + col] +- `distances`: `[float]` Flat representation of a destinations matrix. Element at row;col can be addressed as [row * cols + col] +- `destinations`: `[Waypoint]` Array of `Waypoint` objects. Will be `null` if `skip_waypoints` will be set to `true` +- `rows`: `ushort` Number of rows in durations/destinations matrices. +- `cols`: `ushort` Number of cols in durations/destinations matrices. diff --git a/docs/nodejs/api.md b/docs/nodejs/api.md index ed2282c22..ef52ed790 100644 --- a/docs/nodejs/api.md +++ b/docs/nodejs/api.md @@ -3,8 +3,8 @@ ## OSRM The `OSRM` method is the main constructor for creating an OSRM instance. -An OSRM instance requires a `.osrm` dataset, which is prepared by the OSRM toolchain. -You can create such a `.osrm` file by running the OSRM binaries we ship in `node_modules/osrm/lib/binding/` and default +An OSRM instance requires a `.osrm.*` dataset(`.osrm.*` because it contains several files), which is prepared by the OSRM toolchain. +You can create such a `.osrm.*` dataset by running the OSRM binaries we ship in `node_modules/osrm/lib/binding/` and default profiles (e.g. for setting speeds and determining road types to route on) in `node_modules/osrm/profiles/`: node_modules/osrm/lib/binding/osrm-extract data.osm.pbf -p node_modules/osrm/profiles/car.lua @@ -12,7 +12,7 @@ profiles (e.g. for setting speeds and determining road types to route on) in `no Consult the [osrm-backend](https://github.com/Project-OSRM/osrm-backend) documentation for further details. -Once you have a complete `network.osrm` file, you can calculate routes in javascript with this object. +Once you have a complete `network.osrm.*` dataset, you can calculate routes in javascript with this object. ```javascript var osrm = new OSRM('network.osrm'); @@ -20,18 +20,24 @@ var osrm = new OSRM('network.osrm'); **Parameters** -- `options` **([Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** Options for creating an OSRM object or string to the `.osrm` file. (optional, default `{shared_memory:true}`) - - `options.algorithm` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The algorithm to use for routing. Can be 'CH', 'CoreCH' or 'MLD'. Default is 'CH'. +- `options` **([Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String))** Options for creating an OSRM object or string to the `.osrm` file. (optional, default `{shared_memory:true}`) + - `options.algorithm` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The algorithm to use for routing. Can be 'CH', 'CoreCH' or 'MLD'. Default is 'CH'. 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. + - `options.shared_memory` **[Boolean](https://developer.mozilla.org/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.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). - - `options.max_locations_distance_table` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in distance table query (default: unlimited). - - `options.max_locations_map_matching` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in map-matching query (default: unlimited). - - `options.max_results_nearest` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. results supported in nearest query (default: unlimited). - - `options.max_alternatives` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max.number of alternatives supported in alternative routes query (default: 3). + - `options.dataset_name` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Connects to the persistent shared memory datastore defined by `--dataset_name` option when running `osrm-datastore`. + This requires you to run `osrm-datastore --dataset_name` prior to creating an `OSRM` object. + - `options.memory_file` **[String](https://developer.mozilla.org/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/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/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/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in trip query (default: unlimited). + - `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query (default: unlimited). + - `options.max_locations_distance_table` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in distance table query (default: unlimited). + - `options.max_locations_map_matching` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in map-matching query (default: unlimited). + - `options.max_radius_map_matching` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. radius size supported in map matching query (default: 5). + - `options.max_results_nearest` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. results supported in nearest query (default: unlimited). + - `options.max_alternatives` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. number of alternatives supported in alternative routes query (default: 3). ### route @@ -39,23 +45,29 @@ Returns the fastest route between two or more coordinates while visiting the way **Parameters** -- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the route query. - - `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. - - `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. +- `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the route query. + - `options.coordinates` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. + - `options.bearings` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. - - `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. - - `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. - - `options.alternatives` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Search for alternative routes. (optional, default `false`) - - `options.alternatives` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Search for up to this many alternative routes. + - `options.radiuses` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. + - `options.hints` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. + - `options.exclude` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** List of classes to avoid, order does not matter. + - `options.generate_hints` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether or not adds a Hint to the response which can be used in subsequent requests. (optional, default `true`) + - `options.alternatives` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Search for alternative routes. (optional, default `false`) + - `options.alternatives` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** Search for up to this many alternative routes. _Please note that even if alternative routes are requested, a result cannot be guaranteed._ (optional, default `0`) - - `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route leg. (optional, default `false`) - - `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`) - - `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`) - - `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`) - - `options.continue_straight` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile. - - `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.steps` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route leg. (optional, default `false`) + - `options.annotations` **([Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`) + - `options.geometries` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`) + - `options.overview` **[String](https://developer.mozilla.org/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/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/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. `null`/`true`/`false` -- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** + - `options.waypoints` **[Array](https://developer.mozilla.org/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. + - `options.format` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). + - `options.snapping` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. + - `options.skip_waypoints` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Removes waypoints from the response. Waypoints are still calculated, but not serialized. Could be useful in case you are interested in some other part of response and do not want to transfer waste data. (optional, default `false`) +- `callback` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** **Examples** @@ -68,7 +80,7 @@ osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, functi }); ``` -Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** An array of [Waypoint](#waypoint) objects representing all waypoints in order AND an array of [`Route`](#route) objects ordered by descending recommendation rank. +Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** An array of [Waypoint](#waypoint) objects representing all waypoints in order AND an array of [`Route`](#route) objects ordered by descending recommendation rank. ### nearest @@ -78,16 +90,19 @@ Note: `coordinates` in the general options only supports a single `{longitude},{ **Parameters** -- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the nearest query. - - `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. - - `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. +- `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the nearest query. + - `options.coordinates` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. + - `options.bearings` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. - - `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. - - `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. - - `options.number` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Number of nearest segments that should be returned. + - `options.radiuses` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. + - `options.hints` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. + - `options.generate_hints` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether or not adds a Hint to the response which can be used in subsequent requests. (optional, default `true`) + - `options.number` **[Number](https://developer.mozilla.org/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)** + - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + - `options.format` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). + - `options.snapping` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. +- `callback` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** **Examples** @@ -103,30 +118,34 @@ osrm.nearest(options, function(err, response) { }); ``` -Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** containing `waypoints`. +Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** containing `waypoints`. **`waypoints`**: array of [`Ẁaypoint`](#waypoint) objects sorted by distance to the input coordinate. Each object has an additional `distance` property, which is the distance in meters to the supplied input coordinate. ### 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** -- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the table query. - - `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. - - `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. +- `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the table query. + - `options.coordinates` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. + - `options.bearings` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. - - `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. - - `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. - - `options.sources` **[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 source. Default is to use all. - - `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.radiuses` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. + - `options.hints` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. + - `options.generate_hints` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether or not adds a Hint to the response which can be used in subsequent requests. (optional, default `true`) + - `options.sources` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer < #coordinates`) to use + location with given index as source. Default is to use all. + - `options.destinations` **[Array](https://developer.mozilla.org/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/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + - `options.fallback_speed` **[Number](https://developer.mozilla.org/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/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 distance between two points. + - `options.scale_factor` **[Number](https://developer.mozilla.org/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. + - `options.snapping` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. + - `options.annotations` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Return the requested table or tables in response. Can be `['duration']` (return the duration matrix, default), `[distance']` (return the distance matrix), or `['duration', distance']` (return both the duration matrix and the distance matrix). +- `callback` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** **Examples** @@ -141,16 +160,20 @@ var options = { }; osrm.table(options, function(err, response) { console.log(response.durations); // array of arrays, matrix in row-major order + console.log(response.distances); // array of arrays, matrix in row-major order console.log(response.sources); // array of Waypoint objects console.log(response.destinations); // array of Waypoint objects }); ``` -Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** containing `durations`, `sources`, and `destinations`. +Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** containing `durations`, `distances`, `sources`, and `destinations`. **`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. +**`distances`**: array of arrays that stores the matrix in row-major order. `distances[i][j]` gives the travel time from the i-th waypoint to the j-th waypoint. + Values are given in meters. **`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 @@ -163,10 +186,10 @@ and what weights they have applied. **Parameters** -- `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 +- `ZXY` **[Array](https://developer.mozilla.org/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/docs/Web/JavaScript/Reference/Statements/function)** **Examples** @@ -190,20 +213,23 @@ if they can not be matched successfully. **Parameters** -- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the match query. - - `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. - - `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. +- `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the match query. + - `options.coordinates` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. + - `options.bearings` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. - - `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. - - `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route. (optional, default `false`) - - `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`) - - `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`) - - `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`) - - `options.timestamps` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>?** Timestamp of the input location (integers, UNIX-like timestamp). - - `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`. - - `options.gaps` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore` (optional, default `split`). - - `options.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`). -- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** + - `options.hints` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. + - `options.generate_hints` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether or not adds a Hint to the response which can be used in subsequent requests. (optional, default `true`) + - `options.steps` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route. (optional, default `false`) + - `options.annotations` **([Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`) + - `options.geometries` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`) + - `options.overview` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`) + - `options.timestamps` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)>?** Timestamp of the input location (integers, UNIX-like timestamp). + - `options.radiuses` **[Array](https://developer.mozilla.org/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/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/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Allows the input track modification to obtain better matching quality for noisy tracks. (optional, default `false`) + - `options.waypoints` **[Array](https://developer.mozilla.org/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. + - `options.snapping` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. +- `callback` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** **Examples** @@ -220,12 +246,15 @@ osrm.match(options, function(err, response) { }); ``` -Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** containing `tracepoints` and `matchings`. +Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** containing `tracepoints` and `matchings`. **`tracepoints`** Array of [`Ẁaypoint`](#waypoint) objects representing all points of the trace in order. If the trace point was ommited by map matching because it is an outlier, the entry will be null. - Each `Waypoint` object includes two additional properties, 1) `matchings_index`: Index to the - [`Route`](#route) object in matchings the sub-trace was matched to, 2) `waypoint_index`: Index of + Each `Waypoint` object has the following additional properties, + 1) `matchings_index`: Index to the + [`Route`](#route) object in matchings the sub-trace was matched to, + 2) `waypoint_index`: Index of the waypoint inside the matched route. + 3) `alternatives_count`: Number of probable alternative matchings for this trace point. A value of zero indicate that this point was matched unambiguously. Split the trace at these points for incremental map matching. **`matchings`** is an array of [`Route`](#route) objects that assemble the trace. Each `Route` object has an additional `confidence` property, which is the confidence of the matching. float value between `0` and `1`. `1` is very confident that the matching is correct. @@ -253,21 +282,23 @@ Right now, the following combinations are possible: **Parameters** -- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query. - - `options.coordinates` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. - - `options.bearings` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. +- `options` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query. + - `options.coordinates` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. + - `options.bearings` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the search to segments with given bearing in degrees towards true north in clockwise direction. Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. - - `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `double >= 0` or `null` (unlimited, default). - - `options.hints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. - - `options.steps` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route. (optional, default `false`) - - `options.annotations` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`) - - `options.geometries` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`) - - `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` (optional, default `simplified`) - - `options.roundtrip` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route is a roundtrip. (optional, default `true`) - - `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route starts at `any` or `first` coordinate. (optional, default `any`) - - `options.destination` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route ends at `any` or `last` coordinate. (optional, default `any`) - - `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. -- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** + - `options.radiuses` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Limits the coordinate snapping to streets in the given radius in meters. Can be `double >= 0` or `null` (unlimited, default). + - `options.hints` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Hints for the coordinate snapping. Array of base64 encoded strings. + - `options.generate_hints` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether or not adds a Hint to the response which can be used in subsequent requests. (optional, default `true`) + - `options.steps` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route steps for each route. (optional, default `false`) + - `options.annotations` **([Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`) + - `options.geometries` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`) + - `options.overview` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` (optional, default `simplified`) + - `options.roundtrip` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route is a roundtrip. (optional, default `true`) + - `options.source` **[String](https://developer.mozilla.org/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/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/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + - `options.snapping` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. +- `callback` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** **Examples** @@ -289,16 +320,49 @@ osrm.trip(options, function(err, response) { }); ``` -Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** containing `waypoints` and `trips`. +Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** containing `waypoints` and `trips`. **`waypoints`**: an array of [`Waypoint`](#waypoint) objects representing all waypoints in input order. Each Waypoint object has the following additional properties, 1) `trips_index`: index to trips of the sub-trip the point was matched to, and 2) `waypoint_index`: index of the point in the trip. **`trips`**: an array of [`Route`](#route) objects that assemble the trace. -## Responses +## Configuration -Responses +All plugins support a second additional object that is available to configure some NodeJS +specific behaviours. + +**Parameters** + +- `plugin_config` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** Object literal containing parameters for the trip query. + - `plugin_config.format` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The format of the result object to various API calls. + Valid options are `object` (default if `options.format` is + `json`), which returns a standard Javascript object, as described above, and `buffer`(default if + `options.format` is `flatbuffers`), which will return a NodeJS + **[Buffer](https://nodejs.org/api/buffer.html)** object, containing a JSON string or Flatbuffers + object. 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. Also note that `options.format` set to `flatbuffers` + cannot be used with `plugin_config.format` set to `object`. `json_buffer` is deprecated alias for + `buffer`. + +**Examples** + +```javascript +var osrm = new OSRM('network.osrm'); +var options = { + coordinates: [ + [13.36761474609375, 52.51663871100423], + [13.374481201171875, 52.506191342034576] + ] +}; +osrm.route(options, { format: "buffer" }, function(err, response) { + if (err) throw err; + console.log(response.toString("utf-8")); +}); +``` + +## Responses ### Route @@ -306,8 +370,8 @@ Represents a route through (potentially multiple) waypoints. **Parameters** -- `exteral` **documentation** in - [`osrm-backend`](../http.md#route) +- `external` **documentation** in + [`osrm-backend`](../http.md#route-object) ### RouteLeg @@ -315,8 +379,8 @@ Represents a route between two waypoints. **Parameters** -- `exteral` **documentation** in - [`osrm-backend`](../http.md#routeleg) +- `external` **documentation** in + [`osrm-backend`](../http.md#routeleg-object) ### RouteStep @@ -325,15 +389,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) +- `external` **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) +- `external` **documentation** in + [`osrm-backend`](../http.md#stepmaneuver-object) ### Waypoint @@ -341,5 +405,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) +- `external` **documentation** in + [`osrm-backend`](../http.md#waypoint-object) diff --git a/docs/nodejs/releasing.md b/docs/nodejs/releasing.md deleted file mode 100644 index 63c49f5cb..000000000 --- a/docs/nodejs/releasing.md +++ /dev/null @@ -1,86 +0,0 @@ -# Releasing - -Releasing a new version of `node-osrm` is mostly automated using Travis CI. - -The version of `node-osrm` is locked to the same version as `osrm-backend`. Every `node-osrm` should have a `osrm-backend` release of the same version. Of course, only release a `node-osrm` after the release has been tagged in `osrm-backend`. - -These steps all happen on `master`. After the release is out, create a branch using the MAJOR.MINOR version of the release to document code changes made for that version. - -### Steps to release - -1. Update the `osrm_release` field in `package.json` to the corresonding git tag in `osrm-backend.` - - Confirm the desired OSRM branch and commit to `master`. - -1. Bump node-osrm version - - Update the `CHANGELOG.md` and the `package.json` version if needed. - -1. Check that Travis CI [builds are passing](https://travis-ci.org/Project-OSRM/node-osrm) for the latest commit on `master`. - -1. Publishing binaries - - If travis builds are passing then it's time to publish binaries by committing with a message containing `[publish binary]`. Use an empty commit for this. - - ``` - git commit --allow-empty -m "[publish binary] vMAJOR.MINOR.PATCH" - ``` - -1. Test - - Locally you can now test binaries. Cleanup, re-install, and run the tests like: - - ``` - make clean - npm install # will pull remote binaries - npm ls # confirm deps are correct - make test - ``` - -1. Tag - - Once binaries are published for Linux and OS X then its time to tag a new release and add the changelog to the tag: - - ``` - git tag vMAJOR.MINOR.PATCH -a - git push --tags - ``` - -1. Publish node-osrm. **we only do this for stable releases** - - First ensure your local `node-pre-gyp` is up to date: - - ``` - npm ls - ``` - - This is important because it is bundled during packaging. - - If you see any errors then do: - - ``` - rm -rf node_modules/node-pre-gyp - npm install node-pre-gyp - ``` - - Now we're ready to publish `node-osrm` to : - - ``` - npm publish - ``` - - Dependent apps can now pull from the npm registry like: - - ``` - "dependencies": { - "osrm": "^MAJOR.MINOR.PATCH" - } - ``` - - Or can still pull from the github tag like: - - ``` - "dependencies": { - "osrm": "https://github.com/Project-OSRM/node-osrm/archive/vMAJOR.MINOR.PATCH.tar.gz" - } - ``` diff --git a/docs/profiles.md b/docs/profiles.md index 752b82d86..fa74b8780 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -6,7 +6,7 @@ OSRM supports "profiles". Profiles representing routing behavior for different t ## Available profiles Out-of-the-box OSRM comes with profiles for car, bicycle and foot. You can easily modify these or create new ones if you like. -Profiles have a 'lua' extension, and are places in 'profiles' directory. +Profiles have a 'lua' extension, and are placed in 'profiles' directory. When running OSRM preprocessing commands you specify the profile with the --profile (or the shorthand -p) option, for example: @@ -17,8 +17,8 @@ It's important to understand that profiles are used when preprocessing the OSM d This means that after modifying a profile **you will need to extract, contract and reload the data again** and to see changes in the routing results. See [Processing Flow](https://github.com/Project-OSRM/osrm-backend/wiki/Processing-Flow) for more. -## Profiles are written in LUA -Profiles are not just configuration files. They are scripts written in the [LUA scripting language](http://www.lua.org). The reason for this is that OpenStreetMap data is complex, and it's not possible to simply define tag mappings. LUA scripting offers a powerful way to handle all the possible tag combinations found in OpenStreetMap nodes and ways. +## Profiles are written in Lua +Profiles are not just configuration files. They are scripts written in the [Lua scripting language](http://www.lua.org). The reason for this is that OpenStreetMap data is complex, and it's not possible to simply define tag mappings. Lua scripting offers a powerful way to handle all the possible tag combinations found in OpenStreetMap nodes and ways. ## Basic structure of profiles A profile will process every node and way in the OSM input data to determine what ways are routable in which direction, at what speed, etc. @@ -35,40 +35,40 @@ A profile can also define various local functions it needs. Looking at [car.lua](../profiles/car.lua) as an example, at the top of the file the api version is defined and then required library files are included. -Then follows the `setup` functions, which is called once when the profile is loaded. It returns a big hash table of configurations, specifying things like what speed to use for different way types. The configurations are used later in the various processing functions. Many adjustments can be done just be modifying this configuration table. +Then follows the `setup` function, which is called once when the profile is loaded. It returns a big hash table of configurations, specifying things like what speed to use for different way types. The configurations are used later in the various processing functions. Many adjustments can be done just by modifying this configuration table. -The setup function is also where you can do other setup, like loading elevation data source if you want to consider that when processing ways. +The setup function is also where you can do other setup, like loading an elevation data source if you want to consider that when processing ways. -Then comes the `process_node` and `process_way` functions, which are called for each OSM node and way when extracting OpenStreetMap data with `osrm-extract`. +Then come the `process_node` and `process_way` functions, which are called for each OSM node and way when extracting OpenStreetMap data with `osrm-extract`. The `process_turn` function processes every possible turn in the network, and sets a penalty depending on the angle and turn of the movement. Profiles can also define a `process_segment` function to handle differences in speed along an OSM way, for example to handle elevation. As you can see, this is not currently used in the car profile. -At the end of the file, a table if returned with references to the setup and processing functions the profile has defined. +At the end of the file, a table is returned with references to the setup and processing functions the profile has defined. ## Understanding speed, weight and rate -When computing a route from A to B there can be different measure of what is the best route. That's why there's a need for different profiles. +When computing a route from A to B there can be different measures of what is the best route. That's why there's a need for different profiles. -Because speeds very on different types of roads, the shortest and the fastest route are typically different. But there are many other possible preferences. For example a user might prefer a bicycle route that follow parks or other green areas, even though both duration and distance are a bit longer. +Because speeds vary on different types of roads, the shortest and the fastest route are typically different. But there are many other possible preferences. For example a user might prefer a bicycle route that follow parks or other green areas, even though both duration and distance are a bit longer. -To handle this, OSRM doesn't simply choose the ways with the highest speed. Instead it uses the concept of `weight` and `rate`. The rate is an abstract measure that you can assign to ways as you like to make some ways preferable to others. Routing will prefer ways with high rate. +To handle this, OSRM doesn't simply choose the ways with the highest speed. Instead it uses the concepts of `weight` and `rate`. The rate is an abstract measure that you can assign to ways as you like to make some ways preferable to others. Routing will prefer ways with high rate. -The weight of a way normally computed as length / rate. The weight can be thought of as the resistance or cost when passing the way. Routing will prefer ways with low weight. +The weight of a way is normally computed as length / rate. The weight can be thought of as the resistance or cost when passing the way. Routing will prefer ways with low weight. -You can also set the weight of a way to a fixed value, In this case it's not calculated based on the length or rate, and the rate is ignored. +You can also set the weight of a way to a fixed value. In this case it's not calculated based on the length or rate, and the rate is ignored. -You should set the speed to you best estimate of the actual speed that will be used on a particular way. This will result in the best estimated travel times. +You should set the speed to your best estimate of the actual speed that will be used on a particular way. This will result in the best estimated travel times. -If you want to prefer certain ways due to other factors than the speed, adjust the rate accordingly. If you adjust the speed, the time time estimation will be skewed. +If you want to prefer certain ways due to other factors than the speed, adjust the rate accordingly. If you adjust the speed, the time estimation will be skewed. If you set the same rate on all ways, the result will be shortest path routing. If you set rate = speed on all ways, the result will be fastest path routing. -If you want to prioritize certain street, increase the rate on these. +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. @@ -81,15 +81,15 @@ set.lua | Defines the Set helper for handling sets of values sequence.lua | Defines the Sequence helper for handling sequences of values access.lua | Function for finding relevant access tags destination.lua | Function for finding relevant destination tags -destination.lua | Function for determining maximum speed +maxspeed.lua | Function for determining maximum speed guidance.lua | Function for processing guidance attributes -They all return a table of functions when you use `require` to load them. You can either store this table and reference it's functions later, of if you need only a single you can store that directly. +They all return a table of functions when you use `require` to load them. You can either store this table and reference its functions later, or if you need only a single function you can store that directly. ### setup() The `setup` function is called once when the profile is loaded and must return a table of configurations. It's also where you can do other global setup, like loading data sources that are used during processing. -Note that processing of data is parallelized and several unconnected LUA interpreters will be running at the same time. The `setup` function will be called once for each. Each LUA iinterpreter will have it's own set of globals. +Note that processing of data is parallelized and several unconnected LUA interpreters will be running at the same time. The `setup` function will be called once for each. Each LUA interpreter will have its own set of globals. The following global properties can be set under `properties` in the hash you return in the `setup` function: @@ -98,21 +98,22 @@ Attribute | Type | Notes weight_name | String | Name used in output for the routing weight property (default `'duration'`) weight_precision | Unsigned | Decimal precision of edge weights (default `1`) left_hand_driving | Boolean | Are vehicles assumed to drive on the left? (used in guidance, default `false`) -use_turn_restrictions | Boolean | Are turn instructions followed? (default `false`) +use_turn_restrictions | Boolean | Are turn restrictions followed? (default `false`) continue_straight_at_waypoint | Boolean | Must the route continue straight on at a via point, or are U-turns allowed? (default `true`) max_speed_for_map_matching | Float | Maximum vehicle speed to be assumed in matching (in m/s) max_turn_weight | Float | Maximum turn penalty weight force_split_edges | Boolean | True value forces a split of forward and backward edges of extracted ways and guarantees that `process_segment` will be called for all segments (default `false`) + The following additional global properties can be set in the hash you return in the `setup` function: Attribute | Type | Notes -------------------------------------|------------------|---------------------------------------------------------------------------- -excludable | Sequence of Sets | Determines which class-combinations are supported by the `exclude` option at query time. - | | E.g. `Sequence{Set{"ferry", "motorway"}, Set{"motorway"}}` will allow you to exclude ferries and motorways, or only motorways. +excludable | Sequence of Sets | Determines which class-combinations are supported by the `exclude` option at query time. E.g. `Sequence{Set{"ferry", "motorway"}, Set{"motorway"}}` will allow you to exclude ferries and motorways, or only motorways. classes | Sequence | Determines the allowed classes that can be referenced using `{forward,backward}_classes` on the way in the `process_way` function. restrictions | Sequence | Determines which turn restrictions will be used for this profile. suffix_list | Set | List of name suffixes needed for determining if "Highway 101 NW" the same road as "Highway 101 ES". +relation_types | Sequence | Determines wich relations should be cached for processing in this profile. It contains relations types ### process_node(profile, node, result, relations) Process an OSM node to determine whether this node is a barrier or can be passed and whether passing it incurs a delay. @@ -122,7 +123,7 @@ Argument | Description profile | The configuration table you returned in `setup`. node | The input node to process (read-only). result | The output that you will modify. -relations| The list of relation attributes passed from `process_relation` function for this node. +relations| Storage of relations to access relations, where `node` is a member. The following attributes can be set on `result`: @@ -137,116 +138,68 @@ 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| The list of relation attributes passed from `process_relation` function for this way. +relations| Storage of relations to access relations, where `way` is a member. Importantly it will set `result.forward_mode` and `result.backward_mode` to indicate the travel mode in each direction, as well as set `result.forward_speed` and `result.backward_speed` to integer values representing the speed for traversing the way. It will also set a number of other attributes on `result`. -Using the power of the scripting language you wouldn't typically see something as simple as a `result.forward_speed = 20` line within the `process_way` function. Instead `process_way` will examine the tag set on the way, process this information in various ways, calling other local functions and referencing the configuration in `profile`, etc, before arriving at the result. +Using the power of the scripting language you wouldn't typically see something as simple as a `result.forward_speed = 20` line within the `process_way` function. Instead `process_way` will examine the tag set on the way, process this information in various ways, calling other local functions and referencing the configuration in `profile`, etc., before arriving at the result. The following attributes can be set on the result in `process_way`: Attribute | Type | Notes ----------------------------------------|----------|-------------------------------------------------------------------------- forward_speed | Float | Speed on this way in km/h. Mandatory. -backward_speed | Float | " " +backward_speed | Float | "" forward_rate | Float | Routing weight, expressed as meters/*weight* (e.g. for a fastest-route weighting, you would want this to be meters/second, so set it to forward_speed/3.6) -backward_rate | Float | " " +backward_rate | Float | "" forward_mode | Enum | Mode of travel (e.g. `car`, `ferry`). Mandatory. Defined in `include/extractor/travel_mode.hpp`. -backward_mode | Enum | " " +backward_mode | Enum | "" forward_classes | Table | Mark this way as being of a specific class, e.g. `result.classes["toll"] = true`. This will be exposed in the API as `classes` on each `RouteStep`. -backward_classes | Table | " " +backward_classes | Table | "" duration | Float | Alternative setter for duration of the whole way in both directions weight | Float | Alternative setter for weight of the whole way in both directions turn_lanes_forward | String | Directions for individual lanes (normalized OSM `turn:lanes` value) -turn_lanes_backward | String | " " +turn_lanes_backward | String | "" forward_restricted | Boolean | Is this a restricted access road? (e.g. private, or deliveries only; used to enable high turn penalty, so that way is only chosen for start/end of route) -backward_restricted | Boolean | " " +backward_restricted | Boolean | "" is_startpoint | Boolean | Can a journey start on this way? (e.g. ferry; if `false`, prevents snapping the start point to this way) roundabout | Boolean | Is this part of a roundabout? circular | Boolean | Is this part of a non-roundabout circular junction? name | String | Name of the way -ref | String | Road number +ref | String | Road number (equal to set `forward_ref` and `backward_ref` with one value) +forward_ref | String | Road number in forward way direction +backward_ref | String | Road number in backward way direction destinations | String | The road's destinations exits | String | The ramp's exit numbers or names pronunciation | String | Name pronunciation road_classification.motorway_class | Boolean | Guidance: way is a motorway road_classification.link_class | Boolean | Guidance: way is a slip/link road -road_classification.road_priority_class | Enum | Guidance: order in priority list. Defined in `include/extractor/guidance/road_classification.hpp` +road_classification.road_priority_class | Enum | Guidance: order in priority list. Defined in `include/extractor/road_classification.hpp` road_classification.may_be_ignored | Boolean | Guidance: way is non-highway road_classification.num_lanes | Unsigned | Guidance: total number of lanes in way -### process_relation(profile, relation, result) - -Supported since API **version 3**. - -Given an OpenStreetMap relation, the `process_relation` function should setup values into result structure. - -Argument | Description ----------|------------------------------------------------------- -profile | The configuration table you returned in `setup`. -node | The input relation to process (read-only). -result | The output that you will modify. - -Relation process work flow consist of next steps: -1. Calls `process_relation` function for each relation. It should fill a `result` structure -2. After that each data will be passed for each member of processed relation into `process_node` and `process_way` functions - -The following attributes can be set on that result in `process_relation`: - -Attribute | Type | Notes -----------------------------------------|----------|-------------------------------------------------------------------------- -is_restriction | Boolean | Flag to determine if relation is a turn restriction - -Example processing code: -```lua - -function process_way(profile, way, result, relations) - for _, r in ipairs(relations) do - for k, v in pairs(r) do - print('data_' .. k .. '_value_' .. v) - end - end - print ('process_way ' .. way:id() .. ' ' .. result.name) -end - -function process_relation(profile, relation, result) - local t = relation:get_value_by_key("type") - if t == "route" then - for _, m in ipairs(relation:members()) do - if m:role == "north" then - result[m]['direction'] = 'north' - print('direction_north') - end - end - - print('route_relation') - end -end -``` - - ### process_segment(profile, segment) The `process_segment` function is called for every segment of OSM ways. A segment is a straight line between two OSM nodes. On OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However many ways are long. For example, many ways pass hills without any change in tags. -Processing each segment of an OSM way makes it possible to have different speeds on different parts of a way based on external data like data about elevation, pollution, noise or scenic value and adjust weight and duration of the segment. +Processing each segment of an OSM way makes it possible to have different speeds on different parts of a way based on external data like data about elevation, pollution, noise or scenic value and adjust weight and duration of the segment accordingly. -In the `process_segment` you don't have access to OSM tags. Instead you use the geographical location of the start and end point of the way to lookup other data source, like elevation data. See [rasterbot.lua](../profiles/rasterbot.lua) for an example. +In the `process_segment` function you don't have access to OSM tags. Instead you use the geographical location of the start and end point of the way to look up information from another data source, like elevation data. See [rasterbot.lua](../profiles/rasterbot.lua) for an example. The following attributes can be read and set on the result in `process_segment`: Attribute | Read/write? | Type | Notes -------------------|-------------|---------|---------------------------------------- source.lon | Read | Float | Co-ordinates of segment start -source.lat | Read | Float | " " +source.lat | Read | Float | "" target.lon | Read | Float | Co-ordinates of segment end -target.lat | Read | Float | " " -target.distance | Read | Float | Length of segment +target.lat | Read | Float | "" +distance | Read | Float | Length of segment weight | Read/write | Float | Routing weight for this segment duration | Read/write | Float | Duration for this segment @@ -255,16 +208,103 @@ The `process_turn` function is called for every possible turn in the network. Ba The following attributes can be read and set on the result in `process_turn`: -Attribute | Read/write? | Type | Notes --------------------|-------------|---------|------------------------------------------------------ -direction_modifier | Read | Enum | Geometry of turn. Defined in `include/extractor/guidance/turn_instruction.hpp` -turn_type | Read | Enum | Priority of turn. Defined in `include/extractor/guidance/turn_instruction.hpp` -has_traffic_light | Read | Boolean | Is a traffic light present at this turn? -source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`) -target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`) -angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on) -duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds) -weight | Read/write | Float | Penalty to be applied for this turn (routing weight) +Attribute | Read/write? | Type | Notes +--------------------- | ------------- | --------- | ------------------------------------------------------ +angle | Read | Float | Angle of turn in degrees (`[-179, 180]`: `0`=straight, `180`=u turn, `+x`=x degrees to the right, `-x`= x degrees to the left) +number_of_roads | Read | Integer | Number of ways at the intersection of the turn +is_u_turn | Read | Boolean | Is the turn a u-turn? +has_traffic_light | Read | Boolean | Is a traffic light present at this turn? +is_left_hand_driving | Read | Boolean | Is left-hand traffic? +source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`) +source_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp` +source_is_motorway | Read | Boolean | Is the source road a motorway? +source_is_link | Read | Boolean | Is the source road a link? +source_number_of_lanes | Read | Integer | How many lanes does the source road have? (default when not tagged: 0) +source_highway_turn_classification | Read | Integer | Classification based on highway tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15)) +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/road_classification.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) +target_highway_turn_classification | Read | Integer | Classification based on highway tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15)) +target_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)) +target_speed | Read | Integer | Speed on this target road in km/h +target_priority_class | Read | Enum | The type of road priority class of the target. Defined in `include/extractor/road_classification.hpp` +roads_on_the_right | Read | Vector | Vector with information about other roads on the right of the turn that are also connected at the intersection +roads_on_the_left | Read | Vector | Vector with information about other roads on the left of the turn that are also connected at the intersection. If turn is a u turn, this is empty. +weight | Read/write | Float | Penalty to be applied for this turn (routing weight) +duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds) + +#### `roads_on_the_right` and `roads_on_the_left` + +The information of `roads_on_the_right` and `roads_on_the_left` that can be read are as follows: + +Attribute | Read/write? | Type | Notes +--------------------- | ------------- | --------- | ------------------------------------------------------ +is_restricted | Read | Boolean | Is it a restricted access road? (See definition in `process_way`) +mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp` +is_motorway | Read | Boolean | Is the road a motorway? +is_link | Read | Boolean | Is the road a link? +number_of_lanes | Read | Integer | How many lanes does the road have? (default when not tagged: 0) +highway_turn_classification | Read | Integer | Classification based on highway tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15) +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) +speed | Read | Integer | Speed on this road in km/h +priority_class | Read | Enum | The type of road priority class of the leg. Defined in `include/extractor/road_classification.hpp` +is_incoming | Read | Boolean | Is the road an incoming road of the intersection +is_outgoing | Read | Boolean | Is the road an outgoing road of the intersection + +The order of the roads in `roads_on_the_right` and `roads_on_the_left` are *counter clockwise*. If the turn is a u turn, all other connected roads will be in `roads_on_the_right`. + +**Example** + +``` + c e + | / + | / + a ---- x ---- b + /| + / | + f d + + +``` +When turning from `a` to `b` via `x`, +* `roads_on_the_right[1]` is the road `xf` +* `roads_on_the_right[2]` is the road `xd` +* `roads_on_the_left[1]` is the road `xe` +* `roads_on_the_left[2]` is the road `xc` + +Note that indices of arrays in lua are 1-based. + +#### `highway_turn_classification` and `access_turn_classification` +When setting appropriate turn weights and duration, information about the highway and access tags of roads that are involved in the turn are necessary. The lua turn function `process_turn` does not have access to the original osrm tags anymore. However, `highway_turn_classification` and `access_turn_classification` can be set during setup. The classification set during setup can be later used in `process_turn`. + +**Example** + +In the following example we use `highway_turn_classification` to set the turn weight to `10` if the turn is on a highway and to `5` if the turn is on a primary. + +``` +function setup() + return { + highway_turn_classification = { + ['motorway'] = 2, + ['primary'] = 1 + } + } +end + +function process_turn(profile, turn) { + if turn.source_highway_turn_classification == 2 and turn.target_highway_turn_classification == 2 then + turn.weight = 10 + end + if turn.source_highway_turn_classification == 1 and turn.target_highway_turn_classification == 1 then + turn.weight = 5 + end +} +``` ## Guidance The guidance parameters in profiles are currently a work in progress. They can and will change. @@ -277,7 +317,7 @@ The priority-category influences the decision which road is considered the obvio Forks can be emitted between roads of similar priority category only. Obvious choices follow a major priority road, if the priority difference is large. ### Using raster data -OSRM has build-in support for loading an interpolating raster data in ASCII format. This can be used e.g. for factoring in elevation when computing routes. +OSRM has built-in support for loading an interpolating raster data in ASCII format. This can be used e.g. for factoring in elevation when computing routes. Use `raster:load()` in your `setup` function to load data and store the source in your configuration hash: @@ -330,8 +370,8 @@ See [rasterbot.lua](../profiles/rasterbot.lua) and [rasterbotinterp.lua](../prof ### Helper functions There are a few helper functions defined in the global scope that profiles can use: -durationIsValid -parseDuration -trimLaneString -applyAccessTokens -canonicalizeStringList +- `durationIsValid` +- `parseDuration` +- `trimLaneString` +- `applyAccessTokens` +- `canonicalizeStringList` diff --git a/docs/releasing.md b/docs/releasing.md index fd0090679..cd6dc9cb8 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -43,14 +43,17 @@ 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 OSRM version in `CMakeLists.txt` is up to date -4. Make sure the `package.json` is up to date. -5. Make sure all tests are passing (e.g. Travis CI gives you a :thumbs_up:) -6. Use an annotated tag to mark the release: `git tag vx.y.z -a` Body of the tag description should be the changelog entries. -7. Use `npm run docs` to generate the API documentation. Copy `build/docs/*` to `https://github.com/Project-OSRM/project-osrm.github.com` in the `docs/vN.N.N/api` directory -8. Push tags and commits: `git push; git push --tags` +3. Make sure the `package.json` on branch `x.y` has been committed. +4. Make sure all tests are passing (e.g. Github Actions CI gives you a :heavy_check_mark:) +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`, + write the release tag `vx.y.z` in the `Tag version` field, write the changelog entries in the `Describe this release` field + and press `Publish release`. Note that Github Actions CI deployments will create a release when publishing node binaries, so the release + may already exist. In which case the description should be updated with the changelog entries. 9. If not a release-candidate: Write a mailing-list post to osrm-talk@openstreetmap.org to announce the release -10. Wait until the travis build has been completed and check if the node binaries were published by doing: +10. Wait until the Github Actions build has been completed and check if the node binaries were published by doing: `rm -rf node_modules && npm install` locally. 11. For final releases run `npm publish` or `npm publish --tag next` for release candidates. -12. Bump version in `package.json` to `{MAJOR}.{MINOR+1}.0-latest.1` on the `master` branch after the release. +12. Bump version in `package.json` to `{MAJOR}.{MINOR+1}.0-unreleased` on the `master` branch after the release. diff --git a/docs/windows-deps.md b/docs/windows-deps.md new file mode 100644 index 000000000..32a59d5be --- /dev/null +++ b/docs/windows-deps.md @@ -0,0 +1,31 @@ +# Building OSRM for Windows + +There is experimental support for building OSRM on Windows. + +## Dependencies + +You will need a modern Windows development stack (e.g. Visual Studio 17). The published binaries are built with +[Windows Server 2022](https://github.com/actions/runner-images/blob/main/images/win/Windows2022-Readme.md) Github hosted runners. + +Dependencies are managed via [Conan](https://conan.io/) and built with [CMake](https://cmake.org/). + +## Building + +```bat +cmake -DENABLE_CONAN=ON -DENABLE_NODE_BINDINGS=ON -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G "Visual Studio 17 2022" .. + +msbuild OSRM.sln ^ +/p:Configuration=%CONFIGURATION% ^ +/p:Platform=x64 ^ +/t:rebuild ^ +/p:BuildInParallel=true ^ +/m:%NUMBER_OF_PROCESSORS% ^ +/toolsversion:Current ^ +/clp:Verbosity=normal ^ +/nologo +``` + + + + + diff --git a/example/cmake/FindTBB.cmake b/example/cmake/FindTBB.cmake deleted file mode 100644 index e5ca10039..000000000 --- a/example/cmake/FindTBB.cmake +++ /dev/null @@ -1,283 +0,0 @@ -# Locate Intel Threading Building Blocks include paths and libraries -# FindTBB.cmake can be found at https://code.google.com/p/findtbb/ -# Written by Hannes Hofmann -# Improvements by Gino van den Bergen , -# Florian Uhlig , -# Jiri Marsik - -# The MIT License -# -# Copyright (c) 2011 Hannes Hofmann -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler. -# e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21" -# TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found -# in the TBB installation directory (TBB_INSTALL_DIR). -# -# GvdB: Mac OS X distribution places libraries directly in lib directory. -# -# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER. -# TBB_ARCHITECTURE [ ia32 | em64t | itanium ] -# which architecture to use -# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9 -# which compiler to use (detected automatically on Windows) - -# This module respects -# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR} - -# This module defines -# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc. -# TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc -# TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug -# TBB_INSTALL_DIR, the base TBB install directory -# TBB_LIBRARIES, the libraries to link against to use TBB. -# TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols. -# TBB_FOUND, If false, don't try to use TBB. -# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h - - -if (WIN32) - # has em64t/vc8 em64t/vc9 - # has ia32/vc7.1 ia32/vc8 ia32/vc9 - set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB") - set(_TBB_LIB_NAME "tbb") - set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") - set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") - set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") - if (MSVC71) - set (_TBB_COMPILER "vc7.1") - endif(MSVC71) - if (MSVC80) - set(_TBB_COMPILER "vc8") - endif(MSVC80) - if (MSVC90) - set(_TBB_COMPILER "vc9") - endif(MSVC90) - if(MSVC10) - set(_TBB_COMPILER "vc10") - endif(MSVC10) - # Todo: add other Windows compilers such as ICL. - set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) -endif (WIN32) - -if (UNIX) - if (APPLE) - # MAC - set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions") - # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug - set(_TBB_LIB_NAME "tbb") - set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") - set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") - set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") - # default flavor on apple: ia32/cc4.0.1_os10.4.9 - # Jiri: There is no reason to presume there is only one flavor and - # that user's setting of variables should be ignored. - if(NOT TBB_COMPILER) - set(_TBB_COMPILER "cc4.0.1_os10.4.9") - elseif (NOT TBB_COMPILER) - set(_TBB_COMPILER ${TBB_COMPILER}) - endif(NOT TBB_COMPILER) - if(NOT TBB_ARCHITECTURE) - set(_TBB_ARCHITECTURE "ia32") - elseif(NOT TBB_ARCHITECTURE) - set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) - endif(NOT TBB_ARCHITECTURE) - else (APPLE) - # LINUX - set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include") - set(_TBB_LIB_NAME "tbb") - set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") - set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") - set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") - # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21 - # has ia32/* - # has itanium/* - set(_TBB_COMPILER ${TBB_COMPILER}) - set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) - endif (APPLE) -endif (UNIX) - -if (CMAKE_SYSTEM MATCHES "SunOS.*") -# SUN -# not yet supported -# has em64t/cc3.4.3_kernel5.10 -# has ia32/* -endif (CMAKE_SYSTEM MATCHES "SunOS.*") - - -#-- Clear the public variables -set (TBB_FOUND "NO") - - -#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR} -# first: use CMake variable TBB_INSTALL_DIR -if (TBB_INSTALL_DIR) - set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR}) -endif (TBB_INSTALL_DIR) -# second: use environment variable -if (NOT _TBB_INSTALL_DIR) - if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") - set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR}) - endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") - # Intel recommends setting TBB21_INSTALL_DIR - if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") - set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR}) - endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") - if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") - set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR}) - endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") - if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") - set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR}) - endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") -endif (NOT _TBB_INSTALL_DIR) -# third: try to find path automatically -if (NOT _TBB_INSTALL_DIR) - if (_TBB_DEFAULT_INSTALL_DIR) - set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR}) - endif (_TBB_DEFAULT_INSTALL_DIR) -endif (NOT _TBB_INSTALL_DIR) -# sanity check -if (NOT _TBB_INSTALL_DIR) - message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}") -else (NOT _TBB_INSTALL_DIR) -# finally: set the cached CMake variable TBB_INSTALL_DIR -if (NOT TBB_INSTALL_DIR) - set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory") - mark_as_advanced(TBB_INSTALL_DIR) -endif (NOT TBB_INSTALL_DIR) - - -#-- A macro to rewrite the paths of the library. This is necessary, because -# find_library() always found the em64t/vc9 version of the TBB libs -macro(TBB_CORRECT_LIB_DIR var_name) -# if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") - string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) -# endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") - string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) - string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) - string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) - string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) - string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) -endmacro(TBB_CORRECT_LIB_DIR var_content) - - -#-- Look for include directory and set ${TBB_INCLUDE_DIR} -set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include) -# Jiri: tbbvars now sets the CPATH environment variable to the directory -# containing the headers. -find_path(TBB_INCLUDE_DIR - tbb/task_scheduler_init.h - PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH -) -mark_as_advanced(TBB_INCLUDE_DIR) - - -#-- Look for libraries -# GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh] -if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") - set (_TBB_LIBRARY_DIR - ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM} - ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib - ) -endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") -# Jiri: This block isn't mutually exclusive with the previous one -# (hence no else), instead I test if the user really specified -# the variables in question. -if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) - # HH: deprecated - message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).") - # Jiri: It doesn't hurt to look in more places, so I store the hints from - # ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER - # variables and search them both. - set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR}) -endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) - -# GvdB: Mac OS X distribution places libraries directly in lib directory. -list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib) - -# Jiri: No reason not to check the default paths. From recent versions, -# tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH -# variables, which now point to the directories of the lib files. -# It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS -# argument instead of the implicit PATHS as it isn't hard-coded -# but computed by system introspection. Searching the LIBRARY_PATH -# and LD_LIBRARY_PATH environment variables is now even more important -# that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates -# the use of TBB built from sources. -find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_LIBRARY_DIR} - PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) -find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_LIBRARY_DIR} - PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) - -#Extract path from TBB_LIBRARY name -get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH) - -#TBB_CORRECT_LIB_DIR(TBB_LIBRARY) -#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY) -mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY) - -#-- Look for debug libraries -# Jiri: Changed the same way as for the release libraries. -find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} - PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) -find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} - PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) - -# Jiri: Self-built TBB stores the debug libraries in a separate directory. -# Extract path from TBB_LIBRARY_DEBUG name -get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH) - -#TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG) -#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG) -mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG) - - -if (TBB_INCLUDE_DIR) - if (TBB_LIBRARY) - set (TBB_FOUND "YES") - set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES}) - set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES}) - set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE) - set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE) - # Jiri: Self-built TBB stores the debug libraries in a separate directory. - set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE) - mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES) - message(STATUS "Found Intel TBB") - endif (TBB_LIBRARY) -endif (TBB_INCLUDE_DIR) - -if (NOT TBB_FOUND) - message("ERROR: Intel TBB NOT found!") - message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}") - # do only throw fatal, if this pkg is REQUIRED - if (TBB_FIND_REQUIRED) - message(FATAL_ERROR "Could NOT find TBB library.") - endif (TBB_FIND_REQUIRED) -endif (NOT TBB_FOUND) - -endif (NOT _TBB_INSTALL_DIR) - -if (TBB_FOUND) - set(TBB_INTERFACE_VERSION 0) - FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS) - STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}") - set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}") -endif (TBB_FOUND) diff --git a/example/cmake/FindTBB.cmake b/example/cmake/FindTBB.cmake new file mode 120000 index 000000000..f51bdf742 --- /dev/null +++ b/example/cmake/FindTBB.cmake @@ -0,0 +1 @@ +../../cmake/FindTBB.cmake \ No newline at end of file diff --git a/example/example.cpp b/example/example.cpp index edce8d17a..108fc622e 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -30,9 +30,17 @@ int main(int argc, const char *argv[]) // Configure based on a .osrm base path, and no datasets in shared mem from osrm-datastore EngineConfig config; + config.storage_config = {argv[1]}; config.use_shared_memory = false; + // We support two routing speed up techniques: + // - Contraction Hierarchies (CH): requires extract+contract pre-processing + // - Multi-Level Dijkstra (MLD): requires extract+partition+customize pre-processing + // + // config.algorithm = EngineConfig::Algorithm::CH; + config.algorithm = EngineConfig::Algorithm::MLD; + // Routing machine with several services (such as Route, Table, Nearest, Trip, Match) const OSRM osrm{config}; @@ -44,14 +52,15 @@ int main(int argc, const char *argv[]) params.coordinates.push_back({util::FloatLongitude{7.419505}, util::FloatLatitude{43.736825}}); // Response is in JSON format - json::Object result; + engine::api::ResultT result = json::Object(); // Execute routing request, this does the heavy lifting const auto status = osrm.Route(params, result); + auto &json_result = result.get(); if (status == Status::Ok) { - auto &routes = result.values["routes"].get(); + auto &routes = json_result.values["routes"].get(); // Let's just use the first route auto &route = routes.values.at(0).get(); @@ -71,8 +80,8 @@ int main(int argc, const char *argv[]) } else if (status == Status::Error) { - const auto code = result.values["code"].get().value; - const auto message = result.values["message"].get().value; + const auto code = json_result.values["code"].get().value; + const auto message = json_result.values["message"].get().value; std::cout << "Code: " << code << "\n"; std::cout << "Message: " << code << "\n"; diff --git a/features/bicycle/access.feature b/features/bicycle/access.feature index df8baa757..787dd05e5 100644 --- a/features/bicycle/access.feature +++ b/features/bicycle/access.feature @@ -127,6 +127,7 @@ Feature: Bike - Access tags on ways | | | agricultural | | | | | forestry | | | | | delivery | | + | | | use_sidepath | | Scenario: Bike - Access tags on both node and way Then routability should be diff --git a/features/bicycle/alley.feature b/features/bicycle/alley.feature index 74a87b98d..db7b624a7 100644 --- a/features/bicycle/alley.feature +++ b/features/bicycle/alley.feature @@ -28,7 +28,7 @@ Feature: Bicycle - Route around alleys When I route I should get | from | to | a:nodes | weight | # | - | a | f | 1:2:3:6 | 200.4 | Avoids d,e,f | - | a | e | 1:2:5 | 176.4 | Take the alley b,e if neccessary | - | d | f | 4:1:2:3:6 | 252.6 | Avoids the alley d,e,f | + | a | f | 1:2:3:6 | 196.2 | Avoids d,e,f | + | a | e | 1:2:5 | 172.2 | Take the alley b,e if neccessary | + | d | f | 4:1:2:3:6 | 248.4 | Avoids the alley d,e,f | diff --git a/features/bicycle/barrier.feature b/features/bicycle/barrier.feature index 15cd48433..ae4ab579c 100644 --- a/features/bicycle/barrier.feature +++ b/features/bicycle/barrier.feature @@ -10,6 +10,7 @@ Feature: Barriers | | x | | bollard | x | | gate | x | + | lift_gate | x | | cycle_barrier | x | | cattle_grid | x | | border_control | x | @@ -18,7 +19,7 @@ Feature: Barriers | entrance | x | | wall | | | fence | | - | some_tag | | + | some_tag | x | | block | x | Scenario: Bike - Access tag trumphs barriers diff --git a/features/bicycle/classes.feature b/features/bicycle/classes.feature new file mode 100644 index 000000000..170abc172 --- /dev/null +++ b/features/bicycle/classes.feature @@ -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)],[()],[()] | diff --git a/features/bicycle/cycleway.feature b/features/bicycle/cycleway.feature index f836ef8bf..c04d7aabd 100644 --- a/features/bicycle/cycleway.feature +++ b/features/bicycle/cycleway.feature @@ -46,12 +46,14 @@ Feature: Bike - Cycle tracks/lanes | primary | | | | x | x | | motorway | | | | | | | motorway | track | | | x | | - | motorway | opposite | | | | x | - | motorway | | track | | | x | - | motorway | | opposite | | | x | + | motorway | opposite | | | x | x | + | motorway | | track | | x | | + | motorway | | opposite | | x | x | | motorway | | | track | x | | - | motorway | | | opposite | x | | - | motorway | | track | track | x | x | + | motorway | | | opposite | x | x | + # motorways are implicit oneways and cycleway tracks next to oneways always + # follow the oneway direction (unless tagged as opposite) + | motorway | | track | track | x | | | motorway | | opposite | opposite | x | x | | motorway | | track | opposite | x | x | | motorway | | opposite | track | x | x | @@ -92,6 +94,6 @@ Feature: Bike - Cycle tracks/lanes Then routability should be | highway | cycleway | oneway | forw | backw | | motorway | track | yes | 15 km/h | | - | residential | track | yes | 15 km/h | 6 km/h +-1 | - | cycleway | track | yes | 15 km/h | 6 km/h +-1 | - | footway | track | yes | 15 km/h | 6 km/h +-1 | + | residential | track | yes | 15 km/h | 4 km/h +-1 | + | cycleway | track | yes | 15 km/h | 4 km/h +-1 | + | footway | track | yes | 15 km/h | 4 km/h +-1 | diff --git a/features/bicycle/exclude.feature b/features/bicycle/exclude.feature new file mode 100644 index 000000000..f88315408 --- /dev/null +++ b/features/bicycle/exclude.feature @@ -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 | + + When I request a travel time matrix I should get + | | a | f | + | a | 0 | 301 +- 1 | + | f | 301.2 +- 1 | 0 | + + diff --git a/features/bicycle/maxspeed.feature b/features/bicycle/maxspeed.feature index a4fc57b3d..72f6a0ed6 100644 --- a/features/bicycle/maxspeed.feature +++ b/features/bicycle/maxspeed.feature @@ -9,7 +9,7 @@ Feature: Bike - Max speed restrictions Then routability should be | highway | maxspeed | bothw | | residential | | 15 km/h | - | residential | 10 | 9 km/h | + | residential | 10 | 10 km/h | Scenario: Bicycle - Ignore maxspeed when higher than way speed Then routability should be @@ -65,12 +65,12 @@ Feature: Bike - Max speed restrictions Then routability should be | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | | | | | 15 km/h | 15 km/h | - | 10 | | | 9 km/h | 9 km/h | - | | 10 | | 9 km/h | 15 km/h | - | | | 10 | 14 km/h | 9 km/h | - | 2 | 10 | | 9 km/h | 2 km/h | - | 2 | | 10 | 2 km/h | 9 km/h | - | 2 | 5 | 10 | 5 km/h | 9 km/h | + | 10 | | | 10 km/h | 10 km/h | + | | 10 | | 10 km/h | 15 km/h | + | | | 10 | 15 km/h | 10 km/h | + | 2 | 10 | | 10 km/h | 2 km/h | + | 2 | | 10 | 2 km/h | 10 km/h | + | 2 | 5 | 10 | 5 km/h | 10 km/h | Scenario: Bike - Maxspeed should not allow routing on unroutable ways Then routability should be diff --git a/features/bicycle/oneway.feature b/features/bicycle/oneway.feature index 842ac725e..4099a434c 100644 --- a/features/bicycle/oneway.feature +++ b/features/bicycle/oneway.feature @@ -141,5 +141,12 @@ Feature: Bike - Oneway streets | highway | oneway | cycleway:left | cycleway:right | forw | backw | | primary | yes | | | cycling | pushing bike | | primary | yes | | track | cycling | pushing bike | - | primary | yes | track | | cycling | cycling | - | primary | yes | track | track | cycling | cycling | \ No newline at end of file + | primary | yes | track | | cycling | pushing bike | + | primary | yes | track | track | cycling | pushing bike | + + Scenario: Bike - Left/right cycleways on any oneways + Then routability should be + | foot | oneway | cycleway:left | cycleway:right | forw | backw | + | no | yes | track | | cycling | | + | yes | yes | track | | cycling | pushing bike | + | yes | -1 | track | | pushing bike | cycling | \ No newline at end of file diff --git a/features/bicycle/safety.feature b/features/bicycle/safety.feature index b09099c09..4561e1a5e 100644 --- a/features/bicycle/safety.feature +++ b/features/bicycle/safety.feature @@ -11,15 +11,15 @@ Feature: Bicycle - Adds penalties to unsafe roads Then routability should be | highway | cycleway | forw | backw | forw_rate | backw_rate | | motorway | | | | | | - | primary | | 15 km/h | 15 km/h | 2.9 | 2.9 | - | secondary | | 15 km/h | 15 km/h | 3.1 | 3.1 | + | primary | | 15 km/h | 15 km/h | 2.1 | 2.1 | + | secondary | | 15 km/h | 15 km/h | 2.7 | 2.7 | | tertiary | | 15 km/h | 15 km/h | 3.3 | 3.3 | - | primary_link | | 15 km/h | 15 km/h | 2.9 | 2.9 | - | secondary_link | | 15 km/h | 15 km/h | 3.1 | 3.1 | + | primary_link | | 15 km/h | 15 km/h | 2.1 | 2.1 | + | secondary_link | | 15 km/h | 15 km/h | 2.7 | 2.7 | | tertiary_link | | 15 km/h | 15 km/h | 3.3 | 3.3 | | residential | | 15 km/h | 15 km/h | 4.2 | 4.2 | | cycleway | | 15 km/h | 15 km/h | 4.2 | 4.2 | - | footway | | 6 km/h +-1 | 6 km/h +-1 | 1.7 | 1.7 | + | footway | | 4 km/h +-1 | 4 km/h +-1 | 1.1 | 1.1 | Scenario: Bike - Apply no penalties to ways with cycleways Then routability should be @@ -33,7 +33,7 @@ Feature: Bicycle - Adds penalties to unsafe roads | tertiary_link | track | 15 km/h | 15 km/h | 4.2 | 4.2 | | residential | track | 15 km/h | 15 km/h | 4.2 | 4.2 | | cycleway | track | 15 km/h | 15 km/h | 4.2 | 4.2 | - | footway | track | 15 km/h | 15 km/h | 4.2 | 4.2 | + | footway | track | 14 km/h | 14 km/h | 4.2 | 4.2 | | motorway | lane | 15 km/h | | 4.2 | | | primary | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | | secondary | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | @@ -41,7 +41,7 @@ Feature: Bicycle - Adds penalties to unsafe roads | primary_link | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | | secondary_link | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | | tertiary_link | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | - | residential | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | + | residential | lane | 14 km/h | 14 km/h | 4.2 | 4.2 | | cycleway | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | | footway | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | | motorway | shared_lane | 15 km/h | | 4.2 | | @@ -51,49 +51,49 @@ Feature: Bicycle - Adds penalties to unsafe roads Then routability should be | highway | cycleway:right | cycleway:left | forw | backw | forw_rate | backw_rate | | motorway | track | | 15 km/h | | 4.2 | | - | primary | track | | 15 km/h | 15 km/h | 4.2 | 2.9 | - | secondary | track | | 15 km/h | 15 km/h | 4.2 | 3.1 | + | primary | track | | 15 km/h | 15 km/h | 4.2 | 2.1 | + | secondary | track | | 15 km/h | 15 km/h | 4.2 | 2.7 | | tertiary | track | | 15 km/h | 15 km/h | 4.2 | 3.3 | - | primary_link | track | | 15 km/h | 15 km/h | 4.2 | 2.9 | - | secondary_link | track | | 15 km/h | 15 km/h | 4.2 | 3.1 | + | primary_link | track | | 15 km/h | 15 km/h | 4.2 | 2.1 | + | secondary_link | track | | 15 km/h | 15 km/h | 4.2 | 2.7 | | tertiary_link | track | | 15 km/h | 15 km/h | 4.2 | 3.3 | | residential | track | | 15 km/h | 15 km/h | 4.2 | 4.2 | | cycleway | track | | 15 km/h | 15 km/h | 4.2 | 4.2 | - | footway | track | | 15 km/h | 6 km/h +-1 | 4.2 | 1.7 | - | motorway | | track | | 15 km/h | | 4.2 | - | primary | | track | 15 km/h | 15 km/h | 2.9 | 4.2 | - | secondary | | track | 15 km/h | 15 km/h | 3.1 | 4.2 | + | footway | track | | 14 km/h | 4 km/h +-1 | 4.2 | 1.1 | + | motorway | | track | 15 km/h | | 4.2 | | + | primary | | track | 15 km/h | 15 km/h | 2.1 | 4.2 | + | secondary | | track | 15 km/h | 15 km/h | 2.7 | 4.2 | | tertiary | | track | 15 km/h | 15 km/h | 3.3 | 4.2 | - | primary_link | | track | 15 km/h | 15 km/h | 2.9 | 4.2 | - | secondary_link | | track | 15 km/h | 15 km/h | 3.1 | 4.2 | + | primary_link | | track | 15 km/h | 15 km/h | 2.1 | 4.2 | + | secondary_link | | track | 15 km/h | 15 km/h | 2.7 | 4.2 | | tertiary_link | | track | 15 km/h | 15 km/h | 3.3 | 4.2 | - | residential | | track | 15 km/h | 15 km/h | 4.2 | 4.2 | + | residential | | track | 14 km/h | 14 km/h | 4.2 | 4.2 | | cycleway | | track | 15 km/h | 15 km/h | 4.2 | 4.2 | - | footway | | track | 6 km/h +-1 | 15 km/h | 1.7 | 4.2 | + | footway | | track | 4 km/h +-1 | 15 km/h | 1.1 | 4.2 | | motorway | lane | | 15 km/h | | 4.2 | | - | primary | lane | | 15 km/h | 15 km/h | 4.2 | 2.9 | - | secondary | lane | | 15 km/h | 15 km/h | 4.2 | 3.1 | + | primary | lane | | 15 km/h | 15 km/h | 4.2 | 2.1 | + | secondary | lane | | 15 km/h | 15 km/h | 4.2 | 2.7 | | tertiary | lane | | 15 km/h | 15 km/h | 4.2 | 3.3 | - | primary_link | lane | | 15 km/h | 15 km/h | 4.2 | 2.9 | - | secondary_link | lane | | 15 km/h | 15 km/h | 4.2 | 3.1 | + | primary_link | lane | | 15 km/h | 15 km/h | 4.2 | 2.1 | + | secondary_link | lane | | 14 km/h | 14 km/h | 4.2 | 2.7 | | tertiary_link | lane | | 15 km/h | 15 km/h | 4.2 | 3.3 | | residential | lane | | 15 km/h +-1 | 15 km/h +-1 | 4.2 | 4.2 | | cycleway | lane | | 15 km/h | 15 km/h | 4.2 | 4.2 | - | footway | lane | | 15 km/h | 6 km/h +-1 | 4.2 | 1.7 | - | motorway | | lane | | 15 km/h | | 4.2 | - | primary | | lane | 15 km/h | 15 km/h | 2.9 | 4.2 | - | secondary | | lane | 15 km/h +-1 | 15 km/h +-1 | 3.1 | 4.2 | + | footway | lane | | 15 km/h | 4 km/h +-1 | 4.2 | 1.1 | + | motorway | | lane | 15 km/h | | 4.2 | | + | primary | | lane | 15 km/h | 15 km/h | 2.1 | 4.2 | + | secondary | | lane | 15 km/h +-1 | 15 km/h +-1 | 2.7 | 4.2 | | tertiary | | lane | 15 km/h | 15 km/h | 3.3 | 4.2 | - | primary_link | | lane | 15 km/h | 15 km/h | 2.9 | 4.2 | - | secondary_link | | lane | 15 km/h | 15 km/h | 3.1 | 4.2 | + | primary_link | | lane | 14 km/h | 14 km/h | 2.1 | 4.2 | + | secondary_link | | lane | 15 km/h | 15 km/h | 2.7 | 4.2 | | tertiary_link | | lane | 15 km/h | 15 km/h | 3.3 | 4.2 | | residential | | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | | cycleway | | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | - | footway | | lane | 6 km/h +-1 | 15 km/h | 1.7 | 4.2 | + | footway | | lane | 4 km/h +-1 | 15 km/h | 1.1 | 4.2 | | motorway | shared_lane | | 15 km/h | | 4.2 | | - | primary | shared_lane | | 15 km/h | 15 km/h | 4.2 | 2.9 | - | motorway | | shared_lane | | 15 km/h | | 4.2 | - | primary | | shared_lane | 15 km/h | 15 km/h | 2.9 | 4.2 | + | primary | shared_lane | | 15 km/h | 15 km/h | 4.2 | 2.1 | + | motorway | | shared_lane | 14 km/h | | 4.2 | | + | primary | | shared_lane | 15 km/h | 15 km/h | 2.1 | 4.2 | Scenario: Bike - Don't apply penalties for all kind of cycleways @@ -101,4 +101,4 @@ Feature: Bicycle - Adds penalties to unsafe roads | highway | cycleway | forw | backw | forw_rate | backw_rate | | tertiary | shared_lane | 15 km/h | 15 km/h | 4.2 | 4.2 | | tertiary | lane | 15 km/h | 15 km/h | 4.2 | 4.2 | - | tertiary | opposite | 15 km/h | 15 km/h | 3.3 | 4.2 | + | tertiary | opposite | 15 km/h | 15 km/h | 3.3 | 3.3 | diff --git a/features/bicycle/surface.feature b/features/bicycle/surface.feature index 24e172c78..5ca104fba 100644 --- a/features/bicycle/surface.feature +++ b/features/bicycle/surface.feature @@ -8,29 +8,38 @@ Feature: Bike - Surfaces Then routability should be | highway | surface | bothw | | cycleway | | 48 s | - | cycleway | asphalt | 48 s | + | cycleway | asphalt | 47.9 s | + | cycleway | chipseal | 48 s | + | cycleway | concrete | 48 s | + | cycleway | concrete_lanes | 48 s | | cycleway | cobblestone:flattened | 72 s | | cycleway | paving_stones | 72 s | + | cycleway | wood | 72 s | + | cycleway | metal | 72 s | | cycleway | compacted | 72 s | - | cycleway | cobblestone | 120 s | - | cycleway | fine_gravel | 120 s | + | cycleway | fine_gravel | 72 s | + | cycleway | ground | 72 s | + | cycleway | dirt | 90 s | + | cycleway | cobblestone | 102.9 s | | cycleway | gravel | 120 s | - | cycleway | pebblestone | 120.1 s | - | cycleway | dirt | 120 s | + | cycleway | pebblestone | 120 s | + | cycleway | grass_paver | 120 s | + | cycleway | dirt | 90 s | | cycleway | earth | 120 s | | cycleway | grass | 120 s | | cycleway | mud | 240 s | - | cycleway | sand | 240.1 s | - | cycleway | sett | 72 s | + | cycleway | sand | 240 s | + | cycleway | woodchips | 240 s | + | cycleway | sett | 80 s | Scenario: Bicycle - Good surfaces on small paths Then routability should be - | highway | surface | bothw | - | cycleway | | 48 s | - | path | | 60 s | - | track | | 60 s | - | track | asphalt | 60 s | - | path | asphalt | 60 s | + | highway | surface | bothw | + | cycleway | | 48 s | + | path | | 55.3 s | + | track | | 60 s | + | track | asphalt | 60 s | + | path | asphalt | 55.4 s | Scenario: Bicycle - Surfaces should not make unknown ways routable Then routability should be @@ -54,6 +63,6 @@ Feature: Bike - Surfaces When I route I should get | from | to | route | modes | speed | | a | b | ab,ab | cycling,cycling | 15 km/h | - | b | a | ab,ab | pushing bike,pushing bike | 6 km/h | - | c | d | cd,cd | pushing bike,pushing bike | 6 km/h | - | d | c | cd,cd | pushing bike,pushing bike | 6 km/h | + | b | a | ab,ab | pushing bike,pushing bike | 4 km/h | + | c | d | cd,cd | pushing bike,pushing bike | 4 km/h | + | d | c | cd,cd | pushing bike,pushing bike | 4 km/h | diff --git a/features/bicycle/turn_penalty.feature b/features/bicycle/turn_penalty.feature index d0c144e32..763827527 100644 --- a/features/bicycle/turn_penalty.feature +++ b/features/bicycle/turn_penalty.feature @@ -37,6 +37,6 @@ Feature: Turn Penalties | from | to | distance | weight | # | | a | c | 900m +- 1 | 216 | Going straight has no penalties | | a | d | 900m +- 1 | 220.2 | Turning right had penalties | - | e | g | 2100m +- 4| 503.9 | Going straght has no penalties | - | e | h | 2100m +- 4| 515.1 | Turn sharp right has even higher penalties| + | e | g | 2100m +- 5| 503.9 | Going straght has no penalties | + | e | h | 2100m +- 5| 515.1 | Turn sharp right has even higher penalties| diff --git a/features/car/access.feature b/features/car/access.feature index ea11b5238..0bebd2589 100644 --- a/features/car/access.feature +++ b/features/car/access.feature @@ -157,15 +157,16 @@ Feature: Car - Restricted access Scenario: Car - Access combinations Then routability should be - | highway | access | vehicle | motor_vehicle | motorcar | forw | backw | # | - | runway | private | | | permissive | x | x | | - | primary | forestry | | yes | | x | x | | - | cycleway | | | designated | | x | x | | - | residential | | yes | no | | | | | - | motorway | yes | permissive | | private | x | | implied oneway | - | trunk | agricultural | designated | permissive | no | | | | - | pedestrian | | | | | | | | - | pedestrian | | | | destination | | | temporary disabled #3773 | + | highway | access | vehicle | motor_vehicle | motorcar | forw | backw | # | + | runway | private | | | permissive | x | x | | + | primary | forestry | | yes | | x | x | | + | cycleway | | | designated | | x | x | | + | unclassified | | | destination | destination | x | x | | + | residential | | yes | no | | | | | + | motorway | yes | permissive | | private | x | | implied oneway | + | trunk | agricultural | designated | permissive | no | | | | + | pedestrian | | | | | | | | + | pedestrian | | | | destination | | | temporary disabled #3773 | Scenario: Car - Ignore access tags for other modes Then routability should be @@ -184,7 +185,7 @@ Feature: Car - Restricted access Then routability should be | highway | hov | bothw | forw_rate | backw_rate | | primary | designated | x | 18.2 | 18.2 | - | primary | yes | x | 18.2 | 18.2 | + | primary | yes | x | 18.3 | 18.3 | | primary | no | x | 18.2 | 18.2 | # Models: @@ -195,7 +196,7 @@ Feature: Car - Restricted access Then routability should be | highway | hov | hov:lanes | lanes | access | oneway | forw | backw | forw_rate | | motorway | designated | designated\|designated\|designated | 3 | hov | yes | x | | 25 | - | motorway | lane | | 3 | designated | yes | x | | 25 | + | motorway | lane | | 3 | designated | yes | x | | 25.3 | @hov Scenario: Car - a way with all lanes HOV-designated is highly penalized by default (similar to hov=designated) @@ -205,7 +206,7 @@ Feature: Car - Restricted access # This test is flaky because non-deterministic turn generation sometimes emits a NoTurn here that is marked as restricted. #3769 #| primary | | designated | | | x | x | 18.2 | 18.2 | #| primary | designated | | | | x | x | 18.2 | 18.2 | - | primary | designated\|designated | designated\|designated | | | x | x | 18.2 | 18.2 | + | primary | designated\|designated | designated\|designated | | | x | x | 18.3 | 18.3 | | primary | designated\|no | designated\|no | | | x | x | 18.2 | 18.2 | | primary | yes\|no | yes\|no | | | x | x | 18.2 | 18.2 | | primary | | | | | x | x | 18.2 | 18.2 | diff --git a/features/car/avoid.feature b/features/car/avoid.feature new file mode 100644 index 000000000..7ac9c1f01 --- /dev/null +++ b/features/car/avoid.feature @@ -0,0 +1,23 @@ +@routing @car @way +Feature: Car - Avoid defined areas + + Background: + Given the profile file "car" initialized with + """ + profile.avoid = Set { 'motorway', 'motorway_link' } + profile.speeds = Sequence { + highway = { + motorway = 90, + motorway_link = 45, + primary = 50 + } + } + """ + + Scenario: Car - Avoid motorways + Then routability should be + | highway | bothw | + | motorway | | + | motorway_link | | + | primary | x | + diff --git a/features/car/barrier.feature b/features/car/barrier.feature index 19fdb1290..fd7e7f834 100644 --- a/features/car/barrier.feature +++ b/features/car/barrier.feature @@ -45,3 +45,23 @@ Feature: Car - Barriers | bollard | | | | bollard | rising | x | | bollard | removable | | + + # https://github.com/Project-OSRM/osrm-backend/issues/5996 + Scenario: Car - Kerb exception for barriers + Then routability should be + | node/barrier | node/highway | node/kerb | bothw | + | kerb | | | | + | kerb | crossing | | x | + | kerb | crossing | yes | x | + | kerb | | lowered | x | + | kerb | | flush | x | + | kerb | | raised | | + | kerb | | yes | | + + Scenario: Car - Height restrictions + Then routability should be + | node/barrier | node/maxheight | bothw | + | height_restrictor | | x | + | height_restrictor | 1 | | + | height_restrictor | 3 | x | + | height_restrictor | default | x | diff --git a/features/car/bridge.feature b/features/car/bridge.feature index 1a1c0d3c2..7c43f24cc 100644 --- a/features/car/bridge.feature +++ b/features/car/bridge.feature @@ -20,9 +20,9 @@ Feature: Car - Handle driving | efg | primary | | | When I route I should get - | from | to | route | modes | - | a | g | abc,cde,efg,efg | driving,driving,driving,driving | - | e | a | cde,abc,abc | driving,driving,driving | + | from | to | route | modes | turns | + | a | g | abc,cde,efg,efg | driving,driving,driving,driving | depart,new name right,new name left,arrive | + | e | a | cde,abc,abc | driving,driving,driving | depart,new name left,arrive | Scenario: Car - Control test without durations, osrm uses movable bridge speed to calculate duration Given the node map @@ -39,9 +39,9 @@ Feature: Car - Handle driving | efg | primary | | When I route I should get - | from | to | route | modes | speed | time | - | a | g | abc,cde,efg,efg | driving,driving,driving,driving | 13 km/h | 340s +-1 | - | e | c | cde,cde | driving,driving | 5 km/h | 295s +-1 | + | from | to | route | modes | speed | time | turns | + | a | g | abc,cde,efg,efg | driving,driving,driving,driving | 13 km/h | 332s +-1 | depart,new name right,new name left,arrive | + | e | c | cde,cde | driving,driving | 5 km/h | 288s +-1 | depart,arrive | Scenario: Car - Properly handle durations Given the node map @@ -58,7 +58,7 @@ Feature: Car - Handle driving | efg | primary | | | When I route I should get - | from | to | route | modes | speed | - | a | g | abc,cde,efg,efg | driving,driving,driving,driving | 7 km/h | - | c | e | cde,cde | driving,driving | 2 km/h | - | e | c | cde,cde | driving,driving | 2 km/h | + | from | to | route | modes | speed | turns | + | a | g | abc,cde,efg,efg | driving,driving,driving,driving | 7 km/h | depart,new name right,new name left,arrive | + | c | e | cde,cde | driving,driving | 2 km/h | depart,arrive | + | e | c | cde,cde | driving,driving | 2 km/h | depart,arrive | diff --git a/features/car/classes.feature b/features/car/classes.feature index e8ad41785..6c2a5cf22 100644 --- a/features/car/classes.feature +++ b/features/car/classes.feature @@ -82,7 +82,7 @@ Feature: Car - Mode flag | from | to | route | turns | classes | | a | d | ab,cd | depart,arrive| [(restricted),(motorway,restricted),()],[()] | - Scenario: Car - We toll restricted with a class + Scenario: Car - We tag toll with a class Given the node map """ a b @@ -99,6 +99,45 @@ Feature: Car - Mode flag | from | to | route | turns | classes | | a | d | ab,cd | depart,arrive | [(toll),(motorway,toll),()],[()] | + Scenario: Car - 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: Car - 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: Car - From roundabout on toll road Given the node map """ @@ -124,4 +163,3 @@ Feature: Car - Mode flag When I route I should get | from | to | route | turns | classes | | a | f | ab,df,df,df | depart,roundabout-exit-2,exit roundabout slight right,arrive | [()],[(),(motorway)],[(toll,motorway)],[()] | - diff --git a/features/car/conditional_restrictions.feature b/features/car/conditional_restrictions.feature index d2adb67e3..c2311067c 100644 --- a/features/car/conditional_restrictions.feature +++ b/features/car/conditional_restrictions.feature @@ -17,27 +17,27 @@ Feature: Car - Turn restrictions Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the node map """ - n - p j e - s + a + d j b + c """ And the ways | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | + | aj | no | + | jc | no | + | bj | yes | + | jd | yes | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | only_right_turn @ (has_pygmies > 10 p) | + | restriction | bj | aj | j | only_right_turn @ (has_pygmies > 10 p) | When I route I should get | from | to | route | - | e | s | ej,js,js | - | e | n | ej,nj,nj | - | e | p | ej,jp,jp | + | b | c | bj,jc,jc | + | b | a | bj,aj,aj | + | b | d | bj,jd,jd | @no_turning @conditionals Scenario: Car - Restriction would be on, but the restriction was badly tagged @@ -48,29 +48,29 @@ Feature: Car - Turn restrictions Given the node map """ - n + a p | \ | j | \ - s m + c m """ And the ways | nodes | - | nj | - | js | + | aj | + | jc | | pjm | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | nj | pjm | j | no_left_turn @ (Mo-Fr 07:00-10:30) | - | restriction | js | pjm | j | no_right_turn @ (Mo-Fr 07:00-10:30) | + | restriction | aj | pjm | j | no_left_turn @ (Mo-Fr 07:00-10:30) | + | restriction | jc | pjm | j | no_right_turn @ (Mo-Fr 07:00-10:30) | When I route I should get | from | to | route | - | n | m | nj,pjm,pjm | - | s | m | js,pjm,pjm | + | a | m | aj,pjm,pjm | + | c | m | jc,pjm,pjm | @no_turning @conditionals Scenario: Car - Restriction With Compressed Geometry @@ -149,29 +149,29 @@ Feature: Car - Turn restrictions Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the node map """ - n - p j e - s + a + d j b + c """ And the ways | nodes | oneway | - | nj | no | - | js | no | - | ej | no | - | jp | no | + | aj | no | + | jc | no | + | bj | no | + | jd | no | And the relations | type | way:from | way:to | node:via | restriction:conditional | except | - | restriction | ej | nj | j | only_right_turn @ (Mo-Su 08:00-12:00) | motorcar | - | restriction | jp | nj | j | only_left_turn @ (Mo-Su 08:00-12:00) | bus | + | restriction | bj | aj | j | only_right_turn @ (Mo-Su 08:00-12:00) | motorcar | + | restriction | jd | aj | j | only_left_turn @ (Mo-Su 08:00-12:00) | bus | When I route I should get | from | to | route | # | - | e | s | ej,js,js | | - | e | n | ej,nj,nj | restriction does not apply to cars | - | e | p | ej,jp,jp | | - | p | s | jp,nj,nj,js,js | restriction excepting busses still applies to cars | + | b | c | bj,jc,jc | | + | b | a | bj,aj,aj | restriction does not apply to cars | + | b | d | bj,jd,jd | | + | d | c | jd,aj,aj,jc,jc | restriction excepting busses still applies to cars | @no_turning @conditionals Scenario: Car - only_right_turn @@ -181,27 +181,27 @@ Feature: Car - Turn restrictions Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the node map """ - n - p j e - s + a + d j b + c """ And the ways | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | + | aj | no | + | jc | no | + | bj | yes | + | jd | yes | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | only_right_turn @ (Mo-Su 07:00-14:00) | + | restriction | bj | aj | j | only_right_turn @ (Mo-Su 07:00-14:00) | When I route I should get | from | to | route | - | e | s | ej,nj,nj,js,js | - | e | n | ej,nj,nj | - | e | p | ej,nj,nj,jp,jp | + | b | c | bj,aj,aj,jc,jc | + | b | a | bj,aj,aj | + | b | d | bj,aj,aj,jd,jd | @no_turning @conditionals Scenario: Car - No right turn @@ -211,27 +211,27 @@ Feature: Car - Turn restrictions Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the node map """ - n - p j e - s + a + d j b + c """ And the ways | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | + | aj | no | + | jc | no | + | bj | yes | + | jd | yes | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | no_right_turn @ (Mo-Fr 07:00-13:00) | + | restriction | bj | aj | j | no_right_turn @ (Mo-Fr 07:00-13:00) | When I route I should get | from | to | route | # | - | e | s | ej,js,js | normal turn | - | e | n | ej,js,js,nj,nj | avoids right turn | - | e | p | ej,jp,jp | normal maneuver | + | b | c | bj,jc,jc | normal turn | + | b | a | bj,jc,jc,aj,aj | avoids right turn | + | b | d | bj,jd,jd | normal maneuver | @only_turning @conditionals Scenario: Car - only_left_turn @@ -241,27 +241,27 @@ Feature: Car - Turn restrictions Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the node map """ - n - p j e - s + a + d j b + c """ And the ways | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | + | aj | no | + | jc | no | + | bj | yes | + | jd | yes | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | js | j | only_left_turn @ (Mo-Fr 07:00-16:00) | + | restriction | bj | jc | j | only_left_turn @ (Mo-Fr 07:00-16:00) | When I route I should get | from | to | route | - | e | s | ej,js,js | - | e | n | ej,js,js,nj,nj | - | e | p | ej,js,js,jp,jp | + | b | c | bj,jc,jc | + | b | a | bj,jc,jc,aj,aj | + | b | d | bj,jc,jc,jd,jd | @no_turning @conditionals Scenario: Car - No left turn @@ -271,27 +271,27 @@ Feature: Car - Turn restrictions Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the node map """ - n - p j e - s + a + d j b + c """ And the ways | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | + | aj | no | + | jc | no | + | bj | yes | + | jd | yes | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | js | j | no_left_turn @ (Mo-Su 00:00-23:59) | + | restriction | bj | jc | j | no_left_turn @ (Mo-Su 00:00-23:59) | When I route I should get | from | to | route | - | e | s | ej,nj,nj,js,js | - | e | n | ej,nj,nj | - | e | p | ej,jp,jp | + | b | c | bj,aj,aj,jc,jc | + | b | a | bj,aj,aj | + | b | d | bj,jd,jd | @no_turning @conditionals Scenario: Car - Conditional restriction is off @@ -301,27 +301,27 @@ Feature: Car - Turn restrictions Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the node map """ - n - p j e - s + a + d j b + c """ And the ways | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | + | aj | no | + | jc | no | + | bj | yes | + | jd | yes | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | no_right_turn @ (Mo-Su 16:00-20:00) | + | restriction | bj | aj | j | no_right_turn @ (Mo-Su 16:00-20:00) | When I route I should get | from | to | route | - | e | s | ej,js,js | - | e | n | ej,nj,nj | - | e | p | ej,jp,jp | + | b | c | bj,jc,jc | + | b | a | bj,aj,aj | + | b | d | bj,jd,jd | @no_turning @conditionals Scenario: Car - Conditional restriction is on @@ -331,27 +331,27 @@ Feature: Car - Turn restrictions Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493805600" Given the node map """ - n - p j e - s + a + d j b + c """ And the ways | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | + | aj | no | + | jc | no | + | bj | yes | + | jd | yes | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | no_right_turn @ (Mo-Fr 07:00-14:00) | + | restriction | bj | aj | j | no_right_turn @ (Mo-Fr 07:00-14:00) | When I route I should get | from | to | route | - | e | s | ej,js,js | - | e | n | ej,js,js,nj,nj | - | e | p | ej,jp,jp | + | b | c | bj,jc,jc | + | b | a | bj,jc,jc,aj,aj | + | b | d | bj,jd,jd | @no_turning @conditionals Scenario: Car - Conditional restriction with multiple time windows @@ -362,242 +362,62 @@ Feature: Car - Turn restrictions Given the node map """ - n + a p | \ | j | \ - s m + c m """ And the ways | nodes | oneway | - | nj | no | - | js | no | + | aj | no | + | jc | no | | jp | yes | | mj | yes | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | nj | jp | j | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) | + | restriction | aj | jp | j | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) | When I route I should get | from | to | route | - | n | p | nj,js,js,jp,jp | + | a | p | aj,jc,jc,jp,jp | | m | p | mj,jp,jp | @no_turning @conditionals - Scenario: Car - only_right_turn + Scenario: Car - Multiple conditional restrictions applicable to same turn Given the extract extra arguments "--parse-conditional-restrictions" # time stamp for 10am on Tues, 02 May 2017 GMT Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" + Given the node map """ - n - p j e - s + j + | + k - l - m + | + n """ And the ways - | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | + | nodes | + | kl | + | jl | + | ln | + | lm | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | only_right_turn @ (Mo-Su 07:00-14:00) | + | restriction | kl | lj | l | only_left_turn @ (Sa-Su 07:00-10:30) | + | restriction | kl | ln | l | only_right_turn @ (Mo-Fr 07:00-10:30) | When I route I should get | from | to | route | - | e | s | ej,nj,nj,js,js | - | e | n | ej,nj,nj | - | e | p | ej,nj,nj,jp,jp | + | k | m | kl,ln,ln,lm,lm | - @no_turning @conditionals - Scenario: Car - No right turn - Given the extract extra arguments "--parse-conditional-restrictions" - # time stamp for 10am on Tues, 02 May 2017 GMT - Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" - Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" - Given the node map - """ - n - p j e - s - """ - - And the ways - | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | no_right_turn @ (Mo-Fr 07:00-13:00) | - - When I route I should get - | from | to | route | # | - | e | s | ej,js,js | normal turn | - | e | n | ej,js,js,nj,nj | avoids right turn | - | e | p | ej,jp,jp | normal maneuver | - - @only_turning @conditionals - Scenario: Car - only_left_turn - Given the extract extra arguments "--parse-conditional-restrictions" - # time stamp for 10am on Tues, 02 May 2017 GMT - Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" - Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" - Given the node map - """ - n - p j e - s - """ - - And the ways - | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | js | j | only_left_turn @ (Mo-Fr 07:00-16:00) | - - When I route I should get - | from | to | route | - | e | s | ej,js,js | - | e | n | ej,js,js,nj,nj | - | e | p | ej,js,js,jp,jp | - - @no_turning @conditionals - Scenario: Car - No left turn - Given the extract extra arguments "--parse-conditional-restrictions" - # time stamp for 10am on Tues, 02 May 2017 GMT - Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" - Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" - Given the node map - """ - n - p j e - s - """ - - And the ways - | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | js | j | no_left_turn @ (Mo-Su 00:00-23:59) | - - When I route I should get - | from | to | route | - | e | s | ej,nj,nj,js,js | - | e | n | ej,nj,nj | - | e | p | ej,jp,jp | - - @no_turning @conditionals - Scenario: Car - Conditional restriction is off - Given the extract extra arguments "--parse-conditional-restrictions" - # time stamp for 10am on Tues, 02 May 2017 GMT - Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" - Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" - Given the node map - """ - n - p j e - s - """ - - And the ways - | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | no_right_turn @ (Mo-Su 16:00-20:00) | - - When I route I should get - | from | to | route | - | e | s | ej,js,js | - | e | n | ej,nj,nj | - | e | p | ej,jp,jp | - - @no_turning @conditionals - Scenario: Car - Conditional restriction is on - Given the extract extra arguments "--parse-conditional-restrictions" - # 10am utc, wed - Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493805600" - Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493805600" - Given the node map - """ - n - p j e - s - """ - - And the ways - | nodes | oneway | - | nj | no | - | js | no | - | ej | yes | - | jp | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | ej | nj | j | no_right_turn @ (Mo-Fr 07:00-14:00) | - - When I route I should get - | from | to | route | - | e | s | ej,js,js | - | e | n | ej,js,js,nj,nj | - | e | p | ej,jp,jp | - - @no_turning @conditionals - Scenario: Car - Conditional restriction with multiple time windows - Given the extract extra arguments "--parse-conditional-restrictions" - # 5pm Wed 02 May, 2017 GMT - Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400" - Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493744400" - - Given the node map - """ - n - p | - \ | - j - | \ - s m - """ - - And the ways - | nodes | oneway | - | nj | no | - | js | no | - | jp | yes | - | mj | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | nj | jp | j | no_right_turn @ (Mo-Fr 07:00-11:00,16:00-18:30) | - - When I route I should get - | from | to | route | - | n | p | nj,js,js,jp,jp | - | m | p | mj,jp,jp | @restriction-way Scenario: Car - prohibit turn @@ -677,7 +497,7 @@ Feature: Car - Turn restrictions # https://www.openstreetmap.org/#map=18/38.91099/-77.00888 @no_turning @conditionals Scenario: Car - DC North capitol situation, two on one off - Given the extract extra arguments "--parse-conditional-restrictions=1" + Given the extract extra arguments "--parse-conditional-restrictions" # 9pm Wed 02 May, 2017 UTC, 5pm EDT Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/dc.geojson --parse-conditionals-from-now=1493845200" Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/dc.geojson --parse-conditionals-from-now=1493845200" @@ -691,14 +511,14 @@ Feature: Car - Turn restrictions # """ Given the node locations | node | lat | lon | - | a | 38.9113 | -77.0091 | - | b | 38.9108 | -77.0091 | - | c | 38.9104 | -77.0091 | - | d | 38.9110 | -77.0096 | - | e | 38.9106 | -77.0086 | - | f | 38.9105 | -77.0090 | - | g | 38.9108 | -77.0090 | - | h | 38.9113 | -77.0090 | + | a | 38.91124 | -77.00909 | + | b | 38.91080 | -77.00909 | + | c | 38.91038 | -77.00909 | + | d | 38.91105 | -77.00967 | + | e | 38.91037 | -77.00807 | + | f | 38.91036 | -77.00899 | + | g | 38.91076 | -77.00901 | + | h | 38.91124 | -77.00900 | And the ways | nodes | oneway | name | @@ -719,12 +539,12 @@ Feature: Car - Turn restrictions When I route I should get | from | to | route | turns | | a | e | cap south,florida nw,florida nw,florida ne | depart,turn right,continue uturn,arrive | - | f | d | cap north,florida,florida nw | depart,turn left,arrive | + | f | d | cap north,florida nw,florida nw | depart,turn left,arrive | | e | c | florida ne,florida nw,cap south,cap south | depart,continue uturn,turn right,arrive | @no_turning @conditionals Scenario: Car - DC North capitol situation, one on two off - Given the extract extra arguments "--parse-conditional-restrictions=1" + Given the extract extra arguments "--parse-conditional-restrictions" # 10:30am utc, wed, 6:30am est Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/dc.geojson --parse-conditionals-from-now=1493807400" Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/dc.geojson --parse-conditionals-from-now=1493807400" @@ -738,14 +558,14 @@ Feature: Car - Turn restrictions # """ Given the node locations | node | lat | lon | - | a | 38.9113 | -77.0091 | - | b | 38.9108 | -77.0091 | - | c | 38.9104 | -77.0091 | - | d | 38.9110 | -77.0096 | - | e | 38.9106 | -77.0086 | - | f | 38.9105 | -77.0090 | - | g | 38.9108 | -77.0090 | - | h | 38.9113 | -77.0090 | + | a | 38.91124 | -77.00909 | + | b | 38.91080 | -77.00909 | + | c | 38.91038 | -77.00909 | + | d | 38.91105 | -77.00967 | + | e | 38.91037 | -77.00807 | + | f | 38.91036 | -77.00899 | + | g | 38.91076 | -77.00901 | + | h | 38.91124 | -77.00900 | And the ways | nodes | oneway | name | @@ -765,7 +585,7 @@ Feature: Car - Turn restrictions When I route I should get | from | to | route | turns | - | a | e | cap south,florida,florida ne | depart,turn left,arrive | + | a | e | cap south,florida ne,florida ne | depart,turn left,arrive | | f | d | cap north,florida ne,florida ne,florida nw | depart,turn sharp right,continue uturn,arrive | | e | c | florida ne,cap south,cap south | depart,turn left,arrive | @@ -796,8 +616,8 @@ Feature: Car - Turn restrictions | nodes | name | | ab | albic | | bc | albic | - | db | dobe | - | be | dobe | + | db | dobe | + | be | dobe | And the relations | type | way:from | way:to | node:via | restriction:conditional | @@ -848,7 +668,7 @@ Feature: Car - Turn restrictions @only_turning @conditionals Scenario: Car - Somewhere in London, the UK, GMT timezone - Given the extract extra arguments "--parse-conditional-restrictions=1" + Given the extract extra arguments "--parse-conditional-restrictions" # 9am UTC, 10am BST Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/london.geojson --parse-conditionals-from-now=1493802000" Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/london.geojson --parse-conditionals-from-now=1493802000" @@ -884,7 +704,7 @@ Feature: Car - Turn restrictions | a | c | albic,dobe,dobe,albic,albic | depart,turn left,continue uturn,turn left,arrive | | a | e | albic,dobe,dobe | depart,turn left,arrive | - @no_turning @conditionals + @no_turning @conditionals @restriction-way Scenario: Car - Conditional restriction with multiple time windows Given the extract extra arguments "--parse-conditional-restrictions" # 5pm Wed 02 May, 2017 GMT @@ -1047,11 +867,10 @@ Feature: Car - Turn restrictions | type | way:from | node:via | way:to | restriction:conditional | | restriction | be | e | de | no_right_turn @ (Mo-Fr 07:00-11:00) | - # node restrictino is off, way restriction is on + # node restriction is off, way restriction is on When I route I should get | from | to | route | turns | locations | | a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d | | a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f | | c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d | | c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f | - diff --git a/features/car/destination.feature b/features/car/destination.feature index aee592a11..d5d3c1287 100644 --- a/features/car/destination.feature +++ b/features/car/destination.feature @@ -7,10 +7,10 @@ Feature: Car - Destination only, no passing through Scenario: Car - Destination only street Given the node map """ - a e - b c d + a e + b1 c 2d - x y + x y """ And the ways @@ -23,21 +23,21 @@ Feature: Car - Destination only, no passing through When I route I should get | from | to | route | | a | b | ab,ab | - | a | c | ab,bcd | - | a | d | ab,bcd,bcd | + | a | c | ab,bcd,bcd | + | a | 2 | ab,bcd,bcd | | a | e | axye,axye | | e | d | de,de | - | e | c | de,bcd | - | e | b | de,bcd,bcd | + | e | c | de,bcd,bcd | + | e | 1 | de,bcd,bcd | | e | a | axye,axye | Scenario: Car - Destination only street Given the node map """ - a e - b c d + a e + b1 c 2d - x y + x y """ And the ways @@ -51,12 +51,12 @@ Feature: Car - Destination only, no passing through When I route I should get | from | to | route | | a | b | ab,ab | - | a | c | ab,bc | - | a | d | ab,cd | + | a | c | ab,bc,bc | + | a | 2 | ab,bc,cd | | a | e | axye,axye | | e | d | de,de | - | e | c | de,cd | - | e | b | de,bc | + | e | c | de,cd,cd | + | e | 1 | de,cd,bc | | e | a | axye,axye | Scenario: Car - Routing inside a destination only area @@ -117,6 +117,7 @@ Feature: Car - Destination only, no passing through + \ + | d | + 1 | \___e """ @@ -129,5 +130,60 @@ Feature: Car - Destination only, no passing through When I route I should get | from | to | route | | e | a | acbe,acbe | - | d | a | de,acbe,acbe | + | 1 | a | de,acbe,acbe | | c | d | cd,cd | + + Scenario: Car - Routing through a parking lot tagged access=destination,service + Given the node map + """ + a----c++++b+++g------h---i + | + + + / + | + + + / + | + + + / + | d++++e+f / + z--------------y + """ + + And the ways + | nodes | access | highway | + | ac | | secondary | + | ghi | | secondary | + | azyhi | | secondary | + | cd | destination | service | + | def | destination | service | + | cbg | destination | service | + | be | destination | service | + | gf | destination | service | + + When I route I should get + | from | to | route | + | a | i | azyhi,azyhi | + | b | f | be,def,def | + | b | i | cbg,ghi,azyhi,azyhi | + + Scenario: Car - Disallow snapping to access=private,highway=service + Given a grid size of 20 meters + Given the node map + """ + a---c---b + : + x + : + d + \__e + """ + + And the ways + | nodes | access | highway | + | acb | | primary | + | cx | private | service | + | xd | private | service | + | de | | primary | + + When I route I should get + | from | to | route | + | a | x | acb,xd,xd | + | a | d | acb,xd,xd | + | a | e | acb,xd,de | + | x | e | de,de | + # do not snap to access=private,highway=service roads when routing over them is not necessary diff --git a/features/car/ferry.feature b/features/car/ferry.feature index acdd13f6e..e5b7d363c 100644 --- a/features/car/ferry.feature +++ b/features/car/ferry.feature @@ -46,10 +46,10 @@ Feature: Car - Handle ferry routes When I route I should get | from | to | route | modes | speed | time | - | a | g | abc,cde,efg,efg | driving,ferry,driving,driving | 12 km/h | 173.4s | - | b | f | abc,cde,efg,efg | driving,ferry,driving,driving | 9 km/h | 162.4s | - | c | e | cde,cde | ferry,ferry | 5 km/h | 151.4s | - | e | c | cde,cde | ferry,ferry | 5 km/h | 151.4s | + | a | g | abc,cde,efg,efg | driving,ferry,driving,driving | 12 km/h | 173.5s | + | b | f | abc,cde,efg,efg | driving,ferry,driving,driving | 9 km/h | 162.5s | + | c | e | cde,cde | ferry,ferry | 5 km/h | 151.5s | + | e | c | cde,cde | ferry,ferry | 5 km/h | 151.5s | Scenario: Car - Properly handle simple durations Given the node map @@ -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.000898,1,1.000898,1,1.002695,1,1.002695,1,1.003594,1,1.003594,1,1.005391,1,1.005391,1,1.006289,1 | 611 | diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature index 2c6da2714..d2b8b4f5f 100644 --- a/features/car/maxspeed.feature +++ b/features/car/maxspeed.feature @@ -86,54 +86,79 @@ OSRM will use 4/5 of the projected free-flow speed. Then routability should be | highway | maxspeed | width | maxspeed:forward | maxspeed:backward | forw | backw | forw_rate | backw_rate | - | primary | | | | | 64 km/h | 64 km/h | 18 | 18 | + | primary | | | | | 64 km/h | 64 km/h | 18.1 | 18.1 | | primary | | 3 | | | 64 km/h | 64 km/h | 9 | 9 | - | primary | 60 | | | | 47 km/h | 47 km/h | 13.3 | 13.3 | - | primary | 60 | 3 | | | 47 km/h | 47 km/h | 6.7 | 6.7 | - | primary | | | 60 | | 47 km/h | 64 km/h | 13.3 | 18 | - | primary | | 3 | 60 | | 47 km/h | 64 km/h | 6.7 | 9 | - | primary | | | | 60 | 64 km/h | 47 km/h | 18 | 13.3 | - | primary | | 3 | | 60 | 64 km/h | 47 km/h | 9 | 6.7 | - | primary | 15 | | 60 | | 47 km/h | 11 km/h | 13.3 | 3.3 | + | primary | 60 | | | | 48 km/h | 48 km/h | 13.3 | 13.3 | + | primary | 60 | 3 | | | 48 km/h | 48 km/h | 6.7 | 6.7 | + | primary | | | 60 | | 48 km/h | 64 km/h | 13.3 | 18.1 | + | primary | | 3 | 60 | | 48 km/h | 64 km/h | 6.7 | 9 | + | primary | | | | 60 | 64 km/h | 48 km/h | 18.1 | 13.3 | + | primary | | 3 | | 60 | 64 km/h | 48 km/h | 9 | 6.7 | + | primary | 15 | | 60 | | 48 km/h | 12 km/h | 13.3 | 3.3 | | primary | 15 | 3 | 60 | | 48 km/h | 12 km/h | 6.7 | 1.7 | - | primary | 15 | | | 60 | 12 km/h | 47 km/h | 3.3 | 13.3 | - | primary | 15 | 3 | | 60 | 12 km/h | 47 km/h | 1.7 | 6.7 | - | primary | 15 | | 30 | 60 | 23 km/h | 47 km/h | 6.7 | 13.3 | - | primary | 15 | 3 | 30 | 60 | 23 km/h | 47 km/h | 3.3 | 6.7 | + | primary | 15 | | | 60 | 12 km/h | 48 km/h | 3.3 | 13.3 | + | primary | 15 | 3 | | 60 | 12 km/h | 48 km/h | 1.7 | 6.7 | + | primary | 15 | | 30 | 60 | 24 km/h | 48 km/h | 6.7 | 13.3 | + | primary | 15 | 3 | 30 | 60 | 24 km/h | 48 km/h | 3.3 | 6.7 | Scenario: Car - Single lane streets be ignored or incur a penalty Then routability should be | highway | maxspeed | lanes | maxspeed:forward | maxspeed:backward | forw | backw | forw_rate | backw_rate | - | primary | | | | | 64 km/h | 64 km/h | 18 | 18 | + | primary | | | | | 64 km/h | 64 km/h | 18.1 | 18.1 | | primary | | 1 | | | 64 km/h | 64 km/h | 9 | 9 | - | primary | 60 | | | | 47 km/h | 47 km/h | 13.3 | 13.3 | - | primary | 60 | 1 | | | 47 km/h | 47 km/h | 6.7 | 6.7 | - | primary | | | 60 | | 47 km/h | 64 km/h | 13.3 | 18 | - | primary | | 1 | 60 | | 47 km/h | 64 km/h | 6.7 | 9 | - | primary | | | | 60 | 64 km/h | 47 km/h | 18 | 13.3 | - | primary | | 1 | | 60 | 64 km/h | 47 km/h | 9 | 6.7 | - | primary | 15 | | 60 | | 47 km/h | 11 km/h | 13.3 | 3.3 | + | primary | 60 | | | | 48 km/h | 48 km/h | 13.3 | 13.3 | + | primary | 60 | 1 | | | 48 km/h | 48 km/h | 6.7 | 6.7 | + | primary | | | 60 | | 48 km/h | 64 km/h | 13.3 | 18.1 | + | primary | | 1 | 60 | | 48 km/h | 64 km/h | 6.7 | 9 | + | primary | | | | 60 | 64 km/h | 48 km/h | 18.1 | 13.3 | + | primary | | 1 | | 60 | 64 km/h | 48 km/h | 9 | 6.7 | + | primary | 15 | | 60 | | 48 km/h | 12 km/h | 13.3 | 3.3 | | primary | 15 | 1 | 60 | | 48 km/h | 12 km/h | 6.7 | 1.7 | - | primary | 15 | | | 60 | 12 km/h | 47 km/h | 3.3 | 13.3 | - | primary | 15 | 1 | | 60 | 12 km/h | 47 km/h | 1.7 | 6.7 | - | primary | 15 | | 30 | 60 | 23 km/h | 47 km/h | 6.7 | 13.3 | - | primary | 15 | 1 | 30 | 60 | 23 km/h | 47 km/h | 3.3 | 6.7 | + | primary | 15 | | | 60 | 12 km/h | 48 km/h | 3.3 | 13.3 | + | primary | 15 | 1 | | 60 | 12 km/h | 48 km/h | 1.7 | 6.7 | + | primary | 15 | | 30 | 60 | 24 km/h | 48 km/h | 6.7 | 13.3 | + | primary | 15 | 1 | 30 | 60 | 24 km/h | 48 km/h | 3.3 | 6.7 | Scenario: Car - Single lane streets only incur a penalty for two-way streets Then routability should be | highway | maxspeed | lanes | oneway | forw | backw | forw_rate | backw_rate | - | primary | 30 | 1 | yes | 23 km/h | | 6.7 | | - | primary | 30 | 1 | -1 | | 23 km/h | | 6.7 | - | primary | 30 | 1 | | 23 km/h | 23 km/h | 3.3 | 3.3 | - | primary | 30 | 2 | | 23 km/h | 23 km/h | 6.7 | 6.7 | + | primary | 30 | 1 | yes | 24 km/h | | 6.7 | | + | primary | 30 | 1 | -1 | | 24 km/h | | 6.7 | + | primary | 30 | 1 | | 24 km/h | 24 km/h | 3.3 | 3.3 | + | primary | 30 | 2 | | 24 km/h | 24 km/h | 6.7 | 6.7 | Scenario: Car - Forward/backward maxspeed on reverse oneways Then routability should be | highway | maxspeed | maxspeed:forward | maxspeed:backward | oneway | forw | backw | forw_rate | backw_rate | - | primary | | | | -1 | | 64 km/h | | 18 | - | primary | 30 | | | -1 | | 23 km/h | | 6.7 | - | primary | | 30 | | -1 | | 64 km/h | | 18 | - | 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 | + | primary | | | | -1 | | 64 km/h | | 18.1 | + | primary | 30 | | | -1 | | 24 km/h | | 6.7 | + | primary | | 30 | | -1 | | 64 km/h | | 18.1 | + | primary | | | 30 | -1 | | 24 km/h | | 6.7 | + | primary | 20 | 30 | | -1 | | 16 km/h | | 4.4 | + | primary | 20 | | 30 | -1 | | 24 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 | \ No newline at end of file diff --git a/features/car/multi_via_restrictions.feature b/features/car/multi_via_restrictions.feature new file mode 100644 index 000000000..5714cd45f --- /dev/null +++ b/features/car/multi_via_restrictions.feature @@ -0,0 +1,1091 @@ +@routing @car @restrictions + +Feature: Car - Multiple Via Turn restrictions + + Background: Use car routing + Given the profile "car" + Given a grid size of 200 meters + + + @restriction-way @no_turning @overlap + Scenario: Car - Node restriction inside multiple via restriction + Given the node map + """ + 1 2 3 4 5 + a---b---c---d---e---------f---------g + | | | + |7 |8 |9 + | | | + x---h---------i---------j + """ + + And the ways + | nodes | oneway | name | + | ab | yes | forward | + | bc | yes | forward | + | cd | yes | forward | + | de | yes | forward | + | ef | yes | forward | + | fg | yes | forward | + | eh | yes | first | + | fi | yes | second | + | gj | yes | third | + | ih | yes | back | + | ji | yes | back | + | hx | yes | back | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bc,cd,de,ef | fi | no_right_turn | + + And the relations + | type | way:from | node:via | way:to | restriction | + | restriction | de | e | eh | no_right_turn | + + When I route I should get + | from | to | route | + | 1 | x | forward,third,back,back | + | 2 | x | forward,second,back,back | + | 3 | x | forward,second,back,back | + | 4 | x | forward,second,back,back | + | 5 | x | forward,third,back,back | + | 7 | x | first,back,back | + | 8 | x | second,back,back | + | 9 | x | third,back,back | + + + @restriction-way @no_turning @overlap @conditionals + Scenario: Car - Conditional node restriction inside conditional multiple via restriction + Given the origin -9.2972,10.3811 + # coordinate in Guinée, a country that observes GMT year round + Given the extract extra arguments "--parse-conditional-restrictions" + # time stamp for 10am on Tues, 02 May 2017 GMT + Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" + Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" + Given the node map + """ + 1 2 3 4 5 + a---b---c---d---e---------f---------g + | | | + |7 |8 |9 + | | | + x---h---------i---------j + """ + + And the ways + | nodes | oneway | name | + | ab | yes | forward | + | bc | yes | forward | + | cd | yes | forward | + | de | yes | forward | + | ef | yes | forward | + | fg | yes | forward | + | eh | yes | first | + | fi | yes | second | + | gj | yes | third | + | ih | yes | back | + | ji | yes | back | + | hx | yes | back | + + And the relations + | type | way:from | way:via | way:to | restriction:conditional | + | restriction | ab | bc,cd,de,ef | fi | no_right_turn @ (Mo-Fr 07:00-10:30) | + + And the relations + | type | way:from | node:via | way:to | restriction:conditional | + | restriction | de | e | eh | no_right_turn @ (Mo-Fr 07:00-10:30) | + | restriction | de | e | eh | only_right_turn @ (Sa-Su 07:00-10:30) | + + When I route I should get + | from | to | route | + | 1 | x | forward,third,back,back | + | 2 | x | forward,second,back,back | + | 3 | x | forward,second,back,back | + | 4 | x | forward,second,back,back | + | 5 | x | forward,third,back,back | + | 7 | x | first,back,back | + | 8 | x | second,back,back | + | 9 | x | third,back,back | + + + @restriction-way @no_turning @overlap + Scenario: Car - Multiple via restriction inside multiple via restriction + Given the node map + """ + 1 2 3 4 5 + a---b---c---d---e---------f---------g + | | | + |7 |8 |9 + | | | + x---h---------i---------j + """ + + And the ways + | nodes | oneway | name | + | ab | yes | forward | + | bc | yes | forward | + | cd | yes | forward | + | de | yes | forward | + | ef | yes | forward | + | fg | yes | forward | + | eh | yes | first | + | fi | yes | second | + | gj | yes | third | + | ih | yes | back | + | ji | yes | back | + | hx | yes | back | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bc,cd,de,ef | fi | no_right_turn | + | restriction | bc | cd,de | eh | no_right_turn | + + When I route I should get + | from | to | route | + | 1 | x | forward,third,back,back | + | 2 | x | forward,second,back,back | + | 3 | x | forward,first,back,back | + | 4 | x | forward,second,back,back | + | 5 | x | forward,third,back,back | + | 7 | x | first,back,back | + | 8 | x | second,back,back | + | 9 | x | third,back,back | + + + @restriction-way @no_turning @overlap @conditionals + Scenario: Car - Conditional multiple via restriction inside conditional multiple via restriction + + Given a grid size of 200 meters + Given the origin -9.2972,10.3811 + # coordinate in Guinée, a country that observes GMT year round + Given the extract extra arguments "--parse-conditional-restrictions" + # time stamp for 10am on Tues, 02 May 2017 GMT + Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" + Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" + Given the node map + + """ + 1 2 3 4 5 + a---b---c---d---e---------f---------g + | | | + |7 |8 |9 + | | | + x---h---------i---------j + """ + + And the ways + | nodes | oneway | name | + | ab | yes | forward | + | bc | yes | forward | + | cd | yes | forward | + | de | yes | forward | + | ef | yes | forward | + | fg | yes | forward | + | eh | yes | first | + | fi | yes | second | + | gj | yes | third | + | ih | yes | back | + | ji | yes | back | + | hx | yes | back | + + And the relations + | type | way:from | way:via | way:to | restriction:conditional | + | restriction | ab | bc,cd,de,ef | fi | no_right_turn @ (Mo-Fr 07:00-10:30) | + | restriction | bc | cd,de | eh | no_right_turn @ (Mo-Fr 07:00-10:30) | + | restriction | bc | cd,de | eh | only_right_turn @ (Sa-Su 07:00-10:30) | + + When I route I should get + | from | to | route | + | 1 | x | forward,third,back,back | + | 2 | x | forward,second,back,back | + | 3 | x | forward,first,back,back | + | 4 | x | forward,second,back,back | + | 5 | x | forward,third,back,back | + | 7 | x | first,back,back | + | 8 | x | second,back,back | + | 9 | x | third,back,back | + + + @restriction-way @only_turning @overlap + Scenario: Car - Overlapping multiple via restrictions + Given the node map + """ + a f j + | | | + b---d---e---i---k----m + | | | + c g l + """ + + And the ways + | nodes | oneway | name | + | ab | yes | down | + | cb | yes | up | + | bd | yes | right | + | de | yes | right | + | ef | yes | up | + | eg | yes | down | + | ei | yes | right | + | ik | yes | right | + | kj | yes | up | + | kl | yes | down | + | km | yes | right | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bd,de | ei | only_straight_on | + | restriction | de | ei,ik | km | only_straight_on | + + When I route I should get + | from | to | route | + | a | f | | + | a | g | | + | a | j | | + | a | l | | + | a | m | down,right,right | + | c | f | up,right,up,up | + | c | g | up,right,down,down | + | c | j | | + | c | l | | + | c | m | up,right,right | + | i | j | right,up,up | + | i | l | right,down,down | + | i | m | right,right | + + + @restriction-way @only_turning @overlap @conditionals + Scenario: Car - Overlapping conditional multiple via restrictions + Given a grid size of 200 meters + Given the origin -9.2972,10.3811 + # coordinate in Guinée, a country that observes GMT year round + Given the extract extra arguments "--parse-conditional-restrictions" + # time stamp for 10am on Tues, 02 May 2017 GMT + Given the contract extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" + Given the customize extra arguments "--time-zone-file=test/data/tz/{timezone_names}/guinea.geojson --parse-conditionals-from-now=1493719200" + Given the node map + """ + a f j + | | | + b---d---e---i---k----m + | | | + c g l + """ + + And the ways + | nodes | oneway | name | + | ab | yes | down | + | cb | yes | up | + | bd | yes | right | + | db | yes | left | + | de | yes | right | + | ed | yes | left | + | ef | yes | up | + | eg | yes | down | + | ei | yes | right | + | ie | yes | left | + | ik | yes | right | + | ki | yes | left | + | kj | yes | up | + | kl | yes | down | + | km | no | end | + + And the relations + | type | way:from | way:via | way:to | restriction:conditional | + | restriction | ab | bd,de | ei | only_straight_on @ (Mo-Fr 07:00-10:30) | + | restriction | ab | bd,de | ef | only_left_turn @ (Sa-Su 07:00-10:30) | + | restriction | de | ei,ik | km | only_straight_on @ (Mo-Fr 07:00-10:30) | + + When I route I should get + | from | to | route | + | a | f | down,right,end,end,left,up,up | + | a | g | down,right,end,end,left,down,down | + | a | j | down,right,end,end,up,up | + | a | l | down,right,end,end,down,down | + | a | m | down,right,end,end | + | c | f | up,right,up,up | + | c | g | up,right,down,down | + | c | j | up,right,end,end,up,up | + | c | l | up,right,end,end,down,down | + | c | m | up,right,end,end | + | i | j | right,up,up | + | i | l | right,down,down | + | i | m | right,end,end | + + + + @restriction-way @only_turning @geometry + Scenario: Car - Multiple via restriction with non-compressable via geometry + Given the node map + """ + a---b---c---d---e---f---g---h + | | | + i j k + """ + + And the ways + | nodes | oneway | name | + | ab | yes | right | + | bcd | yes | right | + | defg | yes | right | + | ci | yes | down | + | ej | yes | down | + | gh | yes | end | + | gk | yes | down | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bcd,defg | gh | only_straight_on | + + When I route I should get + | from | to | route | + | a | h | right,end,end | + | a | k | | + + @restriction-way @only_turning @geometry + Scenario: Car - Multiple via restriction with non-compressable from/to nodes + Given the node map + """ + a---b---c---d---e---f---g---h---i---j---k---l + | | | | | + m n o p q + """ + + And the ways + | nodes | oneway | name | + | abcdefg | yes | right | + | ghi | yes | right | + | ijkl | yes | end | + | cm | yes | down | + | en | yes | down | + | go | yes | down | + | ip | yes | down | + | kq | yes | down | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | abcdefg | ghi | ijkl | only_straight_on | + + When I route I should get + | from | to | route | + | a | l | right,end,end | + | a | p | | + + @restriction-way @no_turning + Scenario: Car - Long unrestricted route and short restricted route + Given the node map + """ + a------------------------------------b + | | + c--d--e--f--------------------------- + """ + + And the ways + | nodes | + | ac | + | ab | + | bf | + | cd | + | de | + | ef | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ac | cd | de | no_straight_on | + + When I route I should get + | from | to | route | + | a | f | ab,bf,bf | + + + @restriction-way @overlap @no_turning + Scenario: Car - Junction with multiple via u-turn restrictions + # Example: https://www.openstreetmap.org/#map=19/52.07399/5.09724 + Given the node map + """ + a b + | | + c---d---e---f + | | + g---h---i---j + | | + k l + """ + + And the ways + | nodes | oneway | name | + | ad | yes | down | + | eb | yes | up | + | fe | yes | left | + | ij | yes | right | + | li | yes | up | + | hk | yes | down | + | gh | yes | right | + | dc | yes | left | + | dh | yes | down | + | hi | yes | right | + | ie | yes | up | + | ed | yes | left | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ad | dh,hi | ie | no_u_turn | + | restriction | li | ie,ed | dh | no_u_turn | + + When I route I should get + | from | to | route | + | a | b | | + | a | c | down,left,left | + | a | k | down,down | + | a | j | down,right,right | + | f | b | left,up,up | + | f | c | left,left | + | f | k | left,down,down | + | f | j | left,down,right,right | + | l | b | up,up | + | l | c | up,left,left | + | l | k | | + | l | j | up,right,right | + | g | b | right,up,up | + | g | c | right,up,left,left | + | g | k | right,down,down | + | g | j | right,right | + + + @restriction-way @overlap @no_turning + Scenario: Car - Junction with multiple via u-turn restrictions, service roads + # Example: https://www.openstreetmap.org/#map=19/48.38566/10.88068 + Given the node map + """ + a b + | | + c---d--e--f---g + | _/| + h__/ | + |\ \ | + i---j-k-l-m---n + | | + o p + """ + + And the ways + | nodes | oneway | name | + | ad | yes | down | + | fb | yes | up | + | gf | yes | left | + | mn | yes | right | + | pm | yes | up | + | jo | yes | down | + | ij | yes | right | + | dc | yes | left | + | dh | yes | down | + | hj | yes | down | + | jkl | yes | right | + | lm | yes | right | + | mf | yes | up | + | fe | yes | left | + | ed | yes | left | + + And the ways + | nodes | oneway | name | highway | access | psv | + | kh | yes | service | service | no | yes | + | lh | no | service | service | no | yes | + | fh | yes | service | service | no | yes | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | hj | jkl,lm | mf | no_u_turn | + | restriction | lm | mf | fe | no_u_turn | + | restriction | mf | fe,ed | dh | no_u_turn | + | restriction | ed | dh,hj | jkl | no_u_turn | + + When I route I should get + | from | to | route | + | a | b | | + | a | c | down,left,left | + | a | o | down,down | + | a | n | down,right,right | + | i | b | right,up,up | + | i | c | | + | i | o | right,down,down | + | i | n | right,right | + | p | b | up,up | + | p | c | up,left,left | + | p | o | | + | p | n | up,right,right | + | g | b | left,up,up | + | g | c | left,left | + | g | o | left,down,down | + | g | n | | + + + @restriction-way @overlap @no_turning + Scenario: Car - Junction with overlapping and duplicate multiple via restrictions + # Example: https://www.openstreetmap.org/#map=19/34.66291/33.01711 + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + + And the node map + """ + a b + | | + c---d---e---f + | | + g---h---i---j + | | + k l + """ + + And the nodes + | node | highway | + | d | traffic_signals | + | e | traffic_signals | + | h | traffic_signals | + | i | traffic_signals | + + And the ways + | nodes | oneway | name | + | da | yes | up | + | be | yes | down | + | ef | yes | right | + | ji | yes | left | + | il | yes | down | + | kh | yes | up | + | hg | yes | left | + | cd | yes | right | + | hd | yes | up | + | ih | yes | left | + | ei | yes | down | + | de | yes | right | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | be | ei,ih | hd | no_u_turn | + | restriction | ji | ih,hd | de | no_u_turn | + | restriction | kh | hd,de | ei | no_u_turn | + | restriction | cd | de,ei | ih | no_u_turn | + | restriction | hd | de | ei | no_u_turn | + | restriction | de | ei | ih | no_u_turn | + | restriction | ei | ih | hd | no_u_turn | + | restriction | ei | ih,hd | de | no_u_turn | + | restriction | ih | hd | de | no_u_turn | + | restriction | ih | hd,de | ei | no_u_turn | + + When I route I should get + | from | to | route | + | b | a | | + | b | g | down,left,left | + | b | l | down,down | + | b | f | down,right,right | + | j | a | left,up,up | + | j | g | left,left | + | j | l | left,down,down | + | j | f | | + | k | a | up,up | + | k | g | up,left,left | + | k | l | | + | k | f | up,right,right | + | c | a | right,up,up | + | c | g | | + | c | l | right,down,down | + | c | f | right,right | + + + @restriction-way @no_turning + Scenario: Car - Junction with multiple via restriction to side road, traffic lights + # Example: https://www.openstreetmap.org/#map=19/48.23662/16.42545 + Given the node map + """ + e---d + | + f---c---g + | + h---b---i + | + a + """ + + And the nodes + | node | highway | + | c | traffic_signals | + | b | traffic_signals | + + And the ways + | nodes | oneway | name | + | ab | no | up | + | bc | no | up | + | cd | no | up | + | de | no | left | + | hb | yes | right | + | bi | yes | right | + | gc | yes | left | + | cf | yes | left | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bc,cd | de | no_left_turn | + + When I route I should get + | from | to | route | + | a | e | | + | a | f | up,left,left | + | a | g | | + | a | h | | + | a | i | up,right,right | + + + @restriction-way @overlap @no_turning + Scenario: Car - Many overlapping multiple via restrictions, traffic signals + # Example: https://www.openstreetmap.org/#map=19/48.76987/11.43410 + Given the node map + """ + 8 5 + p______a_______n________o__x + 1| | | + | \ / + r___q____b____ m + | \ \___ _/ 7 + \ c _l____k__w + s \ _/ _/ + \ _d/ __j + \ _/ \ _/ + | ___g e_____i + v__t__/ _/ \ 4 + 6 2/ 3\ + f h + """ + + And the nodes + | node | highway | + | n | traffic_signals | + | m | traffic_signals | + | q | traffic_signals | + + And the ways + | nodes | oneway | + | on | yes | + | na | yes | + | ap | yes | + | pr | yes | + | rqb | yes | + | bl | yes | + | oml | yes | + | ld | yes | + | lk | yes | + | ba | yes | + | bcd | no | + | de | no | + | eh | no | + | ei | no | + | ejk | yes | + | rst | yes | + | dgt | yes | + | fe | yes | + | xo | yes | + | tv | yes | + | kw | yes | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | pr | rqb,bcd | dgt | no_right_turn | + | restriction | rqb | bcd,de | ejk | no_left_turn | + | restriction | rqb | bcd | dgt | no_right_turn | + | restriction | fe | ed | dgt | no_u_turn | + | restriction | fe | ed,dcb | bl | no_right_turn | + | restriction | he | ed,dcb | bl | no_right_turn | + | restriction | oml | ld,de | ejk | no_u_turn | + + And the relations + | type | way:from | node:via | way:to | restriction | + | restriction | ap | p | pr | no_u_turn | + | restriction | rqb | b | ba | no_left_turn | + | restriction | ld | d | dcb | no_right_turn | + | restriction | oml | l | lk | no_left_turn | + | restriction | na | a | ab | no_left_turn | + | restriction | dcb | b | bl | no_right_turn | + | restriction | dcb | b | bcd | no_u_turn | + | restriction | bcd | d | dcb | no_u_turn | + | restriction | bl | l | ld | no_right_turn | + + # Additional relations to prevent u-turns on small roads polluting the results + And the relations + | type | way:from | node:via | way:to | restriction | + | restriction | eh | h | he | no_u_turn | + | restriction | ei | i | ie | no_u_turn | + + When I route I should get + | from | to | route | locations | + | 1 | 6 | pr,rst,tv,tv | _,r,t,_ | + | 1 | 3 | pr,rqb,bcd,de,eh,eh | _,r,b,d,e,_ | + | 1 | 4 | pr,rqb,bcd,de,ei,ei | _,r,b,d,e,_ | + | 1 | 7 | pr,rqb,bl,lk,kw,kw | _,r,b,l,k,_ | + | 1 | 8 | | | + | 2 | 6 | | | + | 2 | 3 | fe,eh,eh | _,e,_ | + | 2 | 4 | fe,ei,ei | _,e,_ | + | 2 | 7 | fe,ejk,kw,kw | _,e,k,_ | + | 2 | 8 | fe,de,bcd,ba,ap,ap | _,e,d,b,a,_ | + | 3 | 6 | eh,de,dgt,tv,tv | _,e,d,t,_ | + | 3 | 4 | eh,ei,ei | _,e,_ | + | 3 | 7 | eh,ejk,kw,kw | _,e,k,_ | + | 3 | 8 | eh,de,bcd,ba,ap,ap | _,e,d,b,a,_ | + | 4 | 6 | ei,de,dgt,tv,tv | _,e,d,t,_ | + | 4 | 3 | ei,eh,eh | _,e,_ | + | 4 | 7 | ei,ejk,kw,kw | _,e,k,_ | + | 4 | 8 | ei,de,bcd,ba,ap,ap | _,e,d,b,a,_ | + | 5 | 6 | xo,oml,ld,dgt,tv,tv | _,o,l,d,t,_ | + | 5 | 3 | xo,oml,ld,de,eh,eh | _,o,l,d,e,_ | + | 5 | 4 | xo,oml,ld,de,ei,ei | _,o,l,d,e,_ | + | 5 | 7 | | | + | 5 | 8 | xo,on,na,ap,ap | _,o,n,a,_ | + + + + @restriction-way @overlap @no_turning + Scenario: Car - Multiple via restriction with start and end on same node + # Example: https://www.openstreetmap.org/#map=19/52.41988/16.96088 + Given the node map + """ + |--g---f---e + a | | + |--b---c---d + + """ + + And the nodes + | node | highway | + | b | traffic_signals | + + And the ways + | nodes | oneway | name | + | abc | yes | enter | + | cd | yes | right | + | de | yes | up | + | ef | yes | left | + | fga | yes | exit | + | fc | yes | down | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | abc | cd,de,ef | fga | no_u_turn | + + When I route I should get + | from | to | route | locations | + | a | g | enter,right,up,left,down,right,up,left,exit,exit | a,c,d,e,f,c,d,e,f,g | + | b | a | enter,right,up,left,down,right,up,left,exit,exit | b,c,d,e,f,c,d,e,f,a | + # This is a correct but not within the spirit of the restriction. + # Does this indicate the restriction is not strong enough? + + + @restriction-way @no_turning + Scenario: Car - Multiple via restriction preventing bypassing main road + # Example: https://www.openstreetmap.org/#map=19/48.72429/21.25912 + Given the node map + """ + a--b--c--d--e--f + \ | + --g--h--i--j + | + k + """ + + And the nodes + | node | highway | + | d | traffic_signals | + | e | traffic_signals | + + And the ways + | nodes | oneway | name | + | ab | yes | main | + | bc | yes | main | + | cd | yes | main | + | de | yes | main | + | ef | yes | main | + | bg | yes | side | + | gh | yes | side | + | hi | yes | side | + | ij | yes | side | + | fj | yes | turn | + | jk | yes | turn | + + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bg,gh,hi,ij | jk | no_right_turn | + + When I route I should get + | from | to | route | + | a | k | main,turn,turn | + + + @restriction-way @overlap @no_turning @only_turning + Scenario: Car - Multiple via restriction with to,via,from sharing same node + # Example: https://www.openstreetmap.org/relation/3972923 + Given the node map + """ + e---d + | | + a---b---c + | + f + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + | cd | yes | + | deb | yes | + | bf | yes | + + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bc,cd,deb | bf | no_u_turn | + + And the relations + | type | way:from | node:via | way:to | restriction | + | restriction | ab | b | bc | only_straight_on | + | restriction | deb | b | bc | no_left_turn | + + When I route I should get + | from | to | route | + | a | f | | + # The last restriction is missing from OSM. Without it, + # it produces the route: ab,bc,cd,deb,bc,cd,deb,bf,bf + + + @restriction-way @except + Scenario: Car - Multiple via restriction, exception applies + # Example: https://www.openstreetmap.org/#map=19/50.04920/19.93251 + Given the node map + """ + a---b---c---d--e + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + | cd | yes | + | de | yes | + + + And the relations + | type | way:from | way:via | way:to | restriction | except | + | restriction | ab | bc,cd | de | no_straight_on | motorcar | + + When I route I should get + | from | to | route | + | a | e | ab,bc,cd,de,de | + + + @restriction-way @except @no_turning + Scenario: Car - Multiple via restriction, exception n/a + # Example: https://www.openstreetmap.org/#map=19/50.04920/19.93251 + Given the node map + """ + a---b---c---d--e + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + | cd | yes | + | de | yes | + + + And the relations + | type | way:from | way:via | way:to | restriction | except | + | restriction | ab | bc,cd | de | no_straight_on | psv;emergency | + + When I route I should get + | from | to | route | + | a | e | | + + + @restriction-way @overlap @only_turning + Scenario: Car - Multiple via restriction overlapping single via restriction + Given the node map + """ + e + | + a---b---c---d + | + f - g + | + h + """ + + And the ways + | nodes | name | + | ab | abcd | + | bc | abcd | + | cd | abcd | + | hf | hfb | + | fb | hfb | + | gf | gf | + | ce | ce | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bc | ce | only_left_turn | + | restriction | gf | fb,bc | cd | only_u_turn | + + When I route I should get + | from | to | route | turns | locations | + | a | d | abcd,ce,ce,abcd,abcd | depart,turn left,continue uturn,turn left,arrive | a,c,e,c,d | + | a | e | abcd,ce,ce | depart,turn left,arrive | a,c,e | + | a | f | abcd,hfb,hfb | depart,turn right,arrive | a,b,f | + | g | e | gf,hfb,abcd,abcd,ce,ce | depart,turn right,turn right,continue uturn,turn right,arrive | g,f,b,d,c,e | + | g | d | gf,hfb,abcd,abcd | depart,turn right,turn right,arrive | g,f,b,d | + | h | e | hfb,abcd,ce,ce | depart,end of road right,turn left,arrive | h,b,c,e | + | h | d | hfb,abcd,abcd | depart,end of road right,arrive | h,b,d | + + + @restriction-way + Scenario: Ambiguous from/to ways + Given the node map + """ + a + | + b---d---e + | | + c f + """ + + And the ways + | nodes | + | abc | + | bd | + | de | + | ef | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | abc | bd,de | ef | no_right_turn | + | restriction | ef | de,bd | abc | no_right_turn | + + When I route I should get + | from | to | route | locations | + | a | f | abc,bd,de,ef,ef | a,b,d,e,f | + | f | a | ef,de,bd,abc,abc | f,e,d,b,a | + | c | f | abc,bd,de,ef,ef | c,b,d,e,f | + | f | c | ef,de,bd,abc,abc | f,e,d,b,c | + + + @restriction-way + Scenario: Ambiguous via ways + Given the node map + """ + a + | + b---d---e---c + | + f + """ + + And the ways + | nodes | + | ab | + | bd | + | dec | + | ef | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bd,dec | ef | no_right_turn | + | restriction | ef | dec,bd | ab | no_right_turn | + + When I route I should get + | from | to | route | locations | + | a | f | ab,bd,dec,ef,ef | a,b,d,e,f | + | f | a | ef,dec,bd,ab,ab | f,e,d,b,a | + + + @restriction-way @invalid + Scenario: Badly tagged restrictions + Given the node map + """ + a--b--c--d--e--f + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + | cd | yes | + | de | yes | + | ef | yes | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | cd,de | ef | no_straight_on | + | restriction | ab | bc,de | ef | no_straight_on | + | restriction | ab | bc,cd | ef | no_straight_on | + | restriction | ef | de,cd | bc | no_straight_on | + + When I route I should get + | from | to | route | locations | + | a | f | ab,bc,cd,de,ef,ef | a,b,c,d,e,f | + + + @restriction-way + Scenario: Snap source/target to via restriction way + Given the node map + """ + a-1-b-2-c-3-d + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bc | cd | no_straight_on | + + When I route I should get + | from | to | route | + | 1 | 2 | ab,bc,bc | + | 2 | 3 | bc,cd,cd | + + + @restriction-way + Scenario: Car - Snap source/target to multi-via restriction way + # Example: https://www.openstreetmap.org/relation/11787041 + Given the node map + """ + |--g---f---e + a | 1 + |--b---c---d + + """ + + And the nodes + | node | highway | + | b | traffic_signals | + + And the ways + | nodes | oneway | name | + | ab | yes | enter | + | bc | yes | enter | + | cd | yes | right | + | de | yes | up | + | ef | yes | left | + | fc | yes | down | + | fg | yes | exit | + | ga | yes | exit | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | bc | cd,de,ef | fg | no_u_turn | + + When I route I should get + | from | to | route | locations | + | a | 1 | enter,right,up,up | a,c,d,_ | + | 1 | a | up,left,exit,exit | _,e,f,a | diff --git a/features/car/physical_limitation.feature b/features/car/physical_limitation.feature new file mode 100644 index 000000000..ba7119c67 --- /dev/null +++ b/features/car/physical_limitation.feature @@ -0,0 +1,71 @@ +@routing @car +Feature: Car - Handle physical limitation + + Background: + Given the profile "car" + + Scenario: Car - Use a narrow way + Then routability should be + | highway | width | narrow | bothw | + | primary | | | x | + | primary | narrow | | x | + | primary | | yes | x | + | primary | 1.8 | | | + | primary | 1.9 | | | + | primary | 2.0 | | x | + | primary | 2.1 | | x | + | primary | 1m | | | + | primary | 1 m | | | + | primary | 3 m | | x | + | primary | 6' | | | + | primary | 6'0" | | | + | primary | 6'2" | | | + | primary | 6'3" | | x | + | primary | 7' | | x | + | primary | 7'0" | | x | + + Scenario: Car - Limited by width + Then routability should be + | highway | maxwidth:physical | maxwidth | width | est_width | bothw | + | primary | 1 | | | | | + | primary | 3 | | | | x | + | primary | | 1 | | | | + | primary | | 3 | | | x | + | primary | | | 1 | | | + | primary | | | 3 | | x | + | primary | | | | 1 | | + | primary | | | | 3 | x | + + Scenario: Car - Limited by height + Then routability should be + | highway | maxheight:physical | maxheight | bothw | + | primary | | | x | + | primary | 1 | | | + | primary | 3 | | x | + | primary | | 1 | | + | primary | | 8' | x | + | primary | | 3 | x | + | primary | | default | x | + | 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 | 2 | x | + | primary | 3.5 | x | + | primary | 35000 kg | x | + | primary | 8.9t | x | + | primary | 0.1 lbs | | + | primary | unsigned | x | diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature index ee325da23..fe65994ff 100644 --- a/features/car/restrictions.feature +++ b/features/car/restrictions.feature @@ -11,27 +11,27 @@ Feature: Car - Turn restrictions Scenario: Car - No left turn Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | wj | j | no_left_turn | + | restriction | cj | dj | j | no_left_turn | When I route I should get | from | to | route | - | s | w | | - | s | n | sj,nj,nj | - | s | e | sj,ej,ej | + | c | d | | + | c | a | cj,aj,aj | + | c | b | cj,bj,bj | @no_turning Scenario: Car - No straight on @@ -67,253 +67,316 @@ Feature: Car - Turn restrictions Scenario: Car - No right turn Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | ej | j | no_right_turn | + | restriction | cj | bj | j | no_right_turn | When I route I should get | from | to | route | - | s | w | sj,wj,wj | - | s | n | sj,nj,nj | - | s | e | | + | c | d | cj,dj,dj | + | c | a | cj,aj,aj | + | c | b | | @no_turning Scenario: Car - No u-turn Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | wj | j | no_u_turn | + | restriction | cj | dj | j | no_u_turn | When I route I should get | from | to | route | - | s | w | | - | s | n | sj,nj,nj | - | s | e | sj,ej,ej | + | c | d | | + | c | a | cj,aj,aj | + | c | b | cj,bj,bj | + + @no_turning + Scenario: Car - No u-turn + # https://www.openstreetmap.org/edit?node=54878482#map=19/34.05242/-117.19067 + Given the node map + """ + c + 3 + a 1 x 2 b + 4 + d + """ + + And the ways + | nodes | + | ax | + | xb | + | cx | + | xd | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | ax | ax | x | no_u_turn | + | restriction | bx | bx | x | no_u_turn | + | restriction | cx | cx | x | no_u_turn | + | restriction | dx | dx | x | no_u_turn | + + When I route I should get + | waypoints | route | turns | + | a,x,a | ax,xb,xb,xb,ax,ax | depart,new name straight,continue uturn,arrive,depart,arrive | @no_turning Scenario: Car - Handle any no_* relation Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | wj | j | no_weird_zigzags | + | restriction | cj | dj | j | no_weird_zigzags | When I route I should get | from | to | route | - | s | w | | - | s | n | sj,nj,nj | - | s | e | sj,ej,ej | + | c | d | | + | c | a | cj,aj,aj | + | c | b | cj,bj,bj | + + @no_turning + Scenario: Car - Ignore no_*_on_red relations + Given the node map + """ + a + d j b + c + """ + + And the ways + | nodes | oneway | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | cj | dj | j | no_turn_on_red | + | restriction | cj | bj | j | no_right_turn_on_red | + + When I route I should get + | from | to | route | + | c | d | cj,dj,dj | + | c | a | cj,aj,aj | + | c | b | cj,bj,bj | @only_turning Scenario: Car - Only left turn Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | wj | j | only_left_turn | + | restriction | cj | dj | j | only_left_turn | + + When I route I should get + | from | to | route | + | c | a | | + | c | b | | + | c | d | cj,dj,dj | Scenario: Car - Only right turn, invalid Given the node map """ - n - w j e r - s + a + d j b r + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | - | re | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | + | rb | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | er | j | only_right_on | + | restriction | cj | br | j | only_right_on | When I route I should get | from | to | route | - | s | r | sj,ej,re,re | + | c | r | cj,bj,rb,rb | @only_turning Scenario: Car - Only right turn Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | ej | j | only_right_turn | + | restriction | cj | bj | j | only_right_turn | When I route I should get | from | to | route | - | s | w | | - | s | n | | - | s | e | sj,ej,ej | + | c | d | | + | c | a | | + | c | b | cj,bj,bj | @only_turning Scenario: Car - Only straight on Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | nj | j | only_straight_on | + | restriction | cj | aj | j | only_straight_on | When I route I should get | from | to | route | - | s | w | | - | s | n | sj,nj,nj | - | s | e | | + | c | d | | + | c | a | cj,aj,aj | + | c | b | | @no_turning Scenario: Car - Handle any only_* restriction Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | nj | j | only_weird_zigzags | + | restriction | cj | aj | j | only_weird_zigzags | When I route I should get | from | to | route | - | s | w | | - | s | n | sj,nj,nj | - | s | e | | + | c | d | | + | c | a | cj,aj,aj | + | c | b | | @specific Scenario: Car - :hgv-qualified on a standard turn restriction Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction:hgv | - | restriction | sj | nj | j | no_straight_on | + | restriction | cj | aj | j | no_straight_on | When I route I should get | from | to | route | - | s | w | sj,wj,wj | - | s | n | sj,nj,nj | - | s | e | sj,ej,ej | + | c | d | cj,dj,dj | + | c | a | cj,aj,aj | + | c | b | cj,bj,bj | @specific Scenario: Car - :motorcar-qualified on a standard turn restriction Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction:motorcar | - | restriction | sj | nj | j | no_straight_on | + | restriction | cj | aj | j | no_straight_on | When I route I should get | from | to | route | - | s | w | sj,wj,wj | - | s | n | | - | s | e | sj,ej,ej | + | c | d | cj,dj,dj | + | c | a | | + | c | b | cj,bj,bj | @except Scenario: Car - Except tag and on no_ restrictions @@ -378,7 +441,7 @@ Feature: Car - Turn restrictions y i j f b x a e g h - c d + c1 d """ And the ways @@ -405,7 +468,7 @@ Feature: Car - Turn restrictions When I route I should get | from | to | route | | e | f | ae,xa,bx,fb,fb | - | c | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb | + | 1 | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb | | d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb | @except @@ -484,27 +547,27 @@ Feature: Car - Turn restrictions Scenario: Car - Ignore unrecognized restriction Given the node map """ - n - w j e - s + a + d j b + c """ And the ways | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | cj | yes | + | aj | -1 | + | dj | -1 | + | bj | -1 | And the relations | type | way:from | way:to | node:via | restriction | - | restriction | sj | wj | j | yield | + | restriction | cj | dj | j | yield | When I route I should get | from | to | route | - | s | w | sj,wj,wj | - | s | n | sj,nj,nj | - | s | e | sj,ej,ej | + | c | d | cj,dj,dj | + | c | a | cj,aj,aj | + | c | b | cj,bj,bj | @restriction @compression Scenario: Restriction On Compressed Geometry @@ -569,7 +632,7 @@ Feature: Car - Turn restrictions | c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d | | c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f | - @restriction @overlap + @restriction-way @overlap Scenario: Car - prohibit turn Given the node map """ @@ -704,7 +767,7 @@ Feature: Car - Turn restrictions | a | j | left,first,right,right | | f | e | right,third,left,left | - @restriction + @restriction-way Scenario: Car - allow only turn Given the node map """ @@ -736,7 +799,7 @@ Feature: Car - Turn restrictions | c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d | | c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f | - @restriction + @restriction-way Scenario: Car - allow only turn Given the node map """ @@ -765,83 +828,7 @@ Feature: Car - Turn restrictions | from | to | route | | a | d | ab,be,de,de | - @restriction - Scenario: Multi Way restriction - Given the node map - """ - k j - | | - h - - g - f - - e - | | - | | - a - - b - c - - d - | | - l i - """ - - And the ways - | nodes | name | oneway | - | ab | horiz | yes | - | bc | horiz | yes | - | cd | horiz | yes | - | ef | horiz | yes | - | fg | horiz | yes | - | gh | horiz | yes | - | ic | vert | yes | - | cf | vert | yes | - | fj | vert | yes | - | kg | vert | yes | - | gb | vert | yes | - | bl | vert | yes | - - And the relations - | type | way:from | way:via | way:to | restriction | - | restriction | ab | bc,cf,fg | gh | no_u_turn | - - When I route I should get - | from | to | route | - | a | h | horiz,vert,horiz,horiz | - - @restriction - Scenario: Multi-Way overlapping single-way - Given the node map - """ - e - | - a - b - c - d - | - f - g - | - h - """ - - And the ways - | nodes | name | - | ab | abcd | - | bc | abcd | - | cd | abcd | - | hf | hfb | - | fb | hfb | - | gf | gf | - | ce | ce | - - And the relations - | type | way:from | way:via | way:to | restriction | - | restriction | ab | bc | ce | only_left_turn | - | restriction | gf | fb,bc | cd | only_u_turn | - - When I route I should get - | from | to | route | turns | locations | - | a | d | abcd,ce,ce,abcd,abcd | depart,turn left,continue uturn,turn left,arrive | a,c,e,c,d | - | a | e | abcd,ce,ce | depart,turn left,arrive | a,c,e | - | a | f | abcd,hfb,hfb | depart,turn right,arrive | a,b,f | - | g | e | gf,hfb,abcd,ce,ce | depart,turn right,turn right,turn left,arrive | g,f,b,c,e | - | g | d | gf,hfb,abcd,abcd | depart,turn right,turn right,arrive | g,f,b,d | - | h | e | hfb,abcd,ce,ce | depart,end of road right,turn left,arrive | h,b,c,e | - | h | d | hfb,abcd,abcd | depart,end of road right,arrive | h,b,d | - - - @restriction + @restriction-way Scenario: Car - prohibit turn, traffic lights Given the node map """ @@ -884,7 +871,7 @@ Feature: Car - Turn restrictions | c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f | - @restriction @overlap @geometry + @restriction-way @overlap @geometry Scenario: Geometry Given the node map """ @@ -919,7 +906,7 @@ Feature: Car - Turn restrictions | c | d | bc,bge,de,de | | c | f | bc,bge,de,de,ef,ef | - @restriction @overlap @geometry @traffic-signals + @restriction-way @overlap @geometry @traffic-signals Scenario: Geometry Given the node map """ @@ -951,8 +938,6 @@ Feature: Car - Turn restrictions | restriction | ab | bge | de | no_right_turn | | restriction | bc | bge | ef | no_left_turn | - # this case is currently not handling the via-way restrictions and we need support for looking across traffic signals. - # It is mainly included to show limitations and to prove that we don't crash hard here When I route I should get | from | to | route | | a | d | ab,bge,ef,ef,de,de | @@ -961,7 +946,7 @@ Feature: Car - Turn restrictions | c | f | bc,bge,de,de,ef,ef | # don't crash hard on invalid restrictions - @restriction @invalid + @restriction-way @invalid Scenario: Geometry Given the node map """ @@ -993,7 +978,7 @@ Feature: Car - Turn restrictions | a | f | ab,be,ef,ef | - @restriction @overlap @geometry + @restriction @restriction-way @overlap @geometry Scenario: Duplicated restriction Given the node map """ @@ -1028,3 +1013,148 @@ Feature: Car - Turn restrictions When I route I should get | from | to | route | | a | d | ab,bc,bc,bge,de,de | + + + Scenario: Ambiguous ways + Given the node map + """ + x---a----b-----c---z + | + d + """ + + And the ways + | nodes | + | abc | + | bd | + | xa | + | cz | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | bd | abc | b | no_left_turn | + + When I route I should get + | from | to | route | + | d | x | bd,abc,xa,xa | + | d | z | bd,abc,cz,cz | + + + Scenario: Multiple restricted entrances + Given the node map + """ + b + | + a----e----c + | + d + """ + + And the ways + | nodes | + | ae | + | be | + | ce | + | de | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | ae,be | ed | e | no_entry | + + When I route I should get + | from | to | route | + | a | d | ae,ce,ce,de,de | + | b | d | be,ce,ce,de,de | + | c | d | ce,de,de | + + + Scenario: Multiple restricted exits + Given the node map + """ + b + | + a----e----c + | + d + """ + + And the ways + | nodes | + | ae | + | be | + | ce | + | de | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | ae | ce,de | e | no_exit | + + When I route I should get + | from | to | route | + | a | b | ae,be,be | + | a | c | ae,be,be,ce,ce | + | a | d | ae,be,be,de,de | + + + Scenario: Invalid restricted entrances/exits + Given the node map + """ + b + | + a----e----c + | + d + """ + + And the ways + | nodes | + | ae | + | be | + | ce | + | de | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | ae | ce,de | e | no_entry | + | restriction | ae,be | ed | e | no_exit | + + When I route I should get + | from | to | route | + | a | b | ae,be,be | + | a | c | ae,ce,ce | + | a | d | ae,de,de | + | b | d | be,de,de | + | c | d | ce,de,de | + + + Scenario: Invalid multi from/to restrictions + Given the node map + """ + b + | + a----e----c + | + d + """ + + And the ways + | nodes | + | ae | + | be | + | ce | + | de | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | ae,de | ce,de | e | no_right_turn | + | restriction | ae,be | ce,de | e | no_straight_on | + | restriction | ae,be | be,ce | e | only_left_turn | + | restriction | ae,be | ce,de | e | only_straight_on | + + When I route I should get + | from | to | route | + | a | b | ae,be,be | + | a | c | ae,ce,ce | + | a | d | ae,de,de | + | b | d | be,de,de | + | c | d | ce,de,de | diff --git a/features/car/route_relations.feature b/features/car/route_relations.feature new file mode 100644 index 000000000..6cc48b0f4 --- /dev/null +++ b/features/car/route_relations.feature @@ -0,0 +1,329 @@ +@routing @car @relations +Feature: Car - route relations + Background: + Given the profile "car" + + Scenario: Assignment using relation membership roles + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + c----------------d + """ + + And the ways + | nodes | name | highway | ref | + | ba | westbound | motorway | I 80 | + | cd | eastbound | motorway | I 80;CO 93 | + + And the relations + | type | way:east | way:west | route | ref | network | + | route | cd | ba | road | 80 | US:I | + | route | cd | ba | road | 93 | US:CO | + + + When I route I should get + | waypoints | route | ref | + | b,a | westbound,westbound | I 80 $west,I 80 $west | + | c,d | eastbound,eastbound | I 80 $east; CO 93 $east,I 80 $east; CO 93 $east | + + Scenario: No cardinal directions by default + Given the profile file "car" initialized with + """ + profile.cardinal_directions = false + """ + Given the node map + """ + a----------------b + c----------------d + """ + + And the ways + | nodes | name | highway | ref | + | ba | westbound | motorway | I 80 | + | cd | eastbound | motorway | I 80;CO 93 | + + And the relations + | type | way:east | way:west | route | ref | network | + | route | cd | ba | road | 80 | US:I | + | route | cd | ba | road | 93 | US:CO | + + + When I route I should get + | waypoints | route | ref | + | b,a | westbound,westbound | I 80,I 80 | + | c,d | eastbound,eastbound | I 80; CO 93,I 80; CO 93 | + + Scenario: No cardinal directions by default + Given the node map + """ + a----------------b + c----------------d + """ + + And the ways + | nodes | name | highway | ref | + | ba | westbound | motorway | I 80 | + | cd | eastbound | motorway | I 80;CO 93 | + + And the relations + | type | way:east | way:west | route | ref | network | + | route | cd | ba | road | 80 | US:I | + | route | cd | ba | road | 93 | US:CO | + + + When I route I should get + | waypoints | route | ref | + | b,a | westbound,westbound | I 80,I 80 | + | c,d | eastbound,eastbound | I 80; CO 93,I 80; CO 93 | + + + Scenario: Assignment using relation direction property (no role on members) + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + c----------------d + """ + + And the ways + | nodes | name | highway | ref | + | ba | westbound | motorway | I 80 | + | cd | eastbound | motorway | I 80;CO 93 | + + And the relations + | type | direction | way | route | ref | network | + | route | west | ba | road | 80 | US:I | + | route | east | cd | road | 80 | US:I | + | route | east | cd | road | 93 | US:CO | + + When I route I should get + | waypoints | route | ref | + | b,a | westbound,westbound | I 80 $west,I 80 $west | + | c,d | eastbound,eastbound | I 80 $east; CO 93 $east,I 80 $east; CO 93 $east | + + + Scenario: Forward assignment on one-way roads using relation direction property + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + c----------------d + """ + + And the ways + | nodes | name | highway | ref | + | ba | westbound | motorway | I 80 | + | cd | eastbound | motorway | I 80;CO 93 | + + And the relations + | type | direction | way:forward | route | ref | network | + | route | west | ba | road | 80 | US:I | + | route | east | cd | road | 80 | US:I | + | route | east | cd | road | 93 | US:CO | + + When I route I should get + | waypoints | route | ref | + | b,a | westbound,westbound | I 80 $west,I 80 $west | + | c,d | eastbound,eastbound | I 80 $east; CO 93 $east,I 80 $east; CO 93 $east | + + + Scenario: Forward/backward assignment on non-divided roads with role direction tag + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + """ + + And the ways + | nodes | name | highway | ref | oneway | + | ab | mainroad | motorway | I 80 | no | + + And the relations + | type | direction | way:forward | route | ref | network | + | route | west | ab | road | 80 | US:I | + + And the relations + | type | direction | way:backward | route | ref | network | + | route | east | ab | road | 80 | US:I | + + When I route I should get + | waypoints | route | ref | + | a,b | mainroad,mainroad | I 80 $west,I 80 $west | + | b,a | mainroad,mainroad | I 80 $east,I 80 $east | + + + Scenario: Conflict between role and direction + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + """ + + And the ways + | nodes | name | highway | ref | + | ab | eastbound | motorway | I 80 | + + And the relations + | type | direction | way:east | route | ref | network | + | route | west | ab | road | 80 | US:I | + + When I route I should get + | waypoints | route | ref | + | a,b | eastbound,eastbound | I 80,I 80 | + + + Scenario: Conflict between role and superrelation direction + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + """ + + And the ways + | nodes | name | highway | ref | + | ab | eastbound | motorway | I 80 | + + And the relations + | type | way:east | route | ref | network | name | + | route | ab | road | 80 | US:I | baserelation | + + And the relations + | type | direction | relation | route | ref | network | name | + | route | west | baserelation | road | 80 | US:I | superrelation | + + When I route I should get + | waypoints | route | ref | + | a,b | eastbound,eastbound | I 80,I 80 | + + Scenario: Conflict between role and superrelation role + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + """ + + And the ways + | nodes | name | highway | ref | + | ab | eastbound | motorway | I 80 | + + And the relations + | type | way:east | route | ref | network | name | + | route | ab | road | 80 | US:I | baserelation | + + And the relations + | type | relation:west | route | ref | network | name | + | route | baserelation | road | 80 | US:I | superrelation | + + When I route I should get + | waypoints | route | ref | + | a,b | eastbound,eastbound | I 80,I 80 | + + Scenario: Direction only available via superrelation role + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + """ + + And the ways + | nodes | name | highway | ref | + | ab | eastbound | motorway | I 80 | + + And the relations + | type | way:forward | route | ref | network | name | + | route | ab | road | 80 | US:I | baserelation | + + And the relations + | type | relation:east | route | ref | network | name | + | route | baserelation | road | 80 | US:I | superrelation | + + When I route I should get + | waypoints | route | ref | + | a,b | eastbound,eastbound | I 80 $east,I 80 $east | + + Scenario: Direction only available via superrelation direction + Given the profile file "car" initialized with + """ + profile.cardinal_directions = true + """ + + Given the node map + """ + a----------------b + """ + + And the ways + | nodes | name | highway | ref | + | ab | eastbound | motorway | I 80 | + + And the relations + | type | way:forward | route | ref | network | name | + | route | ab | road | 80 | US:I | baserelation | + + And the relations + | type | direction | relation | route | ref | network | name | + | route | east | baserelation | road | 80 | US:I | superrelation | + + When I route I should get + | waypoints | route | ref | + | a,b | eastbound,eastbound | I 80 $east,I 80 $east | + + +# Scenario: Three levels of indirection +# Given the node map +# """ +# a----------------b +# """ +# +# And the ways +# | nodes | name | highway | ref | +# | ab | eastbound | motorway | I 80 | +# +# And the relations +# | type | way:forward | route | ref | network | name | +# | route | ab | road | 80 | US:I | baserelation | +# +# And the relations +# | type | relation | route | ref | network | name | +# | route | baserelation | road | 80 | US:I | superrelation1 | +# +# And the relations +# | type | direction | relation | route | ref | network | name | +# | route | east | superrelation1 | road | 80 | US:I | superrelation2 | +# +# When I route I should get +# | waypoints | route | ref | +# | a,b | eastbound,eastbound | I 80 $east,I 80 $east | diff --git a/features/car/side_bias.feature b/features/car/side_bias.feature index 2547ef21a..a44fa08a6 100644 --- a/features/car/side_bias.feature +++ b/features/car/side_bias.feature @@ -4,30 +4,7 @@ Feature: Testbot - side bias Scenario: Left-hand bias Given the profile file "car" initialized with """ - profile.left_hand_driving = true - profile.turn_bias = 1/1.075 - """ - Given the node map - """ - a b c - - d - """ - And the ways - | nodes | - | ab | - | bc | - | bd | - - When I route I should get - | from | to | route | time | - | d | a | bd,ab,ab | 24s +-1 | - | d | c | bd,bc,bc | 27s +-1 | - - Scenario: Right-hand bias - Given the profile file "car" initialized with - """ - profile.left_hand_driving = true + profile.properties.left_hand_driving = true profile.turn_bias = 1.075 """ And the node map @@ -43,7 +20,124 @@ Feature: Testbot - side bias | bd | When I route I should get - | from | to | route | time | - | d | a | bd,ab,ab | 27s +-1 | - # should be inverse of left hand bias - | d | c | bd,bc,bc | 24s +-1 | + | from | to | route | time | driving_side | + | d | a | bd,ab,ab | 24s +-1 | left,left,left | + | d | c | bd,bc,bc | 27s +-1 | left,left,left | + + Scenario: Right-hand bias + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + profile.turn_bias = 1 / 1.075 + """ + And the node map + """ + a b c + + d + """ + And the ways + | nodes | + | ab | + | bc | + | bd | + + When I route I should get + | from | to | route | time | driving_side | # | + | d | a | bd,ab,ab | 27s +-1 | left,left,left | should be inverse of left hand bias | + | d | c | bd,bc,bc | 24s +-1 | left,left,left | | + + Scenario: Roundabout exit counting for left sided driving + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And a grid size of 10 meters + And the node map + """ + a + b + h g c d + e + f + """ + And the ways + | nodes | junction | + | ab | | + | cd | | + | ef | | + | gh | | + | bcegb | roundabout | + + When I route I should get + | waypoints | route | driving_side | turns | + | a,d | ab,cd,cd | left,left,left | depart,roundabout turn left exit-1,arrive | + | a,f | ab,ef,ef | left,left,left | depart,roundabout turn straight exit-2,arrive | + | a,h | ab,gh,gh | left,left,left | depart,roundabout turn right exit-3,arrive | + + + Scenario: Left-hand bias via location-dependent tags + Given the profile "car" + And the node map + """ + a b c + + d + """ + And the ways with locations + | nodes | + | ab | + | bc | + | bd | + And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson" + + When I route I should get + | from | to | route | driving_side | time | + | d | a | bd,ab,ab | left,left,left | 24s +-1 | + | d | c | bd,bc,bc | left,left,left | 27s +-1 | + + + Scenario: Left-hand bias via OSM tags + Given the profile "car" + And the node map + """ + a b c + + d + """ + And the ways with locations + | nodes | driving_side | + | ab | right | + | bc | right | + | bd | right | + And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson" + + When I route I should get + | from | to | route | driving_side | time | + | d | a | bd,ab,ab | right,right,right | 27s +-1 | + | d | c | bd,bc,bc | right,right,right | 24s +-1 | + + Scenario: changing sides + Given the profile "car" + + # Note - the boundary in null-island.geojson is at lon = 2.0, + # and we use the "last node of the way" as the heuristic to detect + # whether the way is in our out of the driving_side polygon + And the node locations + | node | lat | lon | + | a | 0 | 0.5 | + | b | 0 | 1.5 | + | c | 0 | 2.5 | + | d | 0 | 3.5 | + + And the ways + | nodes | + | ab | + | bc | + | cd | + + And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson" + When I route I should get + | from | to | route | driving_side | + | d | a | cd,bc,ab,ab | right,right,left,left | + | a | d | ab,bc,cd,cd | left,right,right,right | diff --git a/features/car/speed.feature b/features/car/speed.feature index bbbb67b6f..37d9f3512 100644 --- a/features/car/speed.feature +++ b/features/car/speed.feature @@ -9,29 +9,29 @@ Feature: Car - speeds Scenario: Car - speed of various way types Then routability should be | highway | oneway | bothw | - | motorway | no | 89 km/h | - | motorway_link | no | 44 km/h | - | trunk | no | 85 km/h | - | trunk_link | no | 39 km/h | + | motorway | no | 90 km/h | + | motorway_link | no | 45 km/h | + | trunk | no | 84 km/h | + | trunk_link | no | 40 km/h | | primary | no | 64 km/h | - | primary_link | no | 29 km/h | - | secondary | no | 55 km/h | - | secondary_link | no | 24 km/h | - | tertiary | no | 39 km/h | + | primary_link | no | 30 km/h | + | secondary | no | 54 km/h | + | secondary_link | no | 25 km/h | + | tertiary | no | 40 km/h | | tertiary_link | no | 20 km/h | - | unclassified | no | 24 km/h | - | residential | no | 24 km/h | - | living_street | no | 9 km/h | + | unclassified | no | 25 km/h | + | residential | no | 25 km/h | + | living_street | no | 10 km/h | | service | no | 15 km/h | # Alternating oneways scale rates but not speeds Scenario: Car - scaled speeds for oneway=alternating Then routability should be | highway | oneway | junction | forw | backw | # | - | tertiary | | | 39 km/h | 39 km/h | | - | tertiary | alternating | | 39 km/h | 39 km/h | | - | motorway | | | 89 km/h | | implied oneway | - | motorway | alternating | | 89 km/h | | implied oneway | + | tertiary | | | 40 km/h | 40 km/h | | + | tertiary | alternating | | 40 km/h | 40 km/h | | + | motorway | | | 90 km/h | | implied oneway | + | motorway | alternating | | 90 km/h | | implied oneway | | motorway | reversible | | | | unroutable | | primary | | roundabout | 64 km/h | | implied oneway | | primary | alternating | roundabout | 64 km/h | | implied oneway | @@ -42,12 +42,12 @@ Feature: Car - speeds | highway | maxspeed | forw | backw | | primary | | 64 km/h | 64 km/h | - | primary | 60 | 47 km/h | 47 km/h | - | primary | 60 | 47 km/h | 47 km/h | - | primary | 60 | 47 km/h | 47 km/h | + | primary | 60 | 48 km/h | 48 km/h | + | primary | 60 | 48 km/h | 48 km/h | + | primary | 60 | 48 km/h | 48 km/h | Scenario: Car - Side road penalties Then routability should be | highway | side_road | forw | backw | forw_rate | backw_rate | - | primary | yes | 64 km/h | 64 km/h | 14.4 | 14.4 | + | primary | yes | 64 km/h | 64 km/h | 14.5 | 14.5 | diff --git a/features/car/startpoint.feature b/features/car/startpoint.feature index 965f57d43..696f1ae31 100644 --- a/features/car/startpoint.feature +++ b/features/car/startpoint.feature @@ -35,3 +35,91 @@ 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.2 | + | b | 35 | 11.1 | + + When I route I should get + | from | to | route | + | 1 | 2 | ab,bc,cd | + | 2 | 1 | cd,bc,ab | + + Scenario: Car - URL override of non-startpoints + Given the node map + """ + a 1 b c 2 d + """ + + Given the query options + | snapping | any | + | bearings | 90,180; | + + And the ways + | nodes | highway | access | + | ab | service | private | + | bc | primary | | + | cd | service | private | + + When I route I should get + | from | to | route | + | 1 | 2 | ab,bc,cd | + | 2 | 1 | cd,bc,ab | + + Scenario: Car - URL override of non-startpoints + Given the node map + """ + a 1 b c 2 d + """ + + Given the query options + | snapping | any | + | radiuses | 100;unlimited | + + And the ways + | nodes | highway | access | + | ab | service | private | + | bc | primary | | + | cd | service | private | + + When I route I should get + | from | to | route | + | 1 | 2 | ab,bc,cd | + | 2 | 1 | cd,bc,ab | + + Scenario: Car - URL override of non-startpoints + Given the node map + """ + a 1 b c 2 d + """ + + Given the query options + | snapping | any | + | bearings | 90,180;0,180;; | + + 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.2 | + | b | 35 | 11.1 | \ No newline at end of file diff --git a/features/car/summaries.feature b/features/car/summaries.feature index 688f203b0..5228d1822 100644 --- a/features/car/summaries.feature +++ b/features/car/summaries.feature @@ -76,7 +76,7 @@ Feature: Basic Routing When I route I should get | waypoints | route | summary | - | a,c | , | 100, 101 | + | a,c | ,, | 100, 101 | Scenario: Single Ref Given the node map diff --git a/features/car/surface.feature b/features/car/surface.feature index 8984a8e06..067e56500 100644 --- a/features/car/surface.feature +++ b/features/car/surface.feature @@ -65,7 +65,7 @@ Feature: Car - Surfaces Then routability should be | highway | oneway | surface | forw | backw | | motorway | no | | 90 km/h | 90 km/h | - | motorway | no | asphalt | 90 km/h | 90 km/h +-1 | + | motorway | no | asphalt | 91 km/h | 90 km/h +-1 | | motorway | no | concrete | 90 km/h +-1 | 90 km/h +-1 | | motorway | no | concrete:plates | 90 km/h +-1 | 90 km/h +-1 | | motorway | no | concrete:lanes | 90 km/h +-1 | 90 km/h +-1 | diff --git a/features/car/traffic_light_penalties.feature b/features/car/traffic_light_penalties.feature index e5bc313a0..048c25f4f 100644 --- a/features/car/traffic_light_penalties.feature +++ b/features/car/traffic_light_penalties.feature @@ -39,7 +39,148 @@ Feature: Car - Handle traffic lights | k | n | 20.7s | turn with traffic light | - Scenario: Tarrif Signal Geometry + Scenario: Car - Traffic signal direction + Given the node map + """ + a-1-b-2-c + + d-3-e-4-f + + g-5-h-6-i + + j-7-k-8-l + + """ + + And the ways + | nodes | highway | + | abc | primary | + | def | primary | + | ghi | primary | + | jkl | primary | + + And the nodes + | node | highway | traffic_signals:direction | + | e | traffic_signals | | + | h | traffic_signals | forward | + | k | traffic_signals | backward | + + When I route I should get + | from | to | time | weight | # | + | 1 | 2 | 11.1s | 11.1 | no turn with no traffic light | + | 2 | 1 | 11.1s | 11.1 | no turn with no traffic light | + | 3 | 4 | 13.1s | 13.1 | no turn with traffic light | + | 4 | 3 | 13.1s | 13.1 | no turn with traffic light | + | 5 | 6 | 13.1s | 13.1 | no turn with traffic light | + | 6 | 5 | 11.1s | 11.1 | no turn with no traffic light | + | 7 | 8 | 11.1s | 11.1 | no turn with no traffic light | + | 8 | 7 | 13.1s | 13.1 | no turn with traffic light | + + + Scenario: Car - Traffic signal direction with distance weight + Given the profile file "car" initialized with + """ + profile.properties.weight_name = 'distance' + profile.properties.traffic_light_penalty = 100000 + """ + + Given the node map + """ + a---b---c + 1 2 + | | + | | + | | + | | + | | + d-------f + + """ + + And the ways + | nodes | highway | + | abc | primary | + | adfc | primary | + + And the nodes + | node | highway | + | b | traffic_signals | + + When I route I should get + | from | to | time | distances | weight | # | + | 1 | 2 | 100033.2s | 599.9m,0m | 599.8 | goes via the expensive traffic signal | + + + + Scenario: Car - Encounters a traffic light + Given the node map + """ + a f k + | | | + b-c-d h-g-i l-m-n + | | | + e j o + + """ + + And the ways + | nodes | highway | + | bcd | primary | + | ace | primary | + | hgi | primary | + | fgj | primary | + | lmn | primary | + | kmo | primary | + + And the nodes + | node | highway | traffic_signals:direction | + | g | traffic_signals | forward | + | m | traffic_signals | backward | + + + When I route I should get + | from | to | time | # | + | a | d | 21.9s | no turn with no traffic light | + | a | e | 22.2s | no turn with traffic light | + | a | b | 18.7s | turn with no traffic light | + | e | b | 21.9s | no turn with no traffic light | + | e | a | 22.2s | no turn with traffic light | + | e | d | 18.7s | turn with no traffic light | + | d | e | 21.9s | no turn with no traffic light | + | d | b | 11s | no turn with traffic light | + | d | a | 18.7s | turn with no traffic light | + | b | a | 21.9s | no turn with no traffic light | + | b | d | 11s | no turn with traffic light | + | b | e | 18.7s | turn with no traffic light | + + | f | i | 23.9s | no turn with no traffic light | + | f | j | 24.2s | no turn with traffic light | + | f | h | 20.7s | turn with no traffic light | + | j | h | 21.9s | no turn with no traffic light | + | j | f | 22.2s | no turn with traffic light | + | j | i | 18.7s | turn with no traffic light | + | i | j | 21.9s | no turn with no traffic light | + | i | h | 11s | no turn with traffic light | + | i | f | 18.7s | turn with no traffic light | + | h | f | 23.9s | no turn with no traffic light | + | h | i | 13s | no turn with traffic light | + | h | j | 20.7s | turn with no traffic light | + + | k | n | 21.9s | no turn with no traffic light | + | k | o | 22.2s | no turn with traffic light | + | k | l | 18.7s | turn with no traffic light | + | o | l | 23.9s | no turn with no traffic light | + | o | k | 24.2s | no turn with traffic light | + | o | n | 20.7s | turn with no traffic light | + | n | o | 23.9s | no turn with no traffic light | + | n | l | 13s | no turn with traffic light | + | n | k | 20.7s | turn with no traffic light | + | l | k | 21.9s | no turn with no traffic light | + | l | n | 11s | no turn with traffic light | + | l | o | 18.7s | turn with no traffic light | + + + Scenario: Traffic Signal Geometry Given the query options | overview | full | | geometries | polyline | @@ -59,7 +200,54 @@ Feature: Car - Handle traffic lights When I route I should get | from | to | route | geometry | - | a | c | abc,abc | _ibE_ibE?gJ?gJ | + | a | c | abc,abc | _ibE_ibE?gJ?eJ | + + + Scenario: Traffic Signal Geometry - forward signal + Given the query options + | overview | full | + | geometries | polyline | + + Given the node map + """ + a - b - c + """ + + And the ways + | nodes | highway | + | abc | primary | + + And the nodes + | node | highway | traffic_signals:direction | + | b | traffic_signals | forward | + + When I route I should get + | from | to | route | geometry | + | a | c | abc,abc | _ibE_ibE?gJ?eJ | + + + Scenario: Traffic Signal Geometry - reverse signal + Given the query options + | overview | full | + | geometries | polyline | + + Given the node map + """ + a - b - c + """ + + And the ways + | nodes | highway | + | abc | primary | + + And the nodes + | node | highway | traffic_signals:direction | + | b | traffic_signals | reverse | + + When I route I should get + | from | to | route | geometry | + | a | c | abc,abc | _ibE_ibE?gJ?eJ | + @traffic Scenario: Traffic update on the edge with a traffic signal @@ -89,5 +277,69 @@ Feature: Car - Handle traffic lights When I route I should get | from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight | - | a | c | abc,abc | 59 km/h | 24.2,0 | 24.2s | 399.9m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 | - | c | a | abc,abc | 59 km/h | 24.2,0 | 24.2s | 399.9m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 | + | a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 | + | c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 | + + + @traffic + Scenario: Traffic update on the edge with a traffic signal - forward + Given the node map + """ + a - b - c + """ + + And the ways + | nodes | highway | + | abc | primary | + + + And the nodes + | node | highway | traffic_signals:direction | + | b | traffic_signals | forward | + + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 1,2,65 + 2,1,65 + """ + And the query options + | annotations | datasources,nodes,speed,duration,weight | + + When I route I should get + | from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight | + | a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 | + | c | a | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 | + + + @traffic + Scenario: Traffic update on the edge with a traffic signal - backward + Given the node map + """ + a - b - c + """ + + And the ways + | nodes | highway | + | abc | primary | + + + And the nodes + | node | highway | traffic_signals:direction | + | b | traffic_signals | backward | + + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 1,2,65 + 2,1,65 + """ + And the query options + | annotations | datasources,nodes,speed,duration,weight | + + When I route I should get + | from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight | + | a | c | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 | + | c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 | diff --git a/features/car/weight.feature b/features/car/weight.feature index 6889a2b1f..d7f02ac57 100644 --- a/features/car/weight.feature +++ b/features/car/weight.feature @@ -6,9 +6,9 @@ Feature: Car - weights And the node map """ a--b--c - | - d - | + | | + d | + | | e--f--g """ And the ways @@ -19,7 +19,7 @@ Feature: Car - weights | bdf | service | When I route I should get | from | to | route | speed | weight | - | a | e | abc,cg,efg,efg | 28 km/h | 126.6 | + | a | e | abc,cg,efg,efg | 29 km/h | 122.4 | | a | d | abc,bdf,bdf | 18 km/h | 71.7 | Scenario: Does not jump off the highway to go down service road @@ -59,7 +59,7 @@ Feature: Car - weights When I route I should get | from | to | route | speed | weight | | a | d | ab,bc,cd,cd | 65 km/h | 44.4 | - | a | e | ab,be,be | 14 km/h | 112 | + | a | e | ab,be,be | 14 km/h | 111.8 | Scenario: Distance weights Given the profile file "car" initialized with @@ -83,4 +83,4 @@ Feature: Car - weights | waypoints | bearings | route | distance | weights | times | | a,b | 90 90 | abc,abc | 200m | 200,0 | 11.1s,0s | | b,c | 90 90 | abc,abc | 200m | 200,0 | 11.1s,0s | - | a,d | 90 180 | abc,bd,bd | 399.9m | 200,200,0 | 13.2s,11.1s,0s | + | a,d | 90 180 | abc,bd,bd | 400m | 200,200,0 | 13.2s,11.1s,0s | diff --git a/features/foot/barrier.feature b/features/foot/barrier.feature index 1dda71928..f8cffdd79 100644 --- a/features/foot/barrier.feature +++ b/features/foot/barrier.feature @@ -10,6 +10,7 @@ Feature: Barriers | | x | | bollard | x | | gate | x | + | lift_gate | x | | cycle_barrier | x | | cattle_grid | x | | border_control | x | @@ -18,7 +19,7 @@ Feature: Barriers | entrance | x | | wall | | | fence | | - | some_tag | | + | some_tag | x | | block | x | Scenario: Foot - Access tag trumphs barriers diff --git a/features/foot/intersection.feature b/features/foot/intersection.feature new file mode 100644 index 000000000..f1ef3f6a5 --- /dev/null +++ b/features/foot/intersection.feature @@ -0,0 +1,31 @@ +@routing @foot +Feature: Foot - Intersections + + Background: + Given the profile "foot" + Given a grid size of 2 meters + + # https://github.com/Project-OSRM/osrm-backend/issues/6218 + Scenario: Foot - Handles non-planar intersections + Given the node map + + """ + f + | + a + | + b---c---d + | + e + """ + + And the ways + | nodes | highway | foot | layer | + | ac | footway | yes | 0 | + | bc | footway | yes | 0 | + | cd | footway | yes | 0 | + | cef | footway | yes | 1 | + + When I route I should get + | from | to | route | + | a | d | ac,cd,cd | diff --git a/features/foot/names.feature b/features/foot/names.feature index c14b00b7f..8b8498c26 100644 --- a/features/foot/names.feature +++ b/features/foot/names.feature @@ -20,3 +20,20 @@ Feature: Foot - Street names in instructions When I route I should get | from | to | route | ref | | a | c | My Way,, | ,A7,A7 | + + + Scenario: Foot - Combines named roads with suffix changes + Given the node map + """ + a b c d + """ + + And the ways + | nodes | name | + | ab | High Street W | + | bc | High Street E | + | cd | Market Street | + + When I route I should get + | from | to | route | + | a | d | High Street W,Market Street,Market Street | diff --git a/features/foot/restrictions.feature b/features/foot/restrictions.feature index 5273a47b1..263aa6416 100644 --- a/features/foot/restrictions.feature +++ b/features/foot/restrictions.feature @@ -29,7 +29,7 @@ Feature: Foot - Turn restrictions When I route I should get | from | to | route | | s | w | sj,wj,wj | - | s | n | sj,nj,nj | + | s | n | sj,nj | | s | e | sj,ej,ej | @only_turning @@ -55,7 +55,7 @@ Feature: Foot - Turn restrictions When I route I should get | from | to | route | | s | w | sj,wj,wj | - | s | n | sj,nj,nj | + | s | n | sj,nj | | s | e | sj,ej,ej | @except diff --git a/features/guidance/advanced-lanes.feature b/features/guidance/advanced-lanes.feature index 09c946c73..b920dfdce 100644 --- a/features/guidance/advanced-lanes.feature +++ b/features/guidance/advanced-lanes.feature @@ -47,7 +47,7 @@ Feature: Turn Lane Guidance e a . . b . . . c g ` . - ` . + ` . ` d f """ diff --git a/features/guidance/anticipate-lanes.feature b/features/guidance/anticipate-lanes.feature index c082dc3c1..74f6f7d4c 100644 --- a/features/guidance/anticipate-lanes.feature +++ b/features/guidance/anticipate-lanes.feature @@ -103,7 +103,7 @@ Feature: Turn Lane Guidance When I route I should get | waypoints | route | turns | lanes | - | a,d | On,Hwy,Off,Off | depart,merge slight right,off ramp right,arrive | ,slight left:false slight left:true,straight:false slight right:true, | + | a,d | On,Hwy,Off,Off | depart,merge slight right,off ramp right,arrive | ,slight left:true slight left:true,straight:false slight right:true, | @anticipate @@ -364,8 +364,8 @@ Feature: Turn Lane Guidance When I route I should get | waypoints | route | turns | lanes | - | a,d | main,left,left | depart,end of road left,arrive | ;left:false straight:false straight:true straight:false straight:false right:false;left:false straight:true straight:false right:false,left:true right:false, | - | a,e | main,right,right | depart,end of road right,arrive | ;left:false straight:false straight:false straight:true straight:false right:false;left:false straight:false straight:true right:false,left:false right:true, | + | a,d | main,left,left | depart,end of road left,arrive | ;left:false straight:true straight:true straight:true straight:true right:false;left:false straight:true straight:true right:false,left:true right:false, | + | a,e | main,right,right | depart,end of road right,arrive | ;left:false straight:true straight:true straight:true straight:true right:false;left:false straight:true straight:true right:false,left:false right:true, | @anticipate Scenario: Anticipate Lanes for through with turn before / after @@ -390,15 +390,15 @@ Feature: Turn Lane Guidance | il | | il | | When I route I should get - | waypoints | route | turns | lanes | # | - | a,f | ab,bdehi,ef,ef | depart,turn right,turn right,arrive | ,right:false right:false right:true right:true,left:false left:false straight:false straight:false straight:false straight:false right:true right:true, | | - | a,g | ab,bdehi,eg,eg | depart,turn right,turn left,arrive | ,right:true right:true right:false right:false,left:true left:true straight:false straight:false straight:false straight:false right:false right:false, | | - | a,j | ab,bdehi,ij,ij | depart,turn right,end of road right,arrive | ,right:true right:true right:false right:false;left:false left:false straight:false straight:false straight:true straight:true right:false right:false,left:false left:false right:true right:true, | | - | a,l | ab,bdehi,il,il | depart,turn right,end of road left,arrive | ,right:false right:false right:true right:true;left:false left:false straight:true straight:true straight:false straight:false right:false right:false,left:true left:true right:false right:false, | not perfect | - | c,g | cb,bdehi,eg,eg | depart,turn left,turn left,arrive | ,left:true left:true left:false left:false,left:true left:true straight:false straight:false straight:false straight:false right:false right:false, | | - | c,f | cb,bdehi,ef,ef | depart,turn left,turn right,arrive | ,left:false left:false left:true left:true,left:false left:false straight:false straight:false straight:false straight:false right:true right:true, | | - | c,l | cb,bdehi,il,il | depart,turn left,end of road left,arrive | ,left:false left:false left:true left:true;left:false left:false straight:true straight:true straight:false straight:false right:false right:false,left:true left:true right:false right:false, | | - | c,j | cb,bdehi,ij,ij | depart,turn left,end of road right,arrive | ,left:true left:true left:false left:false;left:false left:false straight:false straight:false straight:true straight:true right:false right:false,left:false left:false right:true right:true, | not perfect | + | waypoints | route | turns | lanes | # | + | a,f | ab,bdehi,ef,ef | depart,turn right,turn right,arrive | ,right:true right:true right:true right:true,left:false left:false straight:false straight:false straight:false straight:false right:true right:true, | | + | a,g | ab,bdehi,eg,eg | depart,turn right,turn left,arrive | ,right:true right:true right:true right:true,left:true left:true straight:false straight:false straight:false straight:false right:false right:false, | | + | a,j | ab,bdehi,ij,ij | depart,turn right,end of road right,arrive | ,right:true right:true right:true right:true;left:false left:false straight:false straight:false straight:true straight:true right:false right:false,left:false left:false right:true right:true, | | + | a,l | ab,bdehi,il,il | depart,turn right,end of road left,arrive | ,right:true right:true right:true right:true;left:false left:false straight:true straight:true straight:false straight:false right:false right:false,left:true left:true right:false right:false, | not perfect | + | c,g | cb,bdehi,eg,eg | depart,turn left,turn left,arrive | ,left:true left:true left:true left:true,left:true left:true straight:false straight:false straight:false straight:false right:false right:false, | | + | c,f | cb,bdehi,ef,ef | depart,turn left,turn right,arrive | ,left:true left:true left:true left:true,left:false left:false straight:false straight:false straight:false straight:false right:true right:true, | | + | c,l | cb,bdehi,il,il | depart,turn left,end of road left,arrive | ,left:true left:true left:true left:true;left:false left:false straight:true straight:true straight:false straight:false right:false right:false,left:true left:true right:false right:false, | | + | c,j | cb,bdehi,ij,ij | depart,turn left,end of road right,arrive | ,left:true left:true left:true left:true;left:false left:false straight:false straight:false straight:true straight:true right:false right:false,left:false left:false right:true right:true, | not perfect | @anticipate Scenario: Anticipate Lanes for turns with through before and after @@ -811,9 +811,9 @@ Feature: Turn Lane Guidance | hj | 7th | | no | When I route I should get - | waypoints | route | turns | locations | lanes | - | a,i | road,road | depart,arrive | a,i | ;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:false;none:true none:true right:false, | - | a,j | road,7th,7th | depart,turn right,arrive | a,h,j | ;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:false none:false none:true;left:false none:false none:false none:true,none:false none:false right:true, | + | waypoints | route | turns | locations | lanes | + | a,i | road,road | depart,arrive | a,i | ;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;none:true none:true right:false, | + | a,j | road,7th,7th | depart,turn right,arrive | a,h,j | ;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:true none:true none:true;left:false none:false none:false none:true,none:false none:false right:true, | @anticipate Scenario: Oak St, Franklin St diff --git a/features/guidance/bicycle-sliproads.feature b/features/guidance/bicycle-sliproads.feature index 0b297155d..347476b45 100644 --- a/features/guidance/bicycle-sliproads.feature +++ b/features/guidance/bicycle-sliproads.feature @@ -22,11 +22,11 @@ Feature: Bike - Mode flag | c | traffic_signals | And the ways - | nodes | highway | name | oneway:bicycle | - | abcd | cycleway | street | | - | eb | path | | yes | - | icef | tertiary | road | | - | geh | secondary | street | | + | nodes | highway | name | oneway:bicycle | maxspeed:forward | + | abcd | cycleway | street | | 4 km/h | + | eb | path | | yes | | + | icef | tertiary | road | | 4 km/h | + | geh | secondary | street | | | When I route I should get | waypoints | route | turns | diff --git a/features/guidance/bridges_and_tunnels.feature b/features/guidance/bridges_and_tunnels.feature index 17655f831..f95876982 100644 --- a/features/guidance/bridges_and_tunnels.feature +++ b/features/guidance/bridges_and_tunnels.feature @@ -98,11 +98,11 @@ Feature: Car - Guidance - Bridges and Tunnels | dce | primary | | Nebenstraße | When I route I should get - | from | to | route | turns | - | a | d | Hauptstraße,Nebenstraße,Nebenstraße | depart,turn left,arrive | - | a | e | Hauptstraße,Nebenstraße,Nebenstraße | depart,turn right,arrive | - | e | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn left,arrive | - | d | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn right,arrive | + | from | to | route | turns | + | a | d | Hauptstraße,Nebenstraße,Nebenstraße | depart,end of road left,arrive | + | a | e | Hauptstraße,Nebenstraße,Nebenstraße | depart,end of road right,arrive | + | e | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn left,arrive | + | d | a | Nebenstraße,Hauptstraßentunnel,Hauptstraße | depart,turn right,arrive | Scenario: Tunnel with Immediate Turn Front and Back Given the node map @@ -129,4 +129,3 @@ Feature: Car - Guidance - Bridges and Tunnels | e | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn left,turn left,arrive | | d | f | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn right,arrive | | d | g | Nebenstraße,Hauptstraßentunnel,Anderestraße,Anderestraße | depart,turn right,turn left,arrive | - diff --git a/features/guidance/bugs.feature b/features/guidance/bugs.feature index aa26cb19e..6861295f2 100644 --- a/features/guidance/bugs.feature +++ b/features/guidance/bugs.feature @@ -67,3 +67,37 @@ Feature: Features related to bugs When I route I should get | waypoints | route | intersections | | a,c | Pear to Merrit,Merritt to Apricot,Merritt to Apricot | true:0;true:0 false:180;true:180 | + + + # https://github.com/Project-OSRM/osrm-backend/issues/6373 + Scenario: Segregated intersection with no second intersection turns + Given the node map + """ + a b + | | + c--d--e--f + | | + g--h--i--j + + """ + + And the ways + | nodes | oneway | lanes | turn:lanes | + | dc | yes | 4 | | + | ed | yes | 4 | | + | fe | yes | 3 | | + | gh | yes | 4 | left\|left\|through\|through;right | + | hi | yes | 2 | | + | ij | yes | 3 | | + | ie | yes | 4 | | + | eb | yes | 2 | | + | ad | yes | 4 | reverse\|right\|right\|right | + | dh | yes | | | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | dh | hi | h | no_left_turn | + + And the data has been saved to disk + When I try to run "osrm-extract {osm_file} --profile {profile_file}" + Then it should exit successfully diff --git a/features/guidance/collapse-detail.feature b/features/guidance/collapse-detail.feature index 8b98df9db..bd20da416 100644 --- a/features/guidance/collapse-detail.feature +++ b/features/guidance/collapse-detail.feature @@ -147,3 +147,32 @@ Feature: Collapse | waypoints | route | turns | | a,d | road,left,left | depart,turn left,arrive | | a,e | road,right,right | depart,turn right,arrive | + + # https://www.openstreetmap.org/#map=18/53.89755/27.54306 + Scenario: Wide turn into invalid u-turn + Given the node map + """ + g + | + | + f - - - - e + | + | + | + h - - d + | + | + | + a - - - - b - - - - c + """ + + And the ways + | nodes | highway | name | + | abc | secondary | road | + | bdfg | service | | + | hd | service | | + | fe | service | | + + When I route I should get + | waypoints | route | turns | + | c,e | road,,, | depart,turn right,turn right,arrive | diff --git a/features/guidance/collapse.feature b/features/guidance/collapse.feature index aec4f113c..e0341757e 100644 --- a/features/guidance/collapse.feature +++ b/features/guidance/collapse.feature @@ -35,20 +35,46 @@ Feature: Collapse | waypoints | route | turns | locations | | a,l | first,second,second | depart,turn right,arrive | a,b,l | | a,d | first,first | depart,arrive | a,d | - | a,j | first,second,second | depart,turn left,arrive | a,c,j | - | a,h | first,first,first | depart,continue uturn,arrive | a,c,h | + | a,j | first,second,second | depart,turn left,arrive | a,b,j | + | a,h | first,first,first | depart,continue uturn,arrive | a,b,h | | e,j | first,second,second | depart,turn right,arrive | e,f,j | | e,h | first,first | depart,arrive | e,h | - | e,l | first,second,second | depart,turn left,arrive | e,g,l | - | e,d | first,first,first | depart,continue uturn,arrive | e,g,d | + | e,l | first,second,second | depart,turn left,arrive | e,f,l | + | e,d | first,first,first | depart,continue uturn,arrive | e,f,d | | k,h | second,first,first | depart,turn right,arrive | k,g,h | | k,l | second,second | depart,arrive | k,l | - | k,d | second,first,first | depart,turn left,arrive | k,b,d | - | k,j | second,second,second | depart,continue uturn,arrive | k,b,j | + | k,d | second,first,first | depart,turn left,arrive | k,g,d | + | k,j | second,second,second | depart,continue uturn,arrive | k,g,j | | i,d | second,first,first | depart,turn right,arrive | i,c,d | | i,j | second,second | depart,arrive | i,j | - | i,h | second,first,first | depart,turn left,arrive | i,f,h | - | i,l | second,second,second | depart,continue uturn,arrive | i,f,l | + | i,h | second,first,first | depart,turn left,arrive | i,c,h | + | i,l | second,second,second | depart,continue uturn,arrive | i,c,l | + + Scenario: Segregated Intersection, Cross Belonging to Single Street + Given the node map + """ + g + + c b a + d e f + + h i + """ + + And the ways + | nodes | highway | name | oneway | + | ab | primary | first | yes | + | bc | primary | first | yes | + | de | primary | first | yes | + | ef | primary | first | yes | + | gb | primary | second | no | + | be | primary | second | no | + | eh | primary | second | yes | + | ei | primary | third | yes | + + When I route I should get + | waypoints | route | turns | locations | + | a,i | first,third,third | depart,turn sharp left,arrive | a,b,i | Scenario: Segregated Intersection, Cross Belonging to Correct Street Given the node map @@ -80,20 +106,20 @@ Feature: Collapse | waypoints | route | turns | locations | | a,l | first,second,second | depart,turn right,arrive | a,b,l | | a,d | first,first | depart,arrive | a,d | - | a,j | first,second,second | depart,turn left,arrive | a,c,j | - | a,h | first,first,first | depart,continue uturn,arrive | a,c,h | + | a,j | first,second,second | depart,turn left,arrive | a,b,j | + | a,h | first,first,first | depart,continue uturn,arrive | a,b,h | | e,j | first,second,second | depart,turn right,arrive | e,f,j | | e,h | first,first | depart,arrive | e,h | - | e,l | first,second,second | depart,turn left,arrive | e,g,l | - | e,d | first,first,first | depart,continue uturn,arrive | e,g,d | + | e,l | first,second,second | depart,turn left,arrive | e,f,l | + | e,d | first,first,first | depart,continue uturn,arrive | e,f,d | | k,h | second,first,first | depart,turn right,arrive | k,g,h | | k,l | second,second | depart,arrive | k,l | - | k,d | second,first,first | depart,turn left,arrive | k,b,d | - | k,j | second,second,second | depart,continue uturn,arrive | k,b,j | + | k,d | second,first,first | depart,turn left,arrive | k,g,d | + | k,j | second,second,second | depart,continue uturn,arrive | k,g,j | | i,d | second,first,first | depart,turn right,arrive | i,c,d | | i,j | second,second | depart,arrive | i,j | - | i,h | second,first,first | depart,turn left,arrive | i,f,h | - | i,l | second,second,second | depart,continue uturn,arrive | i,f,l | + | i,h | second,first,first | depart,turn left,arrive | i,c,h | + | i,l | second,second,second | depart,continue uturn,arrive | i,c,l | Scenario: Segregated Intersection, Cross Belonging to Mixed Streets Given the node map @@ -125,20 +151,20 @@ Feature: Collapse | waypoints | route | turns | locations | | a,l | first,second,second | depart,turn right,arrive | a,b,l | | a,d | first,first | depart,arrive | a,d | - | a,j | first,second,second | depart,turn left,arrive | a,c,j | - | a,h | first,first,first | depart,continue uturn,arrive | a,c,h | + | a,j | first,second,second | depart,turn left,arrive | a,b,j | + | a,h | first,first,first | depart,continue uturn,arrive | a,b,h | | e,j | first,second,second | depart,turn right,arrive | e,f,j | | e,h | first,first | depart,arrive | e,h | - | e,l | first,second,second | depart,turn left,arrive | e,g,l | - | e,d | first,first,first | depart,continue uturn,arrive | e,g,d | + | e,l | first,second,second | depart,turn left,arrive | e,f,l | + | e,d | first,first,first | depart,continue uturn,arrive | e,f,d | | k,h | second,first,first | depart,turn right,arrive | k,g,h | | k,l | second,second | depart,arrive | k,l | - | k,d | second,first,first | depart,turn left,arrive | k,b,d | - | k,j | second,second,second | depart,continue uturn,arrive | k,b,j | + | k,d | second,first,first | depart,turn left,arrive | k,g,d | + | k,j | second,second,second | depart,continue uturn,arrive | k,g,j | | i,d | second,first,first | depart,turn right,arrive | i,c,d | | i,j | second,second | depart,arrive | i,j | - | i,h | second,first,first | depart,turn left,arrive | i,f,h | - | i,l | second,second,second | depart,continue uturn,arrive | i,f,l | + | i,h | second,first,first | depart,turn left,arrive | i,c,h | + | i,l | second,second,second | depart,continue uturn,arrive | i,c,l | Scenario: Partly Segregated Intersection, Two Segregated Roads Given the node map @@ -183,11 +209,11 @@ Feature: Collapse | d,c | first,first,first | depart,continue uturn,arrive | d,e,c | | g,c | second,first,first | depart,turn right,arrive | g,b,c | | g,j | second,second | depart,arrive | g,j | - | g,f | second,first,first | depart,turn left,arrive | g,e,f | + | g,f | second,first,first | depart,turn left,arrive | g,b,f | | g,h | second,second,second | depart,continue uturn,arrive | g,b,h | | i,f | second,first,first | depart,turn right,arrive | i,e,f | | i,h | second,second | depart,arrive | i,h | - | i,c | second,first,first | depart,turn left,arrive | i,b,c | + | i,c | second,first,first | depart,turn left,arrive | i,e,c | | i,j | second,second,second | depart,continue uturn,arrive | i,e,j | Scenario: Partly Segregated Intersection, Two Segregated Roads, Intersection belongs to Second @@ -237,11 +263,11 @@ Feature: Collapse | d,c | first,first,first | depart,continue uturn,arrive | d,e,c | | g,c | second,first,first | depart,turn right,arrive | g,b,c | | g,j | second,second | depart,arrive | g,j | - | g,f | second,first,first | depart,turn left,arrive | g,e,f | + | g,f | second,first,first | depart,turn left,arrive | g,b,f | | g,h | second,second,second | depart,continue uturn,arrive | g,b,h | | i,f | second,first,first | depart,turn right,arrive | i,e,f | | i,h | second,second | depart,arrive | i,h | - | i,c | second,first,first | depart,turn left,arrive | i,b,c | + | i,c | second,first,first | depart,turn left,arrive | i,e,c | | i,j | second,second,second | depart,continue uturn,arrive | i,e,j | Scenario: Segregated Intersection, Cross Belonging to Mixed Streets - Slight Angles @@ -274,20 +300,20 @@ Feature: Collapse | waypoints | route | turns | locations | | a,l | first,second,second | depart,turn right,arrive | a,b,l | | a,d | first,first | depart,arrive | a,d | - | a,j | first,second,second | depart,turn left,arrive | a,c,j | - | a,h | first,first,first | depart,continue uturn,arrive | a,c,h | + | a,j | first,second,second | depart,turn left,arrive | a,b,j | + | a,h | first,first,first | depart,continue uturn,arrive | a,b,h | | e,j | first,second,second | depart,turn right,arrive | e,f,j | | e,h | first,first | depart,arrive | e,h | - | e,l | first,second,second | depart,turn left,arrive | e,g,l | - | e,d | first,first,first | depart,continue uturn,arrive | e,g,d | + | e,l | first,second,second | depart,turn left,arrive | e,f,l | + | e,d | first,first,first | depart,continue uturn,arrive | e,f,d | | k,h | second,first,first | depart,turn right,arrive | k,g,h | | k,l | second,second | depart,arrive | k,l | - | k,d | second,first,first | depart,turn left,arrive | k,b,d | - | k,j | second,second,second | depart,continue uturn,arrive | k,b,j | + | k,d | second,first,first | depart,turn left,arrive | k,g,d | + | k,j | second,second,second | depart,continue uturn,arrive | k,g,j | | i,d | second,first,first | depart,turn right,arrive | i,c,d | | i,j | second,second | depart,arrive | i,j | - | i,h | second,first,first | depart,turn left,arrive | i,f,h | - | i,l | second,second,second | depart,continue uturn,arrive | i,f,l | + | i,h | second,first,first | depart,turn left,arrive | i,c,h | + | i,l | second,second,second | depart,continue uturn,arrive | i,c,l | Scenario: Segregated Intersection, Cross Belonging to Mixed Streets - Slight Angles (2) Given the node map @@ -319,28 +345,29 @@ Feature: Collapse | waypoints | route | turns | locations | | a,l | first,second,second | depart,turn right,arrive | a,b,l | | a,d | first,first | depart,arrive | a,d | - | a,j | first,second,second | depart,turn left,arrive | a,c,j | - | a,h | first,first,first | depart,continue uturn,arrive | a,c,h | + | a,j | first,second,second | depart,turn left,arrive | a,b,j | + | a,h | first,first,first | depart,continue uturn,arrive | a,b,h | | e,j | first,second,second | depart,turn right,arrive | e,f,j | | e,h | first,first | depart,arrive | e,h | - | e,l | first,second,second | depart,turn left,arrive | e,g,l | - | e,d | first,first,first | depart,continue uturn,arrive | e,g,d | + | e,l | first,second,second | depart,turn left,arrive | e,f,l | + | e,d | first,first,first | depart,continue uturn,arrive | e,f,d | | k,h | second,first,first | depart,turn right,arrive | k,g,h | | k,l | second,second | depart,arrive | k,l | - | k,d | second,first,first | depart,turn left,arrive | k,b,d | - | k,j | second,second,second | depart,continue uturn,arrive | k,b,j | + | k,d | second,first,first | depart,turn left,arrive | k,g,d | + | k,j | second,second,second | depart,continue uturn,arrive | k,g,j | | i,d | second,first,first | depart,turn right,arrive | i,c,d | | i,j | second,second | depart,arrive | i,j | - | i,h | second,first,first | depart,turn left,arrive | i,f,h | - | i,l | second,second,second | depart,continue uturn,arrive | i,f,l | + | i,h | second,first,first | depart,turn left,arrive | i,c,h | + | i,l | second,second,second | depart,continue uturn,arrive | i,c,l | Scenario: Entering a segregated road Given the node map """ - a f g - | | . ' - b-e ' - / / + h + a f | g + | | i ' + b-e ' | + / / j / / c d """ @@ -350,7 +377,8 @@ Feature: Collapse | abc | primary | first | yes | | def | primary | first | yes | | be | primary | first | no | - | ge | primary | second | no | + | gie | primary | second | no | + | hij | primary | maple | no | When I route I should get | waypoints | route | turns | locations | @@ -359,7 +387,7 @@ Feature: Collapse | a,g | first,second,second | depart,turn left,arrive | a,b,g | | d,g | first,second,second | depart,turn right,arrive | d,e,g | | g,f | second,first,first | depart,turn right,arrive | g,e,f | - | g,c | second,first,first | depart,turn left,arrive | g,e,c | + | g,c | second,first,first | depart,end of road left,arrive | g,e,c | Scenario: Do not collapse turning roads Given the node map @@ -577,7 +605,7 @@ Feature: Collapse When I route I should get | waypoints | route | turns | locations | - | i,h | in,road,road | depart,turn left,arrive | i,f,h | + | i,h | in,road,road | depart,turn slight left,arrive | i,c,h | | a,d | road,road | depart,arrive | a,d | | a,j | road,out,out | depart,turn slight right,arrive | a,b,j | @@ -984,7 +1012,7 @@ Feature: Collapse | f,j | hohe,hohe | depart,arrive | f,j | | a,t | hohe,a100,a100 | depart,on ramp right,arrive | a,b,t | | f,e | | | | - | q,j | a100,hohe,hohe | depart,turn right,arrive | q,p,j | + | q,j | a100,hohe,hohe | depart,turn right,arrive | q,i,j | | q,e | a100,hohebruecke,hohe | depart,turn left,arrive | q,p,e | Scenario: Forking before a turn (forky) @@ -1093,3 +1121,26 @@ Feature: Collapse When I route I should get | waypoints | bearing_before | bearing_after | turns | | c,f | 0,268,90 | 270,90,0 | depart,continue uturn,arrive | + + # https://www.openstreetmap.org/#map=18/37.74844/-122.40275 + Scenario: Don't use destinations as names + Given the node map + """ + f - - - - e - - - - d + | + | + | + | + | + a - - - - b - - - - c + """ + + And the ways + | nodes | highway | name | oneway | destination:ref | + | abc | residential | road | yes | | + | def | motorway_link | | yes | US 101 | + | be | residential | cross | no | | + + When I route I should get + | waypoints | route | turns | + | a,f | road,cross,, | depart,turn left,on ramp left,arrive | diff --git a/features/guidance/continue.feature b/features/guidance/continue.feature index 249a34aad..86ac2c3fe 100644 --- a/features/guidance/continue.feature +++ b/features/guidance/continue.feature @@ -22,6 +22,40 @@ Feature: Continue Instructions | a,c | abc,abc,abc | depart,continue left,arrive | | a,d | abc,bd,bd | depart,turn straight,arrive | + Scenario: Road turning left, Suffix changes + Given the node map + """ + c + a - b-d + """ + + And the ways + | nodes | highway | name | + | ab | primary | North Capitol Northeast | + | bc | primary | North Capitol Northwest | + | bd | primary | some random street | + + When I route I should get + | waypoints | route | turns | + | a,c | North Capitol Northeast,North Capitol Northwest,North Capitol Northwest | depart,continue left,arrive | + + Scenario: Road turning left, Suffix changes, no-spaces + Given the node map + """ + c + a - b-d + """ + + And the ways + | nodes | highway | name | + | ab | primary | North CapitolNortheast | + | bc | primary | North CapitolNorthwest | + | bd | primary | some random street | + + When I route I should get + | waypoints | route | turns | + | a,c | North CapitolNortheast,North CapitolNorthwest,North CapitolNorthwest | depart,continue left,arrive | + Scenario: Road turning left and straight Given the node map """ diff --git a/features/guidance/dedicated-turn-roads.feature b/features/guidance/dedicated-turn-roads.feature index c062c8369..055f2af88 100644 --- a/features/guidance/dedicated-turn-roads.feature +++ b/features/guidance/dedicated-turn-roads.feature @@ -687,7 +687,7 @@ Feature: Slipways and Dedicated Turn Lanes When I route I should get | waypoints | route | turns | locations | - | s,f | sabc,ae,dbef,dbef | depart,turn slight right,turn right,arrive | s,a,e,f | + | s,f | sabc,ae,dbef,dbef | depart,turn straight,turn right,arrive | s,a,e,f | @sliproads Scenario: Traffic Signal on Sliproad @@ -992,7 +992,108 @@ Feature: Slipways and Dedicated Turn Lanes | dbef | primary | dbef | | | ae | primary_link | ae | yes | - When I route I should get | waypoints | route | turns | locations | - | s,f | sabc,dbef,dbef | depart,turn right,arrive | s,a,f | \ No newline at end of file + | s,f | sabc,dbef,dbef | depart,turn right,arrive | s,a,f | + + + @sliproads + Scenario: Sliproad from link via link to primary + Given the node map + """ + d + . + s . a . b + ` . + ` . + '. + c + . + f + """ + + And the ways + | nodes | highway | name | oneway | + | sab | primary_link | sab | | + | dbcf | primary | dbcf | | + | ac | primary_link | ae | yes | + + When I route I should get + | waypoints | route | turns | locations | + | s,f | sab,dbcf,dbcf | depart,turn right,arrive | s,a,f | + + + @sliproads + Scenario: Sliproad with a single intersection in a cross-road + Given the node map + """ + d + . + s . a . b + ` . + ' c . g + .. + e + . + f + """ + + And the ways + | nodes | highway | name | oneway | + | sab | primary | sab | | + | dbcef | primary | dbcef | | + | ae | primary_link | sab | yes | + | cg | primary | cg | | + + When I route I should get + | waypoints | route | turns | locations | + | s,f | sab,dbcef,dbcef | depart,turn right,arrive | s,a,f | + + + @sliproads + Scenario: Sliproad converted from a fork + Given the node map + """ + d + . + b + s . a '. + `c + . + f + """ + + And the ways + | nodes | highway | name | ref | oneway | + | sa | tertiary | | D 60A | yes | + | ab | tertiary | ab | D 60A | yes | + | ac | tertiary | | D 60A | yes | + | dbcf | tertiary | dbcf | D 543 | yes | + + When I route I should get + | waypoints | route | turns | locations | + | s,f | ,dbcf,dbcf | depart,turn right,arrive | s,a,f | + + + @sliproads + Scenario: Sliproad to a road with a reference only + Given the node map + """ + s . a . b . d + ` . + ' . + .. + c + . + f + """ + + And the ways + | nodes | highway | name | ref | oneway | + | sabd | primary | road | | | + | bcf | primary | | K108 | | + | ac | primary_link | | | yes | + + When I route I should get + | waypoints | route | turns | locations | + | s,f | road,, | depart,turn right,arrive | s,a,f | diff --git a/features/guidance/divided-highways.feature b/features/guidance/divided-highways.feature index 6bfbca34d..2824293bc 100644 --- a/features/guidance/divided-highways.feature +++ b/features/guidance/divided-highways.feature @@ -13,19 +13,23 @@ Feature: Divided road entry d-------e-----f | | - g + i---g---j + | + | + h """ And the ways - | nodes | name | highway | oneway | - | abc | main st | residential | -1 | - | def | main st | residential | yes | - | be | main st | residential | | - | eg | side st | residential | | + | nodes | name | highway | oneway | + | abc | main st | residential | -1 | + | def | main st | residential | yes | + | be | main st | residential | | + | egh | side st | residential | | + | igj | maple st | residential | | When I route I should get | waypoints | route | turns | - | g,a | side st,main st,main st| depart,end of road left,arrive | + | h,a | side st,main st,main st| depart,end of road left,arrive | # Similar to previous one, but the joining way is tagged with the side-street name @@ -37,18 +41,22 @@ Feature: Divided road entry d-------e-----f | | - g + i---g---j + | + | + h """ And the ways - | nodes | name | highway | oneway | - | abc | main st | residential | -1 | - | def | main st | residential | yes | - | beg | side st | residential | | + | nodes | name | highway | oneway | + | abc | main st | residential | -1 | + | def | main st | residential | yes | + | begh | side st | residential | | + | igj | maple st | residential | | When I route I should get | waypoints | route | turns | - | g,a | side st,main st,main st| depart,end of road left,arrive | + | h,a | side st,main st,main st| depart,end of road left,arrive | # Center join named after crossroad @@ -100,3 +108,32 @@ Feature: Divided road entry When I route I should get | waypoints | route | turns | | g,a | side st,main st,main st| depart,turn left,arrive | + + # Verify end of road left turn across divided roads + Scenario: Join on a divided road, named after the side street + Given the node map + """ + a-----h--b-----c + | | + d-----i--e-----f + | | + | | + m---j--g---n + | | + | | + k l + """ + + And the ways + | nodes | name | highway | oneway | + | ahbc | main st | residential | -1 | + | dief | main st | residential | yes | + | begl | side st | residential | -1 | + | hijk | side st | residential | yes | + | mjgn | maple st| residential | no | + + When I route I should get + | waypoints | route | turns | + | l,a | side st,main st,main st| depart,end of road left,arrive | + + diff --git a/features/guidance/driveway.feature b/features/guidance/driveway.feature index c7e7504eb..7bc3b2605 100644 --- a/features/guidance/driveway.feature +++ b/features/guidance/driveway.feature @@ -46,3 +46,23 @@ Feature: Driveways intersections When I route I should get | waypoints | route | turns | locations | | a,d | ,second | depart,arrive | a,d | + + + Scenario: Road with a turn to service road + Given the node map + """ + /-----------------e + a---b------------------c + `-----------------d + """ + + And the ways + | nodes | highway | name | oneway | + | abc | trunk | road | yes | + | bd | service | serv | yes | + | be | service | serv | yes | + + When I route I should get + | waypoints | route | turns | locations | + | a,d | road,serv,serv | depart,turn slight right,arrive | a,b,d | + | a,e | road,serv,serv | depart,turn slight left,arrive | a,b,e | diff --git a/features/guidance/internal-intersections.feature b/features/guidance/internal-intersections.feature new file mode 100644 index 000000000..887e11c50 --- /dev/null +++ b/features/guidance/internal-intersections.feature @@ -0,0 +1,46 @@ +@guidance +Feature: Internal Intersection Model + + Background: + Given the profile "car" + Given a grid size of 10 meters + + Scenario: Dual-carriage way intersection + Given the node map + """ + a b + | | + c--d--e--f + | | + g--h--i--j + | | + k l + """ + + And the ways + | nodes | oneway | name | + | adhk | yes | Broken Land Parkway | + | lieb | yes | Broken Land Parkway | + | fed | yes | Snowden River Parkway | + | dc | yes | Patuxent Woods Drive | + | gh | yes | Patuxent Woods Drive | + | hij | yes | Snowden River Parkway | + + When I route I should get + | waypoints | route | turns | # | + | a,k | Broken Land Parkway,Broken Land Parkway | depart,arrive || + | l,b | Broken Land Parkway,Broken Land Parkway | depart,arrive || +# | g,j | Patuxent Woods Drive,Snowden River Parkway,Snowden River Parkway | depart,continue,arrive | did not work as expected - might be another issue to handle in post process? | +# | f,c | Snowden River Parkway,Patuxent Woods Drive,Patuxent Woods Drive | depart,continue,arrive | did not work as expected - might be another issue to handle in post process? | + | a,c | Broken Land Parkway,Patuxent Woods Drive,Patuxent Woods Drive | depart,turn right,arrive || + | g,k | Patuxent Woods Drive,Broken Land Parkway,Broken Land Parkway | depart,turn right,arrive || + | l,j | Broken Land Parkway,Snowden River Parkway,Snowden River Parkway | depart,turn right,arrive || + | f,b | Snowden River Parkway,Broken Land Parkway,Broken Land Parkway | depart,turn right,arrive || + | a,j | Broken Land Parkway,Snowden River Parkway,Snowden River Parkway | depart,turn left,arrive || + | g,b | Patuxent Woods Drive,Broken Land Parkway,Broken Land Parkway | depart,turn left,arrive || + | l,c | Broken Land Parkway,Patuxent Woods Drive,Patuxent Woods Drive | depart,turn left,arrive || + | f,k | Snowden River Parkway,Broken Land Parkway,Broken Land Parkway | depart,turn left,arrive || + | a,b | Broken Land Parkway,Broken Land Parkway,Broken Land Parkway | depart,continue uturn,arrive || + | g,c | Patuxent Woods Drive,Patuxent Woods Drive,Patuxent Woods Drive | depart,continue uturn,arrive || + | l,k | Broken Land Parkway,Broken Land Parkway,Broken Land Parkway | depart,continue uturn,arrive || + | f,j | Snowden River Parkway,Snowden River Parkway,Snowden River Parkway | depart,continue uturn,arrive || diff --git a/features/guidance/low-priority.feature b/features/guidance/low-priority.feature index 38dd315cc..a71007e73 100644 --- a/features/guidance/low-priority.feature +++ b/features/guidance/low-priority.feature @@ -64,9 +64,9 @@ Feature: Exceptions for routing onto low-priority roads | bc | service | | When I route I should get - | waypoints | route | turns | - | e,c | service, | depart,arrive | - | c,e | ,service,service | depart,turn straight,arrive | + | waypoints | route | turns | + | e,c | service, | depart,arrive | + | c,e | ,service | depart,arrive | Scenario: Straight onto low-priority Given the node map diff --git a/features/guidance/maneuver-tag.feature b/features/guidance/maneuver-tag.feature new file mode 100644 index 000000000..243090579 --- /dev/null +++ b/features/guidance/maneuver-tag.feature @@ -0,0 +1,329 @@ +# The route results with #original are what the result should be if the maneuver tag is removed +@routing @guidance @maneuver +Feature: Maneuver tag support + + Background: + Given the profile "car" + Given a grid size of 5 meters + + Scenario: simple override #1 + Given the node map + """ + a--b---c----d---e + | + g + | + h------i--------j + """ + And the ways + | nodes | name | oneway | + | abc | A Street | no | + | cde | B Street | no | + | cgi | C Street | no | + | hij | J Street | no | + + And the relations + | type | way:from | node:via | way:to | maneuver | direction | + | maneuver | abc | c | cgi | turn | sharp_right | + | maneuver | hij | i | cde | turn | sharp_left | + | maneuver | abc | c | cde | turn | slight_left | + | maneuver | cde | c | cgi | turn | straight | + | manoeuvre| cgi | c | abc | turn | right | + + And the relations + | type | way:from | node:via | way:to | manoeuvre | maneuver | direction | + | maneuver | cgi | c | cde | fork | turn | slight_right | + + When I route I should get + | waypoints | route | turns | + # Testing directly connected from/to + | a,j | A Street,C Street,J Street,J Street | depart,turn sharp right,turn left,arrive | + | b,g | A Street,C Street,C Street | depart,turn sharp right,arrive | + # Testing re-awakening suppressed turns + | a,e | A Street,B Street,B Street | depart,turn slight left,arrive | + | e,i | B Street,C Street,C Street | depart,turn straight,arrive | + | i,e | C Street,B Street,B Street | depart,fork slight right,arrive | + | i,a | C Street,A Street,A Street | depart,turn right,arrive | + + Scenario: single via-way + Given the node map + """" + a--b---c----d---e + | + g + | + h------i--------j + """ + + And the ways + | nodes | name | oneway | + | abc | A Street | no | + | cde | B Street | no | + | cgi | C Street | no | + | hi | J Street | no | + | ij | J Street | no | + + And the relations + | type | way:from | way:via | way:to | node:via | maneuver | direction | + | maneuver | abc | cgi | ij | c | turn | sharp_right | + + When I route I should get + | waypoints | route | turns | + | a,j | A Street,C Street,J Street,J Street | depart,turn sharp right,turn left,arrive | + + + Scenario: multiple via-way + Given the node map + """" + a--b---c----d---e + | + g-----k + | + h------i--------j + """ + + And the ways + | nodes | name | oneway | + | abc | A Street | no | + | cde | B Street | no | + | cg | C Street | no | + | gi | C Street | no | + | hi | J Street | no | + | ij | J Street | no | + | gk | G Street | no | + + And the relations + | type | way:from | way:via | way:via | way:to | node:via | maneuver | direction | + | maneuver | abc | cg | gi | ij | c | turn | sharp_right | + + When I route I should get + | waypoints | route | turns | + | a,j | A Street,C Street,J Street,J Street | depart,turn sharp right,end of road left,arrive | + + + Scenario: Use maneuver tag to announce a particular turn type + Given the node map + """ + f + * + * + * + * + * + * + * + * + * + t. .. * h + .. ....m** * + / * * + / * * * + / + / + | + | + \ + \ + o + """ + + And the ways + | nodes | name | oneway | highway | + | fm | CA-120 | no | secondary | + | mh | CA-120 | no | secondary | + | mt | Priest Rd | no | unclassified | + | mo | | no | service | + + And the relations + | type | way:from | node:via | way:to | maneuver | direction | + | maneuver | mh | m | mt | turn | left | + + When I route I should get + | waypoints | route | turns | + | h,t | CA-120,Priest Rd,Priest Rd | depart,turn left,arrive | + #original | h,t | CA-120,Priest Rd,Priest Rd | depart,turn straight,arrive | + + Scenario: Use maneuver tag to announce lane guidance + Given a grid size of 10 meters + Given the node map + """ + ad + / \ + / \ + / \ + | | + | | + | | + b-----c------e + | | + | | + | | + | | + r w + """ + + And the ways + | nodes | name | oneway | highway | + | ab | Marsh Rd | yes | secondary | + | br | Marsh Rd | yes | secondary | + | cd | Marsh Rd | yes | secondary | + | cw | Marsh Rd | yes | secondary | + | bc | service | no | service | + | ce | service | no | service | + + And the relations + | type | way:from | node:via | way:via | way:to | maneuver | + | maneuver | ab | c | bc | cd | uturn | + | maneuver | ab | b | bc | cd | suppress | + + When I route I should get + | waypoints | route | turns | + | a,d | Marsh Rd,Marsh Rd,Marsh Rd | depart,turn uturn,arrive | + #original | a,d | Marsh Rd,service,Marsh Rd,Marsh Rd | depart,turn left,turn left,arrive | + + Scenario: Use maneuver tag to suppress a turn + Given the node map + """ + c + | + | + v---y----------z + | + n---p----------k + |\ + | \ + b t + """ + + And the ways + | nodes | name | oneway | highway | + | zy | NY Ave | yes | primary | + | yv | NY Ave | yes | primary | + | np | NY Ave | yes | primary | + | pk | NY Ave | yes | primary | + | cp | 4th St | no | tertiary | + | yp | | no | motorway_link | + | pb | 4th St | no | primary | + | pt | 395 | no | primary | + + And the relations + | type | way:from | node:via | way:via | way:to | maneuver | # | + | maneuver | zy | p | yp | pt | suppress | original: depart,on ramp left,fork slight left,arrive | + + And the relations + | type | way:from | way:via | way:to | maneuver | # | + | maneuver | zy | yp | pb | suppress | invalid relation: missing node:via | + + And the relations + | type | node:via | way:via | way:to | maneuver | # | + | maneuver | p | yp | pb | suppress | invalid relation: missing way:from | + + And the relations + | type | way:from | node:via | way:via | maneuver | # | + | maneuver | zy | p | yp | suppress | invalid relation: missing way:to | + + And the relations + | type | way:from | node:via | way:via | way:to | maneuver | # | + | maneuver | zy | y, p | yp | pb | suppress | invalid relation: multiple node:via | + + When I route I should get + | waypoints | route | turns | + | z,t | NY Ave,395,395 | depart,on ramp left,arrive | + | z,b | NY Ave,,4th St,4th St | depart,on ramp left,fork slight right,arrive | + + Scenario: Gracefully handles maneuvers that are redundant for the profile + Given the node map + """ + a--b---c---d----f + | + | + e + """ + And the ways + | nodes | name | oneway | highway | + | abc | A Street | no | primary | + | ce | B Street | no | construction | + | cdf | A Street | no | primary | + + And the relations + | type | way:from | node:via | way:to | maneuver | direction | + | maneuver | abc | c | cdf | turn | slight_left | + + When I route I should get + | waypoints | route | turns | + | a,f | A Street,A Street | depart,arrive | + + Scenario: Handles uncompressed nodes in maneuver path + Given the node map + """ + a--b---c---f + | | + | | + g d---h + | + | + i-------e-------j + """ + And the ways + | nodes | name | oneway | + | abc | A Street | no | + | cf | B Street | no | + | cde | C Street | no | + | bg | D Street | no | + | dh | E Street | no | + | ei | F Street | no | + | ej | G Street | no | + + And the relations + | type | way:from | node:via | way:via | way:to | maneuver | direction | + | maneuver | abc | e | cde | ei | turn | sharp_right | + + When I route I should get + | waypoints | route | turns | + | a,i | A Street,C Street,F Street,F Street | depart,turn right,turn sharp right,arrive | + + + Scenario: Can be used with turn restrictions + Given the node map + """ + a---b---c + | + | + d + | + e---f + | + | + h------g---i + """ + And the ways + | nodes | name | oneway | + | ab | A Street | no | + | bc | B Street | no | + | bde | C Street | no | + | ef | D Street | no | + | eg | E Street | no | + | hg | F Street | no | + | gi | G Street | no | + + And the relations + | type | way:from | node:via | way:to | maneuver | direction | # | + | maneuver | ab | b | bde | turn | sharp_right | ending on a turn restriction via way | + | maneuver | bde | e | ef | turn | sharp_left | starting on a turn restriction via way | + + And the relations + | type | way:from | node:via | way:via | way:to | maneuver | direction | # | + | maneuver | cb | g | bde,eg | gi | turn | slight_left | turn restricted | + | maneuver | cb | g | bde,eg | hg | turn | slight_right | not turn restricted | + + And the relations + | type | way:from | way:via | way:to | restriction | + | restriction | ab | bde,eg | hg | no_right_turn | + | restriction | bc | bde,eg | gi | no_left_turn | + + When I route I should get + | waypoints | route | turns | + | a,e | A Street,C Street,C Street | depart,turn sharp right,arrive | + | b,f | C Street,D Street,D Street | depart,turn sharp left,arrive | + | c,h | B Street,E Street,F Street,F Street | depart,turn left,turn slight right,arrive | + | c,i | B Street,A Street,E Street,G Street,G Street | depart,turn uturn,turn right,end of road left,arrive | diff --git a/features/guidance/merge-segregated-roads.feature b/features/guidance/merge-segregated-roads.feature index 2e0600221..bb85673f7 100644 --- a/features/guidance/merge-segregated-roads.feature +++ b/features/guidance/merge-segregated-roads.feature @@ -64,7 +64,7 @@ Feature: Merge Segregated Roads When I route I should get | waypoints | route | intersections | - | a,f | road,road,road,road | true:90,false:45 true:135 false:270;true:45 true:180 false:315;true:90 false:225 true:315;true:270 | + | a,f | road,road,road | true:90,false:45 true:135 false:270;true:45 true:180 false:315,true:90 false:225 true:315;true:270 | #https://www.openstreetmap.org/#map=19/52.50003/13.33915 @negative @@ -193,7 +193,7 @@ Feature: Merge Segregated Roads When I route I should get | waypoints | route | intersections | - | a,g | road,road | true:90,false:90 true:150 false:270,true:90 false:270 true:345;true:270 | + | a,g | road,road | true:90,false:90 true:165 false:270,true:90 false:270 true:345;true:270 | Scenario: Merging parallel roads with intermediate bridges # https://www.mapillary.com/app/?lat=52.466483333333336&lng=13.431908333333332&z=17&focus=photo&pKey=LWXnKqoGqUNLnG0lofiO0Q @@ -332,10 +332,11 @@ Feature: Merge Segregated Roads | .b. c h + 1 | + | 4 | | - | | - 1 2 - | | + 2 | + | 3 d g 'e' | @@ -354,13 +355,13 @@ Feature: Merge Segregated Roads | hb | road | yes | When I route I should get - | waypoints | turns | route | intersections | + | waypoints | turns | route | intersections | | a,f | depart,arrive | road,road | true:180,false:0 true:180,false:0 true:180;true:0 | - | c,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 | | 1,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 | + | 2,f | depart,arrive | bridge,road | true:180,false:0 true:180;true:0 | | f,a | depart,arrive | road,road | true:0,true:0 false:180,true:0 false:180;true:180 | - | g,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 | - | 2,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 | + | 3,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 | + | 4,a | depart,arrive | bridge,road | true:0,true:0 false:180;true:180 | @negative Scenario: Traffic Circle @@ -384,40 +385,53 @@ Feature: Merge Segregated Roads | cd | right | no | When I route I should get - | waypoints | route | intersections | - | a,d | left,circle,circle,right,right | true:90;false:90 true:120 false:270;true:60 true:180 false:300;true:90 false:240 true:270;true:270 | - | g,d | bottom,circle,right,right | true:0;true:60 false:180 false:300;true:90 false:240 true:270;true:270 | + | waypoints | route | intersections | + | a,d | left,circle,right,right | true:90,false:90 true:120 false:270;true:60 true:180 false:300;true:90 false:240 true:270;true:270 | + | g,d | bottom,circle,right,right | true:0;true:60 false:180 false:300;true:90 false:240 true:270;true:270 | Scenario: Middle Island Given the node map """ a | - b + b-----z + / \ c h | | | | | | | | + | | + | | + | | + | | + | | d g + \ / e | f """ And the ways - | nodes | name | oneway | - | ab | road | no | - | ef | road | no | - | bcde | road | yes | - | eghb | road | yes | + | nodes | name | oneway | + | ab | road | no | + | ef | road | no | + | bcde | road | yes | + | eghb | road | yes | + | bz | cross | no | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | bz | bcde | b | no_left_turn | When I route I should get - | waypoints | turns | route | - | a,f | depart,arrive | road,road | - | c,f | depart,arrive | road,road | - | f,a | depart,arrive | road,road | - | g,a | depart,arrive | road,road | + | waypoints | turns | route | + | a,f | depart,arrive | road,road | + | c,f | depart,arrive | road,road | + | f,a | depart,arrive | road,road | + | g,a | depart,arrive | road,road | + | z,a | depart,turn right,arrive | cross,road,road | Scenario: Traffic Island Given the node map @@ -518,8 +532,183 @@ Feature: Merge Segregated Roads # the goal here should be not to mention the intersection in the middle at all and also suppress the segregated parts When I route I should get - | waypoints | route | intersections | + | waypoints | route | intersections | | a,l | horiz,vert,vert | true:90;false:0 true:60 true:90 true:180 false:270,true:60 false:120 false:240 false:300,true:0 false:90 false:180 false:240 true:270;true:180 | - | a,d | horiz,horiz | true:90,false:0 true:60 true:90 true:180 false:270,false:0 true:90 false:180 false:270 true:300;true:270 | + | a,d | horiz,horiz | true:90,false:0 true:60 true:90 true:180 false:270,false:0 true:90 false:180 false:270 true:300;true:270 | | j,h | vert,horiz,horiz | true:0;true:0 true:90 false:180 false:270 true:300,false:60 false:120 false:240 true:300,false:0 false:90 false:120 true:180 true:270;true:90 | - | j,l | vert,vert | true:0,true:0 true:90 false:180 false:270 true:300,true:0 false:90 false:180 true:240 false:270;true:180 | + | j,l | vert,vert | true:0,true:0 true:90 false:180 false:270 true:300,true:0 false:90 false:180 true:240 false:270;true:180 | + + + Scenario: Square Area - Don't merge almost circular roads + Given a grid size of 2 meters + Given the node map + """ + i + b ` + ` ` p . + a ` g` ` \ f + \ / o / + \ / \ / + h - - c n / + \ \/ + k e + \ / + l / + \ / + m . d + / + j + """ + + And the ways + | nodes | name | oneway | + | ac | Halenseestraße | yes | + | gb | Halenseestraße | yes | + | cklmdenopgc | Rathenauplatz | yes | + | ig | Kurfürstendamm | yes | + | ef | Kurfürstendamm | yes | + | ch | Hubertusallee | yes | + | jd | Hubertusallee | yes | + + When I route I should get + | waypoints | route | turns | + | i,h | Kurfürstendamm,Rathenauplatz,Hubertusallee,Hubertusallee | depart,turn right,turn right,arrive | + + # https://www.openstreetmap.org/#map=19/52.46339/13.40272 + Scenario: Do not merge links between segregated roads + Given the node map + """ + f + `````````` .............. + ` ` ` ` e - - - - - - - d + a 1 + ```````````.............. | + `````````` b - - - - - - - c + | + | + | + | + g + """ + + And the ways + | nodes | name | oneway | + | ab | germ | yes | + | bc | ober | yes | + | de | ober | yes | + | ef | germ | yes | + | eb | germ | no | + | gb | germ | no | + + When I route I should get + | waypoints | route | turns | + | a,c | germ,ober | depart,arrive | + | a,g | germ,germ,germ | depart,continue right,arrive | + | a,1 | germ,germ,germ | depart,continue left,arrive | + | d,g | ober,germ,germ | depart,turn left,arrive | + + # https://www.openstreetmap.org/#map=19/51.32888/6.57059 + Scenario: Places in presence of oneways + Given the node map + """ + i l + | | + | | + g - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - f + | | + | | + a - - - b - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - c - - - d + | | + | | + j k + """ + + And the ways + | nodes | name | oneway | + | ab | schwert | yes | + | cd | schwert | yes | + | ig | luise | yes | + | bj | luise | yes | + | kc | marianne | yes | + | fl | marianne | yes | + | bc | albrecht | no | + | fg | albrecht | no | + | gb | albrecht | yes | + | cf | albrecht | yes | + + When I route I should get + | waypoints | route | turns | + | a,l | schwert,albrecht,marianne,marianne | depart,new name straight,turn left,arrive | + | a,j | schwert,luise,luise | depart,turn right,arrive | + | a,1 | schwert,albrecht,albrecht,albrecht | depart,new name straight,continue uturn,arrive | + | k,l | marianne,marianne | depart,arrive | + | k,j | marianne,albrecht,luise,luise | depart,turn left,turn left,arrive | + | k,d | marianne,schwert,schwert | depart,turn right,arrive | + | i,j | luise,luise | depart,arrive | + | i,d | luise,albrecht,schwert | depart,turn left,arrive | + | i,l | luise,albrecht,marianne,marianne | depart,turn left,turn left,arrive | + + # https://www.openstreetmap.org/#map=19/52.46339/13.40272 + Scenario: Do not merge links between segregated roads + Given the node map + """ + d + f............... | + `````````` .............. | + a............... ` ` ` ` e + ``````````.............. 1 + `````````` b + - - - - - - - c + """ + + And the ways + | nodes | name | oneway | + | ab | otto | yes | + | bc | otto | no | + | de | neu | no | + | ef | otto | yes | + | eb | otto | no | + + When I route I should get + | waypoints | route | turns | # | + | a,c | otto,otto | depart,arrive | | + | a,f | otto,otto,otto | depart,continue uturn,arrive | | + | a,1 | otto,otto,otto | depart,continue left,arrive | | + | a,d | otto,neu,neu | depart,turn left,arrive | | + | c,1 | otto,otto | depart,arrive | | + | c,f | otto,otto,otto | depart,continue left,arrive | Ideally, this would be depart,arrive, but the obvious discovery making the turn onto `1` from `c` obvious interferes here | + + # https://www.openstreetmap.org/#map=18/50.94608/7.02030 + Scenario: Do not merge oneway places + Given the node map + """ + j + | + | + g - f - - - - - - - e + | | + | | + | d + | \ + | .c. + a - - - - - - b` ` + | ` + | ` h + | + | + i + """ + + And the ways + | nodes | name | oneway | + | efabc | kobe | yes | + | edc | kobe | no | + | fg | arn | no | + | ia | kobu | yes | + | hc | wei | no | + | ej | wei | no | + + When I route I should get + | waypoints | route | turns | + | j,h | wei,wei | depart,arrive | + | a,d | kobe,kobe,kobe | depart,continue left,arrive | diff --git a/features/guidance/merge.feature b/features/guidance/merge.feature index d34170a5f..1533810cb 100644 --- a/features/guidance/merge.feature +++ b/features/guidance/merge.feature @@ -126,3 +126,24 @@ Feature: Merging When I route I should get | waypoints | route | turns | | d,c | ,A100,A100 | depart,merge slight right,arrive | + + + # https://www.openstreetmap.org/way/254299122 + @merge + Scenario: Merge onto a motorway with junction references + Given the node map + """ + a b c d + e f + """ + + And the ways + | nodes | name | junction:ref | highway | oneway | + | abc | A100 | | motorway | yes | + | cd | A100 | 1A | motorway | yes | + | eb | | | motorway_link | yes | + | cf | | 1B | motorway_link | yes | + + When I route I should get + | waypoints | route | turns | + | e,d | ,A100,A100 | depart,merge slight left,arrive | diff --git a/features/guidance/motorway.feature b/features/guidance/motorway.feature index d10cd96af..dc657f50a 100644 --- a/features/guidance/motorway.feature +++ b/features/guidance/motorway.feature @@ -81,7 +81,7 @@ Feature: Motorway Guidance """ ,g,e ,f,d - a-b-c + a-b-c """ And the ways @@ -201,7 +201,7 @@ Feature: Motorway Guidance | a,e | abcde,abcde | depart,arrive | | f,e | fgc,abcde,abcde | depart,merge slight left,arrive | | a,i | abcde,chi,chi | depart,off ramp slight right,arrive | - | f,i | fgc,chi,chi | depart,off ramp right,arrive | + | f,i | fgc,chi,chi | depart,off ramp slight right,arrive | Scenario: On And Off Ramp Left Given the node map @@ -221,7 +221,7 @@ Feature: Motorway Guidance | a,e | abcde,abcde | depart,arrive | | f,e | fgc,abcde,abcde | depart,merge slight right,arrive | | a,i | abcde,chi,chi | depart,off ramp slight left,arrive | - | f,i | fgc,chi,chi | depart,off ramp left,arrive | + | f,i | fgc,chi,chi | depart,off ramp slight left,arrive | Scenario: Merging Motorways Given the node map @@ -281,3 +281,67 @@ Feature: Motorway Guidance | waypoints | route | turns | | a,d | , | depart,arrive | | b,d | , | depart,arrive | + + + Scenario: Ramp Exit with Lower Priority + Given the node map + """ + a-b-c-d-e + `--f-g + """ + + And the ways + | nodes | highway | oneway | + | abcde | trunk | | + | bfg | primary_link | yes | + + When I route I should get + | waypoints | route | turns | + | a,e | abcde,abcde | depart,arrive | + | a,g | abcde,bfg,bfg | depart,off ramp slight right,arrive | + + + # https://www.openstreetmap.org/node/67366428#map=18/33.64613/-84.44425 + Scenario: Ramp Bifurcations should not be suppressed + Given the node map + """ + /-----------c /-----------e + a---b------------------d------------f + """ + + And the ways + | nodes | highway | name | destination | + | ab | motorway | | | + | bc | motorway_link | | City 17 | + | bd | motorway_link | | | + | de | motorway_link | | Domestic Terminal;Camp Creek Parkway;Riverdale Road | + | df | motorway_link | | Montgomery | + + + When I route I should get + | waypoints | route | turns | + | a,c | ,, | depart,fork slight left,arrive | + | a,e | ,,, | depart,fork slight right,fork slight left,arrive | + | a,f | ,,, | depart,fork slight right,fork slight right,arrive | + + + # https://www.openstreetmap.org/#map=19/53.46186/-2.24509 + Scenario: Highway Fork with a Link + Given the node map + """ + /-----------d + a-b-c------------e + \-----------f + """ + + And the ways + | nodes | highway | + | abce | motorway | + | cf | motorway | + | cd | motorway_link | + + When I route I should get + | waypoints | route | turns | + | a,d | abce,cd,cd | depart,off ramp slight left,arrive | + | a,e | abce,abce | depart,arrive | + | a,f | abce,cf,cf | depart,turn slight right,arrive | diff --git a/features/guidance/new-name.feature b/features/guidance/new-name.feature index 65aa38690..e5307fa0c 100644 --- a/features/guidance/new-name.feature +++ b/features/guidance/new-name.feature @@ -274,8 +274,8 @@ Feature: New-Name Instructions | bc | Central Expressway | US 75 | motorway | When I route I should get - | waypoints | route | turns | - | a,c | North Central Expressway,Central Expressway,Central Expressway | depart,new name straight,arrive | + | waypoints | route | turns | + | a,c | North Central Expressway,Central Expressway | depart,arrive | Scenario: Prefix Change Given the node map @@ -289,8 +289,8 @@ Feature: New-Name Instructions | cb | Central Expressway | US 75 | motorway | When I route I should get - | waypoints | route | turns | - | c,a | Central Expressway,North Central Expressway,North Central Expressway | depart,new name straight,arrive | + | waypoints | route | turns | + | c,a | Central Expressway,North Central Expressway | depart,arrive | Scenario: No Name, Same Reference Given the node map @@ -382,6 +382,21 @@ Feature: New-Name Instructions | waypoints | route | turns | | a,c | , | depart,arrive | + Scenario: No Name, Reference changed + Given the node map + """ + a ----- b ----- c + """ + + And the ways + | nodes | name | ref | highway | + | ab | | US 322 | motorway | + | bc | | US 422 | motorway | + + When I route I should get + | waypoints | route | turns | + | a,c | ,, | depart,new name straight,arrive | + Scenario: Spaces in refs for containment check, #3086 Given the node map """ diff --git a/features/guidance/obvious-turn-discovery.feature b/features/guidance/obvious-turn-discovery.feature new file mode 100644 index 000000000..0ad8a0845 --- /dev/null +++ b/features/guidance/obvious-turn-discovery.feature @@ -0,0 +1,1241 @@ +@routing @guidance @obvious +Feature: Simple Turns + + Background: + Given the profile "car" + Given a grid size of 10 meters + + # https://www.openstreetmap.org/#map=19/52.51802/13.31337 + Scenario: Crossing a square + Given the node map + """ + d + | + e - - - - - - - c - g + | | + | | + | | + | | + f - - - - - - - b + | + a + """ + + And the ways + | nodes | highway | name | oneway | + | ab | residential | losch | no | + | cd | residential | ron | no | + | cefb | residential | alt | yes | + | bc | residential | alt | no | + | gc | residential | guer | no | + + When I route I should get + | from | to | route | turns | + | a | d | losch,ron | depart,arrive | + + + # https://www.openstreetmap.org/#map=18/52.51355/13.21988 + Scenario: Turning tertiary next to residential + Given the node map + """ + a - - - b - - - - c + | + d + ` _ + `-_ + e + """ + + And the ways + | nodes | highway | name | + | abde | tertiary | havel | + | bc | residential | anger | + + When I route I should get + | from | to | route | turns | + | a | c | havel,anger | depart,arrive | + | a | e | havel,havel,havel | depart,continue right,arrive | + + + #https://www.openstreetmap.org/#map=19/52.50996/13.23183 + Scenario: Tertiary turning at unclassified + Given the node map + """ + a - - - b - - - c + | + | + d + """ + + And the ways + | nodes | highway | + | ab | tertiary | + | bd | tertiary | + | bc | unclassified | + + When I route I should get + | from | to | route | turns | + | a | c | ab,bc | depart,arrive | + | a | d | ab,bd,bd | depart,turn right,arrive | + + + #https://www.openstreetmap.org/#map=19/52.50602/13.25468 + # this scenario detects obvious correctly, but requires changes in collapsing roads + Scenario: Small offset due to large Intersection + Given the node map + """ + a - - - - - b - - - - - - c + | + d + ` ` + ` ` + f e + """ + + And the ways + | nodes | highway | + | abc | residential | + | bde | residential | + | df | residential | + + When I route I should get + | from | to | route | turns | + | a | e | abc,bde,bde,bde | depart,turn right,continue left,arrive | + | a | f | abc,bde,df,df | depart,turn right,turn right,arrive | + + # https://www.openstreetmap.org/#map=19/52.49709/13.26620 + # https://www.openstreetmap.org/#map=19/52.49458/13.26273 + # scenario requires handling in post-processing + @todo + Scenario: Offsets in road + Given a grid size of 3 meters + Given the node map + """ + i + | + | + | + a - - - - - - - b e - - - - - - - - - f + `c - - - - - - - d` + | | + | | + | | + g h + """ + + And the ways + | nodes | highway | name | + | abcdef | residential | Zikade | + | gc | residential | Lärche | + | hd | residential | Kiefer | + | ei | residential | Kiefer | + + When I route I should get + | from | to | route | turns | locations | + | a | f | Zikade,Zikade | depart,arrive | a,f | + | f | a | Zikade,Zikade | depart,arrive | f,a | + | a | g | Zikade,Lärche,Lärche | depart,turn right,arrive | a,c,g | + | h | i | Kiefer,Kiefer | depart,arrive | h,i | + | i | h | Kiefer,Kiefer | depart,arrive | i,h | + | h | f | Kiefer,Zikade,Zikade | depart,turn right,arrive | h,d,f | + + + # https://www.openstreetmap.org/#map=20/52.49408/13.27375 + Scenario: Straight on unnamed service + Given the node map + """ + a - - - - b - - - - c + ` . + d + """ + + And the ways + | nodes | highway | name | + | abc | service | | + | bd | service | | + + When I route I should get + | from | to | route | turns | locations | + | a | c | , | depart,arrive | a,c | + | a | d | ,, | depart,turn slight right,arrive | a,b,d | + + + # https://www.openstreetmap.org/#map=19/52.49198/13.28069 + Scenario: Curved roads at turn + Given the node map + """ + ............g + .f + e``` + / + a - - - - b + c + ` + ` + ` + d + """ + + And the ways + | nodes | highway | name | oneway | + | abcd | residential | herbert | yes | + | befg | residential | casper | yes | + + When I route I should get + | from | to | route | turns | + | a | d | herbert,herbert,herbert | depart,continue right,arrive | + | a | g | herbert,casper,casper | depart,turn left,arrive | + + # https://www.openstreetmap.org/#map=19/52.49189/13.28431 + Scenario: Turning residential + Given the node map + """ + d + ` + a - - - b + \ + \ + c + """ + + And the ways + | nodes | highway | name | oneway | + | abc | residential | bismark | yes | + | bd | residential | caspar | yes | + + When I route I should get + | from | to | route | turns | + | a | c | bismark,bismark,bismark | depart,continue right,arrive | + | a | d | bismark,caspar,caspar | depart,turn left,arrive | + + # https://www.openstreetmap.org/#map=19/52.48681/13.28547 + Scenario: Slight Loss in Category with turning road + Given the node map + """ + g + / + f + e ..c - - - - d + a - - - - b````` + """ + + And the ways + | nodes | highway | name | + | ab | tertiary | warm | + | bcd | residential | warm | + | befg | tertiary | paul | + + When I route I should get + | from | to | route | turns | + | a | d | warm,warm | depart,arrive | + | a | g | warm,paul,paul | depart,turn slight left,arrive | + + # https://www.openstreetmap.org/#map=19/52.48820/13.29947 + Scenario: Driveway within curved road + Given the node map + """ + f--e + \ + ` + g d + \ | + \| + c + w + ./ + .b + a-` + """ + + And the ways + | nodes | highway | name | oneway | + | abc | residential | charlot | no | + | cdef | residential | fried | yes | + | gc | service | | | + + When I route I should get + | from | to | route | turns | + | a | f | charlot,fried | depart,arrive | + | a | g | charlot,, | depart,turn left,arrive | + + # https://www.openstreetmap.org/#map=20/52.46815/13.33984 + Scenario: Curve onto end of the road + Given the node map + """ + d - - - - e - f-_ + ``g + h + a - - - - - - b - - _ _ _ + ` ` ` c + """ + + And the ways + | nodes | highway | name | + | ab | residential | menz | + | defghbc | residential | rem | + + When I route I should get + | from | to | route | turns | + | a | c | menz,rem | depart,arrive | + | d | c | rem,rem | depart,arrive | + | c | d | rem,rem,rem | depart,continue right,arrive | + | c | a | rem,menz | depart,arrive | + + # https://www.openstreetmap.org/#map=19/37.58151/-122.34863 + Scenario: Straight towards oneway street, Service Category, Unnamed + Given the node map + """ + a - - b - - c + | + d + """ + + And the ways + | nodes | highway | name | oneway | + | ab | service | | | + | cb | service | | yes | + | bd | service | | | + + When I route I should get + | from | to | route | turns | + | a | d | ,, | depart,turn right,arrive | + + + # https://www.openstreetmap.org/#map=19/37.61256/-122.40371 + Scenario: Turning Road with Offset at Segregated Intersection + Given the node map + """ + i h + | | + | . f - - g + a _ | ` | + b - c - - d - - e + | | + | | + j k + """ + + And the ways + | nodes | highway | name | oneway | + | abcd | residential | park | no | + | cfg | residential | diego | no | + | de | service | | yes | + | kdfh | primary | camino | yes | + | icj | primary | camino | yes | + + When I route I should get + | from | to | route | turns | + | a | g | park,diego,diego | depart,turn slight left,arrive | + | a | h | park,diego,camino,camino | depart,turn slight left,turn left,arrive | + | a | j | park,camino,camino | depart,turn right,arrive | + + + # https://www.openstreetmap.org/#map=19/37.76407/-122.49642 + Scenario: Road splitting of straight turn + Given the node map + """ + d - - - - e - - - - -.f - - - - g + .```````` + a - - - - b - - - - - c + """ + + And the ways + | nodes | highway | name | oneway | + | ab | secondary | 37 | yes | + | bc | residential | 37 | yes | + | bf | secondary_link | Sunset | yes | + | defg | secondary | Sunset | yes | + + When I route I should get + | from | to | route | turns | + | a | c | 37,37 | depart,arrive | + | a | g | 37,Sunset,Sunset | depart,turn slight left,arrive | + + + # https://www.openstreetmap.org/#map=19/37.77072/-122.41727 + # requires changes in post-processing + @todo + Scenario: Splitting road at traffic island before a turn + Given the node map + """ + _ _ e + .c - - - - - - - - - d - ` + a - - b ` + `f g` ` + h ` + | ` + i ` + .`.` + j. + . + . + . + k + """ + + And the ways + | nodes | highway | name | oneway | + | ab | primary | howard | no | + | dcb | primary | howard | yes | + | bfghij | primary | howard | yes | + | edjk | primary | ness | yes | + + + When I route I should get + | from | to | route | turns | # | + | a | k | howard,ness,ness | depart,turn left,arrive | | + | e | k | ness,ness | depart,continue slight left,arrive | #if modelled better, a depart/arrive would be more desirable | + | e | a | ness,howard,howard | depart,turn slight right,arrive | | + + # https://www.openstreetmap.org/#map=19/37.63171/-122.46205 + # requires changes in post-processing + @todo + Scenario: Weird combination of turning roads + Given the node map + """ + a + | + b + |` + | e + | `f + | ` g _ + | j-- - - - h - - i + k + | l - - - - m - - n + | q + | p + | o + | + | + c + | + d + """ + + And the ways + | nodes | highway | name | oneway | + | abk | tertiary_link | loop | no | + | kcd | residential | loop | no | + | copqm | tertiary_link | | yes | + | klmn | tertiary_link | drive | yes | + | ih | tertiary_link | drive | yes | + | hjk | residential | drive | yes | + | hgfeb | tertiary_link | | yes | + + When I route I should get + | from | to | turns | route | + | i | a | depart,turn right,arrive | drive,loop,loop | + | i | d | depart,turn left,arrive | drive,loop,loop | + | a | n | depart,turn left,arrive | loop,drive,drive | + | d | n | depart,turn right,arrive | loop,drive,drive | + + # https://www.openstreetmap.org/#map=19/37.26591/-121.84474 + Scenario: Road splitting (unmerged) + Given the node map + """ + . g - - - h + d - - - - c - - e - - f ` + . ` ` + a - - - - b ` + ` + ` + ` + ` + ` + i + """ + + And the ways + | nodes | highway | name | oneway | + | ei | service | | | + | abe | primary | lane | yes | + | ecd | primary | lane | yes | + | hgfe | primary | lane | no | + + When I route I should get + | from | to | route | turns | + | a | h | lane,lane | depart,arrive | + | a | i | lane,, | depart,turn sharp right,arrive | + | h | d | lane,lane | depart,arrive | + | h | i | lane,, | depart,turn left,arrive | + + + # https://www.openstreetmap.org/#map=19/37.85108/-122.27078 + Scenario: Turning Road category + Given the node map + """ + e d + | | + | | + f c i + | | ` + | j` + | ` | + |k | l + | |.` + g b + | | + | | + | | + h a + """ + + And the ways + | nodes | highway | name | oneway | + | abl | primary | adeline | yes | + | bjcd | tertiary | martin | yes | + | efg | tertiary | martin | yes | + | ijkgh | primary | adeline | yes | + + When I route I should get + | from | to | route | turns | + | e | h | martin,adeline,adeline | depart,turn straight,arrive | + | a | d | adeline,martin,martin | depart,turn slight left,arrive | + | a | l | adeline,adeline,adeline | depart,continue slight right,arrive | + | i | h | adeline,adeline | depart,arrive | + + # https://www.openstreetmap.org/#map=19/37.76471/-122.49639 + Scenario: Turning road + Given the node map + """ + f - - - - - - - e - - - - d + g + h + a - - - b - - - - - - - - c + | + | + i + """ + + And the ways + | nodes | highway | name | oneway | + | abd | primary | lincoln | yes | + | def | primary | lincoln | yes | + | eghbi | secondary | 37 | yes | + + When I route I should get + | from | to | route | turns | + | d | i | lincoln,37,37 | depart,turn slight left,arrive | + | d | f | lincoln,lincoln | depart,arrive | + + # https://www.openstreetmap.org/#map=19/37.63541/-122.48343 + # https://www.openstreetmap.org/#map=19/52.47752/13.28864 + Scenario: Road Splitting up + Given the node map + """ + d + ` + ` + ` + a - - - - - - - - - b + ` + ` + ` c + + """ + + And the ways + | nodes | highway | name | + | abc | residential | vista | + | bd | residential | sierra | + + When I route I should get + | from | to | route | turns | + | a | c | vista,vista | depart,arrive | + | a | d | vista,sierra,sierra | depart,turn left,arrive | + + # https://www.openstreetmap.org/#map=19/52.45191/13.44113 + # check service road handling in `is_similar_turn` + @todo + Scenario: Road Splitting up at a Driveway + Given the node map + """ + d + ` + ` + ` + a - - - - - - - - - b - - - - - e + ` + ` + ` + `c + """ + + And the ways + | nodes | highway | name | + | abc | residential | britz | + | bd | residential | palz | + | be | service | | + + When I route I should get + | from | to | route | turns | + | a | c | britz,britz | depart,arrive | + | a | e | britz,, | depart,turn straight,arrive | + + # https://www.openstreetmap.org/#map=20/37.62997/-122.49246 + # test is mutually exclusive with features/guidance/fork.feature:27 "Scenario: Don't Fork On Single Road" + @todo + Scenario: Curving road with name-handoff + Given the node map + """ + a + | + | + b + ` + c + ` + d + l - k h ` e + ` j - i ` ` f - - - - - g + """ + + And the ways + | nodes | highway | name | oneway | + | abcd | tertiary | palm | no | + | defg | tertiary | clare | no | + | lkjihd | residential | clare | yes | + + When I route I should get + | from | to | route | turns | + | a | g | palm,clare,clare | depart,new name slight left,arrive | + | g | a | clare,palm,palm | depart,turn right,arrive | + | l | g | clare,clare | depart,arrive | + | l | a | clare,palm,palm | depart,turn left,arrive | + + # https://www.openstreetmap.org/#map=19/37.84291/-122.23681 + Scenario: Two roads turning into the same direction + Given the node map + """ + e + | + |.c + a - - - b` + | + | + d + """ + + And the ways + | nodes | highway | name | oneway | + | abc | residential | romany | no | + | db | residential | ost | yes | + | be | residential | martin | yes | + + When I route I should get + | from | to | route | turns | + | a | c | romany,romany | depart,arrive | + + + # https://www.openstreetmap.org/#map=19/37.82815/-122.28733 + # the similarity check considers `bc` as non-similar to `bd` due to a name change "mandela"->"horton" + # this behavior is captured by features/guidance/turn.feature:126 "Scenario: Three Way Intersection" + # and is mutually exclusive with the test expectation + @todo + Scenario: Turning Secondary Next to Residential + Given the node map + """ + c + | | + | | + -----` | + a b - - - d + ---------- + """ + + And the ways + | nodes | highway | name | + | ab | secondary | mandela | + | bc | secondary | horton | + | bd | residential | yerda | + + When I route I should get + | from | to | route | turns | + | a | d | mandela,yerda,yerda | depart,turn straight,arrive | + | a | c | mandela,horton,horton | depart,turn left,arrive | + + + # https://www.openstreetmap.org/#map=19/52.46341/13.40272 + Scenario: Loss of road class on turn (segregated) + Given the node map + """ + f - - - e - - - d + | + 1 + | + a - - - b - - - c + | + | + g + """ + + And the ways + | nodes | highway | name | oneway | + | ab | tertiary | germ | yes | + | ef | tertiary | germ | yes | + | de | tertiary | ober | yes | + | bc | tertiary | ober | yes | + | be | tertiary | germ | no | + | bg | residential | germ | no | + + When I route I should get + | from | to | route | turns | + | 1 | g | germ,germ | depart,arrive | + | d | g | ober,germ,germ | depart,turn left,arrive | + | a | g | germ,germ,germ | depart,continue right,arrive | + + # https://www.openstreetmap.org/#map=19/37.29821/-121.86874 + Scenario: Sliproads of Higher Category when entering Intersection + Given the node map + """ + e + | + g| + | + | + h | + i | + a - - b - - - c - - d + j | + k | + | + l| + | + f + """ + + And the ways + | nodes | highway | name | oneway | + | abcd | tertiary | stone | no | + | ecf | primary | curt | yes | + | eghib | primary_link | | yes | + | bjklf | primary_link | | yes | + + When I route I should get + | from | to | route | turns | + | a | d | stone,stone | depart,arrive | + + + # https://www.openstreetmap.org/#map=19/37.63866/-122.46677 + Scenario: Slightly offset traffic circle + Given the node map + """ + i----h + ` g + ` ` + a - - - - - b | + c f + ` d - e ` + """ + + And the ways + | nodes | highway | name | + | abcdefghib | residential | road | + + When I route I should get + | from | to | route | turns | + | a | e | road,road,road | depart,continue right,arrive | + | i | a | road,road,road | depart,continue right,arrive | + | d | a | road,road,road | depart,continue left,arrive | + + + # https://www.openstreetmap.org/#map=19/37.63829/-122.46345 + # scenario geometry must be updated to catch the OSM map + @todo + Scenario: Entering a motorway (curved) + Given the node map + """ + a - - - - - - b - - - c - - - - - d + e g + f + | + i - h - j + """ + + And the ways + | nodes | highway | name | oneway | + | abcd | trunk | sky | yes | + | befgc | trunk_link | | yes | + | fh | trunk_link | | no | + | ihj | residential | susan | no | + + When I route I should get + | from | to | route | turns | + | i | d | susan,,sky | depart,turn left,arrive | + | j | d | susan,,sky | depart,turn right,arrive | + + + # https://www.openstreetmap.org/#map=18/48.99155/8.43520 + Scenario: Passing a motorway link on a trunk road + Given the node map + """ + a - - - - - - - - - - b----- + ` ````````````c + ` d + """ + + And the ways + | nodes | highway | name | ref | oneway | + | abc | trunk | sued | K 9652 | yes | + | bd | motorway_link | | A 5 | yes | + + When I route I should get + | from | to | route | turns | + | a | c | sued,sued | depart,arrive | + | a | d | sued,, | depart,off ramp slight right,arrive | + + + # https://www.openstreetmap.org/#map=19/48.98900/8.43800 + Scenario: Splitting motorway links without names but with destinations + Given the node map + """ + .... h + . .g.` + ..... e..`............... f + ... d---``` + c` + / + / + b + / + a + """ + + And the ways + | nodes | highway | name | destination | oneway | + | abcde | motorway_link | | | yes | + | ef | motorway_link | | right | yes | + | egh | motorway_link | | left | yes | + + When I route I should get + | from | to | route | turns | + | a | f | ,, | depart,fork slight right,arrive | + | a | h | ,, | depart,fork slight left,arrive | + + # https://www.openstreetmap.org/#map=19/49.01098/8.36052 + Scenario: Splitting Road at intersection (modelled turn) + Given the node map + """ + h + | + j - - - - - g - - - - - - - - - - - - i + f + e + d + a - - - b - - - - - - - - - - - - - - c + """ + + And the ways + | nodes | highway | name | oneway | + | ab | primary | ente | yes | + | bc | primary | rhein | yes | + | bdefg | primary_link | rhein | yes | + | ig | primary | rhein | yes | + | gj | primary | ente | yes | + | gh | residential | rhein | no | + + When I route I should get + | from | to | route | turns | + | a | c | ente,rhein,rhein | depart,new name straight,arrive | + | a | h | ente,rhein,rhein | depart,turn left,arrive | + + + # https://www.openstreetmap.org/#map=19/48.99776/8.47766 + Scenario: Narrow cross + Given the node map + """ + a e + \ / + \ / + \ / + b + / \ + / \ + / \ + d c + """ + + And the ways + | nodes | highway | name | + | ab | secondary | baden | + | be | primary | gym | + | bc | tertiary | ritter | + | db | primary | baden | + + When I route I should get + | from | to | route | turns | + | a | d | baden,baden,baden | depart,continue right,arrive | + | a | c | baden,ritter | depart,arrive | + | a | e | baden,gym,gym | depart,turn sharp left,arrive | + + + # https://www.openstreetmap.org/#map=19/48.99870/8.48122 + Scenario: Residential Segregated + Given the node map + """ + f e + | | + | | + | | + | | + | | + | | + | | + a - - b - - c - - d + """ + + And the ways + | nodes | highway | name | oneway | + | ab | residential | possel | no | + | fb | residential | berg | yes | + | bc | residential | berg | no | + | ce | residential | berg | yes | + | cd | residential | kastell | no | + + When I route I should get + | from | to | route | turns | + | a | d | possel,kastell | depart,arrive | + | a | e | possel,berg,berg | depart,turn left,arrive | + + + # https://www.openstreetmap.org/#map=19/48.99810/8.46749 + # the test case depends on geometry: for `da` route both `no_name_change_to_candidate` + # and `compare_road_deviation_is_distinct` are true so `bc` is considered non-similar + @todo + Scenario: Slight End of Road + Given the node map + """ + d + / + / + a - - - - - - b - - - - - - - c + """ + + And the ways + | nodes | highway | name | + | abd | residential | kanzler | + | bc | residential | gartner | + + When I route I should get + | from | to | route | turns | + | a | c | kanzler,gartner | depart,arrive | + | a | d | kanzler,kanzler,kanzler | depart,continue left,arrive | + | d | a | kanzler,kanzler,kanzler | depart,continue right,arrive | + + # https://www.openstreetmap.org/#map=18/52.46942/13.33159 + Scenario: Curved crossing + Given the node map + """ + f + .` + h . + `. e ` + `. . ` + `. . ` + `. . ` + d + c - ` `. + a - - - - - - - - - b - - ` ` ` `. + g + """ + + And the ways + | nodes | highway | name | oneway | + | abcd | residential | hand | no | + | def | residential | hand | yes | + | hdg | secondary | schmi | no | + + When I route I should get + | from | to | route | turns | + | a | f | hand,hand | depart,arrive | + | h | g | schmi,schmi | depart,arrive | + + + # https://www.openstreetmap.org/#map=19/52.56562/13.39109 + # the obviousness check depends on geometry at node `c` + @todo + Scenario: Dented Straight + Given the node map + """ + a - - - b. . d - - - - e + ` ` + `c` + | + | + f + """ + + And the ways + | nodes | highway | name | + | abcde | residential | nord | + | cf | residential | stern | + + When I route I should get + | from | to | route | turns | + | a | e | nord,nord | depart,arrive | + | e | a | nord,nord | depart,arrive | + + + # https://www.openstreetmap.org/#map=17/52.57124/13.39892 + Scenario: Primary road curved turn + Given the node map + """ + m - - l.... + `k. + a - - b - . ``- - - - p + `c . \ + `. `j - - - o + d \ + \ i + e \ + | h + | | + f g + + + """ + + And the ways + | nodes | highway | name | oneway | lanes | + | abc | primary | schoen | yes | 2 | + | cdef | primary | grab | yes | 1 | + | klm | primary | schoen | yes | 2 | + | ghijk | primary | grab | yes | 1 | + | cj | secondary_link | mann | yes | 1 | + | jo | secondary | mann | yes | 1 | + | pk | secondary | mann | yes | 1 | + + When I route I should get + | from | to | route | turns | + | a | f | schoen,grab,grab | depart,turn slight right,arrive | + | g | m | grab,schoen | depart,arrive | + | a | o | schoen,mann,mann | depart,turn straight,arrive | + + + # https://www.openstreetmap.org/#map=18/52.55374/13.41462 + # scenario for internal intersection collapsing + @todo + Scenario: Turn Links as Straights + Given the node map + """ + l k + | | + j - - -i - - hg- - - f + | / |/ + /| / | + a - --bc - - d - - - e + | | + m n + """ + + And the ways + | nodes | highway | oneway | name | + | abc | primary | yes | born | + | ij | primary | yes | born | + | cde | primary | yes | wisb | + | fghi | primary | yes | wisb | + | li | primary | yes | berl | + | hk | primary | yes | berl | + | icm | primary | yes | scho | + | ndh | primary | yes | scho | + | bh | primary_link | yes | | + | gc | primary_link | yes | | + + When I route I should get + | from | to | route | turns | locations | # | + | a | k | born,,berl | depart,turn left,arrive | a,b,k | On improved collapse, this should offer berl on turn | + | f | m | wisb,,scho | depart,turn left,arrive | f,g,m | On improved collapse, this should offer scho on turn | + + + # https://www.openstreetmap.org/#map=19/52.56934/13.40131 + Scenario: Crossing Segregated before a turn + Given the node map + """ + _-d + f - - - e -- ` ` + | _-c + a - - -.b -- ` ` + . ` + g` + """ + + And the ways + | nodes | highway | oneway | name | + | ab | primary | yes | scho | + | bc | primary | yes | brei | + | de | primary | yes | brei | + | ef | primary | yes | scho | + | gb | secondary | no | woll | + | be | secondary_link | no | woll | + + When I route I should get + | from | to | route | turns | + | g | c | woll,brei,brei | depart,turn slight right,arrive | + | g | f | woll,scho,scho | depart,turn sharp left,arrive | + | a | c | scho,brei | depart,arrive | + | d | f | brei,scho | depart,arrive | + + + # https://www.openstreetmap.org/#map=19/52.58072/13.42985 + Scenario: Trunk Turning into Motorway + Given the node map + """ + a - - - - - b - - - + ` . ` ` ` ` ` ` ` ` c + ` - - - - d + + """ + + And the ways + | nodes | highway | name | oneway | + | ab | trunk | prenz | yes | + | bc | motorway | | yes | + | bd | trunk_link | | yes | + + When I route I should get + | from | to | route | turns | + | a | c | prenz, | depart,arrive | + | a | d | prenz,, | depart,off ramp slight right,arrive | + + + # https://www.openstreetmap.org/#map=19/52.57800/13.42900 + Scenario: Splitting Secondary + Given the node map + """ + . . c + .. `` + a - - - - - - - b ` ` ` ` + \ + \ d - - - - - - - - - e + """ + + And the ways + | nodes | highway | name | lanes | oneway | + | ab | secondary | dame | 2 | no | + | bc | secondary | pase | 2 | no | + | bde | secondary | feuc | 1 | yes | + + When I route I should get + | from | to | route | turns | + | a | c | dame,pase,pase | depart,new name straight,arrive | + | a | e | dame,feuc,feuc | depart,turn slight right,arrive | + + # https://www.openstreetmap.org/#map=19/52.48468/13.34532 + Scenario: Forking into Tertiary + Given the node map + """ + d + . . ` + a - - - - - b - - - - - c + """ + + And the ways + | nodes | highway | name | oneway | lanes | + | ab | primary | kenny | yes | 4 | + | bc | tertiary | kenny | yes | 2 | + | bd | primary | domi | yes | 2 | + + When I route I should get + | from | to | route | turns | + | a | c | kenny,kenny,kenny | depart,continue straight,arrive | + | a | d | kenny,domi,domi | depart,turn slight left,arrive | + + # https://www.openstreetmap.org/#map=18/52.56960/13.43815 + Scenario: Turn onto classified + Given the node map + """ + e f + | | + | | + a - - - - - b - - c - - . . + ` ` ` d + """ + + And the ways + | nodes | highway | name | oneway | + | abc | secondary | roma | no | + | cd | unclassified | roma | no | + | eb | secondary | roth | yes | + | cf | secondary | roth | yes | + + When I route I should get + | from | to | route | turns | + | a | d | roma,roma | depart,arrive | + | a | f | roma,roth,roth | depart,turn left,arrive | + + + # https://www.openstreetmap.org/#map=18/52.50908/13.27312 + Scenario: Merging onto a different street + Given the node map + """ + d + `.`.`.`.`.`.b - - - - c + a` + """ + + And the ways + | nodes | highway | name | oneway | + | ab | secondary | masu | yes | + | dbc | primary | theo | yes | + + When I route I should get + | from | to | route | turns | # | + | a | c | masu,theo,theo | depart,turn straight,arrive | theo is a through street | + | d | c | theo,theo | depart,arrive | | + + # https://www.openstreetmap.org/#map=18/52.51299/13.28936 + Scenario: Lanes override road classes + Given the node map + """ + e + | + | + a - - - b - - - c + | + | + d + """ + + And the ways + | nodes | highway | name | lanes | + | ab | primary | knob | 2 | + | bc | unclassified | knob | | + | db | primary | soph | 3 | + | be | living_street | soph | 3 | + + When I route I should get + | from | to | route | 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 | diff --git a/features/guidance/perception.feature b/features/guidance/perception.feature index 0d008a48f..30a739316 100644 --- a/features/guidance/perception.feature +++ b/features/guidance/perception.feature @@ -36,6 +36,36 @@ Feature: Simple Turns | f,a | depart,arrive | road,road | true:0,true:0 false:150 false:180;true:180 | | e,a | depart,turn slight right,arrive | turn,road,road | true:333;true:0 false:150 false:180;true:180 | + Scenario: Turning into splitting road - no improvement + Given the node map + """ + a + b + / | + c d - e + | | + | | + | | + | | + | | + | | + | | + | | + g f + """ + + And the ways + | nodes | name | highway | oneway | + | ab | road | primary | no | + | bcg | road | primary | yes | + | fdb | road | primary | yes | + | ed | turn | primary | yes | + + When I route I should get + | waypoints | turns | route | intersections | + | f,a | depart,arrive | road,road | true:0,true:0 false:90 false:180;true:180 | + | e,a | depart,turn right,arrive | turn,road,road | true:270;true:0 false:90 false:180;true:180 | + Scenario: Turning into splitting road Given the node map """ diff --git a/features/guidance/ramp.feature b/features/guidance/ramp.feature index a4e823ded..560952d0b 100644 --- a/features/guidance/ramp.feature +++ b/features/guidance/ramp.feature @@ -160,8 +160,8 @@ Feature: Ramp Guidance When I route I should get | waypoints | route | turns | - | a,d | ab,bd,bd | depart,on ramp right,arrive | - | a,c | ab,bc,bc | depart,turn left,arrive | + | a,d | ab,bd,bd | depart,on ramp right,arrive | + | a,c | ab,bc | depart,arrive | Scenario: Fork Slight Ramp Given the node map @@ -179,8 +179,8 @@ Feature: Ramp Guidance When I route I should get | waypoints | route | turns | - | a,d | ab,bd,bd | depart,on ramp slight right,arrive | - | a,c | ab,bc,bc | depart,turn slight left,arrive | + | a,d | ab,bd,bd | depart,on ramp slight right,arrive | + | a,c | ab,bc | depart,arrive | Scenario: Fork Slight Ramp on Through Street Given the node map diff --git a/features/guidance/roundabout.feature b/features/guidance/roundabout.feature index ed0eb7a83..5245c310a 100644 --- a/features/guidance/roundabout.feature +++ b/features/guidance/roundabout.feature @@ -745,12 +745,15 @@ Feature: Basic Roundabout Scenario: Drive through roundabout + Given a grid size of 5 meters Given the node map """ - a - b e d f - c - g h + . a . + . . + b e --- d ---- f + . . + .c. + g h """ And the ways @@ -760,12 +763,12 @@ Feature: Basic Roundabout | gch | | yes | When I route I should get - | waypoints | bearings | route | turns | - | e,f | 90 90 | edf,edf | depart,arrive | - | e,h | 90 135 | edf,gch,gch,gch | depart,roundabout-exit-2,exit roundabout straight,arrive | - | g,f | 45 90 | gch,edf,edf,edf | depart,roundabout-exit-2,exit roundabout right,arrive | - | g,h | 45 135 | gch,gch,gch | depart,exit roundabout right,arrive | - | e,e | 90 270 | edf,edf,edf,edf | depart,roundabout-exit-3,exit roundabout sharp left,arrive | + | waypoints | bearings | route | turns | + | e,f | 90 90 | edf,edf | depart,arrive | + | e,h | 90 130 | edf,gch,gch,gch | depart,roundabout-exit-2,exit roundabout straight,arrive | + | g,f | 50 90 | gch,edf,edf,edf | depart,roundabout-exit-2,exit roundabout slight right,arrive | + | g,h | 50 130 | gch,gch,gch | depart,exit roundabout right,arrive | + | e,e | 90 270 | edf,edf,edf,edf | depart,roundabout-exit-3,exit roundabout sharp left,arrive | Scenario: CCW and CW roundabouts with overlaps Given the node map @@ -788,10 +791,10 @@ Feature: Basic Roundabout # the turn angles here are quite strange, so we do get uturns for exiting When I route I should get | from | to | route | turns | distance | - | e | f | ed,af,af,af | depart,roundabout-exit-1,exit roundabout left,arrive | 80.1m | - | f | e | af,ed,ed,ed | depart,roundabout-exit-1,exit roundabout uturn,arrive | 120.1m | - | k | l | kg,hl,hl,hl | depart,roundabout-exit-1,exit roundabout right,arrive | 80.1m | - | l | k | hl,kg,kg,kg | depart,roundabout-exit-1,exit roundabout uturn,arrive | 120.1m | + | e | f | ed,af,af,af | depart,roundabout-exit-1,exit roundabout left,arrive | 80m | + | f | e | af,ed,ed,ed | depart,roundabout-exit-1,exit roundabout uturn,arrive | 120m | + | k | l | kg,hl,hl,hl | depart,roundabout-exit-1,exit roundabout right,arrive | 80m | + | l | k | hl,kg,kg,kg | depart,roundabout-exit-1,exit roundabout uturn,arrive | 120m | @4030 @4075 Scenario: Service roundabout with service exits @@ -829,19 +832,19 @@ Feature: Basic Roundabout """ And the ways - | nodes | highway | junction | oneway | # | - | abcda | tertiary | roundabout | | circle | - | ebds | tertiary | | | road | - | cm | tertiary | | | | - | ds | tertiary | | | road | - | rstur | tertiary | roundabout | | circle2 | - | ufghl | tertiary | | | road | - | tv | tertiary | | | | - | gi | tertiary | | yes | sliproad | - | jhik | tertiary | | | crossroad | + | nodes | highway | junction | oneway | # | + | abcda | tertiary | roundabout | | circle | + | ebds | tertiary | | | road | + | cm | tertiary | | | | + | ds | tertiary | | | road | + | rstur | tertiary | roundabout | | circle2 | + | ufghl | tertiary | | | road | + | tv | tertiary | | | | + | gi | tertiary_link | | yes | sliproad | + | jhik | tertiary | | | crossroad | When I route I should get | from | to | route | turns | distance | - | e | k | ebds,ufghl,ufghl,jhik,jhik | depart,rstur-exit-2,exit rotary right,turn right,arrive | 189.1m | + | e | k | ebds,ufghl,ufghl,jhik,jhik | depart,rstur-exit-2,exit rotary right,turn right,arrive | 189.2m | | 1 | k | ebds,ufghl,ufghl,jhik,jhik | depart,rstur-exit-2,exit rotary right,turn right,arrive | 159.1m | diff --git a/features/guidance/turn-angles.feature b/features/guidance/turn-angles.feature index e277a4163..316d973f1 100644 --- a/features/guidance/turn-angles.feature +++ b/features/guidance/turn-angles.feature @@ -280,6 +280,35 @@ Feature: Simple Turns | a,d | road,road | depart,arrive | | e,a | road,road | depart,arrive | + Scenario: Splitting Road with many lanes; same as above makes sure len(turn:lanes) work as expected + Given the node map + """ + f - - - - - - - - - - - - - - - - - - - - e + ' + ' + ' + ' + ' + a - - - - - b + ' + ' + ' + ' + ' + c - - - - - - - - - - - - - - - - - - - - d + """ + + And the ways + | nodes | highway | name | turn:lanes | oneway | + | ab | primary | road | left\|left\|right\|right | no | + | bcd | primary | road | through\|through | yes | + | efb | primary | road | through\|through | yes | + + When I route I should get + | waypoints | route | turns | + | a,d | road,road | depart,arrive | + | e,a | road,road | depart,arrive | + @todo # currently the intersections don't match up do to the `merging` process. # The intermediate intersection is technically no-turn at all, since the road continues. @@ -819,6 +848,7 @@ Feature: Simple Turns | h,a | Heide,Perle,Perle | depart,turn left,arrive | true:16;true:90 true:195 true:270 true:345;true:90 | #http://www.openstreetmap.org/#map=19/52.53293/13.32956 + # adjusted ways to reflect the case geometry for 2/3/2018 Scenario: Curved Exit from Curved Road Given the node map """ @@ -845,16 +875,16 @@ Feature: Simple Turns And the ways | nodes | name | oneway | lanes | highway | - | abcd | Siemens | no | 5 | secondary | - | defg | Erna | no | 3 | secondary | + | ab | Siemens | no | 5 | secondary | + | bcdefg | Erna | no | 3 | secondary | | dhij | Siemens | no | | residential | When I route I should get - | waypoints | route | turns | - | a,j | Siemens,Siemens,Siemens | depart,continue slight right,arrive | - | a,g | Siemens,Erna | depart,arrive | - | g,j | Erna,Siemens,Siemens | depart,turn left,arrive | - | g,a | Erna,Siemens | depart,arrive | + | waypoints | route | turns | + | a,j | Siemens,Siemens,Siemens | depart,turn slight right,arrive | + | a,g | Siemens,Erna | depart,arrive | + | g,j | Erna,Siemens,Siemens | depart,turn left,arrive | + | g,a | Erna,Siemens | depart,arrive | #http://www.openstreetmap.org/#map=19/52.51303/13.32170 Scenario: Ernst Reuter Platz @@ -932,12 +962,12 @@ Feature: Simple Turns g . . - . - . - f - h . - . . - . j + . + . + h f + . + . . + . j . . c . . . diff --git a/features/guidance/turn-lanes.feature b/features/guidance/turn-lanes.feature index 54a8e3be3..1db63bfcb 100644 --- a/features/guidance/turn-lanes.feature +++ b/features/guidance/turn-lanes.feature @@ -301,7 +301,7 @@ Feature: Turn Lane Guidance | e,l | road,cross,cross | depart,turn right,arrive | ,none:false straight:false straight;right:true, | | i,h | cross,road,road | depart,turn right,arrive | ,, | | i,j | cross,cross | depart,arrive | ;;left:false straight:true, | - | i,l | cross,cross,cross | depart,continue uturn,arrive | ;,left:true straight:false;left:true straight:false;left:false straight:true, | + | i,l | cross,cross,cross | depart,continue uturn,arrive | ,left:true straight:false;left:true straight:false;left:true straight:false;left:false straight:true, | @partition-lanes Scenario: Turn Lanes at Segregated Road @@ -614,8 +614,9 @@ Feature: Turn Lane Guidance | | | | b d - h c - ' -- g - - f + h-----c + | `-f + g """ And the ways @@ -835,9 +836,9 @@ Feature: Turn Lane Guidance | cf | secondary | bottom | | When I route I should get - | waypoints | turns | route | lanes | - | a,d | depart,continue right,continue right,arrive | road,road,road,road | ,straight:false right:true,, | - | d,a | depart,continue left,continue left,arrive | road,road,road,road | ,left:true straight:false,, | + | waypoints | turns | route | lanes | + | a,d | depart,continue uturn,arrive | road,road,road | ,straight:false right:true;, | + | d,a | depart,continue uturn,arrive | road,road,road | ,left:true straight:false;, | @simple Scenario: Merge Lanes Onto Freeway @@ -936,48 +937,52 @@ Feature: Turn Lane Guidance Scenario: Partitioned turn, Slight Curve - maxspeed Given the node map """ - f e - | | - | | - | c - a - b ' | - g d + f e + | | + i | | + | | c + h - a - b ' | + j g d """ And the ways | nodes | name | highway | oneway | turn:lanes:forward | maxspeed | + | ha | road | primary | yes | | 1 | | ab | road | primary | yes | left\|right | 1 | | bc | cross | primary | yes | | 1 | | fbg | cross | primary | yes | | 1 | | dce | cross | primary | yes | | 1 | + | iaj | kross | primary | no | | 1 | When I route I should get | waypoints | route | turns | lanes | locations | - | a,g | road,cross,cross | depart,turn right,arrive | ,left:false right:true, | a,b,g | - | a,e | road,cross,cross | depart,end of road left,arrive | ;left:true right:false,left:true right:false, | a,c,e | + | h,g | road,cross,cross | depart,turn right,arrive | ;,left:false right:true, | h,b,g | + | h,e | road,cross,cross | depart,end of road left,arrive | ;,left:true right:false;left:true right:false, | h,b,e | Scenario: Partitioned turn, Slight Curve Given the node map """ - f e - | | - | | - | c - a - b ' | - g d + f e + | | + i | | + | | c + h - a - b ' | + j g d """ And the ways | nodes | name | highway | oneway | turn:lanes:forward | + | ha | road | primary | yes | | | ab | road | primary | yes | left\|right | | bc | cross | primary | yes | | | fbg | cross | primary | yes | | | dce | cross | primary | yes | | + | iaj | kross | primary | no | | When I route I should get - | waypoints | route | turns | lanes | locations | - | a,g | road,cross,cross | depart,turn right,arrive | ,left:false right:true, | a,b,g | - | a,e | road,cross,cross | depart,end of road left,arrive | ;left:true right:false,left:true right:false, | a,c,e | + | waypoints | route | turns | lanes | locations | + | h,g | road,cross,cross | depart,turn right,arrive | ;,left:false right:true, | h,b,g | + | h,e | road,cross,cross | depart,end of road left,arrive | ;,left:true right:false;left:true right:false, | h,b,e | Scenario: Lane Parsing Issue #2694 Given the node map @@ -1243,4 +1248,4 @@ Feature: Turn Lane Guidance When I route I should get | waypoints | route | turns | lanes | locations | - | a,f | road1,road1,road1 | depart,continue uturn,arrive | ;left:false straight:true straight;right:false,left:true straight:false straight;right:false;;, | a,d,f | + | a,f | road1,road1,road1 | depart,continue uturn,arrive | ,;left:true straight:false straight;right:false;;, | a,c,f | diff --git a/features/guidance/turn.feature b/features/guidance/turn.feature index e27231652..450fddd60 100644 --- a/features/guidance/turn.feature +++ b/features/guidance/turn.feature @@ -899,9 +899,9 @@ Feature: Simple Turns """ And the ways - | nodes | highway | name | - | abc | primary | road | - | bd | residential | in | + | nodes | highway | name | lanes | + | abc | primary | road | 3 | + | bd | residential | in | 1 | When I route I should get | waypoints | turns | route | @@ -964,14 +964,16 @@ Feature: Simple Turns Given the node map """ g - - f y - i - j k a b x - e c - d - + | + _--f-----y + i-' | + j-k-a]|[b---x + e 'c + |'d' + | h + | + q """ And the nodes @@ -981,16 +983,16 @@ Feature: Simple Turns And the ways | nodes | name | highway | oneway | | yf | yf | trunk_link | yes | - | gfeh | Centreville Road | primary | | + | gfehq | Centreville Road | primary | | | fi | fi | trunk_link | yes | | ij | Bloomingdale Road | residential | | - | jkabx | Blue Star Memorial Hwy | trunk | | + | jkabx | Blue Star Memorial Hwy | trunk | yes | | bcde | bcde | trunk_link | yes | | kh | kh | trunk_link | yes | When I route I should get | waypoints | turns | route | - | a,h | depart,off ramp right,turn sharp left,arrive | Blue Star Memorial Hwy,bcde,Centreville Road,Centreville Road | + | a,q | depart,off ramp right,turn sharp left,arrive | Blue Star Memorial Hwy,bcde,Centreville Road,Centreville Road | @todo # https://www.openstreetmap.org/#map=20/52.51609/13.41080 @@ -1370,3 +1372,94 @@ Feature: Simple Turns | waypoints | route | turns | | a,d | ab,bcd,bcd | depart,fork slight right,arrive | | a,g | ab,befg,befg | depart,fork slight left,arrive | + + @routing @car + 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 | ref | turns | + | d | c | ,, | L 460,, | depart,turn right,arrive | + | c | d | ,, | ,L 460,L 460 | depart,turn left,arrive | + + # https://www.openstreetmap.org/#map=18/52.25130/10.42545 + Scenario: Turn for roads with no name, ref changes + Given the node map + """ + d + . + . + e c . . f + . + . + b + . + . + a + """ + + And the ways + | nodes | highway | ref | name | + | abc | tertiary | K 57 | | + | cd | tertiary | K 56 | | + | cf | tertiary | K 56 | | + | ce | residential | | Heinrichshöhe | + + When I route I should get + | waypoints | route | turns | + | a,f | ,, | depart,turn right,arrive | + + # https://www.openstreetmap.org/#map=18/52.24071/10.29066 + Scenario: Turn for roads with no name, ref changes + Given the node map + """ + x + . + . + d + . . + . . + . . + e. . t . c . p. .f + . . + . . + . . + b + . + . + a + """ + + And the ways + | nodes | highway | ref | name | oneway | + | abp | tertiary | K 23 | | yes | + | pdx | tertiary | K 23 | | yes | + | xdt | tertiary | K 23 | | yes | + | tba | tertiary | K 23 | | yes | + | etcpf | primary | B 1 | | no | + + When I route I should get + | waypoints | route | turns | + | e,x | ,, | depart,turn left,arrive | + | f,a | ,, | depart,turn left,arrive | diff --git a/features/lib/hash.js b/features/lib/hash.js index 57563e3da..32f0c1c28 100644 --- a/features/lib/hash.js +++ b/features/lib/hash.js @@ -20,11 +20,11 @@ module.exports = { }); }, - hashOfFile: (path, cb) => { + hashOfFile: (path, additional_content, cb) => { fs.readFile(path, (err, result) => { if (err) return cb(err); let checksum = crypto.createHash('md5'); - checksum.update(result); + checksum.update(result + (additional_content || "") ); cb(null, checksum.digest('hex')); }); } diff --git a/features/lib/osm.js b/features/lib/osm.js index f34751a61..18d688cfa 100644 --- a/features/lib/osm.js +++ b/features/lib/osm.js @@ -61,8 +61,13 @@ class DB { }); w.nodes.forEach((k) => { - way.ele('nd') + + let nd = way.ele('nd') .att('ref', k.id); + if (w.add_locations) { + nd.att('lon', k.lon); + nd.att('lat', k.lat); + } }); for (var k in w.tags) { @@ -81,11 +86,12 @@ class DB { }); r.members.forEach((m) => { - relation.ele('member', { + var d = { type: m.type, - ref: m.id, - role: m.role - }); + ref: m.id + }; + if (m.role) d.role = m.role; + relation.ele('member', d); }); for (var k in r.tags) { @@ -120,13 +126,14 @@ class Node { } class Way { - constructor (id, OSM_USER, OSM_TIMESTAMP, OSM_UID) { + constructor (id, OSM_USER, OSM_TIMESTAMP, OSM_UID, add_locations) { this.id = id; this.OSM_USER = OSM_USER; this.OSM_TIMESTAMP = OSM_TIMESTAMP; this.OSM_UID = OSM_UID; this.tags = {}; this.nodes = []; + this.add_locations = add_locations; } addNode (node) { diff --git a/features/lib/osrm_loader.js b/features/lib/osrm_loader.js index 992eda433..9d409f3d6 100644 --- a/features/lib/osrm_loader.js +++ b/features/lib/osrm_loader.js @@ -45,11 +45,12 @@ class OSRMBaseLoader{ var retryCount = 0; let retry = (err) => { if (err) { - if (retryCount < 10) { + if (retryCount < this.scope.OSRM_CONNECTION_RETRIES) { + const timeoutMs = 10 * Math.pow(this.scope.OSRM_CONNECTION_EXP_BACKOFF_COEF, retryCount); retryCount++; - setTimeout(() => { tryConnect(this.scope.OSRM_PORT, retry); }, 10); + setTimeout(() => { tryConnect(this.scope.OSRM_IP, this.scope.OSRM_PORT, retry); }, timeoutMs); } else { - callback(new Error("Could not connect to osrm-routed after ten retries.")); + callback(new Error(`Could not connect to osrm-routed after ${this.scope.OSRM_CONNECTION_RETRIES} retries.`)); } } else @@ -58,7 +59,7 @@ class OSRMBaseLoader{ } }; - tryConnect(this.scope.OSRM_PORT, retry); + tryConnect(this.scope.OSRM_IP, this.scope.OSRM_PORT, retry); } }; @@ -77,14 +78,54 @@ class OSRMDirectLoader extends OSRMBaseLoader { osrmUp (callback) { if (this.osrmIsRunning()) return callback(new Error("osrm-routed already running!")); - const command_arguments = util.format('%s -p %d -a %s', this.inputFile, this.scope.OSRM_PORT, this.scope.ROUTING_ALGORITHM); + const command_arguments = util.format('%s -p %d -i %s -a %s', 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)); } }); - 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); } }; @@ -107,7 +148,8 @@ class OSRMDatastoreLoader extends OSRMBaseLoader { } loadData (callback) { - this.scope.runBin('osrm-datastore', this.inputFile, this.scope.environment, (err) => { + const command_arguments = util.format('--dataset-name=%s %s', this.scope.DATASET_NAME, this.inputFile); + this.scope.runBin('osrm-datastore', command_arguments, this.scope.environment, (err) => { if (err) return callback(new Error('*** osrm-datastore exited with ' + err.code + ': ' + err)); callback(); }); @@ -116,7 +158,7 @@ class OSRMDatastoreLoader extends OSRMBaseLoader { osrmUp (callback) { if (this.osrmIsRunning()) return callback(); - const command_arguments = util.format('--shared-memory=1 -p %d -a %s', this.scope.OSRM_PORT, this.scope.ROUTING_ALGORITHM); + const command_arguments = util.format('--dataset-name=%s -s -i %s -p %d -a %s', this.scope.DATASET_NAME, this.scope.OSRM_IP, this.scope.OSRM_PORT, 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; @@ -134,22 +176,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)); } diff --git a/features/lib/try_connect.js b/features/lib/try_connect.js index 0461dddb8..4fa205dcb 100644 --- a/features/lib/try_connect.js +++ b/features/lib/try_connect.js @@ -3,8 +3,8 @@ const net = require('net'); const Timeout = require('node-timeout'); -module.exports = function tryConnect(port, callback) { - net.connect({ port: port, host: '127.0.0.1' }) +module.exports = function tryConnect(host, port, callback) { + net.connect({ port: port, host: host }) .on('connect', () => { callback(); }) .on('error', () => { callback(new Error('Could not connect.')); diff --git a/features/nearest/pick.feature b/features/nearest/pick.feature index fb66ef654..dcdf5268c 100644 --- a/features/nearest/pick.feature +++ b/features/nearest/pick.feature @@ -59,6 +59,31 @@ Feature: Locating Nearest node on a Way - pick closest way | 3 | u | | 4 | w | + Scenario: Nearest - inside a oneway triangle + Given the node map + """ + c + + y z + 0 1 + 2 3 4 + a x u w b + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + | ca | yes | + + When I request nearest I should get + | in | out | + | 0 | y | + | 1 | z | + | 2 | x | + | 3 | u | + | 4 | w | + Scenario: Nearest - High lat/lon Given the node locations | node | lat | lon | @@ -78,3 +103,30 @@ Feature: Locating Nearest node on a Way - pick closest way | x | a | | y | b | | z | c | + + Scenario: Nearest - data version + Given the node map + """ + c + + y z + 0 1 + 2 3 4 + a x u w b + """ + + And the ways + | nodes | + | ab | + | bc | + | ca | + + And the extract extra arguments "--data_version cucumber_data_version" + + When I request nearest I should get + | in | out | data_version | + | 0 | y | cucumber_data_version | + | 1 | z | cucumber_data_version | + | 2 | x | cucumber_data_version | + | 3 | u | cucumber_data_version | + | 4 | w | cucumber_data_version | diff --git a/features/nearest/projection.feature b/features/nearest/projection.feature index 3d9e6aa30..dc3ba94c0 100644 --- a/features/nearest/projection.feature +++ b/features/nearest/projection.feature @@ -111,3 +111,28 @@ Feature: Locating Nearest node on a Way - basic projection onto way | 7 | b | | 8 | a | | 9 | b | + + Scenario: Nearest - easy-west way with flatbuffers + Given the node map + """ + 0 1 2 3 4 + a x b + 5 6 7 8 9 + """ + + And the ways + | nodes | + | ab | + + When I request nearest with flatbuffers I should get + | in | out | + | 0 | a | + | 1 | a | + | 2 | x | + | 3 | b | + | 4 | b | + | 5 | a | + | 6 | a | + | 7 | x | + | 8 | b | + | 9 | b | diff --git a/features/options/contract/help.feature b/features/options/contract/help.feature index d33a2c65b..50269483d 100644 --- a/features/options/contract/help.feature +++ b/features/options/contract/help.feature @@ -12,7 +12,6 @@ Feature: osrm-contract command line options: help And stdout should contain "Configuration:" And stdout should contain "--threads" And stdout should contain "--core" - And stdout should contain "--level-cache" And stdout should contain "--segment-speed-file" And it should exit with an error @@ -27,7 +26,6 @@ Feature: osrm-contract command line options: help And stdout should contain "Configuration:" And stdout should contain "--threads" And stdout should contain "--core" - And stdout should contain "--level-cache" And stdout should contain "--segment-speed-file" And it should exit successfully @@ -42,6 +40,5 @@ Feature: osrm-contract command line options: help And stdout should contain "Configuration:" And stdout should contain "--threads" And stdout should contain "--core" - And stdout should contain "--level-cache" And stdout should contain "--segment-speed-file" And it should exit successfully diff --git a/features/options/datastore/datastore.feature b/features/options/datastore/datastore.feature new file mode 100644 index 000000000..667f245a5 --- /dev/null +++ b/features/options/datastore/datastore.feature @@ -0,0 +1,44 @@ +@datastore @options @help +Feature: osrm-datastore command line options + + Background: + Given the profile "testbot" + And the node map + """ + a b + """ + And the ways + | nodes | + | ab | + And the data has been contracted + + Scenario: osrm-datastore - Help should be shown when no options are passed + When I try to run "osrm-datastore --dataset-name test_dataset_42 {processed_file}" + Then it should exit successfully + When I try to run "osrm-datastore --list" + Then it should exit successfully + And stdout should contain "test_dataset_42/static" + And stdout should contain "test_dataset_42/updatable" + + Scenario: osrm-datastore - Only metric update should work + Given the speed file + """ + 0,1,50 + """ + And the data has been extracted + When I try to run "osrm-datastore {processed_file} --dataset-name cucumber/only_metric_test" + Then it should exit successfully + When I try to run "osrm-customize --segment-speed-file {speeds_file} {processed_file}" + Then it should exit successfully + When I try to run "osrm-datastore {processed_file} --dataset-name cucumber/only_metric_test --only-metric" + Then it should exit successfully + + Scenario: osrm-datastore - Displaying help should work + When I try to run "osrm-datastore {processed_file} --help" + Then it should exit successfully + + Scenario: osrm-datastore - Errors on invalid path + When I try to run "osrm-datastore invalid_path.osrm" + Then stderr should contain "[error] Config contains invalid file paths." + And stderr should contain "Missing/Broken" + And it should exit with an error diff --git a/features/options/extract/lua.feature b/features/options/extract/lua.feature index b515d450d..c238cde61 100644 --- a/features/options/extract/lua.feature +++ b/features/options/extract/lua.feature @@ -1,8 +1,22 @@ @extract Feature: osrm-extract lua ways:get_nodes() - Background: - Given the node map + Scenario: osrm-extract - Passing base file + Given the profile file + """ + functions = require('testbot') + + functions.process_way = function(profile, way, result) + for _, node in ipairs(way:get_nodes()) do + print('node id ' .. node:id()) + end + result.forward_mode = mode.driving + result.forward_speed = 1 + end + + return functions + """ + And the node map """ a b """ @@ -11,23 +25,132 @@ Feature: osrm-extract lua ways:get_nodes() | ab | And the data has been saved to disk - Scenario: osrm-extract - Passing base file - Given the profile file - """ - functions = require('testbot') - - function way_function(profile, way, result) - for _, node in ipairs(way:get_nodes()) do - print('node id ' .. node:id()) - end - result.forward_mode = mode.driving - result.forward_speed = 1 - end - - functions.process_way = way_function - return functions - """ When I run "osrm-extract --profile {profile_file} {osm_file}" Then it should exit successfully And stdout should contain "node id 1" And stdout should contain "node id 2" + + + Scenario: osrm-extract location-dependent data without add-locations-to-ways preprocessing and node locations cache + Given the profile file + """ + functions = require('testbot') + + functions.process_way = function(profile, way, result, relations) + print(way:get_location_tag('driving_side')) + end + + return functions + """ + And the node map + """ + a b + """ + And the ways + | nodes | + | ab | + And the data has been saved to disk + + When I try to run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --disable-location-cache" + Then it should exit with an error + And stderr should contain "invalid location" + + Scenario: osrm-extract location-dependent data + Given the profile file + """ + functions = require('testbot') + + functions.process_way = function(profile, way, result, relations) + for _, key in ipairs({'answer', 'boolean', 'object', 'array'}) do + print (key .. ' ' .. tostring(way:get_location_tag(key))) + end + result.forward_mode = mode.driving + result.forward_speed = 1 + end + + return functions + """ + And the node map + """ + a b + """ + And the ways with locations + | nodes | + | ab | + And the data has been saved to disk + + When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --disable-location-cache" + Then it should exit successfully + And stdout should contain "answer 42" + And stdout should contain "boolean true" + And stdout should contain "array nil" + And stdout should contain "object nil" + + + Scenario: osrm-extract location-dependent data with multi-polygons + Given the profile file + """ + functions = require('testbot') + + functions.process_way = function(profile, way, result, relations) + print('ISO3166-1 ' .. (way:get_location_tag('ISO3166-1') or 'none')) + print('answer ' .. (way:get_location_tag('answer') or 'none')) + result.forward_mode = mode.driving + result.forward_speed = 1 + end + + return functions + """ + And the node locations + | node | lat | lon | id | + | a | 22.4903670 | 113.9455227 | 1 | + | b | 22.4901701 | 113.9455899 | 2 | + | c | 22.4901852 | 113.9458608 | 3 | + | d | 22.4904033 | 113.9456999 | 4 | + | e | 1.1 | 1 | 5 | + | f | 1.2 | 1 | 6 | + And the ways with locations + | nodes | # | + | ab | Hong Kong | + | cd | China Mainland | + | ef | Null Island | + And the data has been saved to disk + + When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson --location-dependent-data test/data/regions/hong-kong.geojson --disable-location-cache" + Then it should exit successfully + And stdout should not contain "1 GeoJSON polygon" + And stdout should contain "2 GeoJSON polygons" + And stdout should contain "ISO3166-1 HK" + And stdout should contain "ISO3166-1 none" + And stdout should contain "answer 42" + + Scenario: osrm-extract location-dependent data via locations cache + Given the profile file + """ + functions = require('testbot') + + functions.process_node = function(profile, node, result, relations) + print ('node ' .. tostring(node:get_location_tag('answer'))) + end + + functions.process_way = function(profile, way, result, relations) + print ('way ' .. tostring(way:get_location_tag('answer'))) + result.forward_mode = mode.driving + result.forward_speed = 1 + end + + return functions + """ + And the node map + """ + a b + """ + And the ways + | nodes | + | ab | + And the data has been saved to disk + + When I run "osrm-extract --profile {profile_file} {osm_file} --location-dependent-data test/data/regions/null-island.geojson" + Then it should exit successfully + And stdout should contain "node 42" + And stdout should contain "way 42" diff --git a/features/options/extract/turn_function.feature b/features/options/extract/turn_function.feature new file mode 100644 index 000000000..eecb29604 --- /dev/null +++ b/features/options/extract/turn_function.feature @@ -0,0 +1,209 @@ +@routing @testbot @turn_function +Feature: Turn Function Information + + + Background: + Given the profile file + """ + functions = require('car') + + function test_setup() + profile = functions.setup() + profile.highway_turn_classification = { + ['motorway'] = 4, + ['motorway_link'] = 4, + ['trunk'] = 4, + ['trunk_link'] = 4, + ['primary'] = 4, + ['primary_link'] = 4, + ['secondary'] = 3, + ['secondary_link'] = 3, + ['tertiary'] = 2, + ['tertiary_link'] = 2, + ['residential'] = 1, + ['living_street'] = 1, + } + + profile.access_turn_classification = { + ['discouraged'] = 1; + ['permissive'] = 1; + ['private'] = 1; + ['customers'] = 1; + ['dismount'] = 1; + } + return profile + end + + function turn_leg_string (leg) + return 'speed: ' .. tostring(leg.speed) + .. ', is_incoming: ' .. tostring(leg.is_incoming) + .. ', is_outgoing: ' .. tostring(leg.is_outgoing) + .. ', highway_turn_classification: ' .. tostring(leg.highway_turn_classification) + .. ', access_turn_classification: ' .. tostring(leg.access_turn_classification) + .. ', priority_class: ' .. tostring(leg.priority_class) + end + + function print_turn (profile, turn) + print ('source_restricted ' .. string.format("%s", tostring(turn.source_restricted))) + print ('source_is_motorway ' .. string.format("%s", tostring(turn.source_is_motorway))) + print ('source_is_link ' .. string.format("%s", tostring(turn.source_is_link))) + print ('source_number_of_lanes ' .. string.format("%s", tostring(turn.source_number_of_lanes))) + print ('source_highway_turn_classification ' .. string.format("%s", tostring(turn.source_highway_turn_classification))) + print ('source_access_turn_classification ' .. string.format("%s", tostring(turn.source_access_turn_classification))) + print ('source_speed ' .. string.format("%s", tostring(turn.source_speed))) + print ('source_priority_class ' .. string.format("%s", tostring(turn.source_priority_class))) + print ('source_mode ' .. string.format("%s", tostring(turn.source_mode))) + + print ('target_restricted ' .. string.format("%s", tostring(turn.target_restricted))) + print ('target_is_motorway ' .. string.format("%s", tostring(turn.target_is_motorway))) + print ('target_is_link ' .. string.format("%s", tostring(turn.target_is_link))) + print ('target_number_of_lanes ' .. string.format("%s", tostring(turn.target_number_of_lanes))) + print ('target_highway_turn_classification ' .. string.format("%s", tostring(turn.target_highway_turn_classification))) + print ('target_access_turn_classification ' .. string.format("%s", tostring(turn.target_access_turn_classification))) + print ('target_speed ' .. string.format("%s", tostring(turn.target_speed))) + print ('target_priority_class ' .. string.format("%s", tostring(turn.target_priority_class))) + print ('target_mode ' .. string.format("%s", tostring(turn.target_mode))) + + print ('number_of_roads ' .. string.format("%s", tostring(turn.number_of_roads))) + if not turn.is_u_turn then + for roadCount, road in ipairs(turn.roads_on_the_right) do + print('roads_on_the_right [' .. tostring(roadCount) .. '] ' .. turn_leg_string(road)) + end + + for roadCount, road in ipairs(turn.roads_on_the_left) do + print('roads_on_the_left [' .. tostring(roadCount) .. '] ' .. turn_leg_string(road)) + end + end + end + + return { + setup = test_setup, + process_way = functions.process_way, + process_node = functions.process_node, + process_turn = print_turn + } + """ + + Scenario: Turns should have correct information of source and target + Given the node map + """ + + a b c + + """ + And the ways + | nodes | highway | + | ab | motorway | + | bc | motorway | + And the data has been saved to disk + + When I run "osrm-extract --profile {profile_file} {osm_file}" + Then it should exit successfully + And stdout should contain "source_is_motorway true" + And stdout should contain "target_is_motorway true" + And stdout should contain "source_is_link false" + And stdout should contain "source_priority_class 0" + And stdout should contain "target_is_motorway true" + And stdout should contain "target_is_link false" + And stdout should contain "target_priority_class 0" + + + Scenario: Turns should detect when turn is leaving highway + Given the node map + """ + + a b c + + """ + And the ways + | nodes | highway | lanes | + | ab | motorway | 3 | + | bc | motorway_link | | + + And the data has been saved to disk + + When I run "osrm-extract --profile {profile_file} {osm_file}" + Then it should exit successfully + And stdout should contain "source_is_motorway true" + And stdout should contain "source_is_link false" + And stdout should contain "source_number_of_lanes 3" + And stdout should contain "target_is_motorway false" + And stdout should contain "target_is_link true" + And stdout should contain "target_number_of_lanes 0" + And stdout should contain "number_of_roads 2" + + Scenario: Turns should have correct information of other roads at intersection I + Given the node map + """ + d + ^ + | + a->b->c + """ + And the ways + | nodes | highway | oneway | + | ab | primary | yes | + | bc | motorway | yes | + | bd | residential | yes | + And the data has been saved to disk + + When I run "osrm-extract --profile {profile_file} {osm_file}" + Then it should exit successfully + And stdout should contain "number_of_roads 3" + And stdout should contain "source_priority_class 4" + And stdout should contain "target_priority_class 0" + And stdout should contain "target_priority_class 10" + # turning abd, give information about bc + And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: false, is_outgoing: true, highway_turn_classification: 4, access_turn_classification: 0/ + # turning abc, give information about bd + And stdout should contain /roads_on_the_left \[1\] speed: [0-9]+, is_incoming: false, is_outgoing: true, highway_turn_classification: 1, access_turn_classification: 0/ + + Scenario: Turns should have correct information of other roads at intersection II + Given the node map + """ + d + | + v + a->b->c + """ + And the ways + | nodes | highway | oneway | access | + | ab | secondary | yes | | + | bc | motorway | yes | | + | db | unclassified | yes | discouraged | + And the data has been saved to disk + + When I run "osrm-extract --profile {profile_file} {osm_file}" + Then it should exit successfully + And stdout should contain "number_of_roads 3" + # turning dbc, give information about about ab + And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: false, highway_turn_classification: 3, access_turn_classification: 0/ + # turning abc, give information about about db + And stdout should contain /roads_on_the_left \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: false, highway_turn_classification: 0, access_turn_classification: 1/ + + Scenario: Turns should have correct information of two-way roads at intersection + Given the node map + """ + b + | + a-c-d + | + e + """ + And the ways + | nodes | highway | oneway | + | ac | motorway | yes | + | cd | motorway_link | yes | + | bc | trunk | yes | + | cb | trunk_link | yes | + | ce | primary | yes | + | ec | primary_link | yes | + And the data has been saved to disk + + When I run "osrm-extract --profile {profile_file} {osm_file}" + Then it should exit successfully + # Turn acd + # on the left there should be cb (and bc) + And stdout should contain /roads_on_the_left \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: true, highway_turn_classification: [0-9]+, access_turn_classification: 0, priority_class: 3/ + # on the right there should be ce and ec + And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: true, highway_turn_classification: [0-9]+, access_turn_classification: 0, priority_class: 4/ diff --git a/features/options/profiles/invalid_version.feature b/features/options/profiles/invalid_version.feature index a6ed04f76..d34c56828 100644 --- a/features/options/profiles/invalid_version.feature +++ b/features/options/profiles/invalid_version.feature @@ -24,7 +24,7 @@ Feature: Invalid profile API versions Scenario: Profile API version too high Given the profile file """ - api_version = 4 + api_version = 5 """ And the node map """ diff --git a/features/options/profiles/version3.feature b/features/options/profiles/version3.feature index 5ab00c84c..76f922106 100644 --- a/features/options/profiles/version3.feature +++ b/features/options/profiles/version3.feature @@ -14,7 +14,6 @@ Feature: Profile API version 3 find_access_tag = require("lib/access").find_access_tag limit = require("lib/maxspeed").limit - function setup() return { properties = { @@ -23,7 +22,8 @@ Feature: Profile API version 3 continue_straight_at_waypoint = true, weight_name = 'test_version2', weight_precision = 2 - } + }, + relation_types = Sequence { "route" } } end @@ -39,30 +39,15 @@ Feature: Profile API version 3 result.forward_speed = 36 result.backward_speed = 36 - for _, r in ipairs(relations) do - for k, v in pairs(r) do - print('data_' .. k .. '_value_' .. v) - end + local rel_id_list = relations:get_relations(way) + for i, rel_id in ipairs(rel_id_list) do + local rel = relations:relation(rel_id) + local role = rel:get_role(way) + print('role_' .. role) end print ('process_way ' .. way:id() .. ' ' .. result.name) end - function process_relation(profile, relation, result) - local t = relation:get_value_by_key("type") - if t == "route" then - for _, m in ipairs(relation:members()) do - if m:role() == "north" then - result[m]['direction'] = 'north' - print('direction_north') - end - end - - print('route_relation') - end - - print ('process_relation ' .. relation:id()) - end - function process_turn (profile, turn) print('process_turn', turn.angle, turn.turn_type, turn.direction_modifier, turn.has_traffic_light) turn.weight = turn.angle == 0 and 0 or 4.2 @@ -103,14 +88,11 @@ Feature: Profile API version 3 When I run "osrm-extract --profile {profile_file} {osm_file}" Then it should exit successfully - And stdout should contain "process_relation" - And stdout should contain "route_relation" - And stdout should contain "direction_north" - And stdout should contain "data_direction_value_north" And stdout should contain "process_node" And stdout should contain "process_way" And stdout should contain "process_turn" And stdout should contain "process_segment" + And stdout should contain "role_north" When I route I should get | from | to | route | time | diff --git a/features/raster/extract.feature b/features/raster/extract.feature index 8f2514aef..ad35b9bac 100644 --- a/features/raster/extract.feature +++ b/features/raster/extract.feature @@ -20,6 +20,6 @@ Feature: osrm-extract with a profile containing raster source And the data has been saved to disk When I run "osrm-extract {osm_file} -p {profile_file}" Then stdout should contain "source loader" - Then stdout should contain "slope: 0.0899" - Then stdout should contain "slope: -0.0899" + Then stdout should contain "slope: 0.0904" + Then stdout should contain "slope: -0.0904" And it should exit successfully diff --git a/features/step_definitions/data.js b/features/step_definitions/data.js index d191d62b0..0d9b76e8a 100644 --- a/features/step_definitions/data.js +++ b/features/step_definitions/data.js @@ -8,7 +8,7 @@ var OSM = require('../lib/osm'); module.exports = function () { this.Given(/^the profile "([^"]*)"$/, (profile, callback) => { - this.profile = profile; + this.profile = this.OSRM_PROFILE || profile; this.profileFile = path.join(this.PROFILES_PATH, this.profile + '.lua'); callback(); }); @@ -129,13 +129,13 @@ module.exports = function () { q.awaitAll(callback); }); - this.Given(/^the ways$/, (table, callback) => { + this.Given(/^the ways( with locations)?$/, (add_locations, table, callback) => { if (this.osm_str) throw new Error('*** Map data already defined - did you pass an input file in this scenario?'); let q = d3.queue(); let addWay = (row, cb) => { - let way = new OSM.Way(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID); + let way = new OSM.Way(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID, !!add_locations); let nodes = row.nodes; if (this.nameWayHash.nodes) throw new Error(util.format('*** duplicate way %s', nodes)); @@ -185,40 +185,59 @@ module.exports = function () { let q = d3.queue(); - let addRelation = (row, cb) => { + let addRelation = (headers, row, cb) => { let relation = new OSM.Relation(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID); - for (let key in row) { - let isNode = key.match(/^node:(.*)/), - isWay = key.match(/^way:(.*)/), + + var name = null; + for (let index in row) { + + var key = headers[index]; + var value = row[index]; + let isNode = key.match(/^node:?(.*)/), + isWay = key.match(/^way:?(.*)/), + isRelation = key.match(/^relation:?(.*)/), isColonSeparated = key.match(/^(.*):(.*)/); if (isNode) { - row[key].split(',').map(function(v) { return v.trim(); }).forEach((nodeName) => { + value.split(',').map(function(v) { return v.trim(); }).forEach((nodeName) => { if (nodeName.length !== 1) throw new Error(util.format('*** invalid relation node member "%s"', nodeName)); let node = this.findNodeByName(nodeName); if (!node) throw new Error(util.format('*** unknown relation node member "%s"', nodeName)); relation.addMember('node', node.id, isNode[1]); }); } else if (isWay) { - row[key].split(',').map(function(v) { return v.trim(); }).forEach((wayName) => { + value.split(',').map(function(v) { return v.trim(); }).forEach((wayName) => { let way = this.findWayByName(wayName); if (!way) throw new Error(util.format('*** unknown relation way member "%s"', wayName)); relation.addMember('way', way.id, isWay[1]); }); + } else if (isRelation) { + value.split(',').map(function(v) { return v.trim(); }).forEach((relName) => { + let otherrelation = this.findRelationByName(relName); + if (!otherrelation) throw new Error(util.format('*** unknown relation relation member "%s"', relName)); + relation.addMember('relation', otherrelation.id, isRelation[1]); + }); } else if (isColonSeparated && isColonSeparated[1] !== 'restriction') { throw new Error(util.format('*** unknown relation member type "%s:%s", must be either "node" or "way"', isColonSeparated[1], isColonSeparated[2])); } else { - relation.addTag(key, row[key]); + relation.addTag(key, value); + if (key.match(/name/)) name = value; } } relation.uid = this.OSM_UID; + + if (name) { + this.nameRelationHash[name] = relation; + } + this.OSMDB.addRelation(relation); cb(); }; - table.hashes().forEach((row) => q.defer(addRelation, row)); + var headers = table.raw()[0]; + table.rows().forEach((row) => q.defer(addRelation, headers, row)); q.awaitAll(callback); }); @@ -276,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); }); diff --git a/features/step_definitions/distance_matrix.js b/features/step_definitions/distance_matrix.js index 7e14b3a4f..37de07a26 100644 --- a/features/step_definitions/distance_matrix.js +++ b/features/step_definitions/distance_matrix.js @@ -1,74 +1,143 @@ var util = require('util'); +var flatbuffers = require('../support/flatbuffers').flatbuffers; +var FBResult = require('../support/fbresult_generated').osrm.engine.api.fbresult.FBResult; + 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$/); + const durationsRegexFb = new RegExp(/^I request a travel time matrix with flatbuffers I should get$/); + const distancesRegexFb = new RegExp(/^I request a travel distance matrix with flatbuffers I should get$/); - 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'); + const FORMAT_JSON = 'json'; + const FORMAT_FB = 'flatbuffers'; - var waypoints = [], - columnHeaders = tableRows[0].slice(1), - rowHeaders = tableRows.map((h) => h[0]).slice(1), - symmetric = columnHeaders.every((ele, i) => ele === rowHeaders[i]); + this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', FORMAT_JSON, callback);}.bind(this)); + this.When(distancesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', FORMAT_JSON, callback);}.bind(this)); + this.When(estimatesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'fallback_speed_cells', FORMAT_JSON, callback);}.bind(this)); + this.When(durationsRegexFb, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', FORMAT_FB, callback);}.bind(this)); + this.When(distancesRegexFb, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', FORMAT_FB, callback);}.bind(this)); +}; - 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' }); - }); - } +const durationsParse = function(v) { return isNaN(parseInt(v)); }; +const distancesParse = function(v) { return isNaN(parseFloat(v)); }; +const estimatesParse = function(v) { return isNaN(parseFloat(v)); }; - var actual = []; - actual.push(table.headers); +function tableParse(table, noRoute, annotation, format, callback) { - this.reprocessAndLoadData((e) => { - if (e) return callback(e); - // compute matrix - var params = this.queryParams; + const parse = annotation == 'distances' ? distancesParse : (annotation == 'durations' ? durationsParse : estimatesParse); + const params = this.queryParams; + params.annotations = ['durations','fallback_speed_cells'].indexOf(annotation) !== -1 ? 'duration' : 'distance'; + params.output = format; - this.requestTable(waypoints, params, (err, response) => { - if (err) return callback(err); - if (!response.body.length) return callback(new Error('Invalid response body')); + var tableRows = table.raw(); + if (tableRows[0][0] !== '') throw new Error('*** Top-left cell of matrix table must be empty'); + + 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]); + + 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 result = []; + if (format === 'json') { var json = JSON.parse(response.body); - var result = json['durations'].map(row => { - var hashes = {}; - row.forEach((v, i) => { hashes[tableRows[0][i+1]] = isNaN(parseInt(v)) ? '' : v; }); - return hashes; - }); + 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.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; + }); + } + } else { //flatbuffers + var body = response.body; + var bytes = new Uint8Array(body.length); + for (var indx = 0; indx < body.length; ++indx) { + bytes[indx] = body.charCodeAt(indx); + } + var buf = new flatbuffers.ByteBuffer(bytes); + var fb = FBResult.getRootAsFBResult(buf); - 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 matrix; + if (annotation === 'durations') { + matrix = fb.table().durationsArray(); + } + if (annotation === 'distances') { + matrix = fb.table().distancesArray(); + } + var cols = fb.table().cols(); + var rows = fb.table().rows(); + for (let r = 0; r < rows; ++r) { + result[r]={}; + for(let c=0; c < cols; ++c) { + result[r][tableRows[0][c+1]] = matrix[r*cols + c]; } + } + } - result[ri][''] = row['']; - cb(null, result[ri]); - }; + 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(); + } + } - this.processRowsAndDiff(table, testRow, callback); - }); + result[ri][''] = row['']; + cb(null, result[ri]); + }; + + this.processRowsAndDiff(table, testRow, callback); }); }); -}; +} diff --git a/features/step_definitions/matching.js b/features/step_definitions/matching.js index ef66d7b3c..c8afa5838 100644 --- a/features/step_definitions/matching.js +++ b/features/step_definitions/matching.js @@ -74,7 +74,7 @@ module.exports = function () { if (headers.has('turns')) { if (json.matchings.length != 1) throw new Error('*** Checking turns only supported for matchings with one subtrace'); - turns = this.turnList(json.matchings[0].instructions); + turns = this.turnList(json.matchings[0]); } if (headers.has('route')) { @@ -117,6 +117,10 @@ module.exports = function () { got.duration = duration.toString(); } + if (headers.has('data_version')) { + got.data_version = json.data_version || ''; + } + // if header matches 'a:*', parse out the values for * // and return in that header headers.forEach((k) => { @@ -150,7 +154,8 @@ module.exports = function () { } var ok = true; var encodedResult = '', - extendedTarget = ''; + extendedTarget = '', + resultWaypoints = []; var testSubMatching = (sub, si) => { var testSubNode = (ni) => { @@ -186,6 +191,29 @@ module.exports = function () { }); } + if (headers.has('waypoints')) { + var got_loc = []; + for (let i = 0; i < json.tracepoints.length; i++) { + if (!json.tracepoints[i]) continue; + if (json.tracepoints[i].waypoint_index != null) + got_loc.push(json.tracepoints[i].location); + } + + if (row.waypoints.length != got_loc.length) + return cb(new Error(`Expected ${row.waypoints.length} waypoints, got ${got_loc.length}`)); + + for (i = 0; i < row.waypoints.length; i++) + { + var want_node = this.findNodeByName(row.waypoints[i]); + if (!this.FuzzyMatch.matchLocation(got_loc[i], want_node)) { + resultWaypoints.push(util.format('? [%s,%s]', got_loc[i][0], got_loc[i][1])); + ok = false; + } else { + resultWaypoints.push(row.waypoints[i]); + } + } + } + if (ok) { if (headers.has('matchings')) { got.matchings = row.matchings; @@ -194,7 +222,12 @@ module.exports = function () { if (headers.has('timestamps')) { got.timestamps = row.timestamps; } + + if (headers.has('waypoints')) { + got.waypoints = row.waypoints; + } } else { + got.waypoints = resultWaypoints.join(';'); got.matchings = encodedResult; row.matchings = extendedTarget; } diff --git a/features/step_definitions/nearest.js b/features/step_definitions/nearest.js index f5627b842..49ec0775d 100644 --- a/features/step_definitions/nearest.js +++ b/features/step_definitions/nearest.js @@ -1,10 +1,14 @@ var util = require('util'); +var flatbuffers = require('../support/flatbuffers').flatbuffers; +var FBResult = require('../support/fbresult_generated').osrm.engine.api.fbresult.FBResult; + module.exports = function () { this.When(/^I request nearest I should get$/, (table, callback) => { this.reprocessAndLoadData((e) => { if (e) return callback(e); var testRow = (row, ri, cb) => { + var inNode = this.findNodeByName(row.in); if (!inNode) throw new Error(util.format('*** unknown in-node "%s"', row.in)); @@ -14,6 +18,7 @@ module.exports = function () { this.requestNearest(inNode, this.queryParams, (err, response) => { if (err) return cb(err); var coord; + var headers = new Set(table.raw()[0]); if (response.statusCode === 200 && response.body.length) { var json = JSON.parse(response.body); @@ -22,6 +27,61 @@ module.exports = function () { var got = { in: row.in, out: row.out }; + if (headers.has('data_version')) { + got.data_version = json.data_version || ''; + } + + Object.keys(row).forEach((key) => { + if (key === 'out') { + if (this.FuzzyMatch.matchLocation(coord, outNode)) { + got[key] = row[key]; + } else { + row[key] = util.format('%s [%d,%d]', row[key], outNode.lat, outNode.lon); + } + } + }); + + cb(null, got); + } + else { + cb(); + } + }); + }; + + this.processRowsAndDiff(table, testRow, callback); + }); + }); + + this.When(/^I request nearest with flatbuffers I should get$/, (table, callback) => { + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + var testRow = (row, ri, cb) => { + var inNode = this.findNodeByName(row.in); + if (!inNode) throw new Error(util.format('*** unknown in-node "%s"', row.in)); + + var outNode = this.findNodeByName(row.out); + if (!outNode) throw new Error(util.format('*** unknown out-node "%s"', row.out)); + + this.queryParams.output = 'flatbuffers'; + this.requestNearest(inNode, this.queryParams, (err, response) => { + if (err) return cb(err); + var coord; + + if (response.statusCode === 200 && response.body.length) { + var body = response.body; + var bytes = new Uint8Array(body.length); + for (var indx = 0; indx < body.length; ++indx) { + bytes[indx] = body.charCodeAt(indx); + } + var buf = new flatbuffers.ByteBuffer(bytes); + var fb = FBResult.getRootAsFBResult(buf); + var location = fb.waypoints(0).location(); + + coord = [location.longitude(), location.latitude()]; + + var got = { in: row.in, out: row.out }; + Object.keys(row).forEach((key) => { if (key === 'out') { if (this.FuzzyMatch.matchLocation(coord, outNode)) { diff --git a/features/step_definitions/options.js b/features/step_definitions/options.js index d16ef8d0c..79cb10e9a 100644 --- a/features/step_definitions/options.js +++ b/features/step_definitions/options.js @@ -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); @@ -54,12 +54,14 @@ 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); + assert.ok(typeof not === 'undefined' ? contains : !contains, + '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); + assert.ok(typeof not === 'undefined' ? contains : !contains, + 'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"'); }); this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => { diff --git a/features/step_definitions/requests.js b/features/step_definitions/requests.js index 36eef830b..a16e24a4e 100644 --- a/features/step_definitions/requests.js +++ b/features/step_definitions/requests.js @@ -4,7 +4,7 @@ module.exports = function () { this.When(/^I request \/(.*)$/, (path, callback) => { this.reprocessAndLoadData((e) => { if (e) return callback(e); - this.requestPath(path, {}, (err, res, body) => { + this.requestUrl(path, (err, res, body) => { this.response = res; callback(err, res, body); }); @@ -23,13 +23,13 @@ module.exports = function () { this.ShouldBeWellFormed(); }); - this.Then(/^status code should be (\d+)$/, (code, callback) => { + this.Then(/^status code should be (.+)$/, (code, callback) => { try { this.json = JSON.parse(this.response.body); } catch(e) { return callback(e); } - assert.equal(this.json.status, parseInt(code)); + assert.equal(this.json.code, code); callback(); }); @@ -55,4 +55,4 @@ module.exports = function () { assert.equal(this.processError.process, binary); assert.equal(parseInt(this.processError.code), parseInt(code)); }); -}; +}; \ No newline at end of file diff --git a/features/step_definitions/routability.js b/features/step_definitions/routability.js index 36929ff98..7c9c55d8f 100644 --- a/features/step_definitions/routability.js +++ b/features/step_definitions/routability.js @@ -1,6 +1,6 @@ -var util = require('util'); -var d3 = require('d3-queue'); -var classes = require('../support/data_classes'); +const util = require('util'); +const d3 = require('d3-queue'); +const classes = require('../support/data_classes'); module.exports = function () { this.Then(/^routability should be$/, (table, callback) => { @@ -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 @@ -115,8 +115,11 @@ module.exports = function () { var result = {}; var testDirection = (dir, callback) => { - var a = new classes.Location(this.origin[0] + (1+this.WAY_SPACING*i) * this.zoom, this.origin[1]), - b = new classes.Location(this.origin[0] + (3+this.WAY_SPACING*i) * this.zoom, this.origin[1]), + const coordA = this.offsetOriginBy(1+this.WAY_SPACING*i, 0); + const coordB = this.offsetOriginBy(3+this.WAY_SPACING*i, 0); + + var a = new classes.Location(coordA[0], coordA[1]), + b = new classes.Location(coordB[0], coordB[1]), r = {}; r.which = dir; diff --git a/features/step_definitions/routing.js b/features/step_definitions/routing.js index c3e679aa5..136add5ef 100644 --- a/features/step_definitions/routing.js +++ b/features/step_definitions/routing.js @@ -12,4 +12,9 @@ module.exports = function () { q.awaitAll(callback); }); + + this.Given(/^skip waypoints$/, (callback) => { + this.queryParams['skip_waypoints'] = true; + callback(); + }); }; diff --git a/features/step_definitions/trip.js b/features/step_definitions/trip.js index e72044018..0efbc2259 100644 --- a/features/step_definitions/trip.js +++ b/features/step_definitions/trip.js @@ -43,6 +43,10 @@ module.exports = function () { got.message = json.message; } + if (headers.has('data_version')) { + got.data_version = json.data_version || ''; + } + if (headers.has('geometry')) { if (this.queryParams['geometries'] === 'polyline') { got.geometry = polyline.decode(json.trips[0].geometry).toString(); @@ -61,7 +65,8 @@ module.exports = function () { var subTrips; var trip_durations; var trip_distance; - if (res.statusCode === 200) { + var ok = res.statusCode === 200; + if (ok) { if (headers.has('trips')) { subTrips = json.trips.filter(t => !!t).map(t => t.legs).map(tl => Array.prototype.concat.apply([], tl.map((sl, i) => { var toAdd = []; @@ -84,8 +89,7 @@ module.exports = function () { } } - var ok = true, - encodedResult = ''; + var encodedResult = ''; if (json.trips) row.trips.split(',').forEach((sub, si) => { if (si >= subTrips.length) { diff --git a/features/stress/large_request.feature b/features/stress/large_request.feature new file mode 100644 index 000000000..2211d6cce --- /dev/null +++ b/features/stress/large_request.feature @@ -0,0 +1,39 @@ +Feature: Large requests + Background: + Given the profile "testbot" + Scenario: Table request with a lot of input coordinates + Given the origin 10.90761,47.54966 + Given the node map + """ + a b c d e f g h i j k l m n o p q r s t u v w x y z + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + | de | + | ef | + | fg | + | gh | + | hi | + | ij | + | jk | + | kl | + | lm | + | mn | + | no | + | op | + | pq | + | qr | + | rs | + | st | + | tu | + | uv | + | vw | + | wx | + | xy | + | yz | + When I request /table/v1/driving/10.90761,47.54966;11.93966,47.81606;11.08894,48.62424;11.62135,47.48357;11.5487,47.49729;11.45756,48.03065;11.23334,47.89373;10.88259,47.54795;11.4702,49.52285;11.62638,48.46008;11.98631,49.03973;11.92384,48.65348;11.52325,47.88653;11.56097,48.51048;11.08578,48.77129;11.96313,49.79663;11.7655,49.68107;10.74547,48.18696;11.35802,47.92084;11.31547,47.75373;11.29578,47.63577;11.22657,48.50509;11.31266,48.20597;11.11292,49.30903;10.91056,48.85395;11.01956,47.91374;10.63385,47.91534;11.37957,48.89772;11.23514,47.60342;11.00552,49.66307;11.09602,49.06538;10.58208,49.7129;11.08048,47.95764;10.66334,49.54911;11.99811,47.51836;11.06729,48.93516;11.51662,47.72612;11.3375,49.24294;11.90311,48.68334;11.92122,48.35409;10.87577,49.49948;11.21114,49.42086;10.87195,47.84828;10.98919,49.75728;10.6987,49.77116;11.97602,49.18479;11.94726,48.55827;10.87772,48.65176;10.52576,49.85704;10.6882,47.7531;11.05737,48.99173;11.85929,48.19158;10.84597,49.55252;11.32428,49.21267;11.3375,48.10871;11.01082,48.01289;10.7295,47.94004;11.23957,47.46262;11.80514,48.69129;11.33402,48.81084;11.42753,49.18682;10.86449,48.93515;11.28717,47.7437;11.25911,47.73088;11.18528,48.51873;11.47802,48.44734;11.84338,49.19166;11.23232,49.73384;11.73743,49.92189;10.81741,48.85105;11.96345,49.52129;11.19351,48.71871;11.64791,47.78599;11.56445,48.27622;10.86725,47.86015;10.9428,48.51327;10.84549,48.9471;11.09816,49.28497;11.33345,47.56826;11.06624,47.50943;10.83086,49.66004;10.99761,48.44961;11.1311,49.73714;11.22288,47.52466;11.57479,49.61386;10.55757,47.50472;11.35294,49.75207;11.62176,49.48058;10.69253,49.30151;11.74453,49.66988;10.73915,49.06721;10.66147,47.60705;11.96606,47.62438;11.90213,47.5219;11.23404,47.52766;10.7231,47.87407;11.84783,48.3516;11.84069,48.9192;11.58223,48.65717;10.61954,49.0955;11.88673,49.56121;11.07369,48.32443;11.96949,48.52898;11.30511,48.88208;11.87258,47.91028;11.73445,47.52629;11.63164,49.20231;10.793,49.60652;11.24185,49.92677;10.98617,49.14844;11.01802,49.40513;11.05101,48.06117;11.31047,47.69413;11.07766,49.93023;10.65685,49.11901;10.60773,49.41996;10.95122,48.79153;11.4117,49.4951;11.69883,49.37566;11.82451,49.80235;11.89671,48.40329;11.11972,48.73538;10.57045,49.41698;10.74612,49.68198;11.7765,48.09569;11.04161,49.8671;10.95917,49.12747;10.91793,47.97454;10.54507,48.82384;10.57876,48.75478;10.76263,49.23102;11.33573,47.86198;11.17414,47.88678;11.65555,49.99393;10.77196,49.83992;11.31043,48.56057;10.94094,49.59839;11.92389,49.34819;11.48685,47.73434;11.46912,48.12031;11.34077,49.13553;11.00964,48.8761;11.44085,47.5319;10.52021,49.26626;11.9019,47.65143;11.51561,49.35583;10.52268,48.85212;10.86347,48.31117;11.25467,49.7146;10.52205,48.27031;11.60986,49.48577;11.68148,49.72743;11.75741,49.81563;11.05122,49.80071;11.94883,49.63083;11.02932,48.14442;11.78529,47.96527;11.23927,49.0946;11.18084,48.08152;10.53525,48.98016;10.80783,47.72982;10.81771,47.8415;11.88089,48.06763;10.75608,49.00451;11.09311,48.08249;10.70716,49.44809;10.78888,48.51296;10.95841,49.54797;10.88098,47.45088;10.98406,49.38162;11.51657,48.7231;11.15303,49.65487;10.72106,47.63585;11.87195,48.92029;11.96055,48.30037;11.86625,48.04542;10.74646,48.1694;11.29419,49.29692;11.77349,48.38297;11.61929,49.81509;10.50075,48.2405;11.60097,47.89965;11.68649,48.05119;11.81297,49.76957;10.95531,47.60711;11.99713,48.16887;11.93346,48.57039;11.47905,49.24811;11.10927,49.67728;10.6618,48.28644;11.54246,47.59938;11.51245,49.08808;10.61251,47.46968;10.85949,48.89206;11.05734,47.81972;11.46352,47.90034;11.86184,49.53277;10.95108,49.1559;10.90376,47.7312;11.13149,48.87966;11.84491,49.03545;11.33474,48.39079;10.84499,48.69141;10.67208,49.11536;11.1539,49.54286;10.64563,48.82016;11.53696,48.23053;11.98903,49.80495;10.72386,47.45824;11.23699,48.72638;11.63742,49.29705;11.5438,49.42475;10.78755,47.52848;11.7802,47.56707;11.4288,49.54467;10.74564,49.96728;11.20549,49.71876;11.65907,48.62485;11.39492,49.18665;11.09157,48.06504;10.99312,49.61296;11.89019,48.55865;10.8119,48.04861;11.36204,48.5806;10.91501,49.12398;11.17399,48.48726;11.04085,47.92358;11.06903,48.0575;10.73976,48.30711;11.93584,49.70889;10.5968,47.72353;11.52694,49.55474;10.81782,49.40075;11.84217,48.03225;11.22768,47.98959;10.6082,49.22826;11.46862,49.02127;11.33829,48.41548;11.71223,49.19104;11.41975,48.94869;11.61803,48.96822;10.50347,47.48205;11.60651,49.06259;11.35187,47.93713;10.76661,49.42307;11.86695,49.74779;10.83986,48.57656;10.551,48.90838;11.76523,47.57251;10.55009,49.54098;11.88052,49.85604;11.83511,48.13701;11.22141,49.58347;11.56253,49.80543;11.78782,49.46533;11.57083,49.1185;10.76972,47.67795;10.88535,48.09409;11.93944,48.10515;11.67993,49.27536;11.5906,48.76538;10.63163,48.23638;11.88353,48.85089;11.7295,49.08962;10.63416,49.89273;10.72741,49.7831;11.01236,49.67462;11.04184,49.25215;11.95828,47.93858;11.22746,49.47516;11.97998,49.69944;11.75393,48.84457;11.7618,47.4792;11.51812,48.29168;11.71144,47.66958;11.6494,47.89514;11.84211,49.2127;11.34524,48.6433;10.77714,47.89613;11.40105,47.87601;11.60605,47.89686;10.88092,48.80947;11.97652,49.47796;11.33343,48.80368;11.79732,48.53003;11.55873,49.8888;11.05606,47.59527;11.93572,48.82335;11.65693,49.40953;11.78328,48.46995;11.39285,49.37936;10.84134,47.63308;11.95604,48.11911;11.18343,47.93176;11.95007,48.46438;11.50128,49.25897;11.70257,48.32708;11.79472,49.3613;11.96752,47.99815;11.69199,49.0501;11.12854,49.49936;10.78246,49.26896;11.60707,48.32754;10.65964,49.35687;11.44447,48.32026;11.60625,49.76655;10.74575,49.28163;10.89368,47.58725;11.90005,48.35195;11.95757,48.26339;11.89691,49.36058;10.50237,47.45156;11.29258,47.56293;11.26933,48.4134;11.25534,49.5038;10.92052,49.53341;11.63137,49.01404;11.13264,49.12652;11.30996,48.12275;11.3125,49.31107;11.18353,48.68894;10.52496,48.60723;11.5545,48.01744;11.28575,49.18151;10.60623,47.51181;11.82353,48.54418;10.51634,48.6607;10.54879,48.65214;11.90644,49.8917;11.32017,49.96297;11.01123,49.2065;10.50854,49.59417;10.95013,47.6372;10.73682,49.61629;11.64592,49.94222;11.45368,48.44183;10.64348,48.73343;11.57665,48.77333;11.66549,48.91217;10.71938,47.49757;11.12204,47.53107;10.91103,49.56696;11.95834,47.61315;10.61409,49.36993;11.10758,48.16737;11.19082,49.90288;11.44083,48.99006;11.13477,48.51637;10.95816,48.25012;10.55454,49.99526;10.76371,49.07832;11.60491,48.7684;11.14329,47.5639;11.76087,48.28423;11.06633,48.71908;10.63479,49.07467;11.11831,47.63672;10.51461,49.97606;11.79856,47.51325;11.60394,47.54465;11.78364,49.20929;10.99021,47.92171;10.54795,49.69804;11.9299,49.29828;10.74526,49.44884;10.79157,48.52783;10.73713,49.77397;11.61066,48.41798;11.24592,49.46019;11.33682,49.80602;11.18163,49.94106;10.99738,49.86443;11.29373,47.8579;10.71569,47.74042;10.66168,48.85985;10.88105,49.04741;11.95581,49.23316;11.15938,49.25041;11.75631,47.92095;11.66879,49.83568;11.19202,47.87232;11.26559,49.71521;11.28089,49.76687;10.68274,47.54061;10.6705,48.7493;11.11543,49.90564;11.31847,47.9317;10.98724,49.44027;10.58021,49.00669;10.65988,47.61622;11.74486,48.46057;10.53387,48.56251;11.87333,48.81495;11.86938,48.84568;11.17144,49.90105;11.96628,48.80487;11.3636,47.6345;10.80856,48.00151;11.95887,48.42017;10.84812,49.93127;11.57792,49.40493;11.24702,48.58841;10.53697,49.99427;11.55126,47.45923;11.76386,49.58956;10.72076,48.66803;11.69896,49.06466;10.87897,48.73902;11.7625,48.90216;11.41714,49.13881;10.86463,47.94817;10.84486,49.10723;11.32144,48.12671;11.72769,47.69392;10.95778,48.65459;10.7602,48.44322;11.32139,49.3135;10.75378,47.71793;11.75266,49.04782;10.64936,49.16888;11.02814,47.82052;11.67243,49.14524;10.50856,48.8563;11.35956,48.54955;10.51606,49.55741;11.73378,48.37489;11.71308,49.39755;11.36699,47.45139;10.53954,47.96051;10.8803,49.53059;11.97025,49.07966;10.71181,48.53344;11.48929,47.88551;10.78747,49.25704;11.10914,49.89777;11.66374,48.79059;11.69725,47.89964;10.65969,49.30469;11.01374,48.55548;11.85932,47.67318;11.77681,48.82834;11.91272,48.76547;11.57922,49.2744;10.52352,47.58819;11.44351,49.98144;10.8438,48.29292;11.0613,49.23531;11.75374,47.77367;10.68599,48.88375;10.8381,48.89306;11.78983,48.57816;10.86193,47.86047;11.57646,48.46316;11.6558,48.6255;11.31754,48.56296;10.69917,47.52159;11.48864,47.93436;11.14443,49.34194;10.66421,48.15455;11.69012,49.71597;10.92805,49.39795;10.98026,48.62985;10.63252,49.95795;11.37468,48.32383;11.89213,49.41892;11.39476,48.36131;10.61696,47.97164;11.50761,48.21042;11.31284,48.29539;10.87814,48.67741;10.59776,49.1498;11.17827,48.8733;11.6018,49.45914;10.73621,49.5317;11.38794,49.0252;11.40146,49.55482;10.57116,48.86615;11.89119,48.7372;11.33492,47.66424;11.61472,49.9513;11.63065,48.67025;11.15378,48.6575;11.31485,47.94025;10.55891,47.48489;11.80567,49.04565;10.74453,49.99566;10.74512,47.61681;10.91615,48.93038;11.03106,49.41157;11.66623,48.85904;10.63791,47.50966;11.38506,47.85158;11.82981,48.99957;11.20183,48.28544;11.53728,49.93828;10.84794,49.48396;11.99693,48.55948;11.37453,48.06193;10.79992,48.12021;11.85343,48.03751?generate_hints=false&sources=0&destinations=all&skip_waypoints=true + Then status code should be Ok \ No newline at end of file diff --git a/features/support/cache.js b/features/support/cache.js index 96a81404d..ccf6a8568 100644 --- a/features/support/cache.js +++ b/features/support/cache.js @@ -28,13 +28,16 @@ module.exports = function() { let uri = feature.getUri(); // setup cache for feature data - hash.hashOfFile(uri, (err, hash) => { + // if OSRM_PROFILE is set to force a specific profile, then + // include the profile name in the hash of the profile file + hash.hashOfFile(uri, this.OSRM_PROFILE, (err, hash) => { if (err) return callback(err); // shorten uri to be realtive to 'features/' let featurePath = path.relative(path.resolve('./features'), uri); // bicycle/bollards/{HASH}/ let featureID = path.join(featurePath, hash); + let featureCacheDirectory = this.getFeatureCacheDirectory(featureID); let featureProcessedCacheDirectory = this.getFeatureProcessedCacheDirectory(featureCacheDirectory, this.osrmHash); this.featureIDs[uri] = featureID; @@ -42,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); }); } @@ -84,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); }); }; @@ -111,8 +114,12 @@ module.exports = function() { let dependencies = [ this.OSRM_EXTRACT_PATH, this.OSRM_CONTRACT_PATH, + this.OSRM_CUSTOMIZE_PATH, + this.OSRM_PARTITION_PATH, this.LIB_OSRM_EXTRACT_PATH, - this.LIB_OSRM_CONTRACT_PATH + this.LIB_OSRM_CONTRACT_PATH, + this.LIB_OSRM_CUSTOMIZE_PATH, + this.LIB_OSRM_PARTITION_PATH ]; var addLuaFiles = (directory, callback) => { @@ -141,7 +148,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); diff --git a/features/support/data.js b/features/support/data.js index 2a5deb479..6dd5fc545 100644 --- a/features/support/data.js +++ b/features/support/data.js @@ -9,17 +9,27 @@ const classes = require('./data_classes'); const tableDiff = require('../lib/table_diff'); const ensureDecimal = require('../lib/utils').ensureDecimal; const errorReason = require('../lib/utils').errorReason; +const CheapRuler = require('cheap-ruler'); module.exports = function () { this.setGridSize = (meters) => { + this.gridSize = parseFloat(meters); + // the constant is calculated (with BigDecimal as: 1.0/(DEG_TO_RAD*EARTH_RADIUS_IN_METERS // see ApproximateDistance() in ExtractorStructs.h // it's only accurate when measuring along the equator, or going exactly north-south - this.zoom = parseFloat(meters) * 0.8990679362704610899694577444566908445396483347536032203503E-5; + this.zoom = this.gridSize * 0.8990679362704610899694577444566908445396483347536032203503E-5; }; this.setOrigin = (origin) => { this.origin = origin; + // we use C++ version of `cheap-ruler` inside OSRM in order to do distance calculations, + // so here we use it too to have a bit more precise assertions + this.ruler = new CheapRuler(this.origin[1], 'meters'); + }; + + this.offsetOriginBy = (xCells, yCells) => { + return this.ruler.offset(this.origin, xCells * this.gridSize, yCells * this.gridSize); }; this.buildWaysFromTable = (table, callback) => { @@ -35,9 +45,10 @@ module.exports = function () { // add some nodes var makeFakeNode = (namePrefix, offset) => { + const coord = this.offsetOriginBy(offset + this.WAY_SPACING * ri, 0); return new OSM.Node(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, - this.OSM_UID, this.origin[0]+(offset + this.WAY_SPACING * ri) * this.zoom, - this.origin[1], {name: util.format('%s%d', namePrefix, ri)}); + this.OSM_UID, coord[0], + coord[1], {name: util.format('%s%d', namePrefix, ri)}); }; var nodes = ['a','b','c','d','e'].map((l, i) => makeFakeNode(l, i)); @@ -98,7 +109,7 @@ module.exports = function () { }; this.tableCoordToLonLat = (ci, ri) => { - return [this.origin[0] + ci * this.zoom, this.origin[1] - ri * this.zoom].map(ensureDecimal); + return this.offsetOriginBy(ci, -ri).map(ensureDecimal); }; this.addOSMNode = (name, lon, lat, id) => { @@ -144,6 +155,10 @@ module.exports = function () { return this.nameWayHash[s.toString()] || this.nameWayHash[s.toString().split('').reverse().join('')]; }; + this.findRelationByName = (s) => { + return this.nameRelationHash[s.toString()] || this.nameRelationHash[s.toString().split('').reverse().join('')]; + }; + this.makeOSMId = () => { this.osmID = this.osmID + 1; return this.osmID; @@ -155,6 +170,7 @@ module.exports = function () { this.locationHash = {}; this.shortcutsHash = {}; this.nameWayHash = {}; + this.nameRelationHash = {}; this.osmID = 0; }; diff --git a/features/support/data_classes.js b/features/support/data_classes.js index 5aced6c3b..53003bb9f 100644 --- a/features/support/data_classes.js +++ b/features/support/data_classes.js @@ -12,12 +12,17 @@ module.exports = { FuzzyMatch: class { match (got, want) { + // don't fail if bearings input and extected string is empty and actual result is undefined + if (want === '' && (got === '' || got === undefined)) + 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, @@ -26,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) { @@ -101,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; } diff --git a/features/support/env.js b/features/support/env.js index 5947afffa..eaa25fbc5 100644 --- a/features/support/env.js +++ b/features/support/env.js @@ -22,16 +22,12 @@ module.exports = function () { this.PROFILES_PATH = path.resolve(this.ROOT_PATH, 'profiles'); this.FIXTURES_PATH = path.resolve(this.ROOT_PATH, 'unit_tests/fixtures'); this.BIN_PATH = process.env.OSRM_BUILD_DIR && process.env.OSRM_BUILD_DIR || path.resolve(this.ROOT_PATH, 'build'); - var stxxl_config = path.resolve(this.ROOT_PATH, 'test/.stxxl'); - if (!fs.existsSync(stxxl_config)) { - return callback(new Error('*** '+stxxl_config+ 'does not exist')); - } - + this.DATASET_NAME = 'cucumber'; this.PLATFORM_WINDOWS = process.platform.match(/^win.*/); - this.DEFAULT_ENVIRONMENT = Object.assign({STXXLCFG: stxxl_config}, process.env); + this.DEFAULT_ENVIRONMENT = 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; @@ -43,7 +39,13 @@ module.exports = function () { this.TIMEZONE_NAMES = this.PLATFORM_WINDOWS ? 'win' : 'iana'; this.OSRM_PORT = process.env.OSRM_PORT && parseInt(process.env.OSRM_PORT) || 5000; - this.HOST = 'http://127.0.0.1:' + this.OSRM_PORT; + this.OSRM_IP = process.env.OSRM_IP || '127.0.0.1'; + this.OSRM_CONNECTION_RETRIES = process.env.OSRM_CONNECTION_RETRIES && parseInt(process.env.OSRM_CONNECTION_RETRIES) || 10; + this.OSRM_CONNECTION_EXP_BACKOFF_COEF = process.env.OSRM_CONNECTION_EXP_BACKOFF_COEF && parseFloat(process.env.OSRM_CONNECTION_EXP_BACKOFF_COEF) || 1.0; + + this.HOST = `http://${this.OSRM_IP}:${this.OSRM_PORT}`; + + this.OSRM_PROFILE = process.env.OSRM_PROFILE; if (this.PLATFORM_WINDOWS) { this.TERMSIGNAL = 9; @@ -68,14 +70,18 @@ module.exports = function () { this.OSRM_EXTRACT_PATH = path.resolve(util.format('%s/%s%s', this.BIN_PATH, 'osrm-extract', this.EXE)); this.OSRM_CONTRACT_PATH = path.resolve(util.format('%s/%s%s', this.BIN_PATH, 'osrm-contract', this.EXE)); + this.OSRM_CUSTOMIZE_PATH = path.resolve(util.format('%s/%s%s', this.BIN_PATH, 'osrm-customize', this.EXE)); + this.OSRM_PARTITION_PATH = path.resolve(util.format('%s/%s%s', this.BIN_PATH, 'osrm-partition', this.EXE)); this.OSRM_ROUTED_PATH = path.resolve(util.format('%s/%s%s', this.BIN_PATH, 'osrm-routed', this.EXE)); this.LIB_OSRM_EXTRACT_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_extract'), this.LIB_OSRM_CONTRACT_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_contract'), + this.LIB_OSRM_CUSTOMIZE_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_customize'), + this.LIB_OSRM_PARTITION_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_partition'), this.LIB_OSRM_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm'); // 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) @@ -90,7 +96,7 @@ module.exports = function () { }; this.verifyOSRMIsNotRunning = (callback) => { - tryConnect(this.OSRM_PORT, (err) => { + tryConnect(this.OSRM_IP, this.OSRM_PORT, (err) => { if (!err) return callback(new Error('*** osrm-routed is already running.')); else callback(); }); @@ -111,7 +117,7 @@ module.exports = function () { }; var q = d3.queue(); - [this.OSRM_EXTRACT_PATH, this.OSRM_CONTRACT_PATH, this.OSRM_ROUTED_PATH].forEach(bin => { q.defer(verify, bin); }); + [this.OSRM_EXTRACT_PATH, this.OSRM_CONTRACT_PATH, this.OSRM_CUSTOMIZE_PATH, this.OSRM_PARTITION_PATH, this.OSRM_ROUTED_PATH].forEach(bin => { q.defer(verify, bin); }); q.awaitAll(callback); }; diff --git a/features/support/fbresult_generated.js b/features/support/fbresult_generated.js new file mode 100644 index 000000000..d418e1bc4 --- /dev/null +++ b/features/support/fbresult_generated.js @@ -0,0 +1,3217 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/** + * @const + * @namespace + */ +var osrm = osrm || {}; + +/** + * @const + * @namespace + */ +osrm.engine = osrm.engine || {}; + +/** + * @const + * @namespace + */ +osrm.engine.api = osrm.engine.api || {}; + +/** + * @const + * @namespace + */ +osrm.engine.api.fbresult = osrm.engine.api.fbresult || {}; + +/** + * @enum {number} + */ +osrm.engine.api.fbresult.ManeuverType = { + Turn: 0, + NewName: 1, + Depart: 2, + Arrive: 3, + Merge: 4, + OnRamp: 5, + OffRamp: 6, + Fork: 7, + EndOfRoad: 8, + Continue: 9, + Roundabout: 10, + Rotary: 11, + RoundaboutTurn: 12, + Notification: 13, + ExitRoundabout: 14, + ExitRotary: 15 +}; + +/** + * @enum {string} + */ +osrm.engine.api.fbresult.ManeuverTypeName = { + 0: 'Turn', + 1: 'NewName', + 2: 'Depart', + 3: 'Arrive', + 4: 'Merge', + 5: 'OnRamp', + 6: 'OffRamp', + 7: 'Fork', + 8: 'EndOfRoad', + 9: 'Continue', + 10: 'Roundabout', + 11: 'Rotary', + 12: 'RoundaboutTurn', + 13: 'Notification', + 14: 'ExitRoundabout', + 15: 'ExitRotary' +}; + +/** + * @enum {number} + */ +osrm.engine.api.fbresult.Turn = { + None: 0, + UTurn: 1, + SharpRight: 2, + Right: 3, + SlightRight: 4, + Straight: 5, + SlightLeft: 6, + Left: 7, + SharpLeft: 8 +}; + +/** + * @enum {string} + */ +osrm.engine.api.fbresult.TurnName = { + 0: 'None', + 1: 'UTurn', + 2: 'SharpRight', + 3: 'Right', + 4: 'SlightRight', + 5: 'Straight', + 6: 'SlightLeft', + 7: 'Left', + 8: 'SharpLeft' +}; + +/** + * @constructor + */ +osrm.engine.api.fbresult.Position = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Position} + */ +osrm.engine.api.fbresult.Position.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Position.prototype.longitude = function() { + return this.bb.readFloat32(this.bb_pos); +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Position.prototype.latitude = function() { + return this.bb.readFloat32(this.bb_pos + 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} longitude + * @param {number} latitude + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Position.createPosition = function(builder, longitude, latitude) { + builder.prep(4, 8); + builder.writeFloat32(latitude); + builder.writeFloat32(longitude); + return builder.offset(); +}; + +/** + * @constructor + */ +osrm.engine.api.fbresult.Uint64Pair = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Uint64Pair} + */ +osrm.engine.api.fbresult.Uint64Pair.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @returns {flatbuffers.Long} + */ +osrm.engine.api.fbresult.Uint64Pair.prototype.first = function() { + return this.bb.readUint64(this.bb_pos); +}; + +/** + * @returns {flatbuffers.Long} + */ +osrm.engine.api.fbresult.Uint64Pair.prototype.second = function() { + return this.bb.readUint64(this.bb_pos + 8); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Long} first + * @param {flatbuffers.Long} second + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Uint64Pair.createUint64Pair = function(builder, first, second) { + builder.prep(8, 16); + builder.writeInt64(second); + builder.writeInt64(first); + return builder.offset(); +}; + +/** + * @constructor + */ +osrm.engine.api.fbresult.Waypoint = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Waypoint} + */ +osrm.engine.api.fbresult.Waypoint.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Waypoint=} obj + * @returns {osrm.engine.api.fbresult.Waypoint} + */ +osrm.engine.api.fbresult.Waypoint.getRootAsWaypoint = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Waypoint).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Waypoint=} obj + * @returns {osrm.engine.api.fbresult.Waypoint} + */ +osrm.engine.api.fbresult.Waypoint.getSizePrefixedRootAsWaypoint = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Waypoint).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Waypoint.prototype.hint = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Waypoint.prototype.distance = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Waypoint.prototype.name = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {osrm.engine.api.fbresult.Position=} obj + * @returns {osrm.engine.api.fbresult.Position|null} + */ +osrm.engine.api.fbresult.Waypoint.prototype.location = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? (obj || new osrm.engine.api.fbresult.Position).__init(this.bb_pos + offset, this.bb) : null; +}; + +/** + * @param {osrm.engine.api.fbresult.Uint64Pair=} obj + * @returns {osrm.engine.api.fbresult.Uint64Pair|null} + */ +osrm.engine.api.fbresult.Waypoint.prototype.nodes = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? (obj || new osrm.engine.api.fbresult.Uint64Pair).__init(this.bb_pos + offset, this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Waypoint.prototype.matchingsIndex = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Waypoint.prototype.waypointIndex = function() { + var offset = this.bb.__offset(this.bb_pos, 16); + return offset ? this.bb.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Waypoint.prototype.alternativesCount = function() { + var offset = this.bb.__offset(this.bb_pos, 18); + return offset ? this.bb.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Waypoint.prototype.tripsIndex = function() { + var offset = this.bb.__offset(this.bb_pos, 20); + return offset ? this.bb.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Waypoint.startWaypoint = function(builder) { + builder.startObject(9); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} hintOffset + */ +osrm.engine.api.fbresult.Waypoint.addHint = function(builder, hintOffset) { + builder.addFieldOffset(0, hintOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} distance + */ +osrm.engine.api.fbresult.Waypoint.addDistance = function(builder, distance) { + builder.addFieldFloat32(1, distance, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} nameOffset + */ +osrm.engine.api.fbresult.Waypoint.addName = function(builder, nameOffset) { + builder.addFieldOffset(2, nameOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} locationOffset + */ +osrm.engine.api.fbresult.Waypoint.addLocation = function(builder, locationOffset) { + builder.addFieldStruct(3, locationOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} nodesOffset + */ +osrm.engine.api.fbresult.Waypoint.addNodes = function(builder, nodesOffset) { + builder.addFieldStruct(4, nodesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} matchingsIndex + */ +osrm.engine.api.fbresult.Waypoint.addMatchingsIndex = function(builder, matchingsIndex) { + builder.addFieldInt32(5, matchingsIndex, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} waypointIndex + */ +osrm.engine.api.fbresult.Waypoint.addWaypointIndex = function(builder, waypointIndex) { + builder.addFieldInt32(6, waypointIndex, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} alternativesCount + */ +osrm.engine.api.fbresult.Waypoint.addAlternativesCount = function(builder, alternativesCount) { + builder.addFieldInt32(7, alternativesCount, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} tripsIndex + */ +osrm.engine.api.fbresult.Waypoint.addTripsIndex = function(builder, tripsIndex) { + builder.addFieldInt32(8, tripsIndex, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Waypoint.endWaypoint = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} hintOffset + * @param {number} distance + * @param {flatbuffers.Offset} nameOffset + * @param {flatbuffers.Offset} locationOffset + * @param {flatbuffers.Offset} nodesOffset + * @param {number} matchingsIndex + * @param {number} waypointIndex + * @param {number} alternativesCount + * @param {number} tripsIndex + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Waypoint.createWaypoint = function(builder, hintOffset, distance, nameOffset, locationOffset, nodesOffset, matchingsIndex, waypointIndex, alternativesCount, tripsIndex) { + osrm.engine.api.fbresult.Waypoint.startWaypoint(builder); + osrm.engine.api.fbresult.Waypoint.addHint(builder, hintOffset); + osrm.engine.api.fbresult.Waypoint.addDistance(builder, distance); + osrm.engine.api.fbresult.Waypoint.addName(builder, nameOffset); + osrm.engine.api.fbresult.Waypoint.addLocation(builder, locationOffset); + osrm.engine.api.fbresult.Waypoint.addNodes(builder, nodesOffset); + osrm.engine.api.fbresult.Waypoint.addMatchingsIndex(builder, matchingsIndex); + osrm.engine.api.fbresult.Waypoint.addWaypointIndex(builder, waypointIndex); + osrm.engine.api.fbresult.Waypoint.addAlternativesCount(builder, alternativesCount); + osrm.engine.api.fbresult.Waypoint.addTripsIndex(builder, tripsIndex); + return osrm.engine.api.fbresult.Waypoint.endWaypoint(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.Metadata = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Metadata} + */ +osrm.engine.api.fbresult.Metadata.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Metadata=} obj + * @returns {osrm.engine.api.fbresult.Metadata} + */ +osrm.engine.api.fbresult.Metadata.getRootAsMetadata = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Metadata).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Metadata=} obj + * @returns {osrm.engine.api.fbresult.Metadata} + */ +osrm.engine.api.fbresult.Metadata.getSizePrefixedRootAsMetadata = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Metadata).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {number} index + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array} + */ +osrm.engine.api.fbresult.Metadata.prototype.datasourceNames = function(index, optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Metadata.prototype.datasourceNamesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Metadata.startMetadata = function(builder) { + builder.startObject(1); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} datasourceNamesOffset + */ +osrm.engine.api.fbresult.Metadata.addDatasourceNames = function(builder, datasourceNamesOffset) { + builder.addFieldOffset(0, datasourceNamesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Metadata.createDatasourceNamesVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Metadata.startDatasourceNamesVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Metadata.endMetadata = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} datasourceNamesOffset + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Metadata.createMetadata = function(builder, datasourceNamesOffset) { + osrm.engine.api.fbresult.Metadata.startMetadata(builder); + osrm.engine.api.fbresult.Metadata.addDatasourceNames(builder, datasourceNamesOffset); + return osrm.engine.api.fbresult.Metadata.endMetadata(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.Annotation = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Annotation} + */ +osrm.engine.api.fbresult.Annotation.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Annotation=} obj + * @returns {osrm.engine.api.fbresult.Annotation} + */ +osrm.engine.api.fbresult.Annotation.getRootAsAnnotation = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Annotation).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Annotation=} obj + * @returns {osrm.engine.api.fbresult.Annotation} + */ +osrm.engine.api.fbresult.Annotation.getSizePrefixedRootAsAnnotation = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Annotation).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.distance = function(index) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.readUint32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.distanceLength = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint32Array} + */ +osrm.engine.api.fbresult.Annotation.prototype.distanceArray = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? new Uint32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.duration = function(index) { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readUint32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.durationLength = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint32Array} + */ +osrm.engine.api.fbresult.Annotation.prototype.durationArray = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? new Uint32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.datasources = function(index) { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.readUint32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.datasourcesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint32Array} + */ +osrm.engine.api.fbresult.Annotation.prototype.datasourcesArray = function() { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? new Uint32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.nodes = function(index) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.readUint32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.nodesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint32Array} + */ +osrm.engine.api.fbresult.Annotation.prototype.nodesArray = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? new Uint32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.weight = function(index) { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? this.bb.readUint32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.weightLength = function() { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint32Array} + */ +osrm.engine.api.fbresult.Annotation.prototype.weightArray = function() { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? new Uint32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.speed = function(index) { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.readFloat32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Annotation.prototype.speedLength = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Float32Array} + */ +osrm.engine.api.fbresult.Annotation.prototype.speedArray = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? new Float32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {osrm.engine.api.fbresult.Metadata=} obj + * @returns {osrm.engine.api.fbresult.Metadata|null} + */ +osrm.engine.api.fbresult.Annotation.prototype.metadata = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 16); + return offset ? (obj || new osrm.engine.api.fbresult.Metadata).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Annotation.startAnnotation = function(builder) { + builder.startObject(7); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} distanceOffset + */ +osrm.engine.api.fbresult.Annotation.addDistance = function(builder, distanceOffset) { + builder.addFieldOffset(0, distanceOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Annotation.createDistanceVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Annotation.startDistanceVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} durationOffset + */ +osrm.engine.api.fbresult.Annotation.addDuration = function(builder, durationOffset) { + builder.addFieldOffset(1, durationOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Annotation.createDurationVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Annotation.startDurationVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} datasourcesOffset + */ +osrm.engine.api.fbresult.Annotation.addDatasources = function(builder, datasourcesOffset) { + builder.addFieldOffset(2, datasourcesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Annotation.createDatasourcesVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Annotation.startDatasourcesVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} nodesOffset + */ +osrm.engine.api.fbresult.Annotation.addNodes = function(builder, nodesOffset) { + builder.addFieldOffset(3, nodesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Annotation.createNodesVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Annotation.startNodesVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} weightOffset + */ +osrm.engine.api.fbresult.Annotation.addWeight = function(builder, weightOffset) { + builder.addFieldOffset(4, weightOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Annotation.createWeightVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Annotation.startWeightVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} speedOffset + */ +osrm.engine.api.fbresult.Annotation.addSpeed = function(builder, speedOffset) { + builder.addFieldOffset(5, speedOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Annotation.createSpeedVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addFloat32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Annotation.startSpeedVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} metadataOffset + */ +osrm.engine.api.fbresult.Annotation.addMetadata = function(builder, metadataOffset) { + builder.addFieldOffset(6, metadataOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Annotation.endAnnotation = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} distanceOffset + * @param {flatbuffers.Offset} durationOffset + * @param {flatbuffers.Offset} datasourcesOffset + * @param {flatbuffers.Offset} nodesOffset + * @param {flatbuffers.Offset} weightOffset + * @param {flatbuffers.Offset} speedOffset + * @param {flatbuffers.Offset} metadataOffset + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Annotation.createAnnotation = function(builder, distanceOffset, durationOffset, datasourcesOffset, nodesOffset, weightOffset, speedOffset, metadataOffset) { + osrm.engine.api.fbresult.Annotation.startAnnotation(builder); + osrm.engine.api.fbresult.Annotation.addDistance(builder, distanceOffset); + osrm.engine.api.fbresult.Annotation.addDuration(builder, durationOffset); + osrm.engine.api.fbresult.Annotation.addDatasources(builder, datasourcesOffset); + osrm.engine.api.fbresult.Annotation.addNodes(builder, nodesOffset); + osrm.engine.api.fbresult.Annotation.addWeight(builder, weightOffset); + osrm.engine.api.fbresult.Annotation.addSpeed(builder, speedOffset); + osrm.engine.api.fbresult.Annotation.addMetadata(builder, metadataOffset); + return osrm.engine.api.fbresult.Annotation.endAnnotation(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.StepManeuver = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.StepManeuver} + */ +osrm.engine.api.fbresult.StepManeuver.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.StepManeuver=} obj + * @returns {osrm.engine.api.fbresult.StepManeuver} + */ +osrm.engine.api.fbresult.StepManeuver.getRootAsStepManeuver = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.StepManeuver).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.StepManeuver=} obj + * @returns {osrm.engine.api.fbresult.StepManeuver} + */ +osrm.engine.api.fbresult.StepManeuver.getSizePrefixedRootAsStepManeuver = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.StepManeuver).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {osrm.engine.api.fbresult.Position=} obj + * @returns {osrm.engine.api.fbresult.Position|null} + */ +osrm.engine.api.fbresult.StepManeuver.prototype.location = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? (obj || new osrm.engine.api.fbresult.Position).__init(this.bb_pos + offset, this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.StepManeuver.prototype.bearingBefore = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readUint16(this.bb_pos + offset) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.StepManeuver.prototype.bearingAfter = function() { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.readUint16(this.bb_pos + offset) : 0; +}; + +/** + * @returns {osrm.engine.api.fbresult.ManeuverType} + */ +osrm.engine.api.fbresult.StepManeuver.prototype.type = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? /** @type {osrm.engine.api.fbresult.ManeuverType} */ (this.bb.readInt8(this.bb_pos + offset)) : osrm.engine.api.fbresult.ManeuverType.Turn; +}; + +/** + * @returns {osrm.engine.api.fbresult.Turn} + */ +osrm.engine.api.fbresult.StepManeuver.prototype.modifier = function() { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? /** @type {osrm.engine.api.fbresult.Turn} */ (this.bb.readInt8(this.bb_pos + offset)) : osrm.engine.api.fbresult.Turn.None; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.StepManeuver.prototype.exit = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.readUint8(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.StepManeuver.startStepManeuver = function(builder) { + builder.startObject(6); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} locationOffset + */ +osrm.engine.api.fbresult.StepManeuver.addLocation = function(builder, locationOffset) { + builder.addFieldStruct(0, locationOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} bearingBefore + */ +osrm.engine.api.fbresult.StepManeuver.addBearingBefore = function(builder, bearingBefore) { + builder.addFieldInt16(1, bearingBefore, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} bearingAfter + */ +osrm.engine.api.fbresult.StepManeuver.addBearingAfter = function(builder, bearingAfter) { + builder.addFieldInt16(2, bearingAfter, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {osrm.engine.api.fbresult.ManeuverType} type + */ +osrm.engine.api.fbresult.StepManeuver.addType = function(builder, type) { + builder.addFieldInt8(3, type, osrm.engine.api.fbresult.ManeuverType.Turn); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {osrm.engine.api.fbresult.Turn} modifier + */ +osrm.engine.api.fbresult.StepManeuver.addModifier = function(builder, modifier) { + builder.addFieldInt8(4, modifier, osrm.engine.api.fbresult.Turn.None); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} exit + */ +osrm.engine.api.fbresult.StepManeuver.addExit = function(builder, exit) { + builder.addFieldInt8(5, exit, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.StepManeuver.endStepManeuver = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} locationOffset + * @param {number} bearingBefore + * @param {number} bearingAfter + * @param {osrm.engine.api.fbresult.ManeuverType} type + * @param {osrm.engine.api.fbresult.Turn} modifier + * @param {number} exit + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.StepManeuver.createStepManeuver = function(builder, locationOffset, bearingBefore, bearingAfter, type, modifier, exit) { + osrm.engine.api.fbresult.StepManeuver.startStepManeuver(builder); + osrm.engine.api.fbresult.StepManeuver.addLocation(builder, locationOffset); + osrm.engine.api.fbresult.StepManeuver.addBearingBefore(builder, bearingBefore); + osrm.engine.api.fbresult.StepManeuver.addBearingAfter(builder, bearingAfter); + osrm.engine.api.fbresult.StepManeuver.addType(builder, type); + osrm.engine.api.fbresult.StepManeuver.addModifier(builder, modifier); + osrm.engine.api.fbresult.StepManeuver.addExit(builder, exit); + return osrm.engine.api.fbresult.StepManeuver.endStepManeuver(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.Lane = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Lane} + */ +osrm.engine.api.fbresult.Lane.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Lane=} obj + * @returns {osrm.engine.api.fbresult.Lane} + */ +osrm.engine.api.fbresult.Lane.getRootAsLane = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Lane).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Lane=} obj + * @returns {osrm.engine.api.fbresult.Lane} + */ +osrm.engine.api.fbresult.Lane.getSizePrefixedRootAsLane = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Lane).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {number} index + * @returns {osrm.engine.api.fbresult.Turn} + */ +osrm.engine.api.fbresult.Lane.prototype.indications = function(index) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? /** @type {osrm.engine.api.fbresult.Turn} */ (this.bb.readInt8(this.bb.__vector(this.bb_pos + offset) + index)) : /** @type {osrm.engine.api.fbresult.Turn} */ (0); +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Lane.prototype.indicationsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Int8Array} + */ +osrm.engine.api.fbresult.Lane.prototype.indicationsArray = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @returns {boolean} + */ +osrm.engine.api.fbresult.Lane.prototype.valid = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? !!this.bb.readInt8(this.bb_pos + offset) : false; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Lane.startLane = function(builder) { + builder.startObject(2); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} indicationsOffset + */ +osrm.engine.api.fbresult.Lane.addIndications = function(builder, indicationsOffset) { + builder.addFieldOffset(0, indicationsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Lane.createIndicationsVector = function(builder, data) { + builder.startVector(1, data.length, 1); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt8(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Lane.startIndicationsVector = function(builder, numElems) { + builder.startVector(1, numElems, 1); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {boolean} valid + */ +osrm.engine.api.fbresult.Lane.addValid = function(builder, valid) { + builder.addFieldInt8(1, +valid, +false); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Lane.endLane = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} indicationsOffset + * @param {boolean} valid + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Lane.createLane = function(builder, indicationsOffset, valid) { + osrm.engine.api.fbresult.Lane.startLane(builder); + osrm.engine.api.fbresult.Lane.addIndications(builder, indicationsOffset); + osrm.engine.api.fbresult.Lane.addValid(builder, valid); + return osrm.engine.api.fbresult.Lane.endLane(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.Intersection = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Intersection} + */ +osrm.engine.api.fbresult.Intersection.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Intersection=} obj + * @returns {osrm.engine.api.fbresult.Intersection} + */ +osrm.engine.api.fbresult.Intersection.getRootAsIntersection = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Intersection).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Intersection=} obj + * @returns {osrm.engine.api.fbresult.Intersection} + */ +osrm.engine.api.fbresult.Intersection.getSizePrefixedRootAsIntersection = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Intersection).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {osrm.engine.api.fbresult.Position=} obj + * @returns {osrm.engine.api.fbresult.Position|null} + */ +osrm.engine.api.fbresult.Intersection.prototype.location = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? (obj || new osrm.engine.api.fbresult.Position).__init(this.bb_pos + offset, this.bb) : null; +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Intersection.prototype.bearings = function(index) { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readInt16(this.bb.__vector(this.bb_pos + offset) + index * 2) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Intersection.prototype.bearingsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Int16Array} + */ +osrm.engine.api.fbresult.Intersection.prototype.bearingsArray = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? new Int16Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {number} index + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array} + */ +osrm.engine.api.fbresult.Intersection.prototype.classes = function(index, optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Intersection.prototype.classesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {number} index + * @returns {boolean} + */ +osrm.engine.api.fbresult.Intersection.prototype.entry = function(index) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? !!this.bb.readInt8(this.bb.__vector(this.bb_pos + offset) + index) : false; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Intersection.prototype.entryLength = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Int8Array} + */ +osrm.engine.api.fbresult.Intersection.prototype.entryArray = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Intersection.prototype.inBearing = function() { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? this.bb.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Intersection.prototype.outBearing = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.Lane=} obj + * @returns {osrm.engine.api.fbresult.Lane} + */ +osrm.engine.api.fbresult.Intersection.prototype.lanes = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 16); + return offset ? (obj || new osrm.engine.api.fbresult.Lane).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Intersection.prototype.lanesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 16); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Intersection.startIntersection = function(builder) { + builder.startObject(7); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} locationOffset + */ +osrm.engine.api.fbresult.Intersection.addLocation = function(builder, locationOffset) { + builder.addFieldStruct(0, locationOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} bearingsOffset + */ +osrm.engine.api.fbresult.Intersection.addBearings = function(builder, bearingsOffset) { + builder.addFieldOffset(1, bearingsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Intersection.createBearingsVector = function(builder, data) { + builder.startVector(2, data.length, 2); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt16(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Intersection.startBearingsVector = function(builder, numElems) { + builder.startVector(2, numElems, 2); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} classesOffset + */ +osrm.engine.api.fbresult.Intersection.addClasses = function(builder, classesOffset) { + builder.addFieldOffset(2, classesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Intersection.createClassesVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Intersection.startClassesVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} entryOffset + */ +osrm.engine.api.fbresult.Intersection.addEntry = function(builder, entryOffset) { + builder.addFieldOffset(3, entryOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Intersection.createEntryVector = function(builder, data) { + builder.startVector(1, data.length, 1); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt8(+data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Intersection.startEntryVector = function(builder, numElems) { + builder.startVector(1, numElems, 1); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} inBearing + */ +osrm.engine.api.fbresult.Intersection.addInBearing = function(builder, inBearing) { + builder.addFieldInt32(4, inBearing, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} outBearing + */ +osrm.engine.api.fbresult.Intersection.addOutBearing = function(builder, outBearing) { + builder.addFieldInt32(5, outBearing, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} lanesOffset + */ +osrm.engine.api.fbresult.Intersection.addLanes = function(builder, lanesOffset) { + builder.addFieldOffset(6, lanesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Intersection.createLanesVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Intersection.startLanesVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Intersection.endIntersection = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} locationOffset + * @param {flatbuffers.Offset} bearingsOffset + * @param {flatbuffers.Offset} classesOffset + * @param {flatbuffers.Offset} entryOffset + * @param {number} inBearing + * @param {number} outBearing + * @param {flatbuffers.Offset} lanesOffset + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Intersection.createIntersection = function(builder, locationOffset, bearingsOffset, classesOffset, entryOffset, inBearing, outBearing, lanesOffset) { + osrm.engine.api.fbresult.Intersection.startIntersection(builder); + osrm.engine.api.fbresult.Intersection.addLocation(builder, locationOffset); + osrm.engine.api.fbresult.Intersection.addBearings(builder, bearingsOffset); + osrm.engine.api.fbresult.Intersection.addClasses(builder, classesOffset); + osrm.engine.api.fbresult.Intersection.addEntry(builder, entryOffset); + osrm.engine.api.fbresult.Intersection.addInBearing(builder, inBearing); + osrm.engine.api.fbresult.Intersection.addOutBearing(builder, outBearing); + osrm.engine.api.fbresult.Intersection.addLanes(builder, lanesOffset); + return osrm.engine.api.fbresult.Intersection.endIntersection(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.Step = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Step} + */ +osrm.engine.api.fbresult.Step.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Step=} obj + * @returns {osrm.engine.api.fbresult.Step} + */ +osrm.engine.api.fbresult.Step.getRootAsStep = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Step).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Step=} obj + * @returns {osrm.engine.api.fbresult.Step} + */ +osrm.engine.api.fbresult.Step.getSizePrefixedRootAsStep = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Step).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Step.prototype.distance = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Step.prototype.duration = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.polyline = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.Position=} obj + * @returns {osrm.engine.api.fbresult.Position} + */ +osrm.engine.api.fbresult.Step.prototype.coordinates = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? (obj || new osrm.engine.api.fbresult.Position).__init(this.bb.__vector(this.bb_pos + offset) + index * 8, this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Step.prototype.coordinatesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Step.prototype.weight = function() { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.name = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.ref = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 16); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.pronunciation = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 18); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.destinations = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 20); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.exits = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 22); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.mode = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 24); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {osrm.engine.api.fbresult.StepManeuver=} obj + * @returns {osrm.engine.api.fbresult.StepManeuver|null} + */ +osrm.engine.api.fbresult.Step.prototype.maneuver = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 26); + return offset ? (obj || new osrm.engine.api.fbresult.StepManeuver).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.Intersection=} obj + * @returns {osrm.engine.api.fbresult.Intersection} + */ +osrm.engine.api.fbresult.Step.prototype.intersections = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 28); + return offset ? (obj || new osrm.engine.api.fbresult.Intersection).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Step.prototype.intersectionsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 28); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.rotaryName = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 30); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Step.prototype.rotaryPronunciation = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 32); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @returns {boolean} + */ +osrm.engine.api.fbresult.Step.prototype.drivingSide = function() { + var offset = this.bb.__offset(this.bb_pos, 34); + return offset ? !!this.bb.readInt8(this.bb_pos + offset) : false; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Step.startStep = function(builder) { + builder.startObject(16); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} distance + */ +osrm.engine.api.fbresult.Step.addDistance = function(builder, distance) { + builder.addFieldFloat32(0, distance, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} duration + */ +osrm.engine.api.fbresult.Step.addDuration = function(builder, duration) { + builder.addFieldFloat32(1, duration, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} polylineOffset + */ +osrm.engine.api.fbresult.Step.addPolyline = function(builder, polylineOffset) { + builder.addFieldOffset(2, polylineOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} coordinatesOffset + */ +osrm.engine.api.fbresult.Step.addCoordinates = function(builder, coordinatesOffset) { + builder.addFieldOffset(3, coordinatesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Step.startCoordinatesVector = function(builder, numElems) { + builder.startVector(8, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} weight + */ +osrm.engine.api.fbresult.Step.addWeight = function(builder, weight) { + builder.addFieldFloat32(4, weight, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} nameOffset + */ +osrm.engine.api.fbresult.Step.addName = function(builder, nameOffset) { + builder.addFieldOffset(5, nameOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} refOffset + */ +osrm.engine.api.fbresult.Step.addRef = function(builder, refOffset) { + builder.addFieldOffset(6, refOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} pronunciationOffset + */ +osrm.engine.api.fbresult.Step.addPronunciation = function(builder, pronunciationOffset) { + builder.addFieldOffset(7, pronunciationOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} destinationsOffset + */ +osrm.engine.api.fbresult.Step.addDestinations = function(builder, destinationsOffset) { + builder.addFieldOffset(8, destinationsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} exitsOffset + */ +osrm.engine.api.fbresult.Step.addExits = function(builder, exitsOffset) { + builder.addFieldOffset(9, exitsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} modeOffset + */ +osrm.engine.api.fbresult.Step.addMode = function(builder, modeOffset) { + builder.addFieldOffset(10, modeOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} maneuverOffset + */ +osrm.engine.api.fbresult.Step.addManeuver = function(builder, maneuverOffset) { + builder.addFieldOffset(11, maneuverOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} intersectionsOffset + */ +osrm.engine.api.fbresult.Step.addIntersections = function(builder, intersectionsOffset) { + builder.addFieldOffset(12, intersectionsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Step.createIntersectionsVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Step.startIntersectionsVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} rotaryNameOffset + */ +osrm.engine.api.fbresult.Step.addRotaryName = function(builder, rotaryNameOffset) { + builder.addFieldOffset(13, rotaryNameOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} rotaryPronunciationOffset + */ +osrm.engine.api.fbresult.Step.addRotaryPronunciation = function(builder, rotaryPronunciationOffset) { + builder.addFieldOffset(14, rotaryPronunciationOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {boolean} drivingSide + */ +osrm.engine.api.fbresult.Step.addDrivingSide = function(builder, drivingSide) { + builder.addFieldInt8(15, +drivingSide, +false); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Step.endStep = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} distance + * @param {number} duration + * @param {flatbuffers.Offset} polylineOffset + * @param {flatbuffers.Offset} coordinatesOffset + * @param {number} weight + * @param {flatbuffers.Offset} nameOffset + * @param {flatbuffers.Offset} refOffset + * @param {flatbuffers.Offset} pronunciationOffset + * @param {flatbuffers.Offset} destinationsOffset + * @param {flatbuffers.Offset} exitsOffset + * @param {flatbuffers.Offset} modeOffset + * @param {flatbuffers.Offset} maneuverOffset + * @param {flatbuffers.Offset} intersectionsOffset + * @param {flatbuffers.Offset} rotaryNameOffset + * @param {flatbuffers.Offset} rotaryPronunciationOffset + * @param {boolean} drivingSide + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Step.createStep = function(builder, distance, duration, polylineOffset, coordinatesOffset, weight, nameOffset, refOffset, pronunciationOffset, destinationsOffset, exitsOffset, modeOffset, maneuverOffset, intersectionsOffset, rotaryNameOffset, rotaryPronunciationOffset, drivingSide) { + osrm.engine.api.fbresult.Step.startStep(builder); + osrm.engine.api.fbresult.Step.addDistance(builder, distance); + osrm.engine.api.fbresult.Step.addDuration(builder, duration); + osrm.engine.api.fbresult.Step.addPolyline(builder, polylineOffset); + osrm.engine.api.fbresult.Step.addCoordinates(builder, coordinatesOffset); + osrm.engine.api.fbresult.Step.addWeight(builder, weight); + osrm.engine.api.fbresult.Step.addName(builder, nameOffset); + osrm.engine.api.fbresult.Step.addRef(builder, refOffset); + osrm.engine.api.fbresult.Step.addPronunciation(builder, pronunciationOffset); + osrm.engine.api.fbresult.Step.addDestinations(builder, destinationsOffset); + osrm.engine.api.fbresult.Step.addExits(builder, exitsOffset); + osrm.engine.api.fbresult.Step.addMode(builder, modeOffset); + osrm.engine.api.fbresult.Step.addManeuver(builder, maneuverOffset); + osrm.engine.api.fbresult.Step.addIntersections(builder, intersectionsOffset); + osrm.engine.api.fbresult.Step.addRotaryName(builder, rotaryNameOffset); + osrm.engine.api.fbresult.Step.addRotaryPronunciation(builder, rotaryPronunciationOffset); + osrm.engine.api.fbresult.Step.addDrivingSide(builder, drivingSide); + return osrm.engine.api.fbresult.Step.endStep(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.Leg = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Leg} + */ +osrm.engine.api.fbresult.Leg.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Leg=} obj + * @returns {osrm.engine.api.fbresult.Leg} + */ +osrm.engine.api.fbresult.Leg.getRootAsLeg = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Leg).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Leg=} obj + * @returns {osrm.engine.api.fbresult.Leg} + */ +osrm.engine.api.fbresult.Leg.getSizePrefixedRootAsLeg = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Leg).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Leg.prototype.distance = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.readFloat64(this.bb_pos + offset) : 0.0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Leg.prototype.duration = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readFloat64(this.bb_pos + offset) : 0.0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Leg.prototype.weight = function() { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.readFloat64(this.bb_pos + offset) : 0.0; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Leg.prototype.summary = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {osrm.engine.api.fbresult.Annotation=} obj + * @returns {osrm.engine.api.fbresult.Annotation|null} + */ +osrm.engine.api.fbresult.Leg.prototype.annotations = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? (obj || new osrm.engine.api.fbresult.Annotation).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.Step=} obj + * @returns {osrm.engine.api.fbresult.Step} + */ +osrm.engine.api.fbresult.Leg.prototype.steps = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? (obj || new osrm.engine.api.fbresult.Step).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Leg.prototype.stepsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Leg.startLeg = function(builder) { + builder.startObject(6); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} distance + */ +osrm.engine.api.fbresult.Leg.addDistance = function(builder, distance) { + builder.addFieldFloat64(0, distance, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} duration + */ +osrm.engine.api.fbresult.Leg.addDuration = function(builder, duration) { + builder.addFieldFloat64(1, duration, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} weight + */ +osrm.engine.api.fbresult.Leg.addWeight = function(builder, weight) { + builder.addFieldFloat64(2, weight, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} summaryOffset + */ +osrm.engine.api.fbresult.Leg.addSummary = function(builder, summaryOffset) { + builder.addFieldOffset(3, summaryOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} annotationsOffset + */ +osrm.engine.api.fbresult.Leg.addAnnotations = function(builder, annotationsOffset) { + builder.addFieldOffset(4, annotationsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} stepsOffset + */ +osrm.engine.api.fbresult.Leg.addSteps = function(builder, stepsOffset) { + builder.addFieldOffset(5, stepsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Leg.createStepsVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Leg.startStepsVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Leg.endLeg = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} distance + * @param {number} duration + * @param {number} weight + * @param {flatbuffers.Offset} summaryOffset + * @param {flatbuffers.Offset} annotationsOffset + * @param {flatbuffers.Offset} stepsOffset + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Leg.createLeg = function(builder, distance, duration, weight, summaryOffset, annotationsOffset, stepsOffset) { + osrm.engine.api.fbresult.Leg.startLeg(builder); + osrm.engine.api.fbresult.Leg.addDistance(builder, distance); + osrm.engine.api.fbresult.Leg.addDuration(builder, duration); + osrm.engine.api.fbresult.Leg.addWeight(builder, weight); + osrm.engine.api.fbresult.Leg.addSummary(builder, summaryOffset); + osrm.engine.api.fbresult.Leg.addAnnotations(builder, annotationsOffset); + osrm.engine.api.fbresult.Leg.addSteps(builder, stepsOffset); + return osrm.engine.api.fbresult.Leg.endLeg(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.RouteObject = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.RouteObject} + */ +osrm.engine.api.fbresult.RouteObject.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.RouteObject=} obj + * @returns {osrm.engine.api.fbresult.RouteObject} + */ +osrm.engine.api.fbresult.RouteObject.getRootAsRouteObject = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.RouteObject).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.RouteObject=} obj + * @returns {osrm.engine.api.fbresult.RouteObject} + */ +osrm.engine.api.fbresult.RouteObject.getSizePrefixedRootAsRouteObject = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.RouteObject).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.RouteObject.prototype.distance = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.RouteObject.prototype.duration = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.RouteObject.prototype.weight = function() { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.RouteObject.prototype.weightName = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.RouteObject.prototype.confidence = function() { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.RouteObject.prototype.polyline = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.Position=} obj + * @returns {osrm.engine.api.fbresult.Position} + */ +osrm.engine.api.fbresult.RouteObject.prototype.coordinates = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 16); + return offset ? (obj || new osrm.engine.api.fbresult.Position).__init(this.bb.__vector(this.bb_pos + offset) + index * 8, this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.RouteObject.prototype.coordinatesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 16); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.Leg=} obj + * @returns {osrm.engine.api.fbresult.Leg} + */ +osrm.engine.api.fbresult.RouteObject.prototype.legs = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 18); + return offset ? (obj || new osrm.engine.api.fbresult.Leg).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.RouteObject.prototype.legsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 18); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.RouteObject.startRouteObject = function(builder) { + builder.startObject(8); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} distance + */ +osrm.engine.api.fbresult.RouteObject.addDistance = function(builder, distance) { + builder.addFieldFloat32(0, distance, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} duration + */ +osrm.engine.api.fbresult.RouteObject.addDuration = function(builder, duration) { + builder.addFieldFloat32(1, duration, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} weight + */ +osrm.engine.api.fbresult.RouteObject.addWeight = function(builder, weight) { + builder.addFieldFloat32(2, weight, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} weightNameOffset + */ +osrm.engine.api.fbresult.RouteObject.addWeightName = function(builder, weightNameOffset) { + builder.addFieldOffset(3, weightNameOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} confidence + */ +osrm.engine.api.fbresult.RouteObject.addConfidence = function(builder, confidence) { + builder.addFieldFloat32(4, confidence, 0.0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} polylineOffset + */ +osrm.engine.api.fbresult.RouteObject.addPolyline = function(builder, polylineOffset) { + builder.addFieldOffset(5, polylineOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} coordinatesOffset + */ +osrm.engine.api.fbresult.RouteObject.addCoordinates = function(builder, coordinatesOffset) { + builder.addFieldOffset(6, coordinatesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.RouteObject.startCoordinatesVector = function(builder, numElems) { + builder.startVector(8, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} legsOffset + */ +osrm.engine.api.fbresult.RouteObject.addLegs = function(builder, legsOffset) { + builder.addFieldOffset(7, legsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.RouteObject.createLegsVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.RouteObject.startLegsVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.RouteObject.endRouteObject = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} distance + * @param {number} duration + * @param {number} weight + * @param {flatbuffers.Offset} weightNameOffset + * @param {number} confidence + * @param {flatbuffers.Offset} polylineOffset + * @param {flatbuffers.Offset} coordinatesOffset + * @param {flatbuffers.Offset} legsOffset + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.RouteObject.createRouteObject = function(builder, distance, duration, weight, weightNameOffset, confidence, polylineOffset, coordinatesOffset, legsOffset) { + osrm.engine.api.fbresult.RouteObject.startRouteObject(builder); + osrm.engine.api.fbresult.RouteObject.addDistance(builder, distance); + osrm.engine.api.fbresult.RouteObject.addDuration(builder, duration); + osrm.engine.api.fbresult.RouteObject.addWeight(builder, weight); + osrm.engine.api.fbresult.RouteObject.addWeightName(builder, weightNameOffset); + osrm.engine.api.fbresult.RouteObject.addConfidence(builder, confidence); + osrm.engine.api.fbresult.RouteObject.addPolyline(builder, polylineOffset); + osrm.engine.api.fbresult.RouteObject.addCoordinates(builder, coordinatesOffset); + osrm.engine.api.fbresult.RouteObject.addLegs(builder, legsOffset); + return osrm.engine.api.fbresult.RouteObject.endRouteObject(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.Table = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Table} + */ +osrm.engine.api.fbresult.Table.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Table=} obj + * @returns {osrm.engine.api.fbresult.Table} + */ +osrm.engine.api.fbresult.Table.getRootAsTable = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Table).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Table=} obj + * @returns {osrm.engine.api.fbresult.Table} + */ +osrm.engine.api.fbresult.Table.getSizePrefixedRootAsTable = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Table).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.durations = function(index) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.readFloat32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.durationsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Float32Array} + */ +osrm.engine.api.fbresult.Table.prototype.durationsArray = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? new Float32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.rows = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.readUint16(this.bb_pos + offset) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.cols = function() { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.readUint16(this.bb_pos + offset) : 0; +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.distances = function(index) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.readFloat32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.distancesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Float32Array} + */ +osrm.engine.api.fbresult.Table.prototype.distancesArray = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? new Float32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.Waypoint=} obj + * @returns {osrm.engine.api.fbresult.Waypoint} + */ +osrm.engine.api.fbresult.Table.prototype.destinations = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? (obj || new osrm.engine.api.fbresult.Waypoint).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.destinationsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {number} index + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.fallbackSpeedCells = function(index) { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.readUint32(this.bb.__vector(this.bb_pos + offset) + index * 4) : 0; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.Table.prototype.fallbackSpeedCellsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint32Array} + */ +osrm.engine.api.fbresult.Table.prototype.fallbackSpeedCellsArray = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? new Uint32Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Table.startTable = function(builder) { + builder.startObject(6); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} durationsOffset + */ +osrm.engine.api.fbresult.Table.addDurations = function(builder, durationsOffset) { + builder.addFieldOffset(0, durationsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Table.createDurationsVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addFloat32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Table.startDurationsVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} rows + */ +osrm.engine.api.fbresult.Table.addRows = function(builder, rows) { + builder.addFieldInt16(1, rows, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} cols + */ +osrm.engine.api.fbresult.Table.addCols = function(builder, cols) { + builder.addFieldInt16(2, cols, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} distancesOffset + */ +osrm.engine.api.fbresult.Table.addDistances = function(builder, distancesOffset) { + builder.addFieldOffset(3, distancesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Table.createDistancesVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addFloat32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Table.startDistancesVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} destinationsOffset + */ +osrm.engine.api.fbresult.Table.addDestinations = function(builder, destinationsOffset) { + builder.addFieldOffset(4, destinationsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Table.createDestinationsVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Table.startDestinationsVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} fallbackSpeedCellsOffset + */ +osrm.engine.api.fbresult.Table.addFallbackSpeedCells = function(builder, fallbackSpeedCellsOffset) { + builder.addFieldOffset(5, fallbackSpeedCellsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Table.createFallbackSpeedCellsVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt32(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.Table.startFallbackSpeedCellsVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Table.endTable = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} durationsOffset + * @param {number} rows + * @param {number} cols + * @param {flatbuffers.Offset} distancesOffset + * @param {flatbuffers.Offset} destinationsOffset + * @param {flatbuffers.Offset} fallbackSpeedCellsOffset + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Table.createTable = function(builder, durationsOffset, rows, cols, distancesOffset, destinationsOffset, fallbackSpeedCellsOffset) { + osrm.engine.api.fbresult.Table.startTable(builder); + osrm.engine.api.fbresult.Table.addDurations(builder, durationsOffset); + osrm.engine.api.fbresult.Table.addRows(builder, rows); + osrm.engine.api.fbresult.Table.addCols(builder, cols); + osrm.engine.api.fbresult.Table.addDistances(builder, distancesOffset); + osrm.engine.api.fbresult.Table.addDestinations(builder, destinationsOffset); + osrm.engine.api.fbresult.Table.addFallbackSpeedCells(builder, fallbackSpeedCellsOffset); + return osrm.engine.api.fbresult.Table.endTable(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.Error = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.Error} + */ +osrm.engine.api.fbresult.Error.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Error=} obj + * @returns {osrm.engine.api.fbresult.Error} + */ +osrm.engine.api.fbresult.Error.getRootAsError = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Error).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.Error=} obj + * @returns {osrm.engine.api.fbresult.Error} + */ +osrm.engine.api.fbresult.Error.getSizePrefixedRootAsError = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.Error).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Error.prototype.code = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.Error.prototype.message = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.Error.startError = function(builder) { + builder.startObject(2); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} codeOffset + */ +osrm.engine.api.fbresult.Error.addCode = function(builder, codeOffset) { + builder.addFieldOffset(0, codeOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} messageOffset + */ +osrm.engine.api.fbresult.Error.addMessage = function(builder, messageOffset) { + builder.addFieldOffset(1, messageOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Error.endError = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} codeOffset + * @param {flatbuffers.Offset} messageOffset + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.Error.createError = function(builder, codeOffset, messageOffset) { + osrm.engine.api.fbresult.Error.startError(builder); + osrm.engine.api.fbresult.Error.addCode(builder, codeOffset); + osrm.engine.api.fbresult.Error.addMessage(builder, messageOffset); + return osrm.engine.api.fbresult.Error.endError(builder); +} + +/** + * @constructor + */ +osrm.engine.api.fbresult.FBResult = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {osrm.engine.api.fbresult.FBResult} + */ +osrm.engine.api.fbresult.FBResult.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.FBResult=} obj + * @returns {osrm.engine.api.fbresult.FBResult} + */ +osrm.engine.api.fbresult.FBResult.getRootAsFBResult = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.FBResult).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {osrm.engine.api.fbresult.FBResult=} obj + * @returns {osrm.engine.api.fbresult.FBResult} + */ +osrm.engine.api.fbresult.FBResult.getSizePrefixedRootAsFBResult = function(bb, obj) { + return (obj || new osrm.engine.api.fbresult.FBResult).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns {boolean} + */ +osrm.engine.api.fbresult.FBResult.prototype.error = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? !!this.bb.readInt8(this.bb_pos + offset) : false; +}; + +/** + * @param {osrm.engine.api.fbresult.Error=} obj + * @returns {osrm.engine.api.fbresult.Error|null} + */ +osrm.engine.api.fbresult.FBResult.prototype.code = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? (obj || new osrm.engine.api.fbresult.Error).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null; +}; + +/** + * @param {flatbuffers.Encoding=} optionalEncoding + * @returns {string|Uint8Array|null} + */ +osrm.engine.api.fbresult.FBResult.prototype.dataVersion = function(optionalEncoding) { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.Waypoint=} obj + * @returns {osrm.engine.api.fbresult.Waypoint} + */ +osrm.engine.api.fbresult.FBResult.prototype.waypoints = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? (obj || new osrm.engine.api.fbresult.Waypoint).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.FBResult.prototype.waypointsLength = function() { + var offset = this.bb.__offset(this.bb_pos, 10); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {number} index + * @param {osrm.engine.api.fbresult.RouteObject=} obj + * @returns {osrm.engine.api.fbresult.RouteObject} + */ +osrm.engine.api.fbresult.FBResult.prototype.routes = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? (obj || new osrm.engine.api.fbresult.RouteObject).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null; +}; + +/** + * @returns {number} + */ +osrm.engine.api.fbresult.FBResult.prototype.routesLength = function() { + var offset = this.bb.__offset(this.bb_pos, 12); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @param {osrm.engine.api.fbresult.Table=} obj + * @returns {osrm.engine.api.fbresult.Table|null} + */ +osrm.engine.api.fbresult.FBResult.prototype.table = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? (obj || new osrm.engine.api.fbresult.Table).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +osrm.engine.api.fbresult.FBResult.startFBResult = function(builder) { + builder.startObject(6); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {boolean} error + */ +osrm.engine.api.fbresult.FBResult.addError = function(builder, error) { + builder.addFieldInt8(0, +error, +false); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} codeOffset + */ +osrm.engine.api.fbresult.FBResult.addCode = function(builder, codeOffset) { + builder.addFieldOffset(1, codeOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} dataVersionOffset + */ +osrm.engine.api.fbresult.FBResult.addDataVersion = function(builder, dataVersionOffset) { + builder.addFieldOffset(2, dataVersionOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} waypointsOffset + */ +osrm.engine.api.fbresult.FBResult.addWaypoints = function(builder, waypointsOffset) { + builder.addFieldOffset(3, waypointsOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.FBResult.createWaypointsVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.FBResult.startWaypointsVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} routesOffset + */ +osrm.engine.api.fbresult.FBResult.addRoutes = function(builder, routesOffset) { + builder.addFieldOffset(4, routesOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.FBResult.createRoutesVector = function(builder, data) { + builder.startVector(4, data.length, 4); + for (var i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +osrm.engine.api.fbresult.FBResult.startRoutesVector = function(builder, numElems) { + builder.startVector(4, numElems, 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} tableOffset + */ +osrm.engine.api.fbresult.FBResult.addTable = function(builder, tableOffset) { + builder.addFieldOffset(5, tableOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.FBResult.endFBResult = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} offset + */ +osrm.engine.api.fbresult.FBResult.finishFBResultBuffer = function(builder, offset) { + builder.finish(offset); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} offset + */ +osrm.engine.api.fbresult.FBResult.finishSizePrefixedFBResultBuffer = function(builder, offset) { + builder.finish(offset, undefined, true); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {boolean} error + * @param {flatbuffers.Offset} codeOffset + * @param {flatbuffers.Offset} dataVersionOffset + * @param {flatbuffers.Offset} waypointsOffset + * @param {flatbuffers.Offset} routesOffset + * @param {flatbuffers.Offset} tableOffset + * @returns {flatbuffers.Offset} + */ +osrm.engine.api.fbresult.FBResult.createFBResult = function(builder, error, codeOffset, dataVersionOffset, waypointsOffset, routesOffset, tableOffset) { + osrm.engine.api.fbresult.FBResult.startFBResult(builder); + osrm.engine.api.fbresult.FBResult.addError(builder, error); + osrm.engine.api.fbresult.FBResult.addCode(builder, codeOffset); + osrm.engine.api.fbresult.FBResult.addDataVersion(builder, dataVersionOffset); + osrm.engine.api.fbresult.FBResult.addWaypoints(builder, waypointsOffset); + osrm.engine.api.fbresult.FBResult.addRoutes(builder, routesOffset); + osrm.engine.api.fbresult.FBResult.addTable(builder, tableOffset); + return osrm.engine.api.fbresult.FBResult.endFBResult(builder); +} + +// Exports for Node.js and RequireJS +this.osrm = osrm; diff --git a/features/support/flatbuffers.js b/features/support/flatbuffers.js new file mode 100644 index 000000000..461cd7af8 --- /dev/null +++ b/features/support/flatbuffers.js @@ -0,0 +1,1259 @@ +/// @file +/// @addtogroup flatbuffers_javascript_api +/// @{ +/// @cond FLATBUFFERS_INTERNAL + +/** + * @fileoverview + * + * Need to suppress 'global this' error so the Node.js export line doesn't cause + * closure compile to error out. + * @suppress {globalThis} + */ + +/** + * @const + * @namespace + */ +var flatbuffers = {}; + +/** + * @typedef {number} + */ +flatbuffers.Offset; + +/** + * @typedef {{ + * bb: flatbuffers.ByteBuffer, + * bb_pos: number + * }} + */ +flatbuffers.Table; + +/** + * @type {number} + * @const + */ +flatbuffers.SIZEOF_SHORT = 2; + +/** + * @type {number} + * @const + */ +flatbuffers.SIZEOF_INT = 4; + +/** + * @type {number} + * @const + */ +flatbuffers.FILE_IDENTIFIER_LENGTH = 4; + +/** + * @type {number} + * @const + */ +flatbuffers.SIZE_PREFIX_LENGTH = 4; + +/** + * @enum {number} + */ +flatbuffers.Encoding = { + UTF8_BYTES: 1, + UTF16_STRING: 2 +}; + +/** + * @type {Int32Array} + * @const + */ +flatbuffers.int32 = new Int32Array(2); + +/** + * @type {Float32Array} + * @const + */ +flatbuffers.float32 = new Float32Array(flatbuffers.int32.buffer); + +/** + * @type {Float64Array} + * @const + */ +flatbuffers.float64 = new Float64Array(flatbuffers.int32.buffer); + +/** + * @type {boolean} + * @const + */ +flatbuffers.isLittleEndian = new Uint16Array(new Uint8Array([1, 0]).buffer)[0] === 1; + +//////////////////////////////////////////////////////////////////////////////// + +/** + * @constructor + * @param {number} low + * @param {number} high + */ +flatbuffers.Long = function(low, high) { + /** + * @type {number} + * @const + */ + this.low = low | 0; + + /** + * @type {number} + * @const + */ + this.high = high | 0; +}; + +/** + * @param {number} low + * @param {number} high + * @returns {flatbuffers.Long} + */ +flatbuffers.Long.create = function(low, high) { + // Special-case zero to avoid GC overhead for default values + return low == 0 && high == 0 ? flatbuffers.Long.ZERO : new flatbuffers.Long(low, high); +}; + +/** + * @returns {number} + */ +flatbuffers.Long.prototype.toFloat64 = function() { + return (this.low >>> 0) + this.high * 0x100000000; +}; + +/** + * @param {flatbuffers.Long} other + * @returns {boolean} + */ +flatbuffers.Long.prototype.equals = function(other) { + return this.low == other.low && this.high == other.high; +}; + +/** + * @type {flatbuffers.Long} + * @const + */ +flatbuffers.Long.ZERO = new flatbuffers.Long(0, 0); + +/// @endcond +//////////////////////////////////////////////////////////////////////////////// +/** + * Create a FlatBufferBuilder. + * + * @constructor + * @param {number=} opt_initial_size + */ +flatbuffers.Builder = function(opt_initial_size) { + if (!opt_initial_size) { + var initial_size = 1024; + } else { + var initial_size = opt_initial_size; + } + + /** + * @type {flatbuffers.ByteBuffer} + * @private + */ + this.bb = flatbuffers.ByteBuffer.allocate(initial_size); + + /** + * Remaining space in the ByteBuffer. + * + * @type {number} + * @private + */ + this.space = initial_size; + + /** + * Minimum alignment encountered so far. + * + * @type {number} + * @private + */ + this.minalign = 1; + + /** + * The vtable for the current table. + * + * @type {Array.} + * @private + */ + this.vtable = null; + + /** + * The amount of fields we're actually using. + * + * @type {number} + * @private + */ + this.vtable_in_use = 0; + + /** + * Whether we are currently serializing a table. + * + * @type {boolean} + * @private + */ + this.isNested = false; + + /** + * Starting offset of the current struct/table. + * + * @type {number} + * @private + */ + this.object_start = 0; + + /** + * List of offsets of all vtables. + * + * @type {Array.} + * @private + */ + this.vtables = []; + + /** + * For the current vector being built. + * + * @type {number} + * @private + */ + this.vector_num_elems = 0; + + /** + * False omits default values from the serialized data + * + * @type {boolean} + * @private + */ + this.force_defaults = false; +}; + +flatbuffers.Builder.prototype.clear = function() { + this.bb.clear(); + this.space = this.bb.capacity(); + this.minalign = 1; + this.vtable = null; + this.vtable_in_use = 0; + this.isNested = false; + this.object_start = 0; + this.vtables = []; + this.vector_num_elems = 0; + this.force_defaults = false; +}; + +/** + * In order to save space, fields that are set to their default value + * don't get serialized into the buffer. Forcing defaults provides a + * way to manually disable this optimization. + * + * @param {boolean} forceDefaults true always serializes default values + */ +flatbuffers.Builder.prototype.forceDefaults = function(forceDefaults) { + this.force_defaults = forceDefaults; +}; + +/** + * Get the ByteBuffer representing the FlatBuffer. Only call this after you've + * called finish(). The actual data starts at the ByteBuffer's current position, + * not necessarily at 0. + * + * @returns {flatbuffers.ByteBuffer} + */ +flatbuffers.Builder.prototype.dataBuffer = function() { + return this.bb; +}; + +/** + * Get the bytes representing the FlatBuffer. Only call this after you've + * called finish(). + * + * @returns {Uint8Array} + */ +flatbuffers.Builder.prototype.asUint8Array = function() { + return this.bb.bytes().subarray(this.bb.position(), this.bb.position() + this.offset()); +}; + +/// @cond FLATBUFFERS_INTERNAL +/** + * Prepare to write an element of `size` after `additional_bytes` have been + * written, e.g. if you write a string, you need to align such the int length + * field is aligned to 4 bytes, and the string data follows it directly. If all + * you need to do is alignment, `additional_bytes` will be 0. + * + * @param {number} size This is the of the new element to write + * @param {number} additional_bytes The padding size + */ +flatbuffers.Builder.prototype.prep = function(size, additional_bytes) { + // Track the biggest thing we've ever aligned to. + if (size > this.minalign) { + this.minalign = size; + } + + // Find the amount of alignment needed such that `size` is properly + // aligned after `additional_bytes` + var align_size = ((~(this.bb.capacity() - this.space + additional_bytes)) + 1) & (size - 1); + + // Reallocate the buffer if needed. + while (this.space < align_size + size + additional_bytes) { + var old_buf_size = this.bb.capacity(); + this.bb = flatbuffers.Builder.growByteBuffer(this.bb); + this.space += this.bb.capacity() - old_buf_size; + } + + this.pad(align_size); +}; + +/** + * @param {number} byte_size + */ +flatbuffers.Builder.prototype.pad = function(byte_size) { + for (var i = 0; i < byte_size; i++) { + this.bb.writeInt8(--this.space, 0); + } +}; + +/** + * @param {number} value + */ +flatbuffers.Builder.prototype.writeInt8 = function(value) { + this.bb.writeInt8(this.space -= 1, value); +}; + +/** + * @param {number} value + */ +flatbuffers.Builder.prototype.writeInt16 = function(value) { + this.bb.writeInt16(this.space -= 2, value); +}; + +/** + * @param {number} value + */ +flatbuffers.Builder.prototype.writeInt32 = function(value) { + this.bb.writeInt32(this.space -= 4, value); +}; + +/** + * @param {flatbuffers.Long} value + */ +flatbuffers.Builder.prototype.writeInt64 = function(value) { + this.bb.writeInt64(this.space -= 8, value); +}; + +/** + * @param {number} value + */ +flatbuffers.Builder.prototype.writeFloat32 = function(value) { + this.bb.writeFloat32(this.space -= 4, value); +}; + +/** + * @param {number} value + */ +flatbuffers.Builder.prototype.writeFloat64 = function(value) { + this.bb.writeFloat64(this.space -= 8, value); +}; +/// @endcond + +/** + * Add an `int8` to the buffer, properly aligned, and grows the buffer (if necessary). + * @param {number} value The `int8` to add the the buffer. + */ +flatbuffers.Builder.prototype.addInt8 = function(value) { + this.prep(1, 0); + this.writeInt8(value); +}; + +/** + * Add an `int16` to the buffer, properly aligned, and grows the buffer (if necessary). + * @param {number} value The `int16` to add the the buffer. + */ +flatbuffers.Builder.prototype.addInt16 = function(value) { + this.prep(2, 0); + this.writeInt16(value); +}; + +/** + * Add an `int32` to the buffer, properly aligned, and grows the buffer (if necessary). + * @param {number} value The `int32` to add the the buffer. + */ +flatbuffers.Builder.prototype.addInt32 = function(value) { + this.prep(4, 0); + this.writeInt32(value); +}; + +/** + * Add an `int64` to the buffer, properly aligned, and grows the buffer (if necessary). + * @param {flatbuffers.Long} value The `int64` to add the the buffer. + */ +flatbuffers.Builder.prototype.addInt64 = function(value) { + this.prep(8, 0); + this.writeInt64(value); +}; + +/** + * Add a `float32` to the buffer, properly aligned, and grows the buffer (if necessary). + * @param {number} value The `float32` to add the the buffer. + */ +flatbuffers.Builder.prototype.addFloat32 = function(value) { + this.prep(4, 0); + this.writeFloat32(value); +}; + +/** + * Add a `float64` to the buffer, properly aligned, and grows the buffer (if necessary). + * @param {number} value The `float64` to add the the buffer. + */ +flatbuffers.Builder.prototype.addFloat64 = function(value) { + this.prep(8, 0); + this.writeFloat64(value); +}; + +/// @cond FLATBUFFERS_INTERNAL +/** + * @param {number} voffset + * @param {number} value + * @param {number} defaultValue + */ +flatbuffers.Builder.prototype.addFieldInt8 = function(voffset, value, defaultValue) { + if (this.force_defaults || value != defaultValue) { + this.addInt8(value); + this.slot(voffset); + } +}; + +/** + * @param {number} voffset + * @param {number} value + * @param {number} defaultValue + */ +flatbuffers.Builder.prototype.addFieldInt16 = function(voffset, value, defaultValue) { + if (this.force_defaults || value != defaultValue) { + this.addInt16(value); + this.slot(voffset); + } +}; + +/** + * @param {number} voffset + * @param {number} value + * @param {number} defaultValue + */ +flatbuffers.Builder.prototype.addFieldInt32 = function(voffset, value, defaultValue) { + if (this.force_defaults || value != defaultValue) { + this.addInt32(value); + this.slot(voffset); + } +}; + +/** + * @param {number} voffset + * @param {flatbuffers.Long} value + * @param {flatbuffers.Long} defaultValue + */ +flatbuffers.Builder.prototype.addFieldInt64 = function(voffset, value, defaultValue) { + if (this.force_defaults || !value.equals(defaultValue)) { + this.addInt64(value); + this.slot(voffset); + } +}; + +/** + * @param {number} voffset + * @param {number} value + * @param {number} defaultValue + */ +flatbuffers.Builder.prototype.addFieldFloat32 = function(voffset, value, defaultValue) { + if (this.force_defaults || value != defaultValue) { + this.addFloat32(value); + this.slot(voffset); + } +}; + +/** + * @param {number} voffset + * @param {number} value + * @param {number} defaultValue + */ +flatbuffers.Builder.prototype.addFieldFloat64 = function(voffset, value, defaultValue) { + if (this.force_defaults || value != defaultValue) { + this.addFloat64(value); + this.slot(voffset); + } +}; + +/** + * @param {number} voffset + * @param {flatbuffers.Offset} value + * @param {flatbuffers.Offset} defaultValue + */ +flatbuffers.Builder.prototype.addFieldOffset = function(voffset, value, defaultValue) { + if (this.force_defaults || value != defaultValue) { + this.addOffset(value); + this.slot(voffset); + } +}; + +/** + * Structs are stored inline, so nothing additional is being added. `d` is always 0. + * + * @param {number} voffset + * @param {flatbuffers.Offset} value + * @param {flatbuffers.Offset} defaultValue + */ +flatbuffers.Builder.prototype.addFieldStruct = function(voffset, value, defaultValue) { + if (value != defaultValue) { + this.nested(value); + this.slot(voffset); + } +}; + +/** + * Structures are always stored inline, they need to be created right + * where they're used. You'll get this assertion failure if you + * created it elsewhere. + * + * @param {flatbuffers.Offset} obj The offset of the created object + */ +flatbuffers.Builder.prototype.nested = function(obj) { + if (obj != this.offset()) { + throw new Error('FlatBuffers: struct must be serialized inline.'); + } +}; + +/** + * Should not be creating any other object, string or vector + * while an object is being constructed + */ +flatbuffers.Builder.prototype.notNested = function() { + if (this.isNested) { + throw new Error('FlatBuffers: object serialization must not be nested.'); + } +}; + +/** + * Set the current vtable at `voffset` to the current location in the buffer. + * + * @param {number} voffset + */ +flatbuffers.Builder.prototype.slot = function(voffset) { + this.vtable[voffset] = this.offset(); +}; + +/** + * @returns {flatbuffers.Offset} Offset relative to the end of the buffer. + */ +flatbuffers.Builder.prototype.offset = function() { + return this.bb.capacity() - this.space; +}; + +/** + * Doubles the size of the backing ByteBuffer and copies the old data towards + * the end of the new buffer (since we build the buffer backwards). + * + * @param {flatbuffers.ByteBuffer} bb The current buffer with the existing data + * @returns {flatbuffers.ByteBuffer} A new byte buffer with the old data copied + * to it. The data is located at the end of the buffer. + * + * uint8Array.set() formally takes {Array|ArrayBufferView}, so to pass + * it a uint8Array we need to suppress the type check: + * @suppress {checkTypes} + */ +flatbuffers.Builder.growByteBuffer = function(bb) { + var old_buf_size = bb.capacity(); + + // Ensure we don't grow beyond what fits in an int. + if (old_buf_size & 0xC0000000) { + throw new Error('FlatBuffers: cannot grow buffer beyond 2 gigabytes.'); + } + + var new_buf_size = old_buf_size << 1; + var nbb = flatbuffers.ByteBuffer.allocate(new_buf_size); + nbb.setPosition(new_buf_size - old_buf_size); + nbb.bytes().set(bb.bytes(), new_buf_size - old_buf_size); + return nbb; +}; +/// @endcond + +/** + * Adds on offset, relative to where it will be written. + * + * @param {flatbuffers.Offset} offset The offset to add. + */ +flatbuffers.Builder.prototype.addOffset = function(offset) { + this.prep(flatbuffers.SIZEOF_INT, 0); // Ensure alignment is already done. + this.writeInt32(this.offset() - offset + flatbuffers.SIZEOF_INT); +}; + +/// @cond FLATBUFFERS_INTERNAL +/** + * Start encoding a new object in the buffer. Users will not usually need to + * call this directly. The FlatBuffers compiler will generate helper methods + * that call this method internally. + * + * @param {number} numfields + */ +flatbuffers.Builder.prototype.startObject = function(numfields) { + this.notNested(); + if (this.vtable == null) { + this.vtable = []; + } + this.vtable_in_use = numfields; + for (var i = 0; i < numfields; i++) { + this.vtable[i] = 0; // This will push additional elements as needed + } + this.isNested = true; + this.object_start = this.offset(); +}; + +/** + * Finish off writing the object that is under construction. + * + * @returns {flatbuffers.Offset} The offset to the object inside `dataBuffer` + */ +flatbuffers.Builder.prototype.endObject = function() { + if (this.vtable == null || !this.isNested) { + throw new Error('FlatBuffers: endObject called without startObject'); + } + + this.addInt32(0); + var vtableloc = this.offset(); + + // Trim trailing zeroes. + var i = this.vtable_in_use - 1; + for (; i >= 0 && this.vtable[i] == 0; i--) {} + var trimmed_size = i + 1; + + // Write out the current vtable. + for (; i >= 0; i--) { + // Offset relative to the start of the table. + this.addInt16(this.vtable[i] != 0 ? vtableloc - this.vtable[i] : 0); + } + + var standard_fields = 2; // The fields below: + this.addInt16(vtableloc - this.object_start); + var len = (trimmed_size + standard_fields) * flatbuffers.SIZEOF_SHORT; + this.addInt16(len); + + // Search for an existing vtable that matches the current one. + var existing_vtable = 0; + var vt1 = this.space; +outer_loop: + for (i = 0; i < this.vtables.length; i++) { + var vt2 = this.bb.capacity() - this.vtables[i]; + if (len == this.bb.readInt16(vt2)) { + for (var j = flatbuffers.SIZEOF_SHORT; j < len; j += flatbuffers.SIZEOF_SHORT) { + if (this.bb.readInt16(vt1 + j) != this.bb.readInt16(vt2 + j)) { + continue outer_loop; + } + } + existing_vtable = this.vtables[i]; + break; + } + } + + if (existing_vtable) { + // Found a match: + // Remove the current vtable. + this.space = this.bb.capacity() - vtableloc; + + // Point table to existing vtable. + this.bb.writeInt32(this.space, existing_vtable - vtableloc); + } else { + // No match: + // Add the location of the current vtable to the list of vtables. + this.vtables.push(this.offset()); + + // Point table to current vtable. + this.bb.writeInt32(this.bb.capacity() - vtableloc, this.offset() - vtableloc); + } + + this.isNested = false; + return vtableloc; +}; +/// @endcond + +/** + * Finalize a buffer, poiting to the given `root_table`. + * + * @param {flatbuffers.Offset} root_table + * @param {string=} opt_file_identifier + * @param {boolean=} opt_size_prefix + */ +flatbuffers.Builder.prototype.finish = function(root_table, opt_file_identifier, opt_size_prefix) { + var size_prefix = opt_size_prefix ? flatbuffers.SIZE_PREFIX_LENGTH : 0; + if (opt_file_identifier) { + var file_identifier = opt_file_identifier; + this.prep(this.minalign, flatbuffers.SIZEOF_INT + + flatbuffers.FILE_IDENTIFIER_LENGTH + size_prefix); + if (file_identifier.length != flatbuffers.FILE_IDENTIFIER_LENGTH) { + throw new Error('FlatBuffers: file identifier must be length ' + + flatbuffers.FILE_IDENTIFIER_LENGTH); + } + for (var i = flatbuffers.FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) { + this.writeInt8(file_identifier.charCodeAt(i)); + } + } + this.prep(this.minalign, flatbuffers.SIZEOF_INT + size_prefix); + this.addOffset(root_table); + if (size_prefix) { + this.addInt32(this.bb.capacity() - this.space); + } + this.bb.setPosition(this.space); +}; + +/** + * Finalize a size prefixed buffer, pointing to the given `root_table`. + * + * @param {flatbuffers.Offset} root_table + * @param {string=} opt_file_identifier + */ +flatbuffers.Builder.prototype.finishSizePrefixed = function (root_table, opt_file_identifier) { + this.finish(root_table, opt_file_identifier, true); +}; + +/// @cond FLATBUFFERS_INTERNAL +/** + * This checks a required field has been set in a given table that has + * just been constructed. + * + * @param {flatbuffers.Offset} table + * @param {number} field + */ +flatbuffers.Builder.prototype.requiredField = function(table, field) { + var table_start = this.bb.capacity() - table; + var vtable_start = table_start - this.bb.readInt32(table_start); + var ok = this.bb.readInt16(vtable_start + field) != 0; + + // If this fails, the caller will show what field needs to be set. + if (!ok) { + throw new Error('FlatBuffers: field ' + field + ' must be set'); + } +}; + +/** + * Start a new array/vector of objects. Users usually will not call + * this directly. The FlatBuffers compiler will create a start/end + * method for vector types in generated code. + * + * @param {number} elem_size The size of each element in the array + * @param {number} num_elems The number of elements in the array + * @param {number} alignment The alignment of the array + */ +flatbuffers.Builder.prototype.startVector = function(elem_size, num_elems, alignment) { + this.notNested(); + this.vector_num_elems = num_elems; + this.prep(flatbuffers.SIZEOF_INT, elem_size * num_elems); + this.prep(alignment, elem_size * num_elems); // Just in case alignment > int. +}; + +/** + * Finish off the creation of an array and all its elements. The array must be + * created with `startVector`. + * + * @returns {flatbuffers.Offset} The offset at which the newly created array + * starts. + */ +flatbuffers.Builder.prototype.endVector = function() { + this.writeInt32(this.vector_num_elems); + return this.offset(); +}; +/// @endcond + +/** + * Encode the string `s` in the buffer using UTF-8. If a Uint8Array is passed + * instead of a string, it is assumed to contain valid UTF-8 encoded data. + * + * @param {string|Uint8Array} s The string to encode + * @return {flatbuffers.Offset} The offset in the buffer where the encoded string starts + */ +flatbuffers.Builder.prototype.createString = function(s) { + if (s instanceof Uint8Array) { + var utf8 = s; + } else { + var utf8 = []; + var i = 0; + + while (i < s.length) { + var codePoint; + + // Decode UTF-16 + var a = s.charCodeAt(i++); + if (a < 0xD800 || a >= 0xDC00) { + codePoint = a; + } else { + var b = s.charCodeAt(i++); + codePoint = (a << 10) + b + (0x10000 - (0xD800 << 10) - 0xDC00); + } + + // Encode UTF-8 + if (codePoint < 0x80) { + utf8.push(codePoint); + } else { + if (codePoint < 0x800) { + utf8.push(((codePoint >> 6) & 0x1F) | 0xC0); + } else { + if (codePoint < 0x10000) { + utf8.push(((codePoint >> 12) & 0x0F) | 0xE0); + } else { + utf8.push( + ((codePoint >> 18) & 0x07) | 0xF0, + ((codePoint >> 12) & 0x3F) | 0x80); + } + utf8.push(((codePoint >> 6) & 0x3F) | 0x80); + } + utf8.push((codePoint & 0x3F) | 0x80); + } + } + } + + this.addInt8(0); + this.startVector(1, utf8.length, 1); + this.bb.setPosition(this.space -= utf8.length); + for (var i = 0, offset = this.space, bytes = this.bb.bytes(); i < utf8.length; i++) { + bytes[offset++] = utf8[i]; + } + return this.endVector(); +}; + +/** + * A helper function to avoid generated code depending on this file directly. + * + * @param {number} low + * @param {number} high + * @returns {flatbuffers.Long} + */ +flatbuffers.Builder.prototype.createLong = function(low, high) { + return flatbuffers.Long.create(low, high); +}; +//////////////////////////////////////////////////////////////////////////////// +/// @cond FLATBUFFERS_INTERNAL +/** + * Create a new ByteBuffer with a given array of bytes (`Uint8Array`). + * + * @constructor + * @param {Uint8Array} bytes + */ +flatbuffers.ByteBuffer = function(bytes) { + /** + * @type {Uint8Array} + * @private + */ + this.bytes_ = bytes; + + /** + * @type {number} + * @private + */ + this.position_ = 0; +}; + +/** + * Create and allocate a new ByteBuffer with a given size. + * + * @param {number} byte_size + * @returns {flatbuffers.ByteBuffer} + */ +flatbuffers.ByteBuffer.allocate = function(byte_size) { + return new flatbuffers.ByteBuffer(new Uint8Array(byte_size)); +}; + +flatbuffers.ByteBuffer.prototype.clear = function() { + this.position_ = 0; +}; + +/** + * Get the underlying `Uint8Array`. + * + * @returns {Uint8Array} + */ +flatbuffers.ByteBuffer.prototype.bytes = function() { + return this.bytes_; +}; + +/** + * Get the buffer's position. + * + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.position = function() { + return this.position_; +}; + +/** + * Set the buffer's position. + * + * @param {number} position + */ +flatbuffers.ByteBuffer.prototype.setPosition = function(position) { + this.position_ = position; +}; + +/** + * Get the buffer's capacity. + * + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.capacity = function() { + return this.bytes_.length; +}; + +/** + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.readInt8 = function(offset) { + return this.readUint8(offset) << 24 >> 24; +}; + +/** + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.readUint8 = function(offset) { + return this.bytes_[offset]; +}; + +/** + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.readInt16 = function(offset) { + return this.readUint16(offset) << 16 >> 16; +}; + +/** + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.readUint16 = function(offset) { + return this.bytes_[offset] | this.bytes_[offset + 1] << 8; +}; + +/** + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.readInt32 = function(offset) { + return this.bytes_[offset] | this.bytes_[offset + 1] << 8 | this.bytes_[offset + 2] << 16 | this.bytes_[offset + 3] << 24; +}; + +/** + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.readUint32 = function(offset) { + return this.readInt32(offset) >>> 0; +}; + +/** + * @param {number} offset + * @returns {flatbuffers.Long} + */ +flatbuffers.ByteBuffer.prototype.readInt64 = function(offset) { + return new flatbuffers.Long(this.readInt32(offset), this.readInt32(offset + 4)); +}; + +/** + * @param {number} offset + * @returns {flatbuffers.Long} + */ +flatbuffers.ByteBuffer.prototype.readUint64 = function(offset) { + return new flatbuffers.Long(this.readUint32(offset), this.readUint32(offset + 4)); +}; + +/** + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.readFloat32 = function(offset) { + flatbuffers.int32[0] = this.readInt32(offset); + return flatbuffers.float32[0]; +}; + +/** + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.readFloat64 = function(offset) { + flatbuffers.int32[flatbuffers.isLittleEndian ? 0 : 1] = this.readInt32(offset); + flatbuffers.int32[flatbuffers.isLittleEndian ? 1 : 0] = this.readInt32(offset + 4); + return flatbuffers.float64[0]; +}; + +/** + * @param {number} offset + * @param {number|boolean} value + */ +flatbuffers.ByteBuffer.prototype.writeInt8 = function(offset, value) { + this.bytes_[offset] = /** @type {number} */(value); +}; + +/** + * @param {number} offset + * @param {number} value + */ +flatbuffers.ByteBuffer.prototype.writeUint8 = function(offset, value) { + this.bytes_[offset] = value; +}; + +/** + * @param {number} offset + * @param {number} value + */ +flatbuffers.ByteBuffer.prototype.writeInt16 = function(offset, value) { + this.bytes_[offset] = value; + this.bytes_[offset + 1] = value >> 8; +}; + +/** + * @param {number} offset + * @param {number} value + */ +flatbuffers.ByteBuffer.prototype.writeUint16 = function(offset, value) { + this.bytes_[offset] = value; + this.bytes_[offset + 1] = value >> 8; +}; + +/** + * @param {number} offset + * @param {number} value + */ +flatbuffers.ByteBuffer.prototype.writeInt32 = function(offset, value) { + this.bytes_[offset] = value; + this.bytes_[offset + 1] = value >> 8; + this.bytes_[offset + 2] = value >> 16; + this.bytes_[offset + 3] = value >> 24; +}; + +/** + * @param {number} offset + * @param {number} value + */ +flatbuffers.ByteBuffer.prototype.writeUint32 = function(offset, value) { + this.bytes_[offset] = value; + this.bytes_[offset + 1] = value >> 8; + this.bytes_[offset + 2] = value >> 16; + this.bytes_[offset + 3] = value >> 24; +}; + +/** + * @param {number} offset + * @param {flatbuffers.Long} value + */ +flatbuffers.ByteBuffer.prototype.writeInt64 = function(offset, value) { + this.writeInt32(offset, value.low); + this.writeInt32(offset + 4, value.high); +}; + +/** + * @param {number} offset + * @param {flatbuffers.Long} value + */ +flatbuffers.ByteBuffer.prototype.writeUint64 = function(offset, value) { + this.writeUint32(offset, value.low); + this.writeUint32(offset + 4, value.high); +}; + +/** + * @param {number} offset + * @param {number} value + */ +flatbuffers.ByteBuffer.prototype.writeFloat32 = function(offset, value) { + flatbuffers.float32[0] = value; + this.writeInt32(offset, flatbuffers.int32[0]); +}; + +/** + * @param {number} offset + * @param {number} value + */ +flatbuffers.ByteBuffer.prototype.writeFloat64 = function(offset, value) { + flatbuffers.float64[0] = value; + this.writeInt32(offset, flatbuffers.int32[flatbuffers.isLittleEndian ? 0 : 1]); + this.writeInt32(offset + 4, flatbuffers.int32[flatbuffers.isLittleEndian ? 1 : 0]); +}; + +/** + * Return the file identifier. Behavior is undefined for FlatBuffers whose + * schema does not include a file_identifier (likely points at padding or the + * start of a the root vtable). + * @returns {string} + */ +flatbuffers.ByteBuffer.prototype.getBufferIdentifier = function() { + if (this.bytes_.length < this.position_ + flatbuffers.SIZEOF_INT + + flatbuffers.FILE_IDENTIFIER_LENGTH) { + throw new Error( + 'FlatBuffers: ByteBuffer is too short to contain an identifier.'); + } + var result = ""; + for (var i = 0; i < flatbuffers.FILE_IDENTIFIER_LENGTH; i++) { + result += String.fromCharCode( + this.readInt8(this.position_ + flatbuffers.SIZEOF_INT + i)); + } + return result; +}; + +/** + * Look up a field in the vtable, return an offset into the object, or 0 if the + * field is not present. + * + * @param {number} bb_pos + * @param {number} vtable_offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.__offset = function(bb_pos, vtable_offset) { + var vtable = bb_pos - this.readInt32(bb_pos); + return vtable_offset < this.readInt16(vtable) ? this.readInt16(vtable + vtable_offset) : 0; +}; + +/** + * Initialize any Table-derived type to point to the union at the given offset. + * + * @param {flatbuffers.Table} t + * @param {number} offset + * @returns {flatbuffers.Table} + */ +flatbuffers.ByteBuffer.prototype.__union = function(t, offset) { + t.bb_pos = offset + this.readInt32(offset); + t.bb = this; + return t; +}; + +/** + * Create a JavaScript string from UTF-8 data stored inside the FlatBuffer. + * This allocates a new string and converts to wide chars upon each access. + * + * To avoid the conversion to UTF-16, pass flatbuffers.Encoding.UTF8_BYTES as + * the "optionalEncoding" argument. This is useful for avoiding conversion to + * and from UTF-16 when the data will just be packaged back up in another + * FlatBuffer later on. + * + * @param {number} offset + * @param {flatbuffers.Encoding=} opt_encoding Defaults to UTF16_STRING + * @returns {string|Uint8Array} + */ +flatbuffers.ByteBuffer.prototype.__string = function(offset, opt_encoding) { + offset += this.readInt32(offset); + + var length = this.readInt32(offset); + var result = ''; + var i = 0; + + offset += flatbuffers.SIZEOF_INT; + + if (opt_encoding === flatbuffers.Encoding.UTF8_BYTES) { + return this.bytes_.subarray(offset, offset + length); + } + + while (i < length) { + var codePoint; + + // Decode UTF-8 + var a = this.readUint8(offset + i++); + if (a < 0xC0) { + codePoint = a; + } else { + var b = this.readUint8(offset + i++); + if (a < 0xE0) { + codePoint = + ((a & 0x1F) << 6) | + (b & 0x3F); + } else { + var c = this.readUint8(offset + i++); + if (a < 0xF0) { + codePoint = + ((a & 0x0F) << 12) | + ((b & 0x3F) << 6) | + (c & 0x3F); + } else { + var d = this.readUint8(offset + i++); + codePoint = + ((a & 0x07) << 18) | + ((b & 0x3F) << 12) | + ((c & 0x3F) << 6) | + (d & 0x3F); + } + } + } + + // Encode UTF-16 + if (codePoint < 0x10000) { + result += String.fromCharCode(codePoint); + } else { + codePoint -= 0x10000; + result += String.fromCharCode( + (codePoint >> 10) + 0xD800, + (codePoint & ((1 << 10) - 1)) + 0xDC00); + } + } + + return result; +}; + +/** + * Retrieve the relative offset stored at "offset" + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.__indirect = function(offset) { + return offset + this.readInt32(offset); +}; + +/** + * Get the start of data of a vector whose offset is stored at "offset" in this object. + * + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.__vector = function(offset) { + return offset + this.readInt32(offset) + flatbuffers.SIZEOF_INT; // data starts after the length +}; + +/** + * Get the length of a vector whose offset is stored at "offset" in this object. + * + * @param {number} offset + * @returns {number} + */ +flatbuffers.ByteBuffer.prototype.__vector_len = function(offset) { + return this.readInt32(offset + this.readInt32(offset)); +}; + +/** + * @param {string} ident + * @returns {boolean} + */ +flatbuffers.ByteBuffer.prototype.__has_identifier = function(ident) { + if (ident.length != flatbuffers.FILE_IDENTIFIER_LENGTH) { + throw new Error('FlatBuffers: file identifier must be length ' + + flatbuffers.FILE_IDENTIFIER_LENGTH); + } + for (var i = 0; i < flatbuffers.FILE_IDENTIFIER_LENGTH; i++) { + if (ident.charCodeAt(i) != this.readInt8(this.position_ + flatbuffers.SIZEOF_INT + i)) { + return false; + } + } + return true; +}; + +/** + * A helper function to avoid generated code depending on this file directly. + * + * @param {number} low + * @param {number} high + * @returns {flatbuffers.Long} + */ +flatbuffers.ByteBuffer.prototype.createLong = function(low, high) { + return flatbuffers.Long.create(low, high); +}; + +// Exports for Node.js and RequireJS +this.flatbuffers = flatbuffers; + +/// @endcond +/// @} diff --git a/features/support/hooks.js b/features/support/hooks.js index f3c7fe10d..01c2e6e89 100644 --- a/features/support/hooks.js +++ b/features/support/hooks.js @@ -22,7 +22,7 @@ module.exports = function () { }); this.BeforeFeature((feature, callback) => { - this.profile = this.DEFAULT_PROFILE; + this.profile = this.OSRM_PROFILE || this.DEFAULT_PROFILE; this.profileFile = path.join(this.PROFILES_PATH, this.profile + '.lua'); this.setupFeatureCache(feature); callback(); @@ -50,6 +50,8 @@ module.exports = function () { .defer(mkdirp, logDir) .defer(rimraf, this.scenarioLogFile) .awaitAll(callback); + // uncomment to get path to logfile + // console.log(' Writing logging output to ' + this.scenarioLogFile); }); this.After((scenario, callback) => { diff --git a/features/support/route.js b/features/support/route.js index df50ca2a6..e97153659 100644 --- a/features/support/route.js +++ b/features/support/route.js @@ -199,14 +199,26 @@ module.exports = function () { var merged = {}; instructions.legs.map(l => { - Object.keys(l.annotation).forEach(a => { + Object.keys(l.annotation).filter(a => !a.match(/metadata/)).forEach(a => { if (!merged[a]) merged[a] = []; merged[a].push(l.annotation[a].join(':')); }); + if (l.annotation.metadata) { + merged.metadata = {}; + Object.keys(l.annotation.metadata).forEach(a => { + if (!merged.metadata[a]) merged.metadata[a] = []; + merged.metadata[a].push(l.annotation.metadata[a].join(':')); + }); + } }); - Object.keys(merged).map(a => { + Object.keys(merged).filter(k => !k.match(/metadata/)).map(a => { merged[a] = merged[a].join(','); }); + if (merged.metadata) { + Object.keys(merged.metadata).map(a => { + merged.metadata[a] = merged.metadata[a].join(','); + }); + } return merged; }; @@ -279,6 +291,10 @@ module.exports = function () { return this.extractInstructionList(instructions, s => s.mode); }; + this.drivingSideList = (instructions) => { + return this.extractInstructionList(instructions, s => s.driving_side); + }; + this.classesList = (instructions) => { return this.extractInstructionList(instructions, s => '[' + s.intersections.map(i => '(' + (i.classes ? i.classes.join(',') : '') + ')').join(',') + ']'); }; diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js index 06abd7740..3257c62b2 100644 --- a/features/support/shared_steps.js +++ b/features/support/shared_steps.js @@ -36,7 +36,7 @@ module.exports = function () { if (body && body.length) { let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times, classes, distances, summary, intersections, lanes, locations, annotation, weight_name, weights, approaches, - bearing_befores, bearing_afters; + bearing_befores, bearing_afters, driving_sides; let json = JSON.parse(body); @@ -54,6 +54,7 @@ module.exports = function () { turns = this.turnList(json.routes[0]); intersections = this.intersectionList(json.routes[0]); modes = this.modeList(json.routes[0]); + driving_sides = this.drivingSideList(json.routes[0]); classes = this.classesList(json.routes[0]); times = this.timeList(json.routes[0]); distances = this.distanceList(json.routes[0]); @@ -76,6 +77,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['#']; @@ -116,7 +121,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 { @@ -152,14 +157,22 @@ module.exports = function () { if (headers.has('locations')){ got.locations = (locations || '').trim(); } -/* + if (headers.has('waypoints_count')) { + if ('waypoints' in json) { + got.waypoints_count = json.waypoints.length; + } else{ + got.waypoints_count = 0; + } + } + /* if (headers.has('approaches')){ got.approaches = (approaches || '').trim(); }*/ // if header matches 'a:*', parse out the values for * // and return in that header headers.forEach((k) => { - let whitelist = ['duration', 'distance', 'datasources', 'nodes', 'weight', 'speed']; + let whitelist = ['duration', 'distance', 'datasources', 'nodes', 'weight', 'speed' ]; + let metadata_whitelist = [ 'datasource_names' ]; if (k.match(/^a:/)) { let a_type = k.slice(2); if (whitelist.indexOf(a_type) == -1) @@ -167,6 +180,13 @@ module.exports = function () { if (annotation && !annotation[a_type]) return cb(new Error('Annotation not found in response', a_type)); got[k] = annotation && annotation[a_type] || ''; + } else if (k.match(/^am:/)) { + let a_type = k.slice(3); + if (metadata_whitelist.indexOf(a_type) == -1) + return cb(new Error('Unrecognized annotation field', a_type)); + if (annotation && (!annotation.metadata || !annotation.metadata[a_type])) + return cb(new Error('Annotation not found in response', a_type)); + got[k] = (annotation && annotation.metadata && annotation.metadata[a_type]) || ''; } }); @@ -191,6 +211,10 @@ module.exports = function () { putValue('bearing_before', bearing_befores); putValue('bearing_after', bearing_afters); + if (driving_sides) { + putValue('driving_side', driving_sides); + } + for (var key in row) { if (this.FuzzyMatch.match(got[key], row[key])) { got[key] = row[key]; diff --git a/features/testbot/alternative.feature b/features/testbot/alternative.feature index 05d39dfbb..40bbad5da 100644 --- a/features/testbot/alternative.feature +++ b/features/testbot/alternative.feature @@ -4,6 +4,14 @@ Feature: Alternative route Background: Given the profile "testbot" And a grid size of 200 meters + # Force data preparation to single-threaded to ensure consistent + # results for alternative generation during tests (alternative + # finding is highly sensitive to graph shape, which is in turn + # affected by parallelism during generation) + And the contract extra arguments "--threads 1" + And the extract extra arguments "--threads 1" + And the customize extra arguments "--threads 1" + And the partition extra arguments "--threads 1" And the node map """ @@ -12,6 +20,9 @@ Feature: Alternative route g h i j """ + # enforce multiple cells for filterUnpackedPathsBySharing check + And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16" + And the ways | nodes | | ab | diff --git a/features/testbot/alternative_loop.feature b/features/testbot/alternative_loop.feature index a55568a24..182137969 100644 --- a/features/testbot/alternative_loop.feature +++ b/features/testbot/alternative_loop.feature @@ -4,6 +4,14 @@ Feature: Alternative route Background: Given the profile "testbot" Given a grid size of 200 meters + # Force data preparation to single-threaded to ensure consistent + # results for alternative generation during tests (alternative + # finding is highly sensitive to graph shape, which is in turn + # affected by parallelism during generation) + And the contract extra arguments "--threads 1" + And the extract extra arguments "--threads 1" + And the customize extra arguments "--threads 1" + And the partition extra arguments "--threads 1" Scenario: Alternative Loop Paths Given the node map @@ -31,40 +39,32 @@ Feature: Alternative route | 5 | 6 | dc,ca,ab,bd,dc,dc | | | 7 | 8 | ca,ab,bd,dc,ca,ca | | - # This test case does not work in a platform independent way - # since it depends on a specific CH structure that is only - # present on linux it seems. - @4111 @todo - Scenario: Alternative Loop Paths with single node path + + @mld-only + Scenario: Alternative loop paths on a single node with an asymmetric circle + # The test checks only MLD implementation, alternatives results are unpredictable for CH on windows (#4691, #4693) + Given a grid size of 10 meters Given the node map """ - a1b2c3d - - - e f + a b c + l d + k e + j f + i h g """ + And the nodes + | node | barrier | + | i | bollard | + | g | bollard | + And the ways - | nodes | maxspeed | - | ab | 30 | - | bc | 3 | - | cd | 30 | - | ae | 30 | - | ef | 30 | - | fd | 30 | + | nodes | oneway | + | abcdefghijkla | no | And the query options | alternatives | true | When I route I should get - | from | to | route | alternative | - | b | c | bc,bc | ab,ae,ef,fd,cd,cd | - #| c | b | bc,bc | cd,fd,ef,ae,ab,ab | # alternative path depends on phantom snapping order - | 1 | c | ab,bc,bc | ab,ae,ef,fd,cd,cd | - #| c | 1 | bc,ab | cd,fd,ef,ae,ab | # alternative path depends on phantom snapping order - | 2 | c | bc,bc | | - | c | 2 | bc,bc | | - | 1 | 3 | ab,ae,ef,fd,cd | ab,bc,cd | - #| 3 | 1 | cd,fd,ef,ae,ab | cd,bc,ab | # alternative path depends on phantom snapping order - | b | 3 | bc,cd | ab,ae,ef,fd,cd | - #| 3 | b | cd,bc,bc | cd,fd,ef,ae,ab,ab | # alternative path depends on phantom snapping order + | from | to | route | alternative | weight | + | e | k | abcdefghijkla,abcdefghijkla | abcdefghijkla,abcdefghijkla | 6.8 | diff --git a/features/testbot/annotations.feature b/features/testbot/annotations.feature index 6c71a88ee..c61ebb1aa 100644 --- a/features/testbot/annotations.feature +++ b/features/testbot/annotations.feature @@ -11,7 +11,7 @@ Feature: Annotations """ And the query options - | annotations | duration,speed,weight | + | annotations | duration,speed,weight,nodes | And the ways | nodes | highway | @@ -22,10 +22,10 @@ Feature: Annotations | lm | residential | When I route I should get - | from | to | route | a:speed | a:weight | - | h | j | hk,jk,jk | 6.7:6.7 | 15:15 | - | i | m | il,lm,lm | 6.7:6.7 | 15:15 | - | j | m | jk,lm | 6.7:6.7:6.7 | 15:15:15 | + | from | to | route | a:speed | a:weight | a:nodes | + | h | j | hk,jk,jk | 6.7:6.7 | 15:15 | 1:4:3 | + | i | m | il,lm,lm | 6.7:6.7 | 15:15 | 2:5:6 | + | j | m | jk,lm | 6.7:6.7:6.7 | 15:15:15 | 3:4:5:6 | Scenario: There should be different forward/reverse datasources @@ -59,3 +59,60 @@ Feature: Annotations | from | to | route | a:datasources | a:speed | | a | i | abcdefghi,abcdefghi | 1:0:1:0:1:0:0:0 | 50:10:50:10:50:10:10:10 | | i | a | abcdefghi,abcdefghi | 0:1:0:0:0:0:0:1 | 10:50:10:10:10:10:10:50 | + + Scenario: datasource name annotations + Given the profile "testbot" + + And the node map + """ + a b c + """ + + And the ways + | nodes | + | abc | + + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + + And the speed file + """ + 1,2,180,1 + 2,1,180,1 + """ + + And the query options + | annotations | datasources | + + # Note - the source names here are specific to how the tests are constructed, + # so if this test is moved around (changes line number) or support code + # changes how the filenames are generated, this test will need to be updated + When I route I should get + | from | to | route | am:datasource_names | + | a | c | abc,abc | lua profile:63_datasource_name_annotations_speeds | + | c | a | abc,abc | lua profile:63_datasource_name_annotations_speeds | + + + Scenario: Speed annotations should handle zero segments + Given the profile "testbot" + + Given the node map + """ + a -- b --- c + | + d + """ + + And the ways + | nodes | + | abc | + | cd | + + # This test relies on the snapping to the EBN cd to introduce a zero segment after the turn + And the query options + | annotations | speed,distance,duration,nodes | + | bearings | 90,5;180,5 | + + When I route I should get + | from | to | route | a:speed | a:distance | a:duration | a:nodes | + | a | c | abc,abc | 10:10 | 249.987618946:299.962882039 | 25:30 | 1:2:3 | diff --git a/features/testbot/approaches.feature b/features/testbot/approaches.feature index 73ca1af52..d3e0c4630 100644 --- a/features/testbot/approaches.feature +++ b/features/testbot/approaches.feature @@ -2,11 +2,11 @@ Feature: Approach parameter Background: - Given the profile "testbot" - And a grid size of 10 meters + Given a grid size of 10 meters Scenario: Start End same approach, option unrestricted for Start and End - Given the node map + Given the profile "testbot" + And the node map """ s e a------b------c @@ -22,7 +22,8 @@ Feature: Approach parameter | s | e | unrestricted unrestricted | ab,bc | Scenario: Start End same approach, option unrestricted for Start and curb for End - Given the node map + Given the profile "testbot" + And the node map """ s e a------b------c @@ -38,7 +39,8 @@ Feature: Approach parameter | s | e | unrestricted curb | ab,bc,bc | Scenario: Start End opposite approach, option unrestricted for Start and End - Given the node map + Given the profile "testbot" + And the node map """ s a------b------c @@ -55,7 +57,8 @@ Feature: Approach parameter | s | e | unrestricted unrestricted | ab,bc | Scenario: Start End opposite approach, option unrestricted for Start and curb for End - Given the node map + Given the profile "testbot" + And the node map """ s a------b------c @@ -71,13 +74,15 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | + ############### # Oneway Test # ############### Scenario: Test on oneway segment, Start End same approach, option unrestricted for Start and End - Given the node map + Given the profile "testbot" + And the node map """ s e a------b------c @@ -93,7 +98,8 @@ Feature: Approach parameter | s | e | unrestricted unrestricted | ab,bc | Scenario: Test on oneway segment, Start End same approach, option unrestricted for Start and curb for End - Given the node map + Given the profile "testbot" + And the node map """ s e a------b------c @@ -109,7 +115,8 @@ Feature: Approach parameter | s | e | unrestricted curb | ab,bc | Scenario: Test on oneway segment, Start End opposite approach, option unrestricted for Start and End - Given the node map + Given the profile "testbot" + And the node map """ s a------b------c @@ -126,7 +133,8 @@ Feature: Approach parameter | s | e | unrestricted unrestricted | ab,bc | Scenario: Test on oneway segment, Start End opposite approach, option unrestricted for Start and curb for End - Given the node map + Given the profile "testbot" + And the node map """ s a------b------c @@ -147,7 +155,8 @@ Feature: Approach parameter ############## Scenario: UTurn test, router can't found a route because uturn unauthorized on the segment selected - Given the node map + Given the profile "testbot" + And the node map """ s e a------b------c @@ -168,7 +177,8 @@ Feature: Approach parameter Scenario: UTurn test, router can find a route because he can use the roundabout - Given the node map + Given the profile "testbot" + And the node map """ h s e / \ @@ -190,3 +200,117 @@ Feature: Approach parameter When I route I should get | from | to | approaches | route | | s | e | unrestricted curb | ab,bc,bc | + + + Scenario: Start End same approach, option unrestricted for Start and curb for End, left-hand driving + Given the profile file + """ + local functions = require('testbot') + local testbot_process_way = functions.process_way + functions.process_way = function(profile, way, result) + testbot_process_way(profile, way, result) + result.is_left_hand_driving = true + end + return functions + """ + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc | + + + ####################### + # Left-side countries # + ####################### + + Scenario: [Left-hand-side] Start End same approach, option unrestricted for Start and End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted unrestricted | ab,bc | + + Scenario: [Left-hand-side] Start End same approach, option unrestricted for Start and curb for End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc,bc | + + Scenario: [Left-hand-side] Start End opposite approach, option unrestricted for Start and End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted unrestricted | ab,bc | + + Scenario: [Left-hand-side] Start End opposite approach, option unrestricted for Start and curb for End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc | \ No newline at end of file diff --git a/features/testbot/basic.feature b/features/testbot/basic.feature index c7da7b243..9224cd469 100644 --- a/features/testbot/basic.feature +++ b/features/testbot/basic.feature @@ -17,9 +17,43 @@ 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 | waypoints_count | + | a | b | ab,ab | | 2 | + | b | a | ab,ab | | 2 | + + 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: Skip_waypoints test + Given the node map + """ + a b + """ + + And skip waypoints + + And the ways + | nodes | + | ab | + + When I route I should get + | from | to | route | waypoints_count | + | a | b | ab,ab | 0 | + | b | a | ab,ab | 0 | Scenario: Routing in between two nodes of way Given the node map diff --git a/features/testbot/bearing.feature b/features/testbot/bearing.feature index d74f4bafd..0ae483ca4 100644 --- a/features/testbot/bearing.feature +++ b/features/testbot/bearing.feature @@ -67,10 +67,10 @@ Feature: Compass bearing Scenario: Bearing in a roundabout Given the node map """ - k d c j - e b - f a - l g h i + k d 1c j + e b + f a + l g2 h i """ And the ways @@ -94,8 +94,8 @@ Feature: Compass bearing When I route I should get | from | to | route | bearing | - | c | b | cd,de,ef,fg,gh,ha,ab,ab | 0->270,270->225,225->180,180->135,135->90,90->45,45->0,0->0 | - | g | f | gh,ha,ab,bc,cd,de,ef,ef | 0->90,90->45,45->0,0->315,315->270,270->225,225->180,180->0 | + | 1 | b | cd,de,ef,fg,gh,ha,ab,ab | 0->270,270->225,225->180,180->135,135->90,90->45,45->0,0->0 | + | 2 | f | gh,ha,ab,bc,cd,de,ef,ef | 0->90,90->45,45->0,0->315,315->270,270->225,225->180,180->0 | Scenario: Bearing should stay constant when zig-zagging Given the node map diff --git a/features/testbot/bearing_param.feature b/features/testbot/bearing_param.feature index 1d286ca49..227324bff 100644 --- a/features/testbot/bearing_param.feature +++ b/features/testbot/bearing_param.feature @@ -108,12 +108,12 @@ Feature: Bearing parameter | ha | yes | ring | When I route I should get - | from | to | bearings | route | bearing | - | 0 | q | 0 90 | ia,ring,ring,ring,ring | 0->0,0->90,180->270,270->0,90->0 | - | 0 | a | 45 90 | jb,ring,ring,ring,ring | 0->45,45->180,180->270,270->0,90->0 | - | 0 | q | 90 90 | kc,ring,ring,ring | 0->90,90->180,270->0,90->0 | - | 0 | a | 135 90 | ld,ring,ring,ring | 0->135,135->270,270->0,90->0 | - | 0 | a | 180 90 | me,ring,ring,ring | 0->180,180->270,270->0,90->0 | - | 0 | a | 225 90 | nf,ring,ring | 0->225,225->0,90->0 | - | 0 | a | 270 90 | og,ring,ring | 0->270,270->0,90->0 | - | 0 | a | 315 90 | ph,ring,ring | 0->315,315->90,90->0 | + | from | to | bearings | route | bearing | + | 0 | q | 0 90 | ia,ring,ring,ring,ring,ring,ring | 0->0,0->90,90->180,180->270,270->0,0->90,90->0 | + | 0 | a | 45 90 | jb,ring,ring,ring,ring,ring | 0->45,45->180,180->270,270->0,0->90,90->0 | + | 0 | q | 90 90 | kc,ring,ring,ring,ring,ring | 0->90,90->180,180->270,270->0,0->90,90->0 | + | 0 | a | 135 90 | ld,ring,ring,ring,ring | 0->135,135->270,270->0,0->90,90->0 | + | 0 | a | 180 90 | me,ring,ring,ring | 0->180,180->270,0->90,90->0 | + | 0 | a | 225 90 | nf,ring,ring,ring | 0->225,225->0,0->90,90->0 | + | 0 | a | 270 90 | og,ring,ring | 0->270,270->0,90->0 | + | 0 | a | 315 90 | ph,ring,ring | 0->315,315->90,90->0 | diff --git a/features/testbot/compression.feature b/features/testbot/compression.feature index 033cc3335..da8c0cdef 100644 --- a/features/testbot/compression.feature +++ b/features/testbot/compression.feature @@ -20,5 +20,5 @@ Feature: Geometry Compression When I route I should get | from | to | route | distance | speed | - | b | e | abcdef,abcdef | 588.5m | 36 km/h | - | e | b | abcdef,abcdef | 588.5m | 36 km/h | + | b | e | abcdef,abcdef | 588.7m | 36 km/h | + | e | b | abcdef,abcdef | 588.7m | 36 km/h | diff --git a/features/testbot/distance.feature b/features/testbot/distance.feature index 8500c1df1..50595b087 100644 --- a/features/testbot/distance.feature +++ b/features/testbot/distance.feature @@ -90,8 +90,8 @@ Feature: Distance calculation | b | a | abc,abc | 100m | | b | c | abc,abc | 100m | | c | b | abc,abc | 100m | - | a | c | abc,abc | 200m | - | c | a | abc,abc | 200m | + | a | c | abc,abc | 199.9m | + | c | a | abc,abc | 199.9m | Scenario: 1km distance Given a grid size of 1000 meters @@ -134,7 +134,7 @@ Feature: Distance calculation | a | c | abcdefgh,abcdefgh | 20m | | a | d | abcdefgh,abcdefgh | 30m | | a | e | abcdefgh,abcdefgh | 40m | - | a | f | abcdefgh,abcdefgh | 50m | + | a | f | abcdefgh,abcdefgh | 50.1m | | a | g | abcdefgh,abcdefgh | 60m +-1 | | a | h | abcdefgh,abcdefgh | 70m +-1 | @@ -154,9 +154,9 @@ Feature: Distance calculation | from | to | route | distance | | a | b | abcdefgh,abcdefgh | 10m | | a | c | abcdefgh,abcdefgh | 20m | - | a | d | abcdefgh,abcdefgh | 30m | - | a | e | abcdefgh,abcdefgh | 40m | - | a | f | abcdefgh,abcdefgh | 50m | + | a | d | abcdefgh,abcdefgh | 29.9m | + | a | e | abcdefgh,abcdefgh | 39.9m | + | a | f | abcdefgh,abcdefgh | 49.9m | | a | g | abcdefgh,abcdefgh | 60m +-1 | | a | h | abcdefgh,abcdefgh | 70m +-1 | @@ -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 | diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature index 2dde7de2c..5d1ea444a 100644 --- a/features/testbot/distance_matrix.feature +++ b/features/testbot/distance_matrix.feature @@ -1,62 +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" - - 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 | - - 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 + And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16" + Scenario: Testbot - Travel distance matrix of small grid Given the node map """ a b c @@ -71,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 | 199.9 | 300 | + | b | 100 | 0 | 100 | 200 | + | e | 199.9 | 100 | 0 | 100.1 | + | f | 300 | 200 | 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 | 199.9 | 300 | 399.9 | + | z | 100 | 0 | 100 | 200 | 300 | + | b | 199.9 | 100 | 0 | 100.1 | 200 | + | c | 300 | 200 | 100.1 | 0 | 100 | + | d | 399.9 | 300 | 200 | 100 | 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 | | | + | b | 100 | 0 | | | + | c | | | 0 | 100 | + | d | | | 100 | 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 | 299.9 | 100 | 199.9 | + + 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 | | + + 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 | | | + + 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 | 200 | 300 | + | b | 100 | 0 | 100.1 | 200 | + | c | 200 | 100.1 | 0 | 100 | + | d | 300 | 200 | 100 | 0 | + + When I request a travel distance matrix I should get + | | a | b | c | d | + | a | 0 | 100 | 200 | 300 | + + When I request a travel distance matrix I should get + | | a | + | a | 0 | + | b | 100 | + | c | 200 | + | d | 300 | + + 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 | 199.9 | 300 | + | b | 100 | 0 | 100 | 200 | + | e | 199.9 | 100 | 0 | 100.1 | + | f | 300 | 200 | 100.1 | 0 | + + Scenario: Testbot - Travel distance matrix of network with unroutable parts Given the node map """ a b @@ -88,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 | + | 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 @@ -106,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 | 400 | 300 | + | y | 499.9 | 0 | 300 | 199.9 | + | d | 199.9 | 300 | 0 | 300 | + | e | 300 | 400 | 100.1 | 0 | - Scenario: Testbot - Travel time matrix and with only one source + Scenario: Testbot - Rectangular travel distance matrix Given the node map """ a b c @@ -128,11 +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 | 199.9m | + | e | b | 100m | + | f | a | 300m | + | f | b | 200m | - Scenario: Testbot - Travel time 3x2 matrix + When I request a travel distance matrix I should get + | | a | b | e | f | + | a | 0 | 100 | 199.9 | 300 | + + When I request a travel distance matrix I should get + | | a | + | a | 0 | + | b | 100 | + | e | 199.9 | + | f | 300 | + + When I request a travel distance matrix I should get + | | a | b | e | f | + | a | 0 | 100 | 199.9 | 300 | + | b | 100 | 0 | 100 | 200 | + + When I request a travel distance matrix I should get + | | a | b | + | a | 0 | 100 | + | b | 100 | 0 | + | e | 199.9 | 100 | + | f | 300 | 200 | + + When I request a travel distance matrix I should get + | | a | b | e | f | + | a | 0 | 100 | 199.9 | 300 | + | b | 100 | 0 | 100 | 200 | + | e | 199.9 | 100 | 0 | 100.1 | + + When I request a travel distance matrix I should get + | | a | b | e | + | a | 0 | 100 | 199.9 | + | b | 100 | 0 | 100 | + | e | 199.9 | 100 | 0 | + | f | 300 | 200 | 100.1 | + + When I request a travel distance matrix I should get + | | a | b | e | f | + | a | 0 | 100 | 199.9 | 300 | + | b | 100 | 0 | 100 | 200 | + | e | 199.9 | 100 | 0 | 100.1 | + | f | 300 | 200 | 100.1 | 0 | + + Scenario: Testbot - Travel distance 3x2 matrix Given the node map """ a b c @@ -147,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 | 199.9 | 300 | + | b | 0 | 100 | 200 | Scenario: Testbot - All coordinates are from same small component Given a grid size of 300 meters @@ -169,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 | 300 | + | g | 300 | 0 | Scenario: Testbot - Coordinates are from different small component and snap to big CC Given a grid size of 300 meters @@ -192,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 | 300 | 0 | 300 | + | g | 300 | 0 | 300 | 0 | + | h | 0 | 300 | 0 | 300 | + | i | 300 | 0 | 300 | 0 | + + Scenario: Testbot - Travel distance matrix with loops Given the node map """ a 1 2 b @@ -213,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.9 | 500 | + | 2 | 699.8 | 0 | 299.9 | 399.9 | + | 3 | 399.9 | 500 | 0 | 100.1 | + | 4 | 299.9 | 399.9 | 699.8 | 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') @@ -249,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 | 200 | 300 | 400 | + | b | 100 | 0 | 100.1 | 200 | 300.1 | + | c | 200 | 100.1 | 0 | 100 | 200 | + | d | 300 | 200 | 100 | 0 | 300 | + | e | 400 | 300.1 | 200 | 300 | 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') @@ -298,13 +466,264 @@ 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 | 1099.8 | 300 | 199.9 | 600 | 499.9 | 899.9 | 799.9 | + | 2 | 100.1 | 0 | 400 | 300 | 700 | 600 | 1000 | 899.9 | + | 3 | 899.9 | 799.9 | 0 | 1099.8 | 300 | 199.9 | 600 | 499.9 | + | 4 | 1000 | 899.9 | 100.1 | 0 | 400 | 300 | 700 | 600 | + | 5 | 600 | 499.9 | 899.9 | 799.9 | 0 | 1099.8 | 300 | 199.9 | + | 6 | 700 | 600 | 1000 | 899.9 | 100.1 | 0 | 400 | 300 | + | 7 | 300 | 199.9 | 600 | 499.9 | 899.9 | 799.9 | 0 | 1099.8 | + | 8 | 400 | 300 | 700 | 600 | 1000 | 899.9 | 100.1 | 0 | + + When I request a travel distance matrix I should get + | | 1 | + | 1 | 0 | + | 2 | 100.1 | + | 3 | 899.9 | + | 4 | 1000 | + | 5 | 600 | + | 6 | 700 | + | 7 | 300 | + | 8 | 400 | + + Scenario: Testbot - Travel distance matrix with ties + Given 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 | 20s | 20 | + + 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 | 500m | + + When I request a travel distance matrix I should get + | | a | b | c | d | + | a | 0 | 450 | 200 | 500 | + + When I request a travel distance matrix I should get + | | a | + | a | 0 | + | b | 450 | + | c | 200 | + | d | 500 | + + When I request a travel distance matrix I should get + | | a | c | + | a | 0 | 200 | + | c | 200 | 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.1 | 2000 | 3000.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 | 241.3 | 0 | + + When I request a travel distance matrix I should get + | | a | + | a | 0 | + | b | 241.3 | + + 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 | 300 | 650 | 660.5 | 1534.6 | + | b | 760.6 | 0 | 200 | 550.1 | 560.6 | 1434.6 | + | c | 560.6 | 660.5 | 0 | 350 | 360.5 | 1234.6 | + | d | 1484.6 | 1584.5| 1645.1 | 0 | 1284.5 | 884.6 | + | e | 200 | 300 | 360.5 | 710.6 | 0 | 1595.2 | + | f | 600 | 699.9 | 760.5 | 884.6 | 399.9 | 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 | 900 | 1500 | + | b | 300 | 0 | 600 | 1200.1 | + | f | 900 | 600 | 0 | 300 | + | 1 | 1500 | 1200.1 | 300 | 0 | + + When I request a travel distance matrix I should get + | | a | b | f | 1 | + | a | 0 | 300 | 900 | 1500 | + + When I request a travel distance matrix I should get + | | a | + | a | 0 | + | b | 300 | + | f | 900 | + | 1 | 1500 | + + 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 | 900 | 1500 | + | b | 300 | 0 | 600 | 1200.1 | + | f | 900 | 600 | 0 | 300 | + | 1 | 1500 | 1200.1 | 300 | 0 | + + When I request a travel distance matrix I should get + | | a | b | f | 1 | + | a | 0 | 300 | 900 | 1500 | + + When I request a travel distance matrix I should get + | | a | + | a | 0 | + | b | 300 | + | f | 900 | + | 1 | 1500 | + + + 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 | 900 | 1200 | + | b | 300 | 0 | 600 | 900 | + | f | 900 | 600 | 0 | 300 | + | 1 | 1200 | 900 | 300 | 0 | + + When I request a travel distance matrix I should get + | | a | b | f | 1 | + | a | 0 | 300 | 900 | 1200 | + + When I request a travel distance matrix I should get + | | a | + | a | 0 | + | b | 300 | + | f | 900 | + | 1 | 1200 | + + 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 3 + """ + + And the ways + | nodes | + | abcdef | + | fghij | + + When I route I should get + | from | to | route | distance | + | 1 | 2 | abcdef,fghij,fghij | 1000.1m | + | 1 | 3 | abcdef,fghij,fghij | 1400.1m | + | 2 | 3 | fghij,fghij | 400m | + + + When I request a travel distance matrix I should get + | | 1 | 2 | 3 | + | 1 | 0 | 1000.1 | 1400.1 | + | 2 | 1000.1 | 0 | 400 | + | 3 | 1400.1 | 400 | 0 | diff --git a/features/testbot/duration_matrix.feature b/features/testbot/duration_matrix.feature new file mode 100644 index 000000000..4c6e1510d --- /dev/null +++ b/features/testbot/duration_matrix.feature @@ -0,0 +1,792 @@ +@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 | + + Scenario: Testbot - Travel time matrix of minimal network requested with flatbuffer format + Given the node map + """ + a b + """ + + And the ways + | nodes | + | ab | + + When I request a travel time matrix with flatbuffers 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 | 10.9 | 3 | 1.9 | 6 | 4.9 | 9 | 7.9 | + | 2 | 1.1 | 0 | 4.1 | 3 | 7.1 | 6 | 10.1 | 9 | + | 3 | 9 | 7.9 | 0 | 10.9 | 3 | 1.9 | 6 | 4.9 | + | 4 | 10.1 | 9 | 1.1 | 0 | 4.1 | 3 | 7.1 | 6 | + | 5 | 6 | 4.9 | 9 | 7.9 | 0 | 10.9 | 3 | 1.9 | + | 6 | 7.1 | 6 | 10.1 | 9 | 1.1 | 0 | 4.1 | 3 | + | 7 | 3 | 1.9 | 6 | 4.9 | 9 | 7.9 | 0 | 10.9 | + | 8 | 4.1 | 3 | 7.1 | 6 | 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 | 1s | 1 | + + When I request a travel time matrix I should get + | | a | b | c | d | + | a | 0 | 1 | 1 | 6 | + + When I request a travel time matrix I should get + | | a | + | a | 0 | + | b | 1 | + | c | 1 | + | d | 6 | + + 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 | 17.9 | 30 | + | b | 30 | 0 | 12 | 24 | + | f | 17.9 | 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 | 17.9 | 30 | + + When I request a travel time matrix I should get + | | a | + | a | 0 | + | b | 30 | + | f | 17.9 | + | 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 | 17.9 | 30 | + | b | 30 | 0 | 12 | 24 | + | f | 17.9 | 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 | 17.9 | 30 | + + When I request a travel time matrix I should get + | | a | + | a | 0 | + | b | 30 | + | f | 17.9 | + | 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 | 17.9 | 23.9 | + | b | 30 | 0 | 12 | 17.9 | + | f | 17.9 | 12 | 0 | 30 | + | 1 | 23.9 | 17.9 | 30 | 0 | + + When I request a travel time matrix I should get + | | a | b | f | 1 | + | a | 0 | 30 | 17.9 | 23.9 | + + When I request a travel time matrix I should get + | | a | + | a | 0 | + | b | 30 | + | f | 17.9 | + | 1 | 23.9 | + + 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 | 35.8 | 47.8 | + | b | 60 | 0 | 24 | 35.8 | + | f | 35.8 | 24 | 0 | 60 | + | 1 | 47.8 | 35.8 | 60 | 0 | + + When I request a travel time matrix I should get + | | a | b | f | 1 | + | a | 0 | 60 | 35.8 | 47.8 | + + When I request a travel time matrix I should get + | | a | + | a | 0 | + | b | 60 | + | f | 35.8 | + | 1 | 47.8 | + + 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 | diff --git a/features/testbot/exclude_regressions.feature b/features/testbot/exclude_regressions.feature new file mode 100644 index 000000000..b6c5dd864 --- /dev/null +++ b/features/testbot/exclude_regressions.feature @@ -0,0 +1,68 @@ +@routing @testbot @exclude +Feature: Testbot - Exclude flags regression tests + Background: + Given the profile "testbot" + + Scenario: Testbot - Exclude toll regression 1 + Given the node map + """ + a g + . . + b....d-$-$-e....f + . . + c h + """ + + And the ways + | nodes | highway | toll | # | + | ab | primary | | always drivable | + | cb | primary | | always drivable | + | bd | primary | | always drivable | + | de | motorway | yes | not drivable for exclude=toll | + | ef | primary | | always drivable | + | fg | primary | | always drivable | + | fh | primary | | always drivable | + + Given the query options + | exclude | toll | + + When I route I should get + | from | to | route | + | a | h | | + | a | g | | + | g | a | | + | d | e | | + + Scenario: Testbot - Exclude toll regression 2 + Given the profile "testbot" + + Given the node map + """ + a g + . . + b....d-$-$-e....f + . . + c h..i + """ + + And the ways + | nodes | highway | toll | # | + | ab | primary | | always drivable | + | cb | primary | | always drivable | + | bd | primary | | always drivable | + | de | motorway | yes | not drivable for exclude=toll | + | ef | primary | | always drivable | + | fg | primary | | always drivable | + | fh | primary | | always drivable | + | hi | primary | | always drivable | + + Given the query options + | exclude | toll | + + When I route I should get + | from | to | route | + | a | h | | + | a | g | | + | g | a | | + | d | e | | + | d | i | | diff --git a/features/testbot/fixed.feature b/features/testbot/fixed.feature index 9d83649ff..1eb66b89f 100644 --- a/features/testbot/fixed.feature +++ b/features/testbot/fixed.feature @@ -39,5 +39,64 @@ Feature: Fixed bugs, kept to check for regressions | de | yes | When I route I should get - | from | to | route | - | 1 | 2 | bcd,bcd | + | from | to | route | + | 1 | 2 | bcd,bcd | + + ############################# + # This test models the OSM map at the location for + # https://github.com/Project-OSRM/osrm-backend/issues/5039 + ############################# + Scenario: Mixed Entry and Exit and segregated + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + Given the node locations + | node | lon | lat | + | a | 171.12889297029 | -42.58425289548 | + | b | 171.1299357 | -42.5849295 | + | c | 171.1295427 | -42.5849385 | + | d | 171.1297356 | -42.5852029 | + | e | 171.1296909 | -42.5851986 | + | f | 171.1295097 | -42.585007 | + | g | 171.1298225 | -42.5851928 | + | h | 171.1300262 | -42.5859122 | + | i | 171.1292651 | -42.584698 | + | j | 171.1297209 | -42.5848569 | + | k | 171.1297188 | -42.5854056 | + | l | 171.1298326 | -42.5857266 | + | m | 171.1298871 | -42.5848922 | + | n | 171.1296505 | -42.585189 | + | o | 171.1295206 | -42.5850862 | + | p | 171.1296106 | -42.5848862 | + | q | 171.1299784 | -42.5850191 | + | r | 171.1298867 | -42.5851671 | + | s | 171.1306955 | -42.5845812 | + | t | 171.129525 | -42.584807 | + | u | 171.1299705 | -42.584984 | + | v | 171.1299067 | -42.5849073 | + | w | 171.1302061 | -42.5848173 | + | x | 171.12975 | -42.5855753 | + | y | 171.129969 | -42.585079 | + | 1 | 171.131511926651| -42.584306746421966 | + | 2 | 171.128743886947| -42.58414875714669 | + And the ways + | nodes | highway | maxspeed | name | ref | surface | junction | oneway | + | ws | primary | 100 | Taramakau Highway | SH 6 | asphalt | | | + | kxlh | trunk | | Otira Highway | SH 73 | | | | + | ai | primary | 100 | Kumara Junction Highway | SH 6 | asphalt | | | + | qyrgdenof | primary | 100 | Kumara Junction | | | roundabout | yes | + | ke | trunk | | Otira Highway | SH 73 | | | yes | + | itj | primary | 100 | Kumara Junction Highway | SH 6 | | | yes | + | gk | trunk | | Otira Highway | SH 73 | | | yes | + | fi | primary | 100 | Kumara Junction Highway | SH 6 | | | yes | + | wq | primary | 100 | Taramakau Highway | SH 6 | | | yes | + | vw | primary | 100 | Taramakau Highway | SH 6 | | | yes | + | vbuq | primary | 100 | Kumara Junction | | | roundabout | yes | + | jmv | primary | 100 | Kumara Junction | | | roundabout | yes | + | fcpj | primary | 100 | Kumara Junction | | | roundabout | yes | + + When I route I should get + | waypoints | route | turns | + | 1,2 | Taramakau Highway,Kumara Junction Highway,Kumara Junction Highway,Kumara Junction Highway | depart,Kumara Junction-exit-2,exit rotary slight left,arrive | + diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature index c5ae5cea5..49f42064f 100644 --- a/features/testbot/matching.feature +++ b/features/testbot/matching.feature @@ -21,8 +21,27 @@ Feature: Basic Map Matching | abcd | no | When I match I should get - | trace | timestamps | matchings | - | ab1d | 0 1 2 3 | ad | + | trace | timestamps | matchings | data_version | + | ab1d | 0 1 2 3 | ad | | + + Scenario: Data_version test on matching + Given a grid size of 100 meters + Given the node map + """ + a b c d + + 1 + """ + + And the extract extra arguments "--data_version cucumber_data_version" + + And the ways + | nodes | oneway | + | abcd | no | + + When I match I should get + | trace | timestamps | matchings | data_version | + | ab1d | 0 1 2 3 | ad | cucumber_data_version | Scenario: Testbot - Map matching with trace splitting Given the node map @@ -279,8 +298,8 @@ Feature: Basic Map Matching | fb | yes | When I match I should get - | trace | matchings | geometry | - | efbc | efbc | 1,0.99964,1.00036,0.99964,1.00036,1,1.000719,1 | + | trace | matchings | geometry | + | efbc | efbc | 1,0.999638,1.000359,0.999638,1.000359,1,1.000719,1 | Scenario: Testbot - Geometry details using geojson Given the query options @@ -356,7 +375,7 @@ Feature: Basic Map Matching When I match I should get | trace | matchings | alternatives | - | abcdef | abcde | 0,0,0,0,1,1 | + | abcdef | abcde | 0,0,0,1,1,1 | Scenario: Testbot - Speed greater than speed threshold Given a grid size of 100 meters @@ -480,3 +499,317 @@ Feature: Basic Map Matching | trace | a:nodes | | 12 | 1:2:3:4:5:6 | | 21 | 6:5:4:3:2:1 | + + + Scenario: Matching with waypoints param for start/end + Given the node map + """ + a-----b---c + | + | + d + | + | + e + """ + And the ways + | nodes | oneway | + | abc | no | + | bde | no | + + Given the query options + | waypoints | 0;3 | + + When I match I should get + | trace | code | matchings | waypoints | + | abde | Ok | abde | ae | + + Scenario: Matching with waypoints param that were tidied away + Given the node map + """ + a - b - c - e + | + f + | + g + """ + And the ways + | nodes | oneway | + | abce | no | + | cfg | no | + + Given the query options + | tidy | true | + | waypoints | 0;2;5 | + + When I match I should get + | trace | code | matchings | waypoints | + | abccfg | Ok | abcfg | acg | + + Scenario: Testbot - Map matching refuses to use waypoints with trace splitting + Given the node map + """ + a b c d + e + """ + Given the query options + | waypoints | 0;3 | + + And the ways + | nodes | oneway | + | abcd | no | + + When I match I should get + | trace | timestamps | code | + | abcd | 0 1 62 63 | NoMatch | + + Scenario: Testbot - Map matching invalid waypoints + Given the node map + """ + a b c d + e + """ + Given the query options + | waypoints | 0;4 | + + And the ways + | nodes | oneway | + | abcd | no | + + When I match I should get + | trace | code | + | abcd | InvalidOptions | + + Scenario: Matching fail with waypoints param missing start/end + Given the node map + """ + a-----b---c + | + | + d + | + | + e + """ + And the ways + | nodes | oneway | + | abc | no | + | bde | no | + + Given the query options + | waypoints | 1;3 | + + When I match I should get + | trace | code | + | abde | InvalidValue | + + Scenario: Testbot - Map matching with outlier that has no candidate and waypoint parameter + Given a grid size of 100 meters + Given the node map + """ + a b c d + + 1 + """ + + And the ways + | nodes | oneway | + | abcd | no | + + Given the query options + | waypoints | 0;2;3 | + + When I match I should get + | trace | timestamps | code | + | ab1d | 0 1 2 3 | NoMatch | + + Scenario: Regression test - avoid collapsing legs of a tidied split trace + Given a grid size of 20 meters + Given the node map + """ + a--b--f + | + | + e--c---d--g + """ + Given the query options + | tidy | true | + + And the ways + | nodes | oneway | + | abf | no | + | be | no | + | ecdg | no | + + When I match I should get + | trace | timestamps | matchings | code | + | abbecd | 10 11 27 1516914902 1516914913 1516914952 | ab,ecd | Ok | + + Scenario: Regression test - waypoints trimming too much geometry + # fixes bug in map matching collapsing that was dropping path geometries + # after segments that had 0 distance in internal route results + Given the node map + """ + ad + | + | + | + | + |e g + b--------------c + f h + """ + + And the ways + | nodes | + | ab | + | bc | + + Given the query options + | waypoints | 0;4 | + | overview | full | + + When I match I should get + | trace | geometry | code | + | defgh | 1,1,1,0.999457,1.000674,0.999457 | Ok | + + @match @testbot + Scenario: Regression test - waypoints trimming too much geometry + Given the profile "testbot" + Given a grid size of 10 meters + Given the query options + | geometries | geojson | + Given the node map + """ + bh + | + | + | + c + g\ + \k + \ + \ + \ + j f + """ + And the ways + | nodes | + | hc | + | cf | + Given the query options + | waypoints | 0;3 | + | overview | full | + When I match I should get + | trace | geometry | code | + | bgkj | 1.000135,1,1.000135,0.999638,1.000386,0.999132 | Ok | + + + @match @testbot + # Regression test for issue #4919 + Scenario: Regression test - non-uturn maneuver preferred over uturn + Given the profile "testbot" + Given a grid size of 10 meters + Given the query options + | geometries | geojson | + Given the node map + """ + e + ; + ; + a----hb-----c + ; + ; + d + """ + And the ways + | nodes | + | abc | + | dbe | + Given the query options + | waypoints | 0;2 | + | overview | full | + | steps | true | + When I match I should get + | trace | geometry | turns | code | + | abc | 1,0.999729,1.000269,0.999729,1.000539,0.999729 | depart,arrive | Ok | + | abd | 1,0.999729,1.000269,0.999729,1.000269,0.999457 | depart,turn right,arrive | Ok | + | abe | 1,0.999729,1.000269,0.999729,1.000269,1 | depart,turn left,arrive | Ok | + | ahd | 1,0.999729,1.000269,0.999729,1.000269,0.999457 | depart,turn right,arrive | Ok | + | ahe | 1,0.999729,1.000269,0.999729,1.000269,1 | depart,turn left,arrive | Ok | + + @match @testbot + Scenario: Regression test - add source phantoms properly (one phantom on one edge) + Given the profile "testbot" + Given a grid size of 10 meters + Given the node map + """ + a--1-b2-cd3--e + """ + And the ways + | nodes | + | ab | + | bcd | + | de | + Given the query options + | geometries | geojson | + | overview | full | + | steps | true | + | waypoints | 0;2 | + | annotations | duration,weight | + | generate_hints | false | + When I match I should get + | trace | geometry | a:duration | a:weight | duration | + | 123 | 1.000135,1,1.000225,1,1.000359,1,1.000404,1,1.000449,1 | 1:1.5:0.5:0.4 | 1:1.5:0.5:0.4 | 3.4 | + | 321 | 1.000449,1,1.000404,1,1.000359,1,1.000225,1,1.000135,1 | 0.4:0.5:1.5:1 | 0.4:0.5:1.5:1 | 3.4 | + + @match @testbot + Scenario: Regression test - add source phantom properly (two phantoms on one edge) + Given the profile "testbot" + Given a grid size of 10 meters + Given the node map + """ + a--1-b23-c4--d + """ + And the ways + | nodes | + | ab | + | bc | + | cd | + Given the query options + | geometries | geojson | + | overview | full | + | steps | true | + | waypoints | 0;3 | + | annotations | duration,weight | + | generate_hints | false | + When I match I should get + | trace | geometry | a:duration | a:weight | duration | + | 1234 | 1.000135,1,1.000225,1,1.000404,1,1.000449,1 | 1:2:0.4 | 1:2:0.4 | 3.4 | + | 4321 | 1.000449,1,1.000404,1,1.000225,1,1.000135,1 | 0.4:2:1 | 0.4:2:1 | 3.4 | + + @match @testbot + Scenario: Regression test - add source phantom properly (two phantoms on one edge) + Given the profile "testbot" + Given a grid size of 10 meters + Given the node map + """ + a--12345-b + """ + And the ways + | nodes | + | ab | + Given the query options + | geometries | geojson | + | overview | full | + | steps | true | + | waypoints | 0;3 | + | annotations | duration,weight,distance | + | generate_hints | false | + + # These should have the same weights/duration in either direction + When I match I should get + | trace | geometry | a:distance | a:duration | a:weight | duration | + | 2345 | 1.00018,1,1.000314,1 | 14.914666491 | 1.4 | 1.4 | 1.4 | + | 4321 | 1.00027,1,1.000135,1 | 15.025969972 | 1.5 | 1.5 | 1.5 | + diff --git a/features/testbot/multi_level_routing.feature b/features/testbot/multi_level_routing.feature index a13ee5473..5ffabec5e 100644 --- a/features/testbot/multi_level_routing.feature +++ b/features/testbot/multi_level_routing.feature @@ -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 @@ -63,25 +63,81 @@ Feature: Multi level routing | cm | primary | | hj | primary | | kp | primary | + And the partition extra arguments "--small-component-size 1 --max-cell-sizes 4,16" 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 | 239.2 | 157.1 | 137.1 | + + When I request a travel time matrix I should get + | | 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 | 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 | 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 | 2391.6 | 1570.8 | 1370.9 | + | f | 2391.6 | 0 | 1297.2 | 1620.9 | + | l | 1570.8 | 1297.2 | 0 | 800 | + | o | 1370.9 | 1620.9 | 800 | 0 | + + + When I request a travel distance matrix I should get + | | a | f | l | o | + | a | 0 | 2391.6 | 1570.8 | 1370.9 | + + When I request a travel distance matrix I should get + | | a | + | a | 0 | + | f | 2391.6 | + | l | 1570.8 | + | o | 1370.9 | + + When I request a travel distance matrix I should get + | | a | f | l | o | + | a | 0 | 2391.6 | 1570.8 | 1370.9 | + | f | 2391.6 | 0 | 1297.2 | 1620.9 | + + When I request a travel distance matrix I should get + | | a | o | + | a | 0 | 1370.9 | + | f | 2391.6 | 1620.9 | + | l | 1570.8 | 800 | + | o | 1370.9 | 0 | Scenario: Testbot - Multi level routing: horizontal road Given the node map diff --git a/features/testbot/nil.feature b/features/testbot/nil.feature index af8a0b988..521720af7 100644 --- a/features/testbot/nil.feature +++ b/features/testbot/nil.feature @@ -1,18 +1,18 @@ @routing @testbot @nil -Feature: Testbot - Check assigning nil values - Scenario: Assign nil values to all way strings +Feature: Testbot - Check assigning empty values + Scenario: Assign empty values to all way strings Given the profile file """ functions = require('testbot') function way_function(profile, way, result) - result.name = nil - result.ref = nil - result.destinations = nil - result.exits = nil - result.pronunciation = nil - result.turn_lanes_forward = nil - result.turn_lanes_backward = nil + result.name = "" + result.ref = "" + result.destinations = "" + result.exits = "" + result.pronunciation = "" + result.turn_lanes_forward = "" + result.turn_lanes_backward = "" result.forward_speed = 10 result.backward_speed = 10 diff --git a/features/testbot/oneway_phantom.feature b/features/testbot/oneway_phantom.feature new file mode 100644 index 000000000..9d728a507 --- /dev/null +++ b/features/testbot/oneway_phantom.feature @@ -0,0 +1,85 @@ +@routing @testbot @oneway +Feature: Handle multiple phantom nodes in one-way segment + +# Check we handle routes where source and destination are +# phantom nodes on the same one-way segment. +# See: https://github.com/Project-OSRM/osrm-backend/issues/5788 + + Background: + Given the profile "testbot" + + Scenario: One-way segment with adjacent phantom nodes + Given the node map + """ + d c + + a12b + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | no | + | cd | no | + | da | no | + + When I route I should get + | from | to | route | time | distance | + | 1 | 2 | ab,ab | 5s +-0.1 | 50m ~1% | + | 1 | c | ab,bc,bc | 30s +-0.1 | 300m ~1% | + | 2 | 1 | ab,bc,cd,da,ab | 65s +-0.1 | 650m ~1% | + | 2 | c | ab,bc,bc | 25s +-0.1 | 250m ~1% | + | c | 1 | cd,da,ab | 40s +-0.1 | 400m ~1% | + | c | 2 | cd,da,ab | 45s +-0.1 | 450m ~1% | + + When I request a travel time matrix I should get + | | 1 | 2 | c | + | 1 | 0 | 5 +-0.1 | 30 +-0.1 | + | 2 | 65 +-0.1 | 0 | 25 +-0.1 | + | c | 40 +-0.1 | 45 +-0.1 | 0 | + + When I request a travel time matrix I should get + | | 1 | 2 | c | + | 1 | 0 | 5 +-0.1 | 30 +-0.1 | + + When I request a travel time matrix I should get + | | 1 | 2 | c | + | 2 | 65 +-0.1 | 0 | 25 +-0.1 | + + When I request a travel time matrix I should get + | | 1 | + | 1 | 0 | + | 2 | 65 +-0.1 | + | c | 40 +-0.1 | + + When I request a travel time matrix I should get + | | 2 | + | 1 | 5 +-0.1 | + | 2 | 0 | + | c | 45 +-0.1 | + + When I request a travel distance matrix I should get + | | 1 | 2 | c | + | 1 | 0 | 50 ~1% | 300 ~1% | + | 2 | 650 ~1% | 0 | 250 ~1% | + | c | 400 ~1% | 450 ~1% | 0 | + + When I request a travel distance matrix I should get + | | 1 | 2 | c | + | 1 | 0 | 50 ~1% | 300 ~1% | + + When I request a travel distance matrix I should get + | | 1 | 2 | c | + | 2 | 650 ~1% | 0 | 250 ~1% | + + When I request a travel distance matrix I should get + | | 1 | + | 1 | 0 | + | 2 | 650 ~1% | + | c | 400 ~1% | + + When I request a travel distance matrix I should get + | | 2 | + | 1 | 50 ~1% | + | 2 | 0 | + | c | 450 ~1% | diff --git a/features/testbot/origin.feature b/features/testbot/origin.feature index c21febd07..fd14c86f7 100644 --- a/features/testbot/origin.feature +++ b/features/testbot/origin.feature @@ -53,7 +53,7 @@ Feature: Routing close to the [0,0] origin When I route I should get | from | to | route | distance | - | b | d | abcde,abcde | 200m | + | b | d | abcde,abcde | 198.8m | | d | b | | | Scenario: North-south oneways crossing the origin @@ -71,5 +71,5 @@ Feature: Routing close to the [0,0] origin When I route I should get | from | to | route | distance | - | b | d | abcde,abcde | 200m | + | b | d | abcde,abcde | 200.2m | | d | b | | | diff --git a/features/testbot/planetary.feature b/features/testbot/planetary.feature index 1fff4bded..c70cedb3d 100644 --- a/features/testbot/planetary.feature +++ b/features/testbot/planetary.feature @@ -26,8 +26,8 @@ Feature: Distance calculation | cd | When I route I should get - | from | to | route | distance | - | c | d | cd,cd | 6028844m ~4.5% | + | from | to | route | distance | + | c | d | cd,cd | 6310675.7m ~4.5% | Scenario: Approximated Longitudinal distances at latitude 80 Given the node locations @@ -54,8 +54,8 @@ Feature: Distance calculation | ab | When I route I should get - | from | to | route | distance | - | a | b | ab,ab | 8905559m ~0.1% | + | from | to | route | distance | + | a | b | ab,ab | 8882574.6m ~0.1% | Scenario: Approximated Latitudinal distances at longitude 45 Given the node locations @@ -68,8 +68,8 @@ Feature: Distance calculation | ab | When I route I should get - | from | to | route | distance | - | a | b | ab,ab | 8905559m ~0.1% | + | from | to | route | distance | + | a | b | ab,ab | 8882574.6m ~0.1% | Scenario: Approximated Latitudinal distances at longitude 80 Given the node locations @@ -83,4 +83,4 @@ Feature: Distance calculation When I route I should get | from | to | route | distance | - | a | b | ab,ab | 8905559m ~0.1% | + | a | b | ab,ab | 8882574.6m ~0.1% | diff --git a/features/testbot/projection.feature b/features/testbot/projection.feature index 49a5d8df1..c5bd6be18 100644 --- a/features/testbot/projection.feature +++ b/features/testbot/projection.feature @@ -23,13 +23,13 @@ Feature: Projection to nearest point on road Scenario: Projection onto way at high latitudes, 1km distance When I route I should get - | from | to | route | bearing | distance | - | b | a | abc,abc | 0->225,225->0 | 1000m | - | b | c | abc,abc | 0->45,45->0 | 1000m +- 3 | - | a | d | abc,abc | 0->45,45->0 | 1000m | - | d | a | abc,abc | 0->225,225->0 | 1000m | - | c | d | abc,abc | 0->225,225->0 | 1000m +- 3 | - | d | c | abc,abc | 0->45,45->0 | 1000m +- 3 | + | from | to | route | bearing | distance | + | b | a | abc,abc | 0->225,225->0 | 1002.9m | + | b | c | abc,abc | 0->45,45->0 | 1005m +- 3 | + | a | d | abc,abc | 0->45,45->0 | 1002.9m | + | d | a | abc,abc | 0->225,225->0 | 1002.9m | + | c | d | abc,abc | 0->225,225->0 | 1005m +- 3 | + | d | c | abc,abc | 0->45,45->0 | 1005m +- 3 | Scenario: Projection onto way at high latitudes, no distance When I route I should get diff --git a/features/testbot/snap.feature b/features/testbot/snap.feature index a98d8724e..f9a6fff81 100644 --- a/features/testbot/snap.feature +++ b/features/testbot/snap.feature @@ -47,11 +47,31 @@ Feature: Snap start/end point to the nearest way | adb | When I route I should get - | from | to | route | - | 1 | b | adb,adb | - | 2 | b | adb,adb | - | 6 | b | aub,aub | - | 7 | b | aub,aub | + | from | to | route | data_version | + | 1 | b | adb,adb | | + | 2 | b | adb,adb | | + | 6 | b | aub,aub | | + | 7 | b | aub,aub | | + + Scenario: Data_version check on nearest + Given the node map + """ + 4 5 6 7 + 3 a u + 2 + 1 d b + """ + + And the extract extra arguments "--data_version cucumber_data_version" + + And the ways + | nodes | + | aub | + | adb | + + When I route I should get + | from | to | route | data_version | + | 1 | b | adb,adb | cucumber_data_version | Scenario: Snap to edge right under start/end point Given the node map diff --git a/features/testbot/snap_intersection.feature b/features/testbot/snap_intersection.feature new file mode 100644 index 000000000..f75cb8b8c --- /dev/null +++ b/features/testbot/snap_intersection.feature @@ -0,0 +1,629 @@ +Feature: Snapping at intersections + + Background: + # Use turnbot so that we can validate when we are + # snapping to one of many potential candidate ways + Given the profile "turnbot" + + # https://github.com/Project-OSRM/osrm-backend/issues/4465 + Scenario: Snapping source to intersection with one-way roads + Given the node map + """ + a e c + \ | / + d + + 1 + """ + + And the ways + | nodes | oneway | + | da | yes | + | dc | yes | + | de | yes | + + + When I route I should get + | from | to | route | time | + | 1 | e | de,de | 20s | + | 1 | a | da,da | 28.3s | + | 1 | c | dc,dc | 28.3s | + + When I request a travel time matrix I should get + | | a | c | e | + | 1 | 28.3 | 28.3 | 20 | + + + Scenario: Snapping destination to intersection with one-way roads + Given the node map + """ + a e c + \ | / + d + + 1 + """ + + And the ways + | nodes | oneway | + | da | -1 | + | dc | -1 | + | de | -1 | + + + When I route I should get + | from | to | route | time | + | e | 1 | de,de | 20s | + | a | 1 | da,da | 28.3s | + | c | 1 | dc,dc | 28.3s | + + When I request a travel time matrix I should get + | | 1 | + | a | 28.3 | + | c | 28.3 | + | e | 20 | + + + Scenario: Snapping to intersection with bi-directional roads + Given the node map + """ + a e + | / + d---c + + 1 + """ + + And the ways + | nodes | + | ad | + | ed | + | dc | + + When I route I should get + | from | to | route | time | weight | + | 1 | c | dc,dc | 20s | 20 | + | 1 | a | ad,ad | 20s | 20 | + | 1 | e | ed,ed | 28.3s | 28.3 | + | c | 1 | dc,dc | 20s | 20 | + | a | 1 | ad,ad | 20s | 20 | + | e | 1 | ed,ed | 28.3s | 28.3 | + + When I request a travel time matrix I should get + | | a | c | e | + | 1 | 20 | 20 | 28.3 | + + When I request a travel time matrix I should get + | | 1 | + | a | 20 | + | c | 20 | + | e | 28.3 | + + + Scenario: Snapping at compressible node + Given the node map + """ + a---b---c + """ + + And the ways + | nodes | + | abc | + + When I route I should get + | from | to | route | time | weight | + | b | c | abc,abc | 20s | 20 | + | b | a | abc,abc | 20s | 20 | + | a | b | abc,abc | 20s | 20 | + | c | b | abc,abc | 20s | 20 | + + + Scenario: Snapping at compressible node with traffic lights + Given the node map + """ + a---b---c + """ + + And the ways + | nodes | + | abc | + + # Turnbot will use the turn penalty instead of traffic penalty. + # We do this to induce a penalty between two edges of the same + # segment. + And the nodes + | node | highway | + | b | traffic_signals | + + # Snaps to first edge in forward direction + When I route I should get + | from | to | route | time | weight | + | b | c | abc,abc | 40s | 40 | + | b | a | abc,abc | 20s | 20 | + | a | b | abc,abc | 20s | 20 | + | c | b | abc,abc | 40s | 40 | + + + Scenario: Snapping at compressible node traffic lights, one-way + Given the node map + """ + a-->b-->c + """ + + And the ways + | nodes | oneway | + | abc | yes | + + # Turnbot will use the turn penalty instead of traffic penalty. + # We do this to induce a penalty between two edges of the same + # segment. + And the nodes + | node | highway | + | b | traffic_signals | + + + # Snaps to first edge in forward direction + When I route I should get + | from | to | route | time | weight | + | b | c | abc,abc | 40s | 40 | + | a | b | abc,abc | 20s | 20 | + + When I route I should get + | from | to | code | + | b | a | NoRoute | + | c | b | NoRoute | + + + Scenario: Snapping at compressible node traffic lights, reverse one-way + Given the node map + """ + a<--b<--c + """ + + And the ways + | nodes | oneway | + | abc | -1 | + + # Turnbot will use the turn penalty instead of traffic penalty. + # We do this to induce a penalty between two edges of the same + # segment. + And the nodes + | node | highway | + | b | traffic_signals | + + + # Snaps to first edge in forward direction - as this is one-way, + # the forward direction has changed. + When I route I should get + | from | to | route | time | weight | + | b | a | abc,abc | 40s | 40 | + | c | b | abc,abc | 20s | 20 | + + When I route I should get + | from | to | code | + | b | c | NoRoute | + | a | b | NoRoute | + + + Scenario: Snapping at traffic lights, reverse disabled + Given the node map + """ + a-->b-->c + """ + + And the ways + | nodes | + | abc | + + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 2,1,0 + 3,2,0 + """ + + # Turnbot will use the turn penalty instead of traffic penalty. + # We do this to induce a penalty between two edges of the same + # segment. + And the nodes + | node | highway | + | b | traffic_signals | + + # Snaps to first edge in forward direction. + When I route I should get + | from | to | route | time | weight | + | b | c | abc,abc | 40s | 40 | + | a | b | abc,abc | 20s | 20 | + + When I route I should get + | from | to | code | + | b | a | NoRoute | + | c | b | NoRoute | + + + Scenario: Snapping at traffic lights, forward disabled + Given the node map + """ + a<--b<--c + """ + + And the ways + | nodes | + | abc | + + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 1,2,0 + 2,3,0 + """ + + # Turnbot will use the turn penalty instead of traffic penalty. + # We do this to induce a penalty between two edges of the same + # segment. + And the nodes + | node | highway | + | b | traffic_signals | + + # Forward direction is disabled, still snaps to first edge in forward direction + When I route I should get + | from | to | route | time | weight | + | b | a | abc,abc | 20s | 20 | + | c | b | abc,abc | 40s | 40 | + + When I route I should get + | from | to | code | + | b | c | NoRoute | + | a | b | NoRoute | + + + Scenario: Snap to target node with next section of segment blocked + Given the node map + """ + a-->b---c---d<--e + """ + + And the ways + | nodes | + | abc | + | cde | + + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 2,1,0 + 4,5,0 + """ + + When I route I should get + | from | to | route | time | weight | + | a | d | abc,cde,cde | 60s | 60 | + | e | b | cde,abc,abc | 60s | 60 | + + + When I route I should get + | from | to | code | + | a | e | NoRoute | + | e | a | NoRoute | + + + Scenario: Snapping to source node with previous section of segment blocked + Given the node map + """ + a<--b---c---d-->e + """ + + And the ways + | nodes | + | abc | + | cde | + + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 1,2,0 + 5,4,0 + """ + + When I route I should get + | from | to | code | + | a | e | NoRoute | + | b | e | NoRoute | + | e | a | NoRoute | + | d | a | NoRoute | + + + Scenario: Only snaps to one of many equidistant nearest locations + Given the node map + """ + b-------c + | | + | | + a 1 d + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + + When I route I should get + | from | to | route | time | weight | + | 1 | b | ab,ab | 30s | 30 | + | 1 | c | ab,bc,bc | 80s +-1 | 80 +-1 | + + + Scenario: Snaps to alternative big SCC candidate if nearest candidates are not strongly connected + Given the node map + """ + 1 + g---h---i + a-----b-----c + | + f-----e-----d + j---k---l + 2 + """ + + Given the extract extra arguments "--small-component-size=4" + + And the ways + | nodes | + | abc | + | cd | + | fed | + | ghi | + | jkl | + + # As forward direction is disabled... + When I route I should get + | from | to | route | time | weight | locations | + | 1 | 2 | abc,cd,fed,fed | 100s +-1 | 100 +-1 | b,c,d,e | + + + Scenario: Can use big or small SCC nearest candidates if at same location + Given the node map + """ + 1 + a-----b-----c + | | + g | + | + f-----e-----d + + """ + + Given the extract extra arguments "--small-component-size=4" + + And the ways + | nodes | oneway | + | ab | no | + | bc | no | + | cd | no | + | fed | no | + | bg | yes | # small SCC + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | ab | bg | b | no_right_turn | + | restriction | bc | bg | b | no_left_turn | + + When I route I should get + | from | to | route | time | weight | locations | + | 1 | g | bg,bg | 20s | 20 | b,g | + | 1 | e | bc,cd,fed,fed | 120s +-1 | 120 +-1 | b,c,d,e | + + + Scenario: Using small SCC candidates when at same location as big SCC alternatives is not supported + Given the node map + """ + 1 + g---h---i + a-----b-----c + | | + | | + m | + f-----e-----d + j---k---l + 2 + + """ + + Given the extract extra arguments "--small-component-size=4" + + And the ways + | nodes | oneway | + | ab | no | + | bc | no | + | cd | no | + | fed | no | + | ghi | no | + | jkl | no | + | bm | yes | # small SCC + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | ab | bm | b | no_right_turn | + | restriction | bc | bm | b | no_left_turn | + + When I route I should get + | from | to | route | time | weight | locations | + | 1 | 2 | bc,cd,fed,fed | 120s +-1 | 120 +-1 | b,c,d,e | + | 1 | m | bc,cd,fed,fed | 120s +-1 | 120 +-1 | b,c,d,e | + + + Scenario: Shortest via path with continuation, simple loop + Given the node map + """ + a---b + """ + + And the ways + | nodes | + | ab | + + When I route I should get + | waypoints | route | time | weight | + | a,b,a | ab,ab,ab,ab | 60s | 60 | + + + Scenario: Shortest via path with uturns, simple loop + Given the node map + """ + a---b + """ + + Given the query options + | continue_straight | false | + + And the ways + | nodes | + | ab | + + # Does not pay the cost of the turn + When I route I should get + | waypoints | route | time | weight | + | a,b,a | ab,ab,ab,ab | 40s | 40 | + + + Scenario: Shortest path with multiple endpoint snapping candidates + Given the node map + """ + b + + c + + a d f + + e + """ + + And the ways + | nodes | oneway | + | ab | no | + | ac | no | + | ad | no | + | ae | no | + | bf | no | + | cf | yes | + | df | yes | + | ef | no | + + + When I route I should get + | from | to | route | time | weight | + | a | f | ad,df,df | 40s | 40 | + | f | a | ef,ae,ae | 66.6s | 66.6 | + + When I request a travel time matrix I should get + | | a | f | + | a | 0 | 40 | + | f | 66.6 | 0 | + + + Scenario: Shortest via path with continuation, multiple waypoint snapping candidates + Given the node map + """ + b g + + c h + + a d f i + k + e j + """ + + And the ways + | nodes | oneway | + | ab | no | + | ac | no | + | ad | no | + | ae | no | + | bf | no | + | cf | yes | + | df | yes | + | ef | no | + | fg | no | + | fh | -1 | + | fi | -1 | + | fj | no | + | gk | no | + | hk | no | + | ik | no | + | kj | no | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | df | fg | f | only_left_turn | + | restriction | fi | bf | f | only_right_turn | + + # Longer routes can take different paths from sub-routes + When I route I should get + | waypoints | route | time | weight | + | a,f | ad,df,df | 40s | 40 | + | f,k | fj,kj,kj | 65.6s | 65.6 | + | a,f,k | ac,cf,cf,fj,kj,kj | 132.8s | 132.8 | + | k,f | ik,fi,fi | 54.3s | 54.3 | + | f,a | ef,ae,ae | 66.6s | 66.6 | + | k,f,a | kj,fj,fj,ef,ae,ae | 141.399999999s | 141.399999999 | + + When I request a travel time matrix I should get + | | a | f | k | + | a | 0 | 40 | 132.8 | + | f | 66.6 | 0 | 65.6 | + | k | 141.4 | 54.3 | 0 | + + + Scenario: Shortest via path with uturns, multiple waypoint snapping candidates + Given the node map + """ + b g + + c h + + a d f i + k + e j + """ + + Given the query options + | continue_straight | false | + + And the ways + | nodes | oneway | + | ab | no | + | ac | no | + | ad | no | + | ae | no | + | bf | no | + | cf | yes | + | df | yes | + | ef | no | + | fg | no | + | fh | -1 | + | fi | -1 | + | fj | no | + | gk | no | + | hk | no | + | ik | no | + | kj | no | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | df | fg | f | only_left_turn | + | restriction | fi | bf | f | only_right_turn | + + # Longer routes use same path as sub-routes + When I route I should get + | waypoints | route | time | weight | + | a,f | ad,df,df | 40s | 40 | + | f,k | fj,kj,kj | 65.6s | 65.6 | + | a,f,k | ad,df,df,fj,kj,kj | 105.6s | 105.6 | + | k,f | ik,fi,fi | 54.3s | 54.3 | + | f,a | ef,ae,ae | 66.6s | 66.6 | + | k,f,a | ik,fi,fi,ef,ae,ae | 120.899999999s | 120.899999999 | diff --git a/features/testbot/traffic_speeds.feature b/features/testbot/traffic_speeds.feature index 616668599..db3b2372b 100644 --- a/features/testbot/traffic_speeds.feature +++ b/features/testbot/traffic_speeds.feature @@ -48,13 +48,13 @@ Feature: Traffic - speeds When I route I should get | from | to | route | speed | weights | a:datasources | - | a | b | ad,de,eb,eb | 30 km/h | 1275.7,400.4,378.2,0 | 1:0:0:0 | - | a | c | ad,dc,dc | 31 km/h | 1275.7,956.8,0 | 1:0 | - | b | c | bc,bc | 27 km/h | 741.5,0 | 1:0 | - | a | d | ad,ad | 27 km/h | 1275.7,0 | 1:0 | - | 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 | b | ad,de,eb,eb | 30 km/h | 1273.9,400.8,378.5,0 | 1:0:0 | + | a | c | ad,dc,dc | 31 km/h | 1273.9,955.4,0 | 1:0 | + | b | c | bc,bc | 27 km/h | 737.2,0 | 1 | + | a | d | ad,ad | 27 km/h | 1273.9,0 | 1 | + | d | c | dc,dc | 36 km/h | 955.4,0 | 0 | + | g | b | fb,fb | 36 km/h | 164.4,0 | 0 | + | a | g | ad,df,fb,fb | 30 km/h | 1293.9,486.8,304.3,0 | 1:0:0 | Scenario: Weighting based on speed file weights, ETA based on file durations @@ -74,13 +74,13 @@ Feature: Traffic - speeds When I route I should get | from | to | route | speed | weights | a:datasources | - | a | b | ad,de,eb,eb | 30 km/h | 1275.7,400.4,378.2,0 | 1:0:0:0 | - | a | c | ad,dc,dc | 31 km/h | 1275.7,956.8,0 | 1:0 | - | b | c | bc,bc | 27 km/h | 741.5,0 | 1:0 | - | a | d | ad,ad | 27 km/h | 1275.7,0 | 1:0 | - | d | c | dc,dc | 36 km/h | 956.8,0 | 0 | - | g | b | ab,ab | 1 km/h | 10010.4,0 | 1:0 | - | a | g | ab,ab | 1 km/h | 10010.3,0 | 1 | + | a | b | ad,de,eb,eb | 30 km/h | 1273.9,400.8,378.5,0 | 1:0:0 | + | a | c | ad,dc,dc | 31 km/h | 1273.9,955.4,0 | 1:0 | + | b | c | bc,bc | 27 km/h | 737.2,0 | 1 | + | a | d | ad,ad | 27 km/h | 1273.9,0 | 1 | + | d | c | dc,dc | 36 km/h | 955.4,0 | 0 | + | g | b | ab,ab | 1 km/h | 9951.7,0 | 1 | + | a | g | ab,ab | 1 km/h | 9951.7,0 | 1 | Scenario: Weighting based on speed file weights, ETA based on file durations @@ -106,14 +106,14 @@ Feature: Traffic - speeds When I route I should get | from | to | route | speed | weights | a:datasources | - | a | b | ab,ab | 1 km/h | 20020.73,0 | 1:0 | - | a | c | ab,bc,bc | 2 km/h | 20020.73,741.51,0 | 1:1:0 | - | b | c | bc,bc | 27 km/h | 741.51,0 | 1:0 | - | a | d | ab,eb,de,de | 2 km/h | 20020.73,378.17,400.41,0 | 1:0:0 | - | d | c | dc,dc | 36 km/h | 956.8,0 | 0 | - | g | b | ab,ab | 1 km/h | 10010.37,0 | 1:0 | - | a | g | ab,ab | 1 km/h | 10010.36,0 | 1 | - | g | a | ab,ab | 1 km/h | 10010.36,0 | 1:1 | + | a | b | ab,ab | 1 km/h | 19903.37,0 | 1 | + | a | c | ab,bc,bc | 2 km/h | 19903.37,737.16,0 | 1:1 | + | b | c | bc,bc | 27 km/h | 737.16,0 | 1 | + | a | d | ab,eb,de,de | 2 km/h | 19903.37,378.49,400.75,0 | 1:0:0 | + | d | c | dc,dc | 36 km/h | 955.45,0 | 0 | + | g | b | ab,ab | 1 km/h | 9951.69,0 | 1 | + | a | g | ab,ab | 1 km/h | 9951.68,0 | 1 | + | g | a | ab,ab | 1 km/h | 9951.68,0 | 1 | Scenario: Speeds that isolate a single node (a) @@ -135,14 +135,14 @@ Feature: Traffic - speeds | annotations | true | When I route I should get - | from | to | route | speed | weights | a:datasources | - | a | b | fb,fb | 36 km/h | 329.4,0 | 0 | - | a | c | fb,bc,bc | 30 km/h | 329.4,741.5,0 | 0:1:0 | - | b | c | bc,bc | 27 km/h | 741.5,0 | 1:0 | - | a | d | fb,df,df | 36 km/h | 140,487.5,0 | 0:0:0 | - | d | c | dc,dc | 36 km/h | 956.8,0 | 0 | - | g | b | fb,fb | 36 km/h | 164.7,0 | 0 | - | a | g | fb,fb | 36 km/h | 164.7,0 | 0 | + | from | to | route | speed | weights | a:datasources | a:speed | a:nodes| + | a | b | fb,fb | 36 km/h | 328.9,0 | 0 | 10 | 6:2 | + | a | c | fb,bc,bc | 30 km/h | 328.9,737.2,0 | 0:1 | 10:7.5 | 6:2:3 | + | b | c | bc,bc | 27 km/h | 737.2,0 | 1 | 7.5 | 2:3 | + | a | d | fb,df,df | 36 km/h | 139.8,486.8,0 | 0:0 | 10:10 | 2:6:4 | + | d | c | dc,dc | 36 km/h | 955.4,0 | 0 | 10 | 4:3 | + | g | b | fb,fb | 36 km/h | 164.4,0 | 0 | 10 | 6:2 | + | a | g | fb,fb | 36 km/h | 164.5,0 | 0 | 10 | 6:2 | Scenario: Verify that negative values cause an error, they're not valid at all diff --git a/features/testbot/traffic_turn_penalties.feature b/features/testbot/traffic_turn_penalties.feature index 9d3c45412..86bdeded1 100644 --- a/features/testbot/traffic_turn_penalties.feature +++ b/features/testbot/traffic_turn_penalties.feature @@ -47,7 +47,7 @@ Feature: Traffic - turn penalties applied to turn onto which a phantom node snap | 1 | e | ab,be,be | 36 km/h | 30s +-1 | | b | f | bc,cf,cf | 36 km/h | 40s +-1 | | 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | - | c | g | cd,dg,dg | 144 km/h | 10s +-1 | + | c | g | cd,dg,dg | 72 km/h | 20s +-1 | | 3 | g | cd,dg,dg | 54 km/h | 20s +-1 | Scenario: Weighting based on turn penalty file with weights @@ -62,8 +62,8 @@ Feature: Traffic - turn penalties applied to turn onto which a phantom node snap When I route I should get | from | to | route | speed | time | weights | | a | e | ab,be,be | 36 km/h | 40s +-1 | 16.7,20,0 | - | 1 | e | ab,be,be | 36 km/h | 30s +-1 | 6.7,20,0 | + | 1 | e | ab,be,be | 36 km/h | 30s +-1 | 6.8,20,0 | | b | f | bc,cf,cf | 36 km/h | 40s +-1 | 20,20,0 | - | 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | 10,20,0 | - | c | g | cd,dg,dg | 144 km/h | 10s +-1 | 120.8,20,0 | - | 3 | g | cd,dg,dg | 54 km/h | 20s +-1 | 110.8,20,0 | + | 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | 10.1,20,0 | + | c | g | cd,dg,dg | 72 km/h | 20s +-1 | 120.8,20,0 | + | 3 | g | cd,dg,dg | 54 km/h | 20s +-1 | 110.9,20,0 | diff --git a/features/testbot/trip.feature b/features/testbot/trip.feature index c254f8d75..531ccaa48 100644 --- a/features/testbot/trip.feature +++ b/features/testbot/trip.feature @@ -5,7 +5,7 @@ Feature: Basic trip planning Given the profile "testbot" Given a grid size of 10 meters - Scenario: Testbot - Trip: Roundtrip with one waypoint + Scenario: Testbot - Trip: Invalid options (like was in test suite for a long time) Given the node map """ a b @@ -20,8 +20,46 @@ Feature: Basic trip planning | da | When I plan a trip I should get - | waypoints | trips | - | a | aa | + | waypoints | trips | code | + | a | | InvalidOptions | + + Scenario: Testbot - Trip: Roundtrip between same waypoint + Given the node map + """ + a b + c d + """ + + And the ways + | nodes | + | ab | + | bc | + | cb | + | da | + + When I plan a trip I should get + | waypoints | trips | code | + | a,a | aa | Ok | + + Scenario: Testbot - Trip: data version check + Given the node map + """ + a b + c d + """ + + And the ways + | nodes | + | ab | + | bc | + | cb | + | da | + + And the extract extra arguments "--data_version cucumber_data_version" + + When I plan a trip I should get + | waypoints | trips | data_version | code | + | a,a | aa | cucumber_data_version | Ok | Scenario: Testbot - Trip: Roundtrip with waypoints (less than 10) Given the node map @@ -38,9 +76,9 @@ Feature: Basic trip planning | da | When I plan a trip I should get - | waypoints | trips | durations | - | a,b,c,d | abcda | 7.6 | - | d,b,c,a | dbcad | 7.6 | + | waypoints | trips | durations | code | + | a,b,c,d | abcda | 7.6 | Ok | + | d,b,c,a | dbcad | 7.6 | Ok | Scenario: Testbot - Trip: Roundtrip waypoints (more than 10) Given the node map @@ -69,36 +107,37 @@ Feature: Basic trip planning | waypoints | trips | | a,b,c,d,e,f,g,h,i,j,k,l | alkjihgfedcba | - Scenario: Testbot - Trip: Roundtrip FS waypoints (more than 10) - Given the node map - """ - a b c d - l e - k f - j i h g - """ - - And the ways - | nodes | - | ab | - | bc | - | de | - | ef | - | fg | - | gh | - | hi | - | ij | - | jk | - | kl | - | la | - - When I plan a trip I should get - | waypoints | source | trips | - | a,b,c,d,e,f,g,h,i,j,k,l | first | alkjihgfedcba | - - Scenario: Testbot - Trip: Roundtrip FE waypoints (more than 10) + Scenario: Testbot - Trip: FS waypoints (less than 10) Given the query options - | source | last | + | source | first | + Given the node map + """ + a b c d + l e + + j i g + """ + + And the ways + | nodes | + | ab | + | bc | + | de | + | eg | + | gi | + | ij | + | jl | + | la | + + When I plan a trip I should get + | waypoints | trips | roundtrip | durations | + | a,b,c,d,e,g,i,j,l | abcdegijla | true | 22 | + | a,b,c,d,e,g,i,j,l | abcljiged | false | 13 | + + + Scenario: Testbot - Trip: FS waypoints (more than 10) + Given the query options + | source | first | Given the node map """ a b c d @@ -122,8 +161,67 @@ Feature: Basic trip planning | la | When I plan a trip I should get - | waypoints | trips | - | a,b,c,d,e,f,g,h,i,j,k,l | lkjihgfedcbal | + | waypoints | trips | roundtrip | durations | + | a,b,c,d,e,f,g,h,i,j,k,l | alkjihgfedcba | true | 22 | + | a,b,c,d,e,f,g,h,i,j,k,l | acblkjihgfed | false | 13 | + + + Scenario: Testbot - Trip: FE waypoints (less than 10) + Given the query options + | destination | last | + Given the node map + """ + a b c d + l e + + j i g + """ + + And the ways + | nodes | + | ab | + | bc | + | de | + | eg | + | gi | + | ij | + | jl | + | la | + + When I plan a trip I should get + | waypoints | trips | roundtrip | durations | + | a,b,c,d,e,g,i,j,l | labcdegijl | true | 22 | + | a,b,c,d,e,g,i,j,l | degijabcl | false | 14 | + + Scenario: Testbot - Trip: FE waypoints (more than 10) + Given the query options + | destination | last | + Given the node map + """ + a b c d + l e + k f + j i h g + """ + + And the ways + | nodes | + | ab | + | bc | + | de | + | ef | + | fg | + | gh | + | hi | + | ij | + | jk | + | kl | + | la | + + When I plan a trip I should get + | waypoints | trips | roundtrip | durations | + | a,b,c,d,e,f,g,h,i,j,k,l | lkjihgfedcbal | true | 22 | + | a,b,c,d,e,f,g,h,i,j,k,l | cbakjihgfedl | false | 19 | Scenario: Testbot - Trip: Unroutable roundtrip with waypoints (less than 10) Given the node map @@ -221,7 +319,7 @@ Feature: Basic trip planning When I plan a trip I should get | waypoints | source | destination |roundtrip | trips | durations | distance | - | a,b,d,e,c | first | last | false | abedc | 8.200000000000001 | 81.6 | + | a,b,d,e,c | first | last | false | abedc | 8.200000000000001 | 81.4 | Scenario: Testbot - Trip: FSE with waypoints (more than 10) @@ -274,7 +372,7 @@ Feature: Basic trip planning | a,b,d,e,c | first | last | true | abedca | - Scenario: Testbot - Trip: midway points in isoldated roads should return no trips + Scenario: Testbot - Trip: midway points in isolated roads should return no trips Given the node map """ a 1 b @@ -370,4 +468,4 @@ Feature: Basic trip planning When I plan a trip I should get | waypoints | trips | durations | geometry | | a,b,c,d | abcda | 7.6 | 1,1,1,1.00009,0.99991,1,1,1.00009,1,1,0.99991,1.00009,1,1 | - | d,b,c,a | dbcad | 7.6 | 0.99991,1.00009,1,1,1,1.00009,0.99991,1,1,1.00009,1,1,0.99991,1.00009 | \ No newline at end of file + | d,b,c,a | dbcad | 7.6 | 0.99991,1.00009,1,1,1,1.00009,0.99991,1,1,1.00009,1,1,0.99991,1.00009 | diff --git a/features/testbot/via.feature b/features/testbot/via.feature index 89d041407..017cc54e6 100644 --- a/features/testbot/via.feature +++ b/features/testbot/via.feature @@ -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 @@ -309,7 +356,7 @@ Feature: Via points | waypoints | route | | a,b,e | | - @todo @3359 + @3359 Scenario: U-Turn In Bearings Given the node map """ diff --git a/features/testbot/weight.feature b/features/testbot/weight.feature index cac50ac61..d5ae35206 100644 --- a/features/testbot/weight.feature +++ b/features/testbot/weight.feature @@ -28,12 +28,12 @@ Feature: Weight tests | cde | When I route I should get - | waypoints | route | a:weight | - | s,t | abc,cde | 1.1:2:2:1 | + | waypoints | route | a:weight | + | s,t | abc,cde | 1.1:2:2:0.9 | When I route I should get | waypoints | route | times | weight_name | weights | - | s,t | abc,cde | 6.1s,0s | duration | 6.1,0 | + | s,t | abc,cde | 6s,0s | duration | 6,0 | # FIXME include/engine/guidance/assemble_geometry.hpp:95 Scenario: Start and target on the same and adjacent edge @@ -52,11 +52,11 @@ Feature: Weight tests | abc | When I route I should get - | waypoints | route | distances | weights | times | a:distance | a:duration | a:weight | a:speed | - | s,t | abc,abc | 20m,0m | 2.1,0 | 2.1s,0s | 20.017685 | 3 | 3 | 6.7 | - | t,s | abc,abc | 20m,0m | 2.1,0 | 2.1s,0s | 20.017685 | 3.1 | 3.1 | 6.5 | - | s,e | abc,abc | 40m,0m | 4.1,0 | 4.1s,0s | 30.026527:10.008842 | 3.1:1 | 3.1:1 | 9.7:10 | - | e,s | abc,abc | 40m,0m | 4.1,0 | 4.1s,0s | 10.008842:30.026527 | 1:3.1 | 1:3.1 | 10:9.7 | + | waypoints | route | distances | weights | times | a:distance | a:duration | a:weight | a:speed | + | s,t | abc,abc | 20m,0m | 2,0 | 2s,0s | 20.034626629 | 2 | 2 | 10 | + | t,s | abc,abc | 20m,0m | 2,0 | 2s,0s | 20.034626629 | 2 | 2 | 10 | + | s,e | abc,abc | 40m,0m | 3.9,0 | 3.9s,0s | 29.940636463:10.017313314 | 3:0.9 | 3:0.9 | 10:11.1 | + | e,s | abc,abc | 40m,0m | 3.9,0 | 3.9s,0s | 10.017313314:29.940636463 | 0.9:3 | 0.9:3 | 11.1:10 | Scenario: Step weights -- way_function: fail if no weight or weight_per_meter property @@ -173,13 +173,13 @@ Feature: Weight tests | fgh | When I route I should get - | waypoints | route | distance | weights | times | - | a,f | , | 100m | 99.9,0 | 30s,0s | - | f,a | , | 100m | 199.8,0 | 30s,0s | - | a,h | , | 140m | 139.9,0 | 42s,0s | - | h,a | , | 140m | 279.8,0 | 42s,0s | - | f,h | , | 40m | 40,0 | 12s,0s | - | h,f | , | 40m | 80,0 | 12s,0s | + | waypoints | route | distance | weights | times | + | a,f | , | 100m | 99.8,0 | 30s,0s | + | f,a | , | 100m | 199.9,0 | 30s,0s | + | a,h | , | 140m | 139.8,0 | 42s,0s | + | h,a | , | 140m | 280.1,0 | 42s,0s | + | f,h | , | 40.1m | 40,0 | 12s,0s | + | h,f | , | 40.1m | 80.2,0 | 12s,0s | Scenario: Step weights -- segment_function Given the profile file @@ -281,11 +281,11 @@ Feature: Weight tests When I route I should get | waypoints | route | distance | weights | times | - | a,c | , | 40m +-.1 | 5.119,0 | 289.9s,0s | - | a,e | ,, | 60m +-.1 | 5.119,1.11,0 | 289.9s,100s,0s | - | e,a | ,, | 60m +-.1 | 2.21,2.22,0 | 10.1s,200s,0s | - | e,d | ,, | 40m +-.1 | 4.009,1.11,0 | 189.9s,100s,0s | - | d,e | ,, | 40m +-.1 | 2.21,1.11,0 | 10.1s,100s,0s | + | a,c | , | 40m +-.1 | 2.22,0 | 200s,0s | + | a,e | ,, | 60m +-.1 | 5.12,1.11,0 | 290s,100s,0s | + | e,a | ,, | 60m +-.1 | 2.21,2.22,0 | 10s,200s,0s | + | e,d | ,, | 40m +-.1 | 4.01,1.11,0 | 190s,100s,0s | + | d,e | ,, | 40m +-.1 | 2.21,1.11,0 | 10s,100s,0s | @traffic @speed Scenario: Step weights -- segment_function with speed and turn updates @@ -329,7 +329,7 @@ Feature: Weight tests | ce | And the speed file """ - 1,2,36,42 + 1,2,36.999,42 2,1,36,42 """ And the turn penalty file @@ -341,9 +341,9 @@ Feature: Weight tests When I route I should get | waypoints | route | distance | weights | times | - | a,d | , | 59.9m | 20.5,0 | 24s,0s | - | a,e | ,, | 60.1m | 27.2,10,0 | 38.5s,11s,0s | - | d,e | ,, | 39.9m | 10,10,0 | 11s,11s,0s | + | a,d | , | 60m | 20.5,0 | 23.9s,0s | + | a,e | ,, | 60m | 27.2,10,0 | 38.4s,11s,0s | + | d,e | ,, | 40m | 10,10,0 | 11s,11s,0s | @traffic @speed Scenario: Step weights -- segment_function with speed and turn updates with fallback to durations @@ -375,10 +375,10 @@ Feature: Weight tests And the customize extra arguments "--segment-speed-file {speeds_file} --turn-penalty-file {penalties_file}" When I route I should get - | waypoints | route | distance | weights | times | - | a,d | abcd,abcd | 59.9m | 6.996,0 | 7s,0s | - | a,e | abcd,ce,ce | 60.1m | 6.005,2.002,0 | 6s,2s,0s | - | d,e | abcd,ce,ce | 39.9m | 1.991,2.002,0 | 2s,2s,0s | + | waypoints | route | distance | weights | times | + | a,d | abcd,abcd | 60m | 7,0 | 7s,0s | + | a,e | abcd,ce,ce | 60m | 5.997,2.001,0 | 6s,2s,0s | + | d,e | abcd,ce,ce | 40m | 2.003,2.001,0 | 2s,2s,0s | @traffic @speed Scenario: Updating speeds without affecting weights. @@ -410,5 +410,5 @@ Feature: Weight tests And the customize extra arguments "--segment-speed-file {speeds_file}" When I route I should get - | waypoints | route | distance | weights | times | - | a,b | acdb,acdb | 78.3m | 11.744,0 | 56.4s,0s | + | waypoints | route | distance | weights | times | + | a,b | acdb,acdb | 78.3m | 11.742,0 | 56.4s,0s | diff --git a/features/testbot/zero-speed-updates.feature b/features/testbot/zero-speed-updates.feature index 6acb2b0c8..ae5a99c7f 100644 --- a/features/testbot/zero-speed-updates.feature +++ b/features/testbot/zero-speed-updates.feature @@ -93,6 +93,31 @@ Feature: Check zero speed updates | 1 | 2 | NoRoute | + Scenario: Routing with alternatives on restricted way + Given the node map + """ + a-1-b-2-c + """ + + And the ways + | nodes | oneway | + | abc | no | + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 1,2,0 + 2,1,0 + """ + And the query options + | alternatives | true | + + + When I route I should get + | from | to | code | alternative | + | 1 | 2 | NoRoute | | + + Scenario: Routing on restricted oneway Given the node map """ @@ -162,5 +187,5 @@ Feature: Check zero speed updates When I plan a trip I should get | waypoints | trips | code | - | a,b,c,d | abcda | NoTrips | - | d,b,c,a | dbcad | NoTrips | + | a,b,c,d | | NoTrips | + | d,b,c,a | | NoTrips | diff --git a/fuzz/escape_json.cc b/fuzz/escape_json.cc index 5f5fdc81c..312bb498f 100644 --- a/fuzz/escape_json.cc +++ b/fuzz/escape_json.cc @@ -5,13 +5,14 @@ #include #include -using osrm::util::escape_JSON; +using osrm::util::EscapeJSONString; extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size) { const std::string in(reinterpret_cast(data), size); - const auto escaped = escape_JSON(in); + std::string escaped; + EscapeJSONString(in, escaped); escape(escaped.data()); return 0; diff --git a/include/contractor/contract_excludable_graph.hpp b/include/contractor/contract_excludable_graph.hpp index a83fd0a93..2f49e68eb 100644 --- a/include/contractor/contract_excludable_graph.hpp +++ b/include/contractor/contract_excludable_graph.hpp @@ -12,14 +12,32 @@ namespace osrm namespace contractor { -using GraphFilterAndCore = - std::tuple>, std::vector>>; +using GraphAndFilter = std::tuple>>; + +inline auto contractFullGraph(ContractorGraph contractor_graph, + std::vector node_weights) +{ + auto num_nodes = contractor_graph.GetNumberOfNodes(); + contractGraph(contractor_graph, std::move(node_weights)); + + auto edges = toEdges(std::move(contractor_graph)); + std::vector edge_filter(edges.size(), true); + + return GraphAndFilter{QueryGraph{num_nodes, edges}, {std::move(edge_filter)}}; +} inline auto contractExcludableGraph(ContractorGraph contractor_graph_, std::vector node_weights, - const std::vector> &filters, - const float core_factor = 1.0) + const std::vector> &filters) { + if (filters.size() == 1) + { + if (std::all_of(filters.front().begin(), filters.front().end(), [](auto v) { return v; })) + { + return contractFullGraph(std::move(contractor_graph_), std::move(node_weights)); + } + } + auto num_nodes = contractor_graph_.GetNumberOfNodes(); ContractedEdgeContainer edge_container; ContractorGraph shared_core_graph; @@ -38,11 +56,9 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_, // By not contracting all contractable nodes we avoid creating // a very dense core. This increases the overall graph sizes a little bit // but increases the final CH quality and contraction speed. - constexpr float BASE_CORE = 0.9; - is_shared_core = contractGraph(contractor_graph, - std::move(always_allowed), - node_weights, - std::min(BASE_CORE, core_factor)); + constexpr float BASE_CORE = 0.9f; + is_shared_core = + contractGraph(contractor_graph, std::move(always_allowed), node_weights, BASE_CORE); // Add all non-core edges to container { @@ -53,6 +69,11 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_, }); non_core_edges.resize(new_end - non_core_edges.begin()); edge_container.Insert(std::move(non_core_edges)); + + for (const auto filter_index : util::irange(0, filters.size())) + { + edge_container.Filter(filters[filter_index], filter_index); + } } // Extract core graph for further contraction @@ -60,28 +81,20 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_, [&is_shared_core](const NodeID node) { return is_shared_core[node]; }); } - std::vector> cores; for (const auto &filter : filters) { auto filtered_core_graph = shared_core_graph.Filter([&filter](const NodeID node) { return filter[node]; }); - auto core = contractGraph( - filtered_core_graph, is_shared_core, is_shared_core, node_weights, core_factor); - if (core_factor == 1.0) - { - core.clear(); - } - cores.push_back(std::move(core)); + contractGraph(filtered_core_graph, is_shared_core, is_shared_core, node_weights); edge_container.Merge(toEdges(std::move(filtered_core_graph))); } - return GraphFilterAndCore{QueryGraph{num_nodes, std::move(edge_container.edges)}, - edge_container.MakeEdgeFilters(), - std::move(cores)}; -} -} + return GraphAndFilter{QueryGraph{num_nodes, edge_container.edges}, + edge_container.MakeEdgeFilters()}; } +} // namespace contractor +} // namespace osrm #endif diff --git a/include/contractor/contracted_edge_container.hpp b/include/contractor/contracted_edge_container.hpp index 9ea9cb003..db3ae5cc9 100644 --- a/include/contractor/contracted_edge_container.hpp +++ b/include/contractor/contracted_edge_container.hpp @@ -2,9 +2,17 @@ #define OSRM_CONTRACTOR_CONTRACTED_EDGE_CONTAINER_HPP #include "contractor/query_edge.hpp" -#include "util/deallocating_vector.hpp" +#include "util/integer_range.hpp" +#include "util/permutation.hpp" + +#include + +#include #include +#include +#include +#include namespace osrm { @@ -43,7 +51,7 @@ struct ContractedEdgeContainer } public: - void Insert(util::DeallocatingVector new_edges) + void Insert(std::vector new_edges) { BOOST_ASSERT(edges.size() == 0); BOOST_ASSERT(flags.empty()); @@ -52,80 +60,89 @@ struct ContractedEdgeContainer flags.resize(edges.size(), ALL_FLAGS); } - void Merge(util::DeallocatingVector new_edges) + void Filter(const std::vector &filter, std::size_t index) + { + BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT); + const MergedFlags flag = 1 << index; + + for (auto edge_index : util::irange(0, edges.size())) + { + auto allowed = filter[edges[edge_index].source] && filter[edges[edge_index].target]; + if (allowed) + { + flags[edge_index] |= flag; + } + else + { + flags[edge_index] &= ~flag; + } + } + } + + void Merge(std::vector new_edges) { BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT); const MergedFlags flag = 1 << index++; - std::vector merged_flags; - merged_flags.reserve(flags.size() * 1.1); - util::DeallocatingVector merged_edges; - merged_edges.reserve(edges.size() * 1.1); - + auto edge_iter = edges.cbegin(); + auto edge_end = edges.cend(); auto flags_iter = flags.begin(); - // destructive iterators, this is single-pass only - // FIXME using dbegin() dend() will result in segfaults. - auto edges_iter = edges.dbegin(); - auto edges_end = edges.dend(); - auto new_edges_iter = new_edges.dbegin(); - auto new_edges_end = new_edges.dend(); - while (edges_iter != edges_end && new_edges_iter != new_edges_end) - { - while (edges_iter != edges_end && mergeCompare(*edges_iter, *new_edges_iter)) - { - merged_edges.push_back(*edges_iter); - merged_flags.push_back(*flags_iter); - edges_iter++; - flags_iter++; - } + // Remove all edges that are contained in the old set of edges and set the appropriate flag. + auto new_end = + std::remove_if(new_edges.begin(), new_edges.end(), [&](const QueryEdge &edge) { + // check if the new edge would be sorted before the currend old edge + // if so it is not contained yet in the set of old edges + if (edge_iter == edge_end || mergeCompare(edge, *edge_iter)) + { + return false; + } - if (edges_iter == edges_end) - { - break; - } + // find the first old edge that is equal or greater then the new edge + while (edge_iter != edge_end && mergeCompare(*edge_iter, edge)) + { + BOOST_ASSERT(flags_iter != flags.end()); + edge_iter++; + flags_iter++; + } - while (new_edges_iter != new_edges_end && mergeCompare(*new_edges_iter, *edges_iter)) - { - merged_edges.push_back(*new_edges_iter); - merged_flags.push_back(flag); - new_edges_iter++; - } + // all new edges will be sorted after the old edges + if (edge_iter == edge_end) + { + return false; + } - if (new_edges_iter == new_edges_end) - { - break; - } + BOOST_ASSERT(edge_iter != edge_end); + if (mergable(edge, *edge_iter)) + { + *flags_iter = *flags_iter | flag; + return true; + } + BOOST_ASSERT(mergeCompare(edge, *edge_iter)); + return false; + }); - while (edges_iter != edges_end && new_edges_iter != new_edges_end && - mergable(*edges_iter, *new_edges_iter)) - { - merged_edges.push_back(*edges_iter); - merged_flags.push_back(*flags_iter | flag); + // append new edges + edges.insert(edges.end(), new_edges.begin(), new_end); + auto edges_size = edges.size(); + auto new_edges_size = std::distance(new_edges.begin(), new_end); + BOOST_ASSERT(static_cast(edges_size) >= new_edges_size); + flags.resize(edges_size); + std::fill(flags.begin() + edges_size - new_edges_size, flags.end(), flag); - edges_iter++; - flags_iter++; - new_edges_iter++; - } - } + // enforce sorting for next merge step + std::vector ordering(edges_size); + std::iota(ordering.begin(), ordering.end(), 0); + tbb::parallel_sort( + ordering.begin(), ordering.end(), [&](const auto lhs_idx, const auto rhs_idx) { + return mergeCompare(edges[lhs_idx], edges[rhs_idx]); + }); + auto permutation = util::orderingToPermutation(ordering); - while (edges_iter != edges_end) - { - BOOST_ASSERT(new_edges_iter == new_edges_end); - merged_edges.push_back(*edges_iter++); - merged_flags.push_back(*flags_iter++); - } - - while (new_edges_iter != new_edges_end) - { - BOOST_ASSERT(edges_iter == edges_end); - merged_edges.push_back(*new_edges_iter++); - merged_flags.push_back(flag); - } - - flags = std::move(merged_flags); - edges = std::move(merged_edges); + util::inplacePermutation(edges.begin(), edges.end(), permutation); + util::inplacePermutation(flags.begin(), flags.end(), permutation); + BOOST_ASSERT(std::is_sorted(edges.begin(), edges.end(), mergeCompare)); } auto MakeEdgeFilters() const @@ -145,9 +162,9 @@ struct ContractedEdgeContainer std::size_t index = 0; std::vector flags; - util::DeallocatingVector edges; + std::vector edges; }; -} -} +} // namespace contractor +} // namespace osrm #endif diff --git a/include/contractor/contracted_metric.hpp b/include/contractor/contracted_metric.hpp new file mode 100644 index 000000000..c795a139a --- /dev/null +++ b/include/contractor/contracted_metric.hpp @@ -0,0 +1,25 @@ +#ifndef OSMR_CONTRACTOR_CONTRACTED_METRIC_HPP +#define OSMR_CONTRACTOR_CONTRACTED_METRIC_HPP + +#include "contractor/query_graph.hpp" + +namespace osrm +{ +namespace contractor +{ + +namespace detail +{ +template struct ContractedMetric +{ + detail::QueryGraph graph; + std::vector> edge_filter; +}; +} // namespace detail + +using ContractedMetric = detail::ContractedMetric; +using ContractedMetricView = detail::ContractedMetric; +} // namespace contractor +} // namespace osrm + +#endif diff --git a/include/contractor/contractor.hpp b/include/contractor/contractor.hpp index 7fabd34cf..a0335d8ea 100644 --- a/include/contractor/contractor.hpp +++ b/include/contractor/contractor.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -29,16 +29,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define CONTRACTOR_CONTRACTOR_HPP #include "contractor/contractor_config.hpp" -#include "contractor/query_edge.hpp" -#include "extractor/edge_based_edge.hpp" -#include "extractor/edge_based_node_segment.hpp" -#include "util/deallocating_vector.hpp" -#include "util/typedefs.hpp" - -#include -#include - -#include namespace osrm { @@ -49,8 +39,6 @@ namespace contractor class Contractor { public: - using EdgeData = QueryEdge::EdgeData; - explicit Contractor(const ContractorConfig &config_) : config{config_} {} Contractor(const Contractor &) = delete; @@ -58,18 +46,10 @@ class Contractor int Run(); - protected: - void ContractGraph(const unsigned max_edge_id, - util::DeallocatingVector &edge_based_edge_list, - util::DeallocatingVector &contracted_edge_list, - std::vector &&node_weights, - std::vector &is_core_node, - std::vector &inout_node_levels) const; - private: ContractorConfig config; }; -} -} +} // namespace contractor +} // namespace osrm #endif // PROCESSING_CHAIN_HPP diff --git a/include/contractor/contractor_config.hpp b/include/contractor/contractor_config.hpp index 23dc32959..18e8ae222 100644 --- a/include/contractor/contractor_config.hpp +++ b/include/contractor/contractor_config.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -43,10 +43,8 @@ namespace contractor struct ContractorConfig final : storage::IOConfig { ContractorConfig() - : IOConfig({".osrm.ebg", ".osrm.ebg_nodes", ".osrm.properties"}, - {}, - {".osrm.level", ".osrm.core", ".osrm.hsgr", ".osrm.enw"}), - requested_num_threads(0) + : IOConfig( + {".osrm.ebg", ".osrm.ebg_nodes", ".osrm.properties"}, {}, {".osrm.hsgr", ".osrm.enw"}) { } @@ -61,17 +59,19 @@ struct ContractorConfig final : storage::IOConfig updater::UpdaterConfig updater_config; - bool use_cached_priority; + // DEPRECATED to be removed in v6.0 + bool use_cached_priority = false; - unsigned requested_num_threads; + unsigned requested_num_threads = 0; + // DEPRECATED to be removed in v6.0 // A percentage of vertices that will be contracted for the hierarchy. // Offers a trade-off between preprocessing and query time. // The remaining vertices form the core of the hierarchy //(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%) - double core_factor; + double core_factor = 1.0; }; -} -} +} // namespace contractor +} // namespace osrm #endif // EXTRACTOR_OPTIONS_HPP diff --git a/include/contractor/contractor_graph.hpp b/include/contractor/contractor_graph.hpp index 3424568a6..02cad2e08 100644 --- a/include/contractor/contractor_graph.hpp +++ b/include/contractor/contractor_graph.hpp @@ -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; diff --git a/include/contractor/crc32_processor.hpp b/include/contractor/crc32_processor.hpp index 4130ed583..a441ae576 100644 --- a/include/contractor/crc32_processor.hpp +++ b/include/contractor/crc32_processor.hpp @@ -125,7 +125,7 @@ struct RangebasedCRC32 private: IteratorbasedCRC32 crc32; }; -} -} +} // namespace contractor +} // namespace osrm #endif /* ITERATOR_BASED_CRC32_H */ diff --git a/include/contractor/files.hpp b/include/contractor/files.hpp index 3fbad54c1..39ffa5b54 100644 --- a/include/contractor/files.hpp +++ b/include/contractor/files.hpp @@ -1,12 +1,9 @@ #ifndef OSRM_CONTRACTOR_FILES_HPP #define OSRM_CONTRACTOR_FILES_HPP -#include "contractor/query_graph.hpp" +#include "contractor/serialization.hpp" -#include "util/serialization.hpp" - -#include "storage/io.hpp" -#include "storage/serialization.hpp" +#include namespace osrm { @@ -14,108 +11,49 @@ namespace contractor { namespace files { -// reads .osrm.core -template -void readCoreMarker(const boost::filesystem::path &path, std::vector &cores) -{ - static_assert(util::is_view_or_vector::value, - "cores must be a vector of boolean vectors"); - storage::io::FileReader reader(path, storage::io::FileReader::VerifyFingerprint); - - auto num_cores = reader.ReadElementCount64(); - cores.resize(num_cores); - for (const auto index : util::irange(0, num_cores)) - { - storage::serialization::read(reader, cores[index]); - } -} - -// writes .osrm.core -template -void writeCoreMarker(const boost::filesystem::path &path, const std::vector &cores) -{ - static_assert(util::is_view_or_vector::value, - "cores must be a vector of boolean vectors"); - storage::io::FileWriter writer(path, storage::io::FileWriter::GenerateFingerprint); - - writer.WriteElementCount64(cores.size()); - for (const auto &core : cores) - { - storage::serialization::write(writer, core); - } -} - // reads .osrm.hsgr file -template +template inline void readGraph(const boost::filesystem::path &path, - unsigned &checksum, - QueryGraphT &graph, - std::vector &edge_filter) + std::unordered_map &metrics, + std::uint32_t &connectivity_checksum) { - static_assert(std::is_same::value || - std::is_same::value, - "graph must be of type QueryGraph<>"); - static_assert(std::is_same>::value || - std::is_same>::value, - "edge_filter must be a container of vector or vector_view"); + static_assert(std::is_same::value || + std::is_same::value, + "metric must be of type ContractedMetric<>"); - const auto fingerprint = storage::io::FileReader::VerifyFingerprint; - storage::io::FileReader reader{path, fingerprint}; + const auto fingerprint = storage::tar::FileReader::VerifyFingerprint; + storage::tar::FileReader reader{path, fingerprint}; - reader.ReadInto(checksum); - util::serialization::read(reader, graph); - auto count = reader.ReadElementCount64(); - edge_filter.resize(count); - for (const auto index : util::irange(0, count)) + reader.ReadInto("/ch/connectivity_checksum", connectivity_checksum); + + for (auto &pair : metrics) { - storage::serialization::read(reader, edge_filter[index]); + serialization::read(reader, "/ch/metrics/" + pair.first, pair.second); } } // writes .osrm.hsgr file -template +template inline void writeGraph(const boost::filesystem::path &path, - unsigned checksum, - const QueryGraphT &graph, - const std::vector &edge_filter) + const std::unordered_map &metrics, + const std::uint32_t connectivity_checksum) { - static_assert(std::is_same::value || - std::is_same::value, - "graph must be of type QueryGraph<>"); - static_assert(std::is_same>::value || - std::is_same>::value, - "edge_filter must be a container of vector or vector_view"); - const auto fingerprint = storage::io::FileWriter::GenerateFingerprint; - storage::io::FileWriter writer{path, fingerprint}; + static_assert(std::is_same::value || + std::is_same::value, + "metric must be of type ContractedMetric<>"); + const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint; + storage::tar::FileWriter writer{path, fingerprint}; - writer.WriteOne(checksum); - util::serialization::write(writer, graph); - writer.WriteElementCount64(edge_filter.size()); - for (const auto &filter : edge_filter) + writer.WriteElementCount64("/ch/connectivity_checksum", 1); + writer.WriteFrom("/ch/connectivity_checksum", connectivity_checksum); + + for (const auto &pair : metrics) { - storage::serialization::write(writer, filter); + serialization::write(writer, "/ch/metrics/" + pair.first, pair.second); } } - -// reads .levels file -inline void readLevels(const boost::filesystem::path &path, std::vector &node_levels) -{ - const auto fingerprint = storage::io::FileReader::VerifyFingerprint; - storage::io::FileReader reader{path, fingerprint}; - - storage::serialization::read(reader, node_levels); -} - -// writes .levels file -inline void writeLevels(const boost::filesystem::path &path, const std::vector &node_levels) -{ - const auto fingerprint = storage::io::FileWriter::GenerateFingerprint; - storage::io::FileWriter writer{path, fingerprint}; - - storage::serialization::write(writer, node_levels); -} -} -} -} +} // namespace files +} // namespace contractor +} // namespace osrm #endif diff --git a/include/contractor/graph_contractor_adaptors.hpp b/include/contractor/graph_contractor_adaptors.hpp index f509a5d9f..94dc7e62b 100644 --- a/include/contractor/graph_contractor_adaptors.hpp +++ b/include/contractor/graph_contractor_adaptors.hpp @@ -2,6 +2,7 @@ #define OSRM_CONTRACTOR_GRAPH_CONTRACTION_ADAPTORS_HPP_ #include "contractor/contractor_graph.hpp" + #include "util/log.hpp" #include "util/percent.hpp" @@ -40,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, @@ -50,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, @@ -81,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) { @@ -89,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; } @@ -125,44 +133,44 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp return ContractorGraph{number_of_nodes, edges}; } -template inline util::DeallocatingVector toEdges(GraphT graph) +template inline std::vector toEdges(GraphT graph) { - util::DeallocatingVector edges; + util::Log() << "Converting contracted graph with " << graph.GetNumberOfEdges() + << " to edge list (" << (graph.GetNumberOfEdges() * sizeof(Edge)) << " bytes)"; + std::vector edges(graph.GetNumberOfEdges()); - util::UnbufferedLog log; - log << "Getting edges of minimized graph "; - util::Percent p(log, graph.GetNumberOfNodes()); - const NodeID number_of_nodes = graph.GetNumberOfNodes(); - if (graph.GetNumberOfNodes()) { - Edge new_edge; + util::UnbufferedLog log; + log << "Getting edges of minimized graph "; + util::Percent p(log, graph.GetNumberOfNodes()); + const NodeID number_of_nodes = graph.GetNumberOfNodes(); + std::size_t edge_index = 0; for (const auto node : util::irange(0u, number_of_nodes)) { p.PrintStatus(node); for (auto edge : graph.GetAdjacentEdgeRange(node)) { const NodeID target = graph.GetTarget(edge); - const ContractorGraph::EdgeData &data = graph.GetEdgeData(edge); + const auto &data = graph.GetEdgeData(edge); + auto &new_edge = edges[edge_index++]; new_edge.source = node; new_edge.target = target; 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 "edge id invalid"); new_edge.data.forward = data.forward; new_edge.data.backward = data.backward; - edges.push_back(new_edge); } } + BOOST_ASSERT(edge_index == edges.size()); } - // sort and remove duplicates tbb::parallel_sort(edges.begin(), edges.end()); - auto new_end = std::unique(edges.begin(), edges.end()); - edges.resize(new_end - edges.begin()); return edges; } diff --git a/include/contractor/query_edge.hpp b/include/contractor/query_edge.hpp index a1d24f861..1b42faae2 100644 --- a/include/contractor/query_edge.hpp +++ b/include/contractor/query_edge.hpp @@ -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,12 +53,13 @@ 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) {} - QueryEdge(NodeID source, NodeID target, EdgeData data) - : source(source), target(target), data(std::move(data)) + QueryEdge(NodeID source, NodeID target, const EdgeData &data) + : source(source), target(target), data(data) { } @@ -69,10 +73,11 @@ 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); } }; -} -} +} // namespace contractor +} // namespace osrm #endif // QUERYEDGE_HPP diff --git a/include/contractor/query_graph.hpp b/include/contractor/query_graph.hpp index e5758dcfe..c0c4b6cf5 100644 --- a/include/contractor/query_graph.hpp +++ b/include/contractor/query_graph.hpp @@ -15,11 +15,11 @@ namespace detail { template using QueryGraph = util::StaticGraph; -} +} // namespace detail using QueryGraph = detail::QueryGraph; using QueryGraphView = detail::QueryGraph; -} -} +} // namespace contractor +} // namespace osrm #endif // QUERYEDGE_HPP diff --git a/include/contractor/serialization.hpp b/include/contractor/serialization.hpp new file mode 100644 index 000000000..693216d6a --- /dev/null +++ b/include/contractor/serialization.hpp @@ -0,0 +1,53 @@ +#ifndef OSRM_CONTRACTOR_SERIALIZATION_HPP +#define OSRM_CONTRACTOR_SERIALIZATION_HPP + +#include "contractor/contracted_metric.hpp" + +#include "util/serialization.hpp" + +#include "storage/serialization.hpp" +#include "storage/tar.hpp" + +namespace osrm +{ +namespace contractor +{ +namespace serialization +{ + +template +void write(storage::tar::FileWriter &writer, + const std::string &name, + const detail::ContractedMetric &metric) +{ + util::serialization::write(writer, name + "/contracted_graph", metric.graph); + + writer.WriteElementCount64(name + "/exclude", metric.edge_filter.size()); + for (const auto index : util::irange(0, metric.edge_filter.size())) + { + storage::serialization::write(writer, + name + "/exclude/" + std::to_string(index) + "/edge_filter", + metric.edge_filter[index]); + } +} + +template +void read(storage::tar::FileReader &reader, + const std::string &name, + detail::ContractedMetric &metric) +{ + util::serialization::read(reader, name + "/contracted_graph", metric.graph); + + metric.edge_filter.resize(reader.ReadElementCount64(name + "/exclude")); + for (const auto index : util::irange(0, metric.edge_filter.size())) + { + storage::serialization::read(reader, + name + "/exclude/" + std::to_string(index) + "/edge_filter", + metric.edge_filter[index]); + } +} +} // namespace serialization +} // namespace contractor +} // namespace osrm + +#endif diff --git a/include/customizer/cell_customizer.hpp b/include/customizer/cell_customizer.hpp index 0b9a7c020..9e27236d0 100644 --- a/include/customizer/cell_customizer.hpp +++ b/include/customizer/cell_customizer.hpp @@ -1,11 +1,12 @@ #ifndef OSRM_CELLS_CUSTOMIZER_HPP #define OSRM_CELLS_CUSTOMIZER_HPP -#include "partition/cell_storage.hpp" -#include "partition/multi_level_partition.hpp" +#include "partitioner/cell_storage.hpp" +#include "partitioner/multi_level_partition.hpp" #include "util/query_heap.hpp" #include +#include #include @@ -21,6 +22,7 @@ class CellCustomizer { bool from_clique; EdgeDuration duration; + EdgeDistance distance; }; public: @@ -28,12 +30,12 @@ class CellCustomizer util::QueryHeap>; using HeapPtr = tbb::enumerable_thread_specific; - CellCustomizer(const partition::MultiLevelPartition &partition) : partition(partition) {} + CellCustomizer(const partitioner::MultiLevelPartition &partition) : partition(partition) {} template void Customize(const GraphT &graph, Heap &heap, - const partition::CellStorage &cells, + const partitioner::CellStorage &cells, const std::vector &allowed_nodes, CellMetric &metric, LevelID level, @@ -59,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()) @@ -67,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); } @@ -76,27 +88,33 @@ 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()); } } template void Customize(const GraphT &graph, - const partition::CellStorage &cells, + const partitioner::CellStorage &cells, const std::vector &allowed_nodes, CellMetric &metric) const { @@ -120,14 +138,15 @@ class CellCustomizer private: template void RelaxNode(const GraphT &graph, - const partition::CellStorage &cells, + const partitioner::CellStorage &cells, const std::vector &allowed_nodes, const CellMetric &metric, Heap &heap, LevelID level, NodeID node, EdgeWeight weight, - EdgeDuration duration) const + EdgeDuration duration, + EdgeDistance distance) const { auto first_level = level == 1; BOOST_ASSERT(heap.WasInserted(node)); @@ -148,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) @@ -159,19 +179,25 @@ 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, duration + *subcell_duration}); + heap.Insert(to, to_weight, {true, to_duration, to_distance}); } - else if (to_weight < heap.GetKey(to)) + 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, duration + *subcell_duration}; + heap.GetData(to) = {true, to_duration, to_distance}; } } ++subcell_destination; ++subcell_duration; + ++subcell_distance; } } } @@ -186,27 +212,31 @@ class CellCustomizer } const auto &data = graph.GetEdgeData(edge); - if (data.forward && - (first_level || - partition.GetCell(level - 1, node) != partition.GetCell(level - 1, to))) + if (data.forward && (first_level || partition.GetCell(level - 1, node) != + partition.GetCell(level - 1, to))) { 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 (to_weight < heap.GetKey(to)) + 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, duration + data.duration}; + heap.GetData(to) = {false, to_duration, to_distance}; } } } } - const partition::MultiLevelPartition &partition; + const partitioner::MultiLevelPartition &partition; }; -} -} +} // namespace customizer +} // namespace osrm #endif // OSRM_CELLS_CUSTOMIZER_HPP diff --git a/include/customizer/cell_metric.hpp b/include/customizer/cell_metric.hpp index 530a18559..a522facc3 100644 --- a/include/customizer/cell_metric.hpp +++ b/include/customizer/cell_metric.hpp @@ -20,12 +20,13 @@ template struct CellMetricImpl Vector weights; Vector durations; + Vector distances; }; -} +} // namespace detail using CellMetric = detail::CellMetricImpl; using CellMetricView = detail::CellMetricImpl; -} -} +} // namespace customizer +} // namespace osrm #endif diff --git a/include/customizer/customizer_config.hpp b/include/customizer/customizer_config.hpp index f889dc2e6..4df629de5 100644 --- a/include/customizer/customizer_config.hpp +++ b/include/customizer/customizer_config.hpp @@ -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) @@ -38,7 +39,7 @@ struct CustomizationConfig final : storage::IOConfig updater::UpdaterConfig updater_config; }; -} -} +} // namespace customizer +} // namespace osrm #endif // OSRM_CUSTOMIZE_CUSTOMIZER_CONFIG_HPP diff --git a/include/customizer/edge_based_graph.hpp b/include/customizer/edge_based_graph.hpp index 6dfa28aff..5ef3277f9 100644 --- a/include/customizer/edge_based_graph.hpp +++ b/include/customizer/edge_based_graph.hpp @@ -2,8 +2,8 @@ #define OSRM_CUSTOMIZE_EDGE_BASED_GRAPH_HPP #include "extractor/edge_based_edge.hpp" -#include "partition/edge_based_graph.hpp" -#include "partition/multi_level_graph.hpp" +#include "partitioner/edge_based_graph.hpp" +#include "partitioner/multi_level_graph.hpp" #include "util/static_graph.hpp" #include "util/typedefs.hpp" @@ -16,28 +16,117 @@ namespace osrm namespace customizer { -using EdgeBasedGraphEdgeData = partition::EdgeBasedGraphEdgeData; - -struct MultiLevelEdgeBasedGraph - : public partition::MultiLevelGraph +struct EdgeBasedGraphEdgeData { - using Base = partition::MultiLevelGraph; - using Base::Base; + NodeID turn_id; // ID of the edge based node (node based edge) }; -struct MultiLevelEdgeBasedGraphView - : public partition::MultiLevelGraph +template class MultiLevelGraph; + +namespace serialization { - using Base = partition::MultiLevelGraph; - using Base::Base; +template +void read(storage::tar::FileReader &reader, + const std::string &name, + MultiLevelGraph &graph); + +template +void write(storage::tar::FileWriter &writer, + const std::string &name, + const MultiLevelGraph &graph); +} // namespace serialization + +template +class MultiLevelGraph : public partitioner::MultiLevelGraph +{ + private: + using SuperT = partitioner::MultiLevelGraph; + using PartitionerGraphT = partitioner::MultiLevelGraph; + template using Vector = util::ViewOrVector; + + 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 node_weights_, + Vector node_durations_, + Vector node_distances_) + : node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)), + node_distances(std::move(node_distances_)) + { + util::ViewOrVector + 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 node_array_, + Vector edge_array_, + Vector node_to_edge_offset_, + Vector node_weights_, + Vector node_durations_, + Vector node_distances_, + Vector is_forward_edge_, + Vector 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(storage::tar::FileReader &reader, + const std::string &name, + MultiLevelGraph &graph); + friend void + serialization::write(storage::tar::FileWriter &writer, + const std::string &name, + const MultiLevelGraph &graph); + + protected: + Vector node_weights; + Vector node_durations; + Vector node_distances; + Vector is_forward_edge; + Vector is_backward_edge; }; -struct StaticEdgeBasedGraphEdge : MultiLevelEdgeBasedGraph::InputEdge -{ - using Base = MultiLevelEdgeBasedGraph::InputEdge; - using Base::Base; -}; -} -} +using MultiLevelEdgeBasedGraph = + MultiLevelGraph; +using MultiLevelEdgeBasedGraphView = + MultiLevelGraph; +} // namespace customizer +} // namespace osrm #endif diff --git a/include/customizer/files.hpp b/include/customizer/files.hpp index c5cc28c25..335b77a30 100644 --- a/include/customizer/files.hpp +++ b/include/customizer/files.hpp @@ -3,10 +3,12 @@ #include "customizer/serialization.hpp" -#include "storage/io.hpp" +#include "storage/tar.hpp" #include "util/integer_range.hpp" +#include + namespace osrm { namespace customizer @@ -16,44 +18,96 @@ namespace files // reads .osrm.cell_metrics file template -inline void readCellMetrics(const boost::filesystem::path &path, std::vector &metrics) +inline void readCellMetrics(const boost::filesystem::path &path, + std::unordered_map> &metrics) { static_assert(std::is_same::value || std::is_same::value, ""); - const auto fingerprint = storage::io::FileReader::VerifyFingerprint; - storage::io::FileReader reader{path, fingerprint}; + const auto fingerprint = storage::tar::FileReader::VerifyFingerprint; + storage::tar::FileReader reader{path, fingerprint}; - auto num_metrics = reader.ReadElementCount64(); - metrics.resize(num_metrics); - - for (auto &metric : metrics) + for (auto &pair : metrics) { - serialization::read(reader, metric); + const auto &metric_name = pair.first; + auto &metric_exclude_classes = pair.second; + + auto prefix = "/mld/metrics/" + metric_name + "/exclude"; + auto num_exclude_classes = reader.ReadElementCount64(prefix); + metric_exclude_classes.resize(num_exclude_classes); + + auto id = 0; + for (auto &metric : metric_exclude_classes) + { + serialization::read(reader, prefix + "/" + std::to_string(id++), metric); + } } } // writes .osrm.cell_metrics file template -inline void writeCellMetrics(const boost::filesystem::path &path, - const std::vector &metrics) +inline void +writeCellMetrics(const boost::filesystem::path &path, + const std::unordered_map> &metrics) { static_assert(std::is_same::value || std::is_same::value, ""); - const auto fingerprint = storage::io::FileWriter::GenerateFingerprint; - storage::io::FileWriter writer{path, fingerprint}; + const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint; + storage::tar::FileWriter writer{path, fingerprint}; - writer.WriteElementCount64(metrics.size()); - for (const auto &metric : metrics) + for (const auto &pair : metrics) { - serialization::write(writer, metric); + const auto &metric_name = pair.first; + const auto &metric_exclude_classes = pair.second; + + auto prefix = "/mld/metrics/" + metric_name + "/exclude"; + writer.WriteElementCount64(prefix, metric_exclude_classes.size()); + + auto id = 0; + for (auto &exclude_metric : metric_exclude_classes) + { + serialization::write(writer, prefix + "/" + std::to_string(id++), exclude_metric); + } } } -} -} + +// reads .osrm.mldgr file +template +inline void readGraph(const boost::filesystem::path &path, + MultiLevelGraphT &graph, + std::uint32_t &connectivity_checksum) +{ + static_assert(std::is_same::value || + std::is_same::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 +inline void writeGraph(const boost::filesystem::path &path, + const MultiLevelGraphT &graph, + const std::uint32_t connectivity_checksum) +{ + static_assert(std::is_same::value || + std::is_same::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); +} +} // namespace files +} // namespace customizer +} // namespace osrm + #endif diff --git a/include/customizer/serialization.hpp b/include/customizer/serialization.hpp index f463b59d4..c242f8ba3 100644 --- a/include/customizer/serialization.hpp +++ b/include/customizer/serialization.hpp @@ -1,11 +1,13 @@ #ifndef OSRM_CUSTOMIZER_SERIALIZATION_HPP #define OSRM_CUSTOMIZER_SERIALIZATION_HPP -#include "partition/cell_storage.hpp" +#include "customizer/edge_based_graph.hpp" + +#include "partitioner/cell_storage.hpp" -#include "storage/io.hpp" #include "storage/serialization.hpp" #include "storage/shared_memory_ownership.hpp" +#include "storage/tar.hpp" namespace osrm { @@ -15,20 +17,56 @@ namespace serialization { template -inline void read(storage::io::FileReader &reader, detail::CellMetricImpl &metric) +inline void read(storage::tar::FileReader &reader, + const std::string &name, + detail::CellMetricImpl &metric) { - storage::serialization::read(reader, metric.weights); - storage::serialization::read(reader, metric.durations); + 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 -inline void write(storage::io::FileWriter &writer, const detail::CellMetricImpl &metric) +inline void write(storage::tar::FileWriter &writer, + const std::string &name, + const detail::CellMetricImpl &metric) { - storage::serialization::write(writer, metric.weights); - storage::serialization::write(writer, metric.durations); -} -} -} + 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 +inline void read(storage::tar::FileReader &reader, + const std::string &name, + MultiLevelGraph &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 +inline void write(storage::tar::FileWriter &writer, + const std::string &name, + const MultiLevelGraph &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); +} +} // namespace serialization +} // namespace customizer +} // namespace osrm + #endif diff --git a/include/engine/algorithm.hpp b/include/engine/algorithm.hpp index a8da0236f..1d65cac04 100644 --- a/include/engine/algorithm.hpp +++ b/include/engine/algorithm.hpp @@ -16,28 +16,25 @@ namespace ch struct Algorithm final { }; -} -// Contraction Hiearchy with core -namespace corech -{ -struct Algorithm final -{ -}; -} +} // namespace ch // Multi-Level Dijkstra namespace mld { struct Algorithm final { }; -} +} // namespace mld // Algorithm names template const char *name(); template <> inline const char *name() { return "CH"; } -template <> inline const char *name() { return "CoreCH"; } template <> inline const char *name() { return "MLD"; } +// Algorithm identifier +template const char *identifier(); +template <> inline const char *identifier() { return "ch"; } +template <> inline const char *identifier() { return "mld"; } + template struct HasAlternativePathSearch final : std::false_type { }; @@ -53,6 +50,9 @@ template struct HasMapMatching final : std::false_type template struct HasManyToManySearch final : std::false_type { }; +template struct SupportsDistanceAnnotationType final : std::false_type +{ +}; template struct HasGetTileTurns final : std::false_type { }; @@ -76,6 +76,9 @@ template <> struct HasMapMatching final : std::true_type template <> struct HasManyToManySearch final : std::true_type { }; +template <> struct SupportsDistanceAnnotationType final : std::true_type +{ +}; template <> struct HasGetTileTurns final : std::true_type { }; @@ -83,24 +86,6 @@ template <> struct HasExcludeFlags final : std::true_type { }; -// Algorithms supported by Contraction Hierarchies with core -// the rest is disabled because of performance reasons -template <> struct HasShortestPathSearch final : std::true_type -{ -}; -template <> struct HasDirectShortestPathSearch final : std::true_type -{ -}; -template <> struct HasMapMatching final : std::true_type -{ -}; -template <> struct HasGetTileTurns final : std::true_type -{ -}; -template <> struct HasExcludeFlags final : std::true_type -{ -}; - // Algorithms supported by Multi-Level Dijkstra template <> struct HasAlternativePathSearch final : std::true_type { @@ -117,14 +102,17 @@ template <> struct HasMapMatching final : std::true_type template <> struct HasManyToManySearch final : std::true_type { }; +template <> struct SupportsDistanceAnnotationType final : std::false_type +{ +}; template <> struct HasGetTileTurns final : std::true_type { }; template <> struct HasExcludeFlags final : std::true_type { }; -} -} -} +} // namespace routing_algorithms +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/base_api.hpp b/include/engine/api/base_api.hpp index 0e0dad33b..086c787de 100644 --- a/include/engine/api/base_api.hpp +++ b/include/engine/api/base_api.hpp @@ -2,14 +2,20 @@ #define ENGINE_API_BASE_API_HPP #include "engine/api/base_parameters.hpp" +#include "engine/api/flatbuffers/fbresult_generated.h" #include "engine/datafacade/datafacade_base.hpp" #include "engine/api/json_factory.hpp" #include "engine/hint.hpp" +#include "util/coordinate_calculation.hpp" +#include #include +#include #include +#include +#include #include namespace osrm @@ -19,6 +25,8 @@ namespace engine namespace api { +static const constexpr char *INTERSECTION_DELIMITER = " / "; + class BaseAPI { public: @@ -27,51 +35,143 @@ class BaseAPI { } - util::json::Array MakeWaypoints(const std::vector &segment_end_coordinates) const + util::json::Array + MakeWaypoints(const std::vector &waypoint_candidates) const { BOOST_ASSERT(parameters.coordinates.size() > 0); - BOOST_ASSERT(parameters.coordinates.size() == segment_end_coordinates.size() + 1); + BOOST_ASSERT(parameters.coordinates.size() == waypoint_candidates.size()); util::json::Array waypoints; waypoints.values.resize(parameters.coordinates.size()); - waypoints.values[0] = MakeWaypoint(segment_end_coordinates.front().source_phantom); - auto out_iter = std::next(waypoints.values.begin()); boost::range::transform( - segment_end_coordinates, out_iter, [this](const PhantomNodes &phantom_pair) { - return MakeWaypoint(phantom_pair.target_phantom); - }); + waypoint_candidates, + waypoints.values.begin(), + [this](const PhantomNodeCandidates &candidates) { return MakeWaypoint(candidates); }); return waypoints; } // FIXME: gcc 4.9 does not like MakeWaypoints to be protected // protected: - util::json::Object MakeWaypoint(const PhantomNode &phantom) const + util::json::Object MakeWaypoint(const PhantomNodeCandidates &candidates) const { + // TODO: check forward/reverse + const auto toName = [this](const auto &phantom) { + return facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)) + .to_string(); + }; + const auto noEmpty = [](const auto &name) { return !name.empty(); }; + + // At an intersection we may have multiple phantom node candidates. + // Combine them to represent the waypoint name. + std::string waypoint_name = boost::algorithm::join( + candidates | boost::adaptors::transformed(toName) | boost::adaptors::filtered(noEmpty), + INTERSECTION_DELIMITER); + + const auto &snapped_location = candidatesSnappedLocation(candidates); + const auto &input_location = candidatesInputLocation(candidates); if (parameters.generate_hints) { - // TODO: check forward/reverse + std::vector seg_hints(candidates.size()); + std::transform(candidates.begin(), + candidates.end(), + seg_hints.begin(), + [this](const auto &phantom) { + return SegmentHint{phantom, facade.GetCheckSum()}; + }); + return json::makeWaypoint( - phantom.location, - facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string(), - Hint{phantom, facade.GetCheckSum()}); + snapped_location, + util::coordinate_calculation::greatCircleDistance(snapped_location, input_location), + waypoint_name, + {std::move(seg_hints)}); } else { - // TODO: check forward/reverse return json::makeWaypoint( - phantom.location, - facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)) - .to_string()); + snapped_location, + util::coordinate_calculation::greatCircleDistance(snapped_location, input_location), + waypoint_name); } } + flatbuffers::Offset>> + MakeWaypoints(flatbuffers::FlatBufferBuilder *builder, + const std::vector &waypoint_candidates) const + { + BOOST_ASSERT(parameters.coordinates.size() > 0); + BOOST_ASSERT(parameters.coordinates.size() == waypoint_candidates.size()); + + std::vector> waypoints; + waypoints.resize(parameters.coordinates.size()); + + std::transform(waypoint_candidates.begin(), + waypoint_candidates.end(), + waypoints.begin(), + [this, builder](const PhantomNodeCandidates &candidates) { + return MakeWaypoint(builder, candidates)->Finish(); + }); + return builder->CreateVector(waypoints); + } + + // FIXME: gcc 4.9 does not like MakeWaypoints to be protected + // protected: + std::unique_ptr + MakeWaypoint(flatbuffers::FlatBufferBuilder *builder, + const PhantomNodeCandidates &candidates) const + { + + const auto &snapped_location = candidatesSnappedLocation(candidates); + const auto &input_location = candidatesInputLocation(candidates); + auto location = fbresult::Position( + static_cast(static_cast(util::toFloating(snapped_location.lon))), + static_cast(static_cast(util::toFloating(snapped_location.lat)))); + + const auto toName = [this](const auto &phantom) { + return facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)) + .to_string(); + }; + const auto noEmpty = [](const auto &name) { return !name.empty(); }; + + // At an intersection we may have multiple phantom node candidates. + // Combine them to represent the waypoint name. + std::string waypoint_name = boost::algorithm::join( + candidates | boost::adaptors::transformed(toName) | boost::adaptors::filtered(noEmpty), + INTERSECTION_DELIMITER); + auto name_string = builder->CreateString(waypoint_name); + + flatbuffers::Offset hint_string; + if (parameters.generate_hints) + { + std::vector seg_hints(candidates.size()); + std::transform(candidates.begin(), + candidates.end(), + seg_hints.begin(), + [this](const auto &phantom) { + return SegmentHint{phantom, facade.GetCheckSum()}; + }); + Hint hint{std::move(seg_hints)}; + hint_string = builder->CreateString(hint.ToBase64()); + } + + auto waypoint = std::make_unique(*builder); + waypoint->add_location(&location); + waypoint->add_distance(static_cast( + util::coordinate_calculation::greatCircleDistance(snapped_location, input_location))); + waypoint->add_name(name_string); + if (parameters.generate_hints) + { + waypoint->add_hint(hint_string); + } + return waypoint; + } + const datafacade::BaseDataFacade &facade; const BaseParameters ¶meters; }; -} // ns api -} // ns engine -} // ns osrm +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/base_parameters.hpp b/include/engine/api/base_parameters.hpp index d63c58e5c..d5bb71a53 100644 --- a/include/engine/api/base_parameters.hpp +++ b/include/engine/api/base_parameters.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -51,41 +51,62 @@ namespace api * Holds member attributes: * - coordinates: for specifying location(s) to services * - hints: hint for the service to derive the position(s) in the road network more efficiently, - * optional per coordinate + * optional per coordinate. Multiple hints can be provided for a coordinate. * - radiuses: limits the search for segments in the road network to given radius(es) in meter, * optional per coordinate * - bearings: limits the search for segments in the road network to given bearing(s) in degree * towards true north in clockwise direction, optional per coordinate * - approaches: force the phantom node to start towards the node with the road country side. * - * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters, + * \see OSRM, Coordinate, Hint, Bearing, RouteParameters, TableParameters, * NearestParameters, TripParameters, MatchParameters and TileParameters */ struct BaseParameters { + + enum class SnappingType + { + Default, + Any + }; + + enum class OutputFormatType + { + JSON, + FLATBUFFERS + }; + std::vector coordinates; std::vector> hints; std::vector> radiuses; std::vector> bearings; std::vector> approaches; std::vector exclude; + boost::optional format = OutputFormatType::JSON; // Adds hints to response which can be included in subsequent requests, see `hints` above. bool generate_hints = true; - BaseParameters(const std::vector coordinates_ = {}, - const std::vector> hints_ = {}, + // Remove waypoints array from the response. + bool skip_waypoints = false; + + SnappingType snapping = SnappingType::Default; + + BaseParameters(std::vector coordinates_ = {}, + std::vector> hints_ = {}, std::vector> radiuses_ = {}, std::vector> bearings_ = {}, std::vector> approaches_ = {}, bool generate_hints_ = true, - std::vector exclude = {}) - : coordinates(coordinates_), hints(hints_), radiuses(radiuses_), bearings(bearings_), - approaches(approaches_), exclude(std::move(exclude)), generate_hints(generate_hints_) + std::vector exclude = {}, + const SnappingType snapping_ = SnappingType::Default) + : coordinates(std::move(coordinates_)), hints(std::move(hints_)), + radiuses(std::move(radiuses_)), bearings(std::move(bearings_)), + approaches(std::move(approaches_)), exclude(std::move(exclude)), + generate_hints(generate_hints_), snapping(snapping_) { } - // FIXME add validation for invalid bearing values bool IsValid() const { return (hints.empty() || hints.size() == coordinates.size()) && @@ -94,7 +115,7 @@ struct BaseParameters (approaches.empty() || approaches.size() == coordinates.size()) && std::all_of(bearings.begin(), bearings.end(), - [](const boost::optional bearing_and_range) { + [](const boost::optional &bearing_and_range) { if (bearing_and_range) { return bearing_and_range->IsValid(); @@ -103,8 +124,8 @@ struct BaseParameters }); } }; -} -} -} +} // namespace api +} // namespace engine +} // namespace osrm #endif // ROUTE_PARAMETERS_HPP diff --git a/include/engine/api/base_result.hpp b/include/engine/api/base_result.hpp new file mode 100644 index 000000000..5dd63e7a9 --- /dev/null +++ b/include/engine/api/base_result.hpp @@ -0,0 +1,23 @@ +#ifndef ENGINE_API_BASE_RESULT_HPP +#define ENGINE_API_BASE_RESULT_HPP + +#include +#include + +#include + +#include "util/json_container.hpp" + +namespace osrm +{ +namespace engine +{ +namespace api +{ +using ResultT = + mapbox::util::variant; +} // namespace api +} // namespace engine +} // namespace osrm + +#endif diff --git a/include/engine/api/flatbuffers/fbresult.fbs b/include/engine/api/flatbuffers/fbresult.fbs new file mode 100644 index 000000000..a587899a3 --- /dev/null +++ b/include/engine/api/flatbuffers/fbresult.fbs @@ -0,0 +1,20 @@ +include "route.fbs"; +include "table.fbs"; + +namespace osrm.engine.api.fbresult; + +table Error { + code: string; + message: string; +} + +table FBResult { + error: bool = false; + code: Error; + data_version: string; + waypoints: [Waypoint]; //Used as 'sources' waypoints for a 'Table' service + routes: [RouteObject]; + table: Table; +} + +root_type FBResult; \ No newline at end of file diff --git a/include/engine/api/flatbuffers/fbresult_generated.h b/include/engine/api/flatbuffers/fbresult_generated.h new file mode 100644 index 000000000..f3f05de4a --- /dev/null +++ b/include/engine/api/flatbuffers/fbresult_generated.h @@ -0,0 +1,2439 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_FBRESULT_OSRM_ENGINE_API_FBRESULT_H_ +#define FLATBUFFERS_GENERATED_FBRESULT_OSRM_ENGINE_API_FBRESULT_H_ + +#include "flatbuffers/flatbuffers.h" + +namespace osrm { +namespace engine { +namespace api { +namespace fbresult { + +struct Position; + +struct Uint64Pair; + +struct Waypoint; +struct WaypointT; + +struct Metadata; +struct MetadataT; + +struct Annotation; +struct AnnotationT; + +struct StepManeuver; +struct StepManeuverT; + +struct Lane; +struct LaneT; + +struct Intersection; +struct IntersectionT; + +struct Step; +struct StepT; + +struct Leg; +struct LegT; + +struct RouteObject; +struct RouteObjectT; + +struct Table; +struct TableT; + +struct Error; +struct ErrorT; + +struct FBResult; +struct FBResultT; + +enum ManeuverType { + ManeuverType_Turn = 0, + ManeuverType_NewName = 1, + ManeuverType_Depart = 2, + ManeuverType_Arrive = 3, + ManeuverType_Merge = 4, + ManeuverType_OnRamp = 5, + ManeuverType_OffRamp = 6, + ManeuverType_Fork = 7, + ManeuverType_EndOfRoad = 8, + ManeuverType_Continue = 9, + ManeuverType_Roundabout = 10, + ManeuverType_Rotary = 11, + ManeuverType_RoundaboutTurn = 12, + ManeuverType_Notification = 13, + ManeuverType_ExitRoundabout = 14, + ManeuverType_ExitRotary = 15, + ManeuverType_MIN = ManeuverType_Turn, + ManeuverType_MAX = ManeuverType_ExitRotary +}; + +inline const ManeuverType (&EnumValuesManeuverType())[16] { + static const ManeuverType values[] = { + ManeuverType_Turn, + ManeuverType_NewName, + ManeuverType_Depart, + ManeuverType_Arrive, + ManeuverType_Merge, + ManeuverType_OnRamp, + ManeuverType_OffRamp, + ManeuverType_Fork, + ManeuverType_EndOfRoad, + ManeuverType_Continue, + ManeuverType_Roundabout, + ManeuverType_Rotary, + ManeuverType_RoundaboutTurn, + ManeuverType_Notification, + ManeuverType_ExitRoundabout, + ManeuverType_ExitRotary + }; + return values; +} + +inline const char * const *EnumNamesManeuverType() { + static const char * const names[17] = { + "Turn", + "NewName", + "Depart", + "Arrive", + "Merge", + "OnRamp", + "OffRamp", + "Fork", + "EndOfRoad", + "Continue", + "Roundabout", + "Rotary", + "RoundaboutTurn", + "Notification", + "ExitRoundabout", + "ExitRotary", + nullptr + }; + return names; +} + +inline const char *EnumNameManeuverType(ManeuverType e) { + if (e < ManeuverType_Turn || e > ManeuverType_ExitRotary) return ""; + const size_t index = static_cast(e); + return EnumNamesManeuverType()[index]; +} + +enum Turn { + Turn_None = 0, + Turn_UTurn = 1, + Turn_SharpRight = 2, + Turn_Right = 3, + Turn_SlightRight = 4, + Turn_Straight = 5, + Turn_SlightLeft = 6, + Turn_Left = 7, + Turn_SharpLeft = 8, + Turn_MIN = Turn_None, + Turn_MAX = Turn_SharpLeft +}; + +inline const Turn (&EnumValuesTurn())[9] { + static const Turn values[] = { + Turn_None, + Turn_UTurn, + Turn_SharpRight, + Turn_Right, + Turn_SlightRight, + Turn_Straight, + Turn_SlightLeft, + Turn_Left, + Turn_SharpLeft + }; + return values; +} + +inline const char * const *EnumNamesTurn() { + static const char * const names[10] = { + "None", + "UTurn", + "SharpRight", + "Right", + "SlightRight", + "Straight", + "SlightLeft", + "Left", + "SharpLeft", + nullptr + }; + return names; +} + +inline const char *EnumNameTurn(Turn e) { + if (e < Turn_None || e > Turn_SharpLeft) return ""; + const size_t index = static_cast(e); + return EnumNamesTurn()[index]; +} + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Position FLATBUFFERS_FINAL_CLASS { + private: + float longitude_; + float latitude_; + + public: + Position() { + memset(static_cast(this), 0, sizeof(Position)); + } + Position(float _longitude, float _latitude) + : longitude_(flatbuffers::EndianScalar(_longitude)), + latitude_(flatbuffers::EndianScalar(_latitude)) { + } + float longitude() const { + return flatbuffers::EndianScalar(longitude_); + } + float latitude() const { + return flatbuffers::EndianScalar(latitude_); + } +}; +FLATBUFFERS_STRUCT_END(Position, 8); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Uint64Pair FLATBUFFERS_FINAL_CLASS { + private: + uint64_t first_; + uint64_t second_; + + public: + Uint64Pair() { + memset(static_cast(this), 0, sizeof(Uint64Pair)); + } + Uint64Pair(uint64_t _first, uint64_t _second) + : first_(flatbuffers::EndianScalar(_first)), + second_(flatbuffers::EndianScalar(_second)) { + } + uint64_t first() const { + return flatbuffers::EndianScalar(first_); + } + uint64_t second() const { + return flatbuffers::EndianScalar(second_); + } +}; +FLATBUFFERS_STRUCT_END(Uint64Pair, 16); + +struct WaypointT : public flatbuffers::NativeTable { + typedef Waypoint TableType; + std::string hint; + float distance; + std::string name; + std::unique_ptr location; + std::unique_ptr nodes; + uint32_t matchings_index; + uint32_t waypoint_index; + uint32_t alternatives_count; + uint32_t trips_index; + WaypointT() + : distance(0.0f), + matchings_index(0), + waypoint_index(0), + alternatives_count(0), + trips_index(0) { + } +}; + +struct Waypoint FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef WaypointT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_HINT = 4, + VT_DISTANCE = 6, + VT_NAME = 8, + VT_LOCATION = 10, + VT_NODES = 12, + VT_MATCHINGS_INDEX = 14, + VT_WAYPOINT_INDEX = 16, + VT_ALTERNATIVES_COUNT = 18, + VT_TRIPS_INDEX = 20 + }; + const flatbuffers::String *hint() const { + return GetPointer(VT_HINT); + } + float distance() const { + return GetField(VT_DISTANCE, 0.0f); + } + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + const osrm::engine::api::fbresult::Position *location() const { + return GetStruct(VT_LOCATION); + } + const osrm::engine::api::fbresult::Uint64Pair *nodes() const { + return GetStruct(VT_NODES); + } + uint32_t matchings_index() const { + return GetField(VT_MATCHINGS_INDEX, 0); + } + uint32_t waypoint_index() const { + return GetField(VT_WAYPOINT_INDEX, 0); + } + uint32_t alternatives_count() const { + return GetField(VT_ALTERNATIVES_COUNT, 0); + } + uint32_t trips_index() const { + return GetField(VT_TRIPS_INDEX, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_HINT) && + verifier.VerifyString(hint()) && + VerifyField(verifier, VT_DISTANCE) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField(verifier, VT_LOCATION) && + VerifyField(verifier, VT_NODES) && + VerifyField(verifier, VT_MATCHINGS_INDEX) && + VerifyField(verifier, VT_WAYPOINT_INDEX) && + VerifyField(verifier, VT_ALTERNATIVES_COUNT) && + VerifyField(verifier, VT_TRIPS_INDEX) && + verifier.EndTable(); + } + WaypointT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(WaypointT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const WaypointT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct WaypointBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_hint(flatbuffers::Offset hint) { + fbb_.AddOffset(Waypoint::VT_HINT, hint); + } + void add_distance(float distance) { + fbb_.AddElement(Waypoint::VT_DISTANCE, distance, 0.0f); + } + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Waypoint::VT_NAME, name); + } + void add_location(const osrm::engine::api::fbresult::Position *location) { + fbb_.AddStruct(Waypoint::VT_LOCATION, location); + } + void add_nodes(const osrm::engine::api::fbresult::Uint64Pair *nodes) { + fbb_.AddStruct(Waypoint::VT_NODES, nodes); + } + void add_matchings_index(uint32_t matchings_index) { + fbb_.AddElement(Waypoint::VT_MATCHINGS_INDEX, matchings_index, 0); + } + void add_waypoint_index(uint32_t waypoint_index) { + fbb_.AddElement(Waypoint::VT_WAYPOINT_INDEX, waypoint_index, 0); + } + void add_alternatives_count(uint32_t alternatives_count) { + fbb_.AddElement(Waypoint::VT_ALTERNATIVES_COUNT, alternatives_count, 0); + } + void add_trips_index(uint32_t trips_index) { + fbb_.AddElement(Waypoint::VT_TRIPS_INDEX, trips_index, 0); + } + explicit WaypointBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + WaypointBuilder &operator=(const WaypointBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateWaypoint( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset hint = 0, + float distance = 0.0f, + flatbuffers::Offset name = 0, + const osrm::engine::api::fbresult::Position *location = 0, + const osrm::engine::api::fbresult::Uint64Pair *nodes = 0, + uint32_t matchings_index = 0, + uint32_t waypoint_index = 0, + uint32_t alternatives_count = 0, + uint32_t trips_index = 0) { + WaypointBuilder builder_(_fbb); + builder_.add_trips_index(trips_index); + builder_.add_alternatives_count(alternatives_count); + builder_.add_waypoint_index(waypoint_index); + builder_.add_matchings_index(matchings_index); + builder_.add_nodes(nodes); + builder_.add_location(location); + builder_.add_name(name); + builder_.add_distance(distance); + builder_.add_hint(hint); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateWaypointDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *hint = nullptr, + float distance = 0.0f, + const char *name = nullptr, + const osrm::engine::api::fbresult::Position *location = 0, + const osrm::engine::api::fbresult::Uint64Pair *nodes = 0, + uint32_t matchings_index = 0, + uint32_t waypoint_index = 0, + uint32_t alternatives_count = 0, + uint32_t trips_index = 0) { + auto hint__ = hint ? _fbb.CreateString(hint) : 0; + auto name__ = name ? _fbb.CreateString(name) : 0; + return osrm::engine::api::fbresult::CreateWaypoint( + _fbb, + hint__, + distance, + name__, + location, + nodes, + matchings_index, + waypoint_index, + alternatives_count, + trips_index); +} + +flatbuffers::Offset CreateWaypoint(flatbuffers::FlatBufferBuilder &_fbb, const WaypointT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct MetadataT : public flatbuffers::NativeTable { + typedef Metadata TableType; + std::vector datasource_names; + MetadataT() { + } +}; + +struct Metadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MetadataT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DATASOURCE_NAMES = 4 + }; + const flatbuffers::Vector> *datasource_names() const { + return GetPointer> *>(VT_DATASOURCE_NAMES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_DATASOURCE_NAMES) && + verifier.VerifyVector(datasource_names()) && + verifier.VerifyVectorOfStrings(datasource_names()) && + verifier.EndTable(); + } + MetadataT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MetadataT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MetadataT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct MetadataBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_datasource_names(flatbuffers::Offset>> datasource_names) { + fbb_.AddOffset(Metadata::VT_DATASOURCE_NAMES, datasource_names); + } + explicit MetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + MetadataBuilder &operator=(const MetadataBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMetadata( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> datasource_names = 0) { + MetadataBuilder builder_(_fbb); + builder_.add_datasource_names(datasource_names); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateMetadataDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector> *datasource_names = nullptr) { + auto datasource_names__ = datasource_names ? _fbb.CreateVector>(*datasource_names) : 0; + return osrm::engine::api::fbresult::CreateMetadata( + _fbb, + datasource_names__); +} + +flatbuffers::Offset CreateMetadata(flatbuffers::FlatBufferBuilder &_fbb, const MetadataT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct AnnotationT : public flatbuffers::NativeTable { + typedef Annotation TableType; + std::vector distance; + std::vector duration; + std::vector datasources; + std::vector nodes; + std::vector weight; + std::vector speed; + std::unique_ptr metadata; + AnnotationT() { + } +}; + +struct Annotation FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef AnnotationT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DISTANCE = 4, + VT_DURATION = 6, + VT_DATASOURCES = 8, + VT_NODES = 10, + VT_WEIGHT = 12, + VT_SPEED = 14, + VT_METADATA = 16 + }; + const flatbuffers::Vector *distance() const { + return GetPointer *>(VT_DISTANCE); + } + const flatbuffers::Vector *duration() const { + return GetPointer *>(VT_DURATION); + } + const flatbuffers::Vector *datasources() const { + return GetPointer *>(VT_DATASOURCES); + } + const flatbuffers::Vector *nodes() const { + return GetPointer *>(VT_NODES); + } + const flatbuffers::Vector *weight() const { + return GetPointer *>(VT_WEIGHT); + } + const flatbuffers::Vector *speed() const { + return GetPointer *>(VT_SPEED); + } + const osrm::engine::api::fbresult::Metadata *metadata() const { + return GetPointer(VT_METADATA); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_DISTANCE) && + verifier.VerifyVector(distance()) && + VerifyOffset(verifier, VT_DURATION) && + verifier.VerifyVector(duration()) && + VerifyOffset(verifier, VT_DATASOURCES) && + verifier.VerifyVector(datasources()) && + VerifyOffset(verifier, VT_NODES) && + verifier.VerifyVector(nodes()) && + VerifyOffset(verifier, VT_WEIGHT) && + verifier.VerifyVector(weight()) && + VerifyOffset(verifier, VT_SPEED) && + verifier.VerifyVector(speed()) && + VerifyOffset(verifier, VT_METADATA) && + verifier.VerifyTable(metadata()) && + verifier.EndTable(); + } + AnnotationT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AnnotationT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const AnnotationT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AnnotationBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_distance(flatbuffers::Offset> distance) { + fbb_.AddOffset(Annotation::VT_DISTANCE, distance); + } + void add_duration(flatbuffers::Offset> duration) { + fbb_.AddOffset(Annotation::VT_DURATION, duration); + } + void add_datasources(flatbuffers::Offset> datasources) { + fbb_.AddOffset(Annotation::VT_DATASOURCES, datasources); + } + void add_nodes(flatbuffers::Offset> nodes) { + fbb_.AddOffset(Annotation::VT_NODES, nodes); + } + void add_weight(flatbuffers::Offset> weight) { + fbb_.AddOffset(Annotation::VT_WEIGHT, weight); + } + void add_speed(flatbuffers::Offset> speed) { + fbb_.AddOffset(Annotation::VT_SPEED, speed); + } + void add_metadata(flatbuffers::Offset metadata) { + fbb_.AddOffset(Annotation::VT_METADATA, metadata); + } + explicit AnnotationBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + AnnotationBuilder &operator=(const AnnotationBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAnnotation( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> distance = 0, + flatbuffers::Offset> duration = 0, + flatbuffers::Offset> datasources = 0, + flatbuffers::Offset> nodes = 0, + flatbuffers::Offset> weight = 0, + flatbuffers::Offset> speed = 0, + flatbuffers::Offset metadata = 0) { + AnnotationBuilder builder_(_fbb); + builder_.add_metadata(metadata); + builder_.add_speed(speed); + builder_.add_weight(weight); + builder_.add_nodes(nodes); + builder_.add_datasources(datasources); + builder_.add_duration(duration); + builder_.add_distance(distance); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateAnnotationDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *distance = nullptr, + const std::vector *duration = nullptr, + const std::vector *datasources = nullptr, + const std::vector *nodes = nullptr, + const std::vector *weight = nullptr, + const std::vector *speed = nullptr, + flatbuffers::Offset metadata = 0) { + auto distance__ = distance ? _fbb.CreateVector(*distance) : 0; + auto duration__ = duration ? _fbb.CreateVector(*duration) : 0; + auto datasources__ = datasources ? _fbb.CreateVector(*datasources) : 0; + auto nodes__ = nodes ? _fbb.CreateVector(*nodes) : 0; + auto weight__ = weight ? _fbb.CreateVector(*weight) : 0; + auto speed__ = speed ? _fbb.CreateVector(*speed) : 0; + return osrm::engine::api::fbresult::CreateAnnotation( + _fbb, + distance__, + duration__, + datasources__, + nodes__, + weight__, + speed__, + metadata); +} + +flatbuffers::Offset CreateAnnotation(flatbuffers::FlatBufferBuilder &_fbb, const AnnotationT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct StepManeuverT : public flatbuffers::NativeTable { + typedef StepManeuver TableType; + std::unique_ptr location; + uint16_t bearing_before; + uint16_t bearing_after; + osrm::engine::api::fbresult::ManeuverType type; + osrm::engine::api::fbresult::Turn modifier; + uint8_t exit; + StepManeuverT() + : bearing_before(0), + bearing_after(0), + type(osrm::engine::api::fbresult::ManeuverType_Turn), + modifier(osrm::engine::api::fbresult::Turn_None), + exit(0) { + } +}; + +struct StepManeuver FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef StepManeuverT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_LOCATION = 4, + VT_BEARING_BEFORE = 6, + VT_BEARING_AFTER = 8, + VT_TYPE = 10, + VT_MODIFIER = 12, + VT_EXIT = 14 + }; + const osrm::engine::api::fbresult::Position *location() const { + return GetStruct(VT_LOCATION); + } + uint16_t bearing_before() const { + return GetField(VT_BEARING_BEFORE, 0); + } + uint16_t bearing_after() const { + return GetField(VT_BEARING_AFTER, 0); + } + osrm::engine::api::fbresult::ManeuverType type() const { + return static_cast(GetField(VT_TYPE, 0)); + } + osrm::engine::api::fbresult::Turn modifier() const { + return static_cast(GetField(VT_MODIFIER, 0)); + } + uint8_t exit() const { + return GetField(VT_EXIT, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_LOCATION) && + VerifyField(verifier, VT_BEARING_BEFORE) && + VerifyField(verifier, VT_BEARING_AFTER) && + VerifyField(verifier, VT_TYPE) && + VerifyField(verifier, VT_MODIFIER) && + VerifyField(verifier, VT_EXIT) && + verifier.EndTable(); + } + StepManeuverT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(StepManeuverT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const StepManeuverT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct StepManeuverBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_location(const osrm::engine::api::fbresult::Position *location) { + fbb_.AddStruct(StepManeuver::VT_LOCATION, location); + } + void add_bearing_before(uint16_t bearing_before) { + fbb_.AddElement(StepManeuver::VT_BEARING_BEFORE, bearing_before, 0); + } + void add_bearing_after(uint16_t bearing_after) { + fbb_.AddElement(StepManeuver::VT_BEARING_AFTER, bearing_after, 0); + } + void add_type(osrm::engine::api::fbresult::ManeuverType type) { + fbb_.AddElement(StepManeuver::VT_TYPE, static_cast(type), 0); + } + void add_modifier(osrm::engine::api::fbresult::Turn modifier) { + fbb_.AddElement(StepManeuver::VT_MODIFIER, static_cast(modifier), 0); + } + void add_exit(uint8_t exit) { + fbb_.AddElement(StepManeuver::VT_EXIT, exit, 0); + } + explicit StepManeuverBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + StepManeuverBuilder &operator=(const StepManeuverBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateStepManeuver( + flatbuffers::FlatBufferBuilder &_fbb, + const osrm::engine::api::fbresult::Position *location = 0, + uint16_t bearing_before = 0, + uint16_t bearing_after = 0, + osrm::engine::api::fbresult::ManeuverType type = osrm::engine::api::fbresult::ManeuverType_Turn, + osrm::engine::api::fbresult::Turn modifier = osrm::engine::api::fbresult::Turn_None, + uint8_t exit = 0) { + StepManeuverBuilder builder_(_fbb); + builder_.add_location(location); + builder_.add_bearing_after(bearing_after); + builder_.add_bearing_before(bearing_before); + builder_.add_exit(exit); + builder_.add_modifier(modifier); + builder_.add_type(type); + return builder_.Finish(); +} + +flatbuffers::Offset CreateStepManeuver(flatbuffers::FlatBufferBuilder &_fbb, const StepManeuverT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LaneT : public flatbuffers::NativeTable { + typedef Lane TableType; + std::vector indications; + bool valid; + LaneT() + : valid(false) { + } +}; + +struct Lane FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LaneT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_INDICATIONS = 4, + VT_VALID = 6 + }; + const flatbuffers::Vector *indications() const { + return GetPointer *>(VT_INDICATIONS); + } + bool valid() const { + return GetField(VT_VALID, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_INDICATIONS) && + verifier.VerifyVector(indications()) && + VerifyField(verifier, VT_VALID) && + verifier.EndTable(); + } + LaneT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LaneT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LaneT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LaneBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_indications(flatbuffers::Offset> indications) { + fbb_.AddOffset(Lane::VT_INDICATIONS, indications); + } + void add_valid(bool valid) { + fbb_.AddElement(Lane::VT_VALID, static_cast(valid), 0); + } + explicit LaneBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + LaneBuilder &operator=(const LaneBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLane( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> indications = 0, + bool valid = false) { + LaneBuilder builder_(_fbb); + builder_.add_indications(indications); + builder_.add_valid(valid); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateLaneDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *indications = nullptr, + bool valid = false) { + auto indications__ = indications ? _fbb.CreateVector(*indications) : 0; + return osrm::engine::api::fbresult::CreateLane( + _fbb, + indications__, + valid); +} + +flatbuffers::Offset CreateLane(flatbuffers::FlatBufferBuilder &_fbb, const LaneT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct IntersectionT : public flatbuffers::NativeTable { + typedef Intersection TableType; + std::unique_ptr location; + std::vector bearings; + std::vector classes; + std::vector entry; + uint32_t in_bearing; + uint32_t out_bearing; + std::vector> lanes; + IntersectionT() + : in_bearing(0), + out_bearing(0) { + } +}; + +struct Intersection FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef IntersectionT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_LOCATION = 4, + VT_BEARINGS = 6, + VT_CLASSES = 8, + VT_ENTRY = 10, + VT_IN_BEARING = 12, + VT_OUT_BEARING = 14, + VT_LANES = 16 + }; + const osrm::engine::api::fbresult::Position *location() const { + return GetStruct(VT_LOCATION); + } + const flatbuffers::Vector *bearings() const { + return GetPointer *>(VT_BEARINGS); + } + const flatbuffers::Vector> *classes() const { + return GetPointer> *>(VT_CLASSES); + } + const flatbuffers::Vector *entry() const { + return GetPointer *>(VT_ENTRY); + } + uint32_t in_bearing() const { + return GetField(VT_IN_BEARING, 0); + } + uint32_t out_bearing() const { + return GetField(VT_OUT_BEARING, 0); + } + const flatbuffers::Vector> *lanes() const { + return GetPointer> *>(VT_LANES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_LOCATION) && + VerifyOffset(verifier, VT_BEARINGS) && + verifier.VerifyVector(bearings()) && + VerifyOffset(verifier, VT_CLASSES) && + verifier.VerifyVector(classes()) && + verifier.VerifyVectorOfStrings(classes()) && + VerifyOffset(verifier, VT_ENTRY) && + verifier.VerifyVector(entry()) && + VerifyField(verifier, VT_IN_BEARING) && + VerifyField(verifier, VT_OUT_BEARING) && + VerifyOffset(verifier, VT_LANES) && + verifier.VerifyVector(lanes()) && + verifier.VerifyVectorOfTables(lanes()) && + verifier.EndTable(); + } + IntersectionT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(IntersectionT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const IntersectionT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct IntersectionBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_location(const osrm::engine::api::fbresult::Position *location) { + fbb_.AddStruct(Intersection::VT_LOCATION, location); + } + void add_bearings(flatbuffers::Offset> bearings) { + fbb_.AddOffset(Intersection::VT_BEARINGS, bearings); + } + void add_classes(flatbuffers::Offset>> classes) { + fbb_.AddOffset(Intersection::VT_CLASSES, classes); + } + void add_entry(flatbuffers::Offset> entry) { + fbb_.AddOffset(Intersection::VT_ENTRY, entry); + } + void add_in_bearing(uint32_t in_bearing) { + fbb_.AddElement(Intersection::VT_IN_BEARING, in_bearing, 0); + } + void add_out_bearing(uint32_t out_bearing) { + fbb_.AddElement(Intersection::VT_OUT_BEARING, out_bearing, 0); + } + void add_lanes(flatbuffers::Offset>> lanes) { + fbb_.AddOffset(Intersection::VT_LANES, lanes); + } + explicit IntersectionBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + IntersectionBuilder &operator=(const IntersectionBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateIntersection( + flatbuffers::FlatBufferBuilder &_fbb, + const osrm::engine::api::fbresult::Position *location = 0, + flatbuffers::Offset> bearings = 0, + flatbuffers::Offset>> classes = 0, + flatbuffers::Offset> entry = 0, + uint32_t in_bearing = 0, + uint32_t out_bearing = 0, + flatbuffers::Offset>> lanes = 0) { + IntersectionBuilder builder_(_fbb); + builder_.add_lanes(lanes); + builder_.add_out_bearing(out_bearing); + builder_.add_in_bearing(in_bearing); + builder_.add_entry(entry); + builder_.add_classes(classes); + builder_.add_bearings(bearings); + builder_.add_location(location); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateIntersectionDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const osrm::engine::api::fbresult::Position *location = 0, + const std::vector *bearings = nullptr, + const std::vector> *classes = nullptr, + const std::vector *entry = nullptr, + uint32_t in_bearing = 0, + uint32_t out_bearing = 0, + const std::vector> *lanes = nullptr) { + auto bearings__ = bearings ? _fbb.CreateVector(*bearings) : 0; + auto classes__ = classes ? _fbb.CreateVector>(*classes) : 0; + auto entry__ = entry ? _fbb.CreateVector(*entry) : 0; + auto lanes__ = lanes ? _fbb.CreateVector>(*lanes) : 0; + return osrm::engine::api::fbresult::CreateIntersection( + _fbb, + location, + bearings__, + classes__, + entry__, + in_bearing, + out_bearing, + lanes__); +} + +flatbuffers::Offset CreateIntersection(flatbuffers::FlatBufferBuilder &_fbb, const IntersectionT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct StepT : public flatbuffers::NativeTable { + typedef Step TableType; + float distance; + float duration; + std::string polyline; + std::vector coordinates; + float weight; + std::string name; + std::string ref; + std::string pronunciation; + std::string destinations; + std::string exits; + std::string mode; + std::unique_ptr maneuver; + std::vector> intersections; + std::string rotary_name; + std::string rotary_pronunciation; + bool driving_side; + StepT() + : distance(0.0f), + duration(0.0f), + weight(0.0f), + driving_side(false) { + } +}; + +struct Step FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef StepT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DISTANCE = 4, + VT_DURATION = 6, + VT_POLYLINE = 8, + VT_COORDINATES = 10, + VT_WEIGHT = 12, + VT_NAME = 14, + VT_REF = 16, + VT_PRONUNCIATION = 18, + VT_DESTINATIONS = 20, + VT_EXITS = 22, + VT_MODE = 24, + VT_MANEUVER = 26, + VT_INTERSECTIONS = 28, + VT_ROTARY_NAME = 30, + VT_ROTARY_PRONUNCIATION = 32, + VT_DRIVING_SIDE = 34 + }; + float distance() const { + return GetField(VT_DISTANCE, 0.0f); + } + float duration() const { + return GetField(VT_DURATION, 0.0f); + } + const flatbuffers::String *polyline() const { + return GetPointer(VT_POLYLINE); + } + const flatbuffers::Vector *coordinates() const { + return GetPointer *>(VT_COORDINATES); + } + float weight() const { + return GetField(VT_WEIGHT, 0.0f); + } + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + const flatbuffers::String *ref() const { + return GetPointer(VT_REF); + } + const flatbuffers::String *pronunciation() const { + return GetPointer(VT_PRONUNCIATION); + } + const flatbuffers::String *destinations() const { + return GetPointer(VT_DESTINATIONS); + } + const flatbuffers::String *exits() const { + return GetPointer(VT_EXITS); + } + const flatbuffers::String *mode() const { + return GetPointer(VT_MODE); + } + const osrm::engine::api::fbresult::StepManeuver *maneuver() const { + return GetPointer(VT_MANEUVER); + } + const flatbuffers::Vector> *intersections() const { + return GetPointer> *>(VT_INTERSECTIONS); + } + const flatbuffers::String *rotary_name() const { + return GetPointer(VT_ROTARY_NAME); + } + const flatbuffers::String *rotary_pronunciation() const { + return GetPointer(VT_ROTARY_PRONUNCIATION); + } + bool driving_side() const { + return GetField(VT_DRIVING_SIDE, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_DISTANCE) && + VerifyField(verifier, VT_DURATION) && + VerifyOffset(verifier, VT_POLYLINE) && + verifier.VerifyString(polyline()) && + VerifyOffset(verifier, VT_COORDINATES) && + verifier.VerifyVector(coordinates()) && + VerifyField(verifier, VT_WEIGHT) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffset(verifier, VT_REF) && + verifier.VerifyString(ref()) && + VerifyOffset(verifier, VT_PRONUNCIATION) && + verifier.VerifyString(pronunciation()) && + VerifyOffset(verifier, VT_DESTINATIONS) && + verifier.VerifyString(destinations()) && + VerifyOffset(verifier, VT_EXITS) && + verifier.VerifyString(exits()) && + VerifyOffset(verifier, VT_MODE) && + verifier.VerifyString(mode()) && + VerifyOffset(verifier, VT_MANEUVER) && + verifier.VerifyTable(maneuver()) && + VerifyOffset(verifier, VT_INTERSECTIONS) && + verifier.VerifyVector(intersections()) && + verifier.VerifyVectorOfTables(intersections()) && + VerifyOffset(verifier, VT_ROTARY_NAME) && + verifier.VerifyString(rotary_name()) && + VerifyOffset(verifier, VT_ROTARY_PRONUNCIATION) && + verifier.VerifyString(rotary_pronunciation()) && + VerifyField(verifier, VT_DRIVING_SIDE) && + verifier.EndTable(); + } + StepT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(StepT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const StepT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct StepBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_distance(float distance) { + fbb_.AddElement(Step::VT_DISTANCE, distance, 0.0f); + } + void add_duration(float duration) { + fbb_.AddElement(Step::VT_DURATION, duration, 0.0f); + } + void add_polyline(flatbuffers::Offset polyline) { + fbb_.AddOffset(Step::VT_POLYLINE, polyline); + } + void add_coordinates(flatbuffers::Offset> coordinates) { + fbb_.AddOffset(Step::VT_COORDINATES, coordinates); + } + void add_weight(float weight) { + fbb_.AddElement(Step::VT_WEIGHT, weight, 0.0f); + } + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Step::VT_NAME, name); + } + void add_ref(flatbuffers::Offset ref) { + fbb_.AddOffset(Step::VT_REF, ref); + } + void add_pronunciation(flatbuffers::Offset pronunciation) { + fbb_.AddOffset(Step::VT_PRONUNCIATION, pronunciation); + } + void add_destinations(flatbuffers::Offset destinations) { + fbb_.AddOffset(Step::VT_DESTINATIONS, destinations); + } + void add_exits(flatbuffers::Offset exits) { + fbb_.AddOffset(Step::VT_EXITS, exits); + } + void add_mode(flatbuffers::Offset mode) { + fbb_.AddOffset(Step::VT_MODE, mode); + } + void add_maneuver(flatbuffers::Offset maneuver) { + fbb_.AddOffset(Step::VT_MANEUVER, maneuver); + } + void add_intersections(flatbuffers::Offset>> intersections) { + fbb_.AddOffset(Step::VT_INTERSECTIONS, intersections); + } + void add_rotary_name(flatbuffers::Offset rotary_name) { + fbb_.AddOffset(Step::VT_ROTARY_NAME, rotary_name); + } + void add_rotary_pronunciation(flatbuffers::Offset rotary_pronunciation) { + fbb_.AddOffset(Step::VT_ROTARY_PRONUNCIATION, rotary_pronunciation); + } + void add_driving_side(bool driving_side) { + fbb_.AddElement(Step::VT_DRIVING_SIDE, static_cast(driving_side), 0); + } + explicit StepBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + StepBuilder &operator=(const StepBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateStep( + flatbuffers::FlatBufferBuilder &_fbb, + float distance = 0.0f, + float duration = 0.0f, + flatbuffers::Offset polyline = 0, + flatbuffers::Offset> coordinates = 0, + float weight = 0.0f, + flatbuffers::Offset name = 0, + flatbuffers::Offset ref = 0, + flatbuffers::Offset pronunciation = 0, + flatbuffers::Offset destinations = 0, + flatbuffers::Offset exits = 0, + flatbuffers::Offset mode = 0, + flatbuffers::Offset maneuver = 0, + flatbuffers::Offset>> intersections = 0, + flatbuffers::Offset rotary_name = 0, + flatbuffers::Offset rotary_pronunciation = 0, + bool driving_side = false) { + StepBuilder builder_(_fbb); + builder_.add_rotary_pronunciation(rotary_pronunciation); + builder_.add_rotary_name(rotary_name); + builder_.add_intersections(intersections); + builder_.add_maneuver(maneuver); + builder_.add_mode(mode); + builder_.add_exits(exits); + builder_.add_destinations(destinations); + builder_.add_pronunciation(pronunciation); + builder_.add_ref(ref); + builder_.add_name(name); + builder_.add_weight(weight); + builder_.add_coordinates(coordinates); + builder_.add_polyline(polyline); + builder_.add_duration(duration); + builder_.add_distance(distance); + builder_.add_driving_side(driving_side); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateStepDirect( + flatbuffers::FlatBufferBuilder &_fbb, + float distance = 0.0f, + float duration = 0.0f, + const char *polyline = nullptr, + const std::vector *coordinates = nullptr, + float weight = 0.0f, + const char *name = nullptr, + const char *ref = nullptr, + const char *pronunciation = nullptr, + const char *destinations = nullptr, + const char *exits = nullptr, + const char *mode = nullptr, + flatbuffers::Offset maneuver = 0, + const std::vector> *intersections = nullptr, + const char *rotary_name = nullptr, + const char *rotary_pronunciation = nullptr, + bool driving_side = false) { + auto polyline__ = polyline ? _fbb.CreateString(polyline) : 0; + auto coordinates__ = coordinates ? _fbb.CreateVectorOfStructs(*coordinates) : 0; + auto name__ = name ? _fbb.CreateString(name) : 0; + auto ref__ = ref ? _fbb.CreateString(ref) : 0; + auto pronunciation__ = pronunciation ? _fbb.CreateString(pronunciation) : 0; + auto destinations__ = destinations ? _fbb.CreateString(destinations) : 0; + auto exits__ = exits ? _fbb.CreateString(exits) : 0; + auto mode__ = mode ? _fbb.CreateString(mode) : 0; + auto intersections__ = intersections ? _fbb.CreateVector>(*intersections) : 0; + auto rotary_name__ = rotary_name ? _fbb.CreateString(rotary_name) : 0; + auto rotary_pronunciation__ = rotary_pronunciation ? _fbb.CreateString(rotary_pronunciation) : 0; + return osrm::engine::api::fbresult::CreateStep( + _fbb, + distance, + duration, + polyline__, + coordinates__, + weight, + name__, + ref__, + pronunciation__, + destinations__, + exits__, + mode__, + maneuver, + intersections__, + rotary_name__, + rotary_pronunciation__, + driving_side); +} + +flatbuffers::Offset CreateStep(flatbuffers::FlatBufferBuilder &_fbb, const StepT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LegT : public flatbuffers::NativeTable { + typedef Leg TableType; + double distance; + double duration; + double weight; + std::string summary; + std::unique_ptr annotations; + std::vector> steps; + LegT() + : distance(0.0), + duration(0.0), + weight(0.0) { + } +}; + +struct Leg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LegT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DISTANCE = 4, + VT_DURATION = 6, + VT_WEIGHT = 8, + VT_SUMMARY = 10, + VT_ANNOTATIONS = 12, + VT_STEPS = 14 + }; + double distance() const { + return GetField(VT_DISTANCE, 0.0); + } + double duration() const { + return GetField(VT_DURATION, 0.0); + } + double weight() const { + return GetField(VT_WEIGHT, 0.0); + } + const flatbuffers::String *summary() const { + return GetPointer(VT_SUMMARY); + } + const osrm::engine::api::fbresult::Annotation *annotations() const { + return GetPointer(VT_ANNOTATIONS); + } + const flatbuffers::Vector> *steps() const { + return GetPointer> *>(VT_STEPS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_DISTANCE) && + VerifyField(verifier, VT_DURATION) && + VerifyField(verifier, VT_WEIGHT) && + VerifyOffset(verifier, VT_SUMMARY) && + verifier.VerifyString(summary()) && + VerifyOffset(verifier, VT_ANNOTATIONS) && + verifier.VerifyTable(annotations()) && + VerifyOffset(verifier, VT_STEPS) && + verifier.VerifyVector(steps()) && + verifier.VerifyVectorOfTables(steps()) && + verifier.EndTable(); + } + LegT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LegT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LegT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LegBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_distance(double distance) { + fbb_.AddElement(Leg::VT_DISTANCE, distance, 0.0); + } + void add_duration(double duration) { + fbb_.AddElement(Leg::VT_DURATION, duration, 0.0); + } + void add_weight(double weight) { + fbb_.AddElement(Leg::VT_WEIGHT, weight, 0.0); + } + void add_summary(flatbuffers::Offset summary) { + fbb_.AddOffset(Leg::VT_SUMMARY, summary); + } + void add_annotations(flatbuffers::Offset annotations) { + fbb_.AddOffset(Leg::VT_ANNOTATIONS, annotations); + } + void add_steps(flatbuffers::Offset>> steps) { + fbb_.AddOffset(Leg::VT_STEPS, steps); + } + explicit LegBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + LegBuilder &operator=(const LegBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLeg( + flatbuffers::FlatBufferBuilder &_fbb, + double distance = 0.0, + double duration = 0.0, + double weight = 0.0, + flatbuffers::Offset summary = 0, + flatbuffers::Offset annotations = 0, + flatbuffers::Offset>> steps = 0) { + LegBuilder builder_(_fbb); + builder_.add_weight(weight); + builder_.add_duration(duration); + builder_.add_distance(distance); + builder_.add_steps(steps); + builder_.add_annotations(annotations); + builder_.add_summary(summary); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateLegDirect( + flatbuffers::FlatBufferBuilder &_fbb, + double distance = 0.0, + double duration = 0.0, + double weight = 0.0, + const char *summary = nullptr, + flatbuffers::Offset annotations = 0, + const std::vector> *steps = nullptr) { + auto summary__ = summary ? _fbb.CreateString(summary) : 0; + auto steps__ = steps ? _fbb.CreateVector>(*steps) : 0; + return osrm::engine::api::fbresult::CreateLeg( + _fbb, + distance, + duration, + weight, + summary__, + annotations, + steps__); +} + +flatbuffers::Offset CreateLeg(flatbuffers::FlatBufferBuilder &_fbb, const LegT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct RouteObjectT : public flatbuffers::NativeTable { + typedef RouteObject TableType; + float distance; + float duration; + float weight; + std::string weight_name; + float confidence; + std::string polyline; + std::vector coordinates; + std::vector> legs; + RouteObjectT() + : distance(0.0f), + duration(0.0f), + weight(0.0f), + confidence(0.0f) { + } +}; + +struct RouteObject FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef RouteObjectT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DISTANCE = 4, + VT_DURATION = 6, + VT_WEIGHT = 8, + VT_WEIGHT_NAME = 10, + VT_CONFIDENCE = 12, + VT_POLYLINE = 14, + VT_COORDINATES = 16, + VT_LEGS = 18 + }; + float distance() const { + return GetField(VT_DISTANCE, 0.0f); + } + float duration() const { + return GetField(VT_DURATION, 0.0f); + } + float weight() const { + return GetField(VT_WEIGHT, 0.0f); + } + const flatbuffers::String *weight_name() const { + return GetPointer(VT_WEIGHT_NAME); + } + float confidence() const { + return GetField(VT_CONFIDENCE, 0.0f); + } + const flatbuffers::String *polyline() const { + return GetPointer(VT_POLYLINE); + } + const flatbuffers::Vector *coordinates() const { + return GetPointer *>(VT_COORDINATES); + } + const flatbuffers::Vector> *legs() const { + return GetPointer> *>(VT_LEGS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_DISTANCE) && + VerifyField(verifier, VT_DURATION) && + VerifyField(verifier, VT_WEIGHT) && + VerifyOffset(verifier, VT_WEIGHT_NAME) && + verifier.VerifyString(weight_name()) && + VerifyField(verifier, VT_CONFIDENCE) && + VerifyOffset(verifier, VT_POLYLINE) && + verifier.VerifyString(polyline()) && + VerifyOffset(verifier, VT_COORDINATES) && + verifier.VerifyVector(coordinates()) && + VerifyOffset(verifier, VT_LEGS) && + verifier.VerifyVector(legs()) && + verifier.VerifyVectorOfTables(legs()) && + verifier.EndTable(); + } + RouteObjectT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(RouteObjectT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const RouteObjectT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct RouteObjectBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_distance(float distance) { + fbb_.AddElement(RouteObject::VT_DISTANCE, distance, 0.0f); + } + void add_duration(float duration) { + fbb_.AddElement(RouteObject::VT_DURATION, duration, 0.0f); + } + void add_weight(float weight) { + fbb_.AddElement(RouteObject::VT_WEIGHT, weight, 0.0f); + } + void add_weight_name(flatbuffers::Offset weight_name) { + fbb_.AddOffset(RouteObject::VT_WEIGHT_NAME, weight_name); + } + void add_confidence(float confidence) { + fbb_.AddElement(RouteObject::VT_CONFIDENCE, confidence, 0.0f); + } + void add_polyline(flatbuffers::Offset polyline) { + fbb_.AddOffset(RouteObject::VT_POLYLINE, polyline); + } + void add_coordinates(flatbuffers::Offset> coordinates) { + fbb_.AddOffset(RouteObject::VT_COORDINATES, coordinates); + } + void add_legs(flatbuffers::Offset>> legs) { + fbb_.AddOffset(RouteObject::VT_LEGS, legs); + } + explicit RouteObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + RouteObjectBuilder &operator=(const RouteObjectBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRouteObject( + flatbuffers::FlatBufferBuilder &_fbb, + float distance = 0.0f, + float duration = 0.0f, + float weight = 0.0f, + flatbuffers::Offset weight_name = 0, + float confidence = 0.0f, + flatbuffers::Offset polyline = 0, + flatbuffers::Offset> coordinates = 0, + flatbuffers::Offset>> legs = 0) { + RouteObjectBuilder builder_(_fbb); + builder_.add_legs(legs); + builder_.add_coordinates(coordinates); + builder_.add_polyline(polyline); + builder_.add_confidence(confidence); + builder_.add_weight_name(weight_name); + builder_.add_weight(weight); + builder_.add_duration(duration); + builder_.add_distance(distance); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateRouteObjectDirect( + flatbuffers::FlatBufferBuilder &_fbb, + float distance = 0.0f, + float duration = 0.0f, + float weight = 0.0f, + const char *weight_name = nullptr, + float confidence = 0.0f, + const char *polyline = nullptr, + const std::vector *coordinates = nullptr, + const std::vector> *legs = nullptr) { + auto weight_name__ = weight_name ? _fbb.CreateString(weight_name) : 0; + auto polyline__ = polyline ? _fbb.CreateString(polyline) : 0; + auto coordinates__ = coordinates ? _fbb.CreateVectorOfStructs(*coordinates) : 0; + auto legs__ = legs ? _fbb.CreateVector>(*legs) : 0; + return osrm::engine::api::fbresult::CreateRouteObject( + _fbb, + distance, + duration, + weight, + weight_name__, + confidence, + polyline__, + coordinates__, + legs__); +} + +flatbuffers::Offset CreateRouteObject(flatbuffers::FlatBufferBuilder &_fbb, const RouteObjectT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct TableT : public flatbuffers::NativeTable { + typedef Table TableType; + std::vector durations; + uint16_t rows; + uint16_t cols; + std::vector distances; + std::vector> destinations; + std::vector fallback_speed_cells; + TableT() + : rows(0), + cols(0) { + } +}; + +struct Table FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TableT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DURATIONS = 4, + VT_ROWS = 6, + VT_COLS = 8, + VT_DISTANCES = 10, + VT_DESTINATIONS = 12, + VT_FALLBACK_SPEED_CELLS = 14 + }; + const flatbuffers::Vector *durations() const { + return GetPointer *>(VT_DURATIONS); + } + uint16_t rows() const { + return GetField(VT_ROWS, 0); + } + uint16_t cols() const { + return GetField(VT_COLS, 0); + } + const flatbuffers::Vector *distances() const { + return GetPointer *>(VT_DISTANCES); + } + const flatbuffers::Vector> *destinations() const { + return GetPointer> *>(VT_DESTINATIONS); + } + const flatbuffers::Vector *fallback_speed_cells() const { + return GetPointer *>(VT_FALLBACK_SPEED_CELLS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_DURATIONS) && + verifier.VerifyVector(durations()) && + VerifyField(verifier, VT_ROWS) && + VerifyField(verifier, VT_COLS) && + VerifyOffset(verifier, VT_DISTANCES) && + verifier.VerifyVector(distances()) && + VerifyOffset(verifier, VT_DESTINATIONS) && + verifier.VerifyVector(destinations()) && + verifier.VerifyVectorOfTables(destinations()) && + VerifyOffset(verifier, VT_FALLBACK_SPEED_CELLS) && + verifier.VerifyVector(fallback_speed_cells()) && + verifier.EndTable(); + } + TableT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(TableT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const TableT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct TableBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_durations(flatbuffers::Offset> durations) { + fbb_.AddOffset(Table::VT_DURATIONS, durations); + } + void add_rows(uint16_t rows) { + fbb_.AddElement(Table::VT_ROWS, rows, 0); + } + void add_cols(uint16_t cols) { + fbb_.AddElement(Table::VT_COLS, cols, 0); + } + void add_distances(flatbuffers::Offset> distances) { + fbb_.AddOffset(Table::VT_DISTANCES, distances); + } + void add_destinations(flatbuffers::Offset>> destinations) { + fbb_.AddOffset(Table::VT_DESTINATIONS, destinations); + } + void add_fallback_speed_cells(flatbuffers::Offset> fallback_speed_cells) { + fbb_.AddOffset(Table::VT_FALLBACK_SPEED_CELLS, fallback_speed_cells); + } + explicit TableBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + TableBuilder &operator=(const TableBuilder &); + flatbuffers::Offset
Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset
(end); + return o; + } +}; + +inline flatbuffers::Offset
CreateTable( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> durations = 0, + uint16_t rows = 0, + uint16_t cols = 0, + flatbuffers::Offset> distances = 0, + flatbuffers::Offset>> destinations = 0, + flatbuffers::Offset> fallback_speed_cells = 0) { + TableBuilder builder_(_fbb); + builder_.add_fallback_speed_cells(fallback_speed_cells); + builder_.add_destinations(destinations); + builder_.add_distances(distances); + builder_.add_durations(durations); + builder_.add_cols(cols); + builder_.add_rows(rows); + return builder_.Finish(); +} + +inline flatbuffers::Offset
CreateTableDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *durations = nullptr, + uint16_t rows = 0, + uint16_t cols = 0, + const std::vector *distances = nullptr, + const std::vector> *destinations = nullptr, + const std::vector *fallback_speed_cells = nullptr) { + auto durations__ = durations ? _fbb.CreateVector(*durations) : 0; + auto distances__ = distances ? _fbb.CreateVector(*distances) : 0; + auto destinations__ = destinations ? _fbb.CreateVector>(*destinations) : 0; + auto fallback_speed_cells__ = fallback_speed_cells ? _fbb.CreateVector(*fallback_speed_cells) : 0; + return osrm::engine::api::fbresult::CreateTable( + _fbb, + durations__, + rows, + cols, + distances__, + destinations__, + fallback_speed_cells__); +} + +flatbuffers::Offset
CreateTable(flatbuffers::FlatBufferBuilder &_fbb, const TableT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ErrorT : public flatbuffers::NativeTable { + typedef Error TableType; + std::string code; + std::string message; + ErrorT() { + } +}; + +struct Error FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ErrorT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_CODE = 4, + VT_MESSAGE = 6 + }; + const flatbuffers::String *code() const { + return GetPointer(VT_CODE); + } + const flatbuffers::String *message() const { + return GetPointer(VT_MESSAGE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_CODE) && + verifier.VerifyString(code()) && + VerifyOffset(verifier, VT_MESSAGE) && + verifier.VerifyString(message()) && + verifier.EndTable(); + } + ErrorT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ErrorT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ErrorT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ErrorBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_code(flatbuffers::Offset code) { + fbb_.AddOffset(Error::VT_CODE, code); + } + void add_message(flatbuffers::Offset message) { + fbb_.AddOffset(Error::VT_MESSAGE, message); + } + explicit ErrorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ErrorBuilder &operator=(const ErrorBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateError( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset code = 0, + flatbuffers::Offset message = 0) { + ErrorBuilder builder_(_fbb); + builder_.add_message(message); + builder_.add_code(code); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateErrorDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *code = nullptr, + const char *message = nullptr) { + auto code__ = code ? _fbb.CreateString(code) : 0; + auto message__ = message ? _fbb.CreateString(message) : 0; + return osrm::engine::api::fbresult::CreateError( + _fbb, + code__, + message__); +} + +flatbuffers::Offset CreateError(flatbuffers::FlatBufferBuilder &_fbb, const ErrorT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct FBResultT : public flatbuffers::NativeTable { + typedef FBResult TableType; + bool error; + std::unique_ptr code; + std::string data_version; + std::vector> waypoints; + std::vector> routes; + std::unique_ptr table; + FBResultT() + : error(false) { + } +}; + +struct FBResult FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FBResultT NativeTableType; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ERROR = 4, + VT_CODE = 6, + VT_DATA_VERSION = 8, + VT_WAYPOINTS = 10, + VT_ROUTES = 12, + VT_TABLE = 14 + }; + bool error() const { + return GetField(VT_ERROR, 0) != 0; + } + const osrm::engine::api::fbresult::Error *code() const { + return GetPointer(VT_CODE); + } + const flatbuffers::String *data_version() const { + return GetPointer(VT_DATA_VERSION); + } + const flatbuffers::Vector> *waypoints() const { + return GetPointer> *>(VT_WAYPOINTS); + } + const flatbuffers::Vector> *routes() const { + return GetPointer> *>(VT_ROUTES); + } + const osrm::engine::api::fbresult::Table *table() const { + return GetPointer(VT_TABLE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ERROR) && + VerifyOffset(verifier, VT_CODE) && + verifier.VerifyTable(code()) && + VerifyOffset(verifier, VT_DATA_VERSION) && + verifier.VerifyString(data_version()) && + VerifyOffset(verifier, VT_WAYPOINTS) && + verifier.VerifyVector(waypoints()) && + verifier.VerifyVectorOfTables(waypoints()) && + VerifyOffset(verifier, VT_ROUTES) && + verifier.VerifyVector(routes()) && + verifier.VerifyVectorOfTables(routes()) && + VerifyOffset(verifier, VT_TABLE) && + verifier.VerifyTable(table()) && + verifier.EndTable(); + } + FBResultT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(FBResultT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const FBResultT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct FBResultBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_error(bool error) { + fbb_.AddElement(FBResult::VT_ERROR, static_cast(error), 0); + } + void add_code(flatbuffers::Offset code) { + fbb_.AddOffset(FBResult::VT_CODE, code); + } + void add_data_version(flatbuffers::Offset data_version) { + fbb_.AddOffset(FBResult::VT_DATA_VERSION, data_version); + } + void add_waypoints(flatbuffers::Offset>> waypoints) { + fbb_.AddOffset(FBResult::VT_WAYPOINTS, waypoints); + } + void add_routes(flatbuffers::Offset>> routes) { + fbb_.AddOffset(FBResult::VT_ROUTES, routes); + } + void add_table(flatbuffers::Offset table) { + fbb_.AddOffset(FBResult::VT_TABLE, table); + } + explicit FBResultBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + FBResultBuilder &operator=(const FBResultBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFBResult( + flatbuffers::FlatBufferBuilder &_fbb, + bool error = false, + flatbuffers::Offset code = 0, + flatbuffers::Offset data_version = 0, + flatbuffers::Offset>> waypoints = 0, + flatbuffers::Offset>> routes = 0, + flatbuffers::Offset table = 0) { + FBResultBuilder builder_(_fbb); + builder_.add_table(table); + builder_.add_routes(routes); + builder_.add_waypoints(waypoints); + builder_.add_data_version(data_version); + builder_.add_code(code); + builder_.add_error(error); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateFBResultDirect( + flatbuffers::FlatBufferBuilder &_fbb, + bool error = false, + flatbuffers::Offset code = 0, + const char *data_version = nullptr, + const std::vector> *waypoints = nullptr, + const std::vector> *routes = nullptr, + flatbuffers::Offset table = 0) { + auto data_version__ = data_version ? _fbb.CreateString(data_version) : 0; + auto waypoints__ = waypoints ? _fbb.CreateVector>(*waypoints) : 0; + auto routes__ = routes ? _fbb.CreateVector>(*routes) : 0; + return osrm::engine::api::fbresult::CreateFBResult( + _fbb, + error, + code, + data_version__, + waypoints__, + routes__, + table); +} + +flatbuffers::Offset CreateFBResult(flatbuffers::FlatBufferBuilder &_fbb, const FBResultT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +inline WaypointT *Waypoint::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new WaypointT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Waypoint::UnPackTo(WaypointT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = hint(); if (_e) _o->hint = _e->str(); }; + { auto _e = distance(); _o->distance = _e; }; + { auto _e = name(); if (_e) _o->name = _e->str(); }; + { auto _e = location(); if (_e) _o->location = std::unique_ptr(new osrm::engine::api::fbresult::Position(*_e)); }; + { auto _e = nodes(); if (_e) _o->nodes = std::unique_ptr(new osrm::engine::api::fbresult::Uint64Pair(*_e)); }; + { auto _e = matchings_index(); _o->matchings_index = _e; }; + { auto _e = waypoint_index(); _o->waypoint_index = _e; }; + { auto _e = alternatives_count(); _o->alternatives_count = _e; }; + { auto _e = trips_index(); _o->trips_index = _e; }; +} + +inline flatbuffers::Offset Waypoint::Pack(flatbuffers::FlatBufferBuilder &_fbb, const WaypointT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateWaypoint(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateWaypoint(flatbuffers::FlatBufferBuilder &_fbb, const WaypointT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const WaypointT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _hint = _o->hint.empty() ? 0 : _fbb.CreateString(_o->hint); + auto _distance = _o->distance; + auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name); + auto _location = _o->location ? _o->location.get() : 0; + auto _nodes = _o->nodes ? _o->nodes.get() : 0; + auto _matchings_index = _o->matchings_index; + auto _waypoint_index = _o->waypoint_index; + auto _alternatives_count = _o->alternatives_count; + auto _trips_index = _o->trips_index; + return osrm::engine::api::fbresult::CreateWaypoint( + _fbb, + _hint, + _distance, + _name, + _location, + _nodes, + _matchings_index, + _waypoint_index, + _alternatives_count, + _trips_index); +} + +inline MetadataT *Metadata::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new MetadataT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Metadata::UnPackTo(MetadataT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = datasource_names(); if (_e) { _o->datasource_names.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->datasource_names[_i] = _e->Get(_i)->str(); } } }; +} + +inline flatbuffers::Offset Metadata::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MetadataT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMetadata(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMetadata(flatbuffers::FlatBufferBuilder &_fbb, const MetadataT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MetadataT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _datasource_names = _o->datasource_names.size() ? _fbb.CreateVectorOfStrings(_o->datasource_names) : 0; + return osrm::engine::api::fbresult::CreateMetadata( + _fbb, + _datasource_names); +} + +inline AnnotationT *Annotation::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new AnnotationT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Annotation::UnPackTo(AnnotationT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = distance(); if (_e) { _o->distance.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->distance[_i] = _e->Get(_i); } } }; + { auto _e = duration(); if (_e) { _o->duration.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->duration[_i] = _e->Get(_i); } } }; + { auto _e = datasources(); if (_e) { _o->datasources.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->datasources[_i] = _e->Get(_i); } } }; + { auto _e = nodes(); if (_e) { _o->nodes.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->nodes[_i] = _e->Get(_i); } } }; + { auto _e = weight(); if (_e) { _o->weight.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weight[_i] = _e->Get(_i); } } }; + { auto _e = speed(); if (_e) { _o->speed.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->speed[_i] = _e->Get(_i); } } }; + { auto _e = metadata(); if (_e) _o->metadata = std::unique_ptr(_e->UnPack(_resolver)); }; +} + +inline flatbuffers::Offset Annotation::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AnnotationT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateAnnotation(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateAnnotation(flatbuffers::FlatBufferBuilder &_fbb, const AnnotationT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AnnotationT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _distance = _o->distance.size() ? _fbb.CreateVector(_o->distance) : 0; + auto _duration = _o->duration.size() ? _fbb.CreateVector(_o->duration) : 0; + auto _datasources = _o->datasources.size() ? _fbb.CreateVector(_o->datasources) : 0; + auto _nodes = _o->nodes.size() ? _fbb.CreateVector(_o->nodes) : 0; + auto _weight = _o->weight.size() ? _fbb.CreateVector(_o->weight) : 0; + auto _speed = _o->speed.size() ? _fbb.CreateVector(_o->speed) : 0; + auto _metadata = _o->metadata ? CreateMetadata(_fbb, _o->metadata.get(), _rehasher) : 0; + return osrm::engine::api::fbresult::CreateAnnotation( + _fbb, + _distance, + _duration, + _datasources, + _nodes, + _weight, + _speed, + _metadata); +} + +inline StepManeuverT *StepManeuver::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new StepManeuverT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void StepManeuver::UnPackTo(StepManeuverT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = location(); if (_e) _o->location = std::unique_ptr(new osrm::engine::api::fbresult::Position(*_e)); }; + { auto _e = bearing_before(); _o->bearing_before = _e; }; + { auto _e = bearing_after(); _o->bearing_after = _e; }; + { auto _e = type(); _o->type = _e; }; + { auto _e = modifier(); _o->modifier = _e; }; + { auto _e = exit(); _o->exit = _e; }; +} + +inline flatbuffers::Offset StepManeuver::Pack(flatbuffers::FlatBufferBuilder &_fbb, const StepManeuverT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateStepManeuver(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateStepManeuver(flatbuffers::FlatBufferBuilder &_fbb, const StepManeuverT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const StepManeuverT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _location = _o->location ? _o->location.get() : 0; + auto _bearing_before = _o->bearing_before; + auto _bearing_after = _o->bearing_after; + auto _type = _o->type; + auto _modifier = _o->modifier; + auto _exit = _o->exit; + return osrm::engine::api::fbresult::CreateStepManeuver( + _fbb, + _location, + _bearing_before, + _bearing_after, + _type, + _modifier, + _exit); +} + +inline LaneT *Lane::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new LaneT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Lane::UnPackTo(LaneT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = indications(); if (_e) { _o->indications.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->indications[_i] = static_cast(_e->Get(_i)); } } }; + { auto _e = valid(); _o->valid = _e; }; +} + +inline flatbuffers::Offset Lane::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LaneT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLane(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLane(flatbuffers::FlatBufferBuilder &_fbb, const LaneT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LaneT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _indications = _o->indications.size() ? _fbb.CreateVectorScalarCast(flatbuffers::data(_o->indications), _o->indications.size()) : 0; + auto _valid = _o->valid; + return osrm::engine::api::fbresult::CreateLane( + _fbb, + _indications, + _valid); +} + +inline IntersectionT *Intersection::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new IntersectionT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Intersection::UnPackTo(IntersectionT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = location(); if (_e) _o->location = std::unique_ptr(new osrm::engine::api::fbresult::Position(*_e)); }; + { auto _e = bearings(); if (_e) { _o->bearings.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->bearings[_i] = _e->Get(_i); } } }; + { auto _e = classes(); if (_e) { _o->classes.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->classes[_i] = _e->Get(_i)->str(); } } }; + { auto _e = entry(); if (_e) { _o->entry.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->entry[_i] = _e->Get(_i) != 0; } } }; + { auto _e = in_bearing(); _o->in_bearing = _e; }; + { auto _e = out_bearing(); _o->out_bearing = _e; }; + { auto _e = lanes(); if (_e) { _o->lanes.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->lanes[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; +} + +inline flatbuffers::Offset Intersection::Pack(flatbuffers::FlatBufferBuilder &_fbb, const IntersectionT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateIntersection(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateIntersection(flatbuffers::FlatBufferBuilder &_fbb, const IntersectionT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const IntersectionT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _location = _o->location ? _o->location.get() : 0; + auto _bearings = _o->bearings.size() ? _fbb.CreateVector(_o->bearings) : 0; + auto _classes = _o->classes.size() ? _fbb.CreateVectorOfStrings(_o->classes) : 0; + auto _entry = _o->entry.size() ? _fbb.CreateVector(_o->entry) : 0; + auto _in_bearing = _o->in_bearing; + auto _out_bearing = _o->out_bearing; + auto _lanes = _o->lanes.size() ? _fbb.CreateVector> (_o->lanes.size(), [](size_t i, _VectorArgs *__va) { return CreateLane(*__va->__fbb, __va->__o->lanes[i].get(), __va->__rehasher); }, &_va ) : 0; + return osrm::engine::api::fbresult::CreateIntersection( + _fbb, + _location, + _bearings, + _classes, + _entry, + _in_bearing, + _out_bearing, + _lanes); +} + +inline StepT *Step::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new StepT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Step::UnPackTo(StepT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = distance(); _o->distance = _e; }; + { auto _e = duration(); _o->duration = _e; }; + { auto _e = polyline(); if (_e) _o->polyline = _e->str(); }; + { auto _e = coordinates(); if (_e) { _o->coordinates.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->coordinates[_i] = *_e->Get(_i); } } }; + { auto _e = weight(); _o->weight = _e; }; + { auto _e = name(); if (_e) _o->name = _e->str(); }; + { auto _e = ref(); if (_e) _o->ref = _e->str(); }; + { auto _e = pronunciation(); if (_e) _o->pronunciation = _e->str(); }; + { auto _e = destinations(); if (_e) _o->destinations = _e->str(); }; + { auto _e = exits(); if (_e) _o->exits = _e->str(); }; + { auto _e = mode(); if (_e) _o->mode = _e->str(); }; + { auto _e = maneuver(); if (_e) _o->maneuver = std::unique_ptr(_e->UnPack(_resolver)); }; + { auto _e = intersections(); if (_e) { _o->intersections.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->intersections[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; + { auto _e = rotary_name(); if (_e) _o->rotary_name = _e->str(); }; + { auto _e = rotary_pronunciation(); if (_e) _o->rotary_pronunciation = _e->str(); }; + { auto _e = driving_side(); _o->driving_side = _e; }; +} + +inline flatbuffers::Offset Step::Pack(flatbuffers::FlatBufferBuilder &_fbb, const StepT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateStep(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateStep(flatbuffers::FlatBufferBuilder &_fbb, const StepT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const StepT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _distance = _o->distance; + auto _duration = _o->duration; + auto _polyline = _o->polyline.empty() ? 0 : _fbb.CreateString(_o->polyline); + auto _coordinates = _o->coordinates.size() ? _fbb.CreateVectorOfStructs(_o->coordinates) : 0; + auto _weight = _o->weight; + auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name); + auto _ref = _o->ref.empty() ? 0 : _fbb.CreateString(_o->ref); + auto _pronunciation = _o->pronunciation.empty() ? 0 : _fbb.CreateString(_o->pronunciation); + auto _destinations = _o->destinations.empty() ? 0 : _fbb.CreateString(_o->destinations); + auto _exits = _o->exits.empty() ? 0 : _fbb.CreateString(_o->exits); + auto _mode = _o->mode.empty() ? 0 : _fbb.CreateString(_o->mode); + auto _maneuver = _o->maneuver ? CreateStepManeuver(_fbb, _o->maneuver.get(), _rehasher) : 0; + auto _intersections = _o->intersections.size() ? _fbb.CreateVector> (_o->intersections.size(), [](size_t i, _VectorArgs *__va) { return CreateIntersection(*__va->__fbb, __va->__o->intersections[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _rotary_name = _o->rotary_name.empty() ? 0 : _fbb.CreateString(_o->rotary_name); + auto _rotary_pronunciation = _o->rotary_pronunciation.empty() ? 0 : _fbb.CreateString(_o->rotary_pronunciation); + auto _driving_side = _o->driving_side; + return osrm::engine::api::fbresult::CreateStep( + _fbb, + _distance, + _duration, + _polyline, + _coordinates, + _weight, + _name, + _ref, + _pronunciation, + _destinations, + _exits, + _mode, + _maneuver, + _intersections, + _rotary_name, + _rotary_pronunciation, + _driving_side); +} + +inline LegT *Leg::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new LegT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Leg::UnPackTo(LegT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = distance(); _o->distance = _e; }; + { auto _e = duration(); _o->duration = _e; }; + { auto _e = weight(); _o->weight = _e; }; + { auto _e = summary(); if (_e) _o->summary = _e->str(); }; + { auto _e = annotations(); if (_e) _o->annotations = std::unique_ptr(_e->UnPack(_resolver)); }; + { auto _e = steps(); if (_e) { _o->steps.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->steps[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; +} + +inline flatbuffers::Offset Leg::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LegT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLeg(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLeg(flatbuffers::FlatBufferBuilder &_fbb, const LegT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LegT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _distance = _o->distance; + auto _duration = _o->duration; + auto _weight = _o->weight; + auto _summary = _o->summary.empty() ? 0 : _fbb.CreateString(_o->summary); + auto _annotations = _o->annotations ? CreateAnnotation(_fbb, _o->annotations.get(), _rehasher) : 0; + auto _steps = _o->steps.size() ? _fbb.CreateVector> (_o->steps.size(), [](size_t i, _VectorArgs *__va) { return CreateStep(*__va->__fbb, __va->__o->steps[i].get(), __va->__rehasher); }, &_va ) : 0; + return osrm::engine::api::fbresult::CreateLeg( + _fbb, + _distance, + _duration, + _weight, + _summary, + _annotations, + _steps); +} + +inline RouteObjectT *RouteObject::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new RouteObjectT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void RouteObject::UnPackTo(RouteObjectT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = distance(); _o->distance = _e; }; + { auto _e = duration(); _o->duration = _e; }; + { auto _e = weight(); _o->weight = _e; }; + { auto _e = weight_name(); if (_e) _o->weight_name = _e->str(); }; + { auto _e = confidence(); _o->confidence = _e; }; + { auto _e = polyline(); if (_e) _o->polyline = _e->str(); }; + { auto _e = coordinates(); if (_e) { _o->coordinates.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->coordinates[_i] = *_e->Get(_i); } } }; + { auto _e = legs(); if (_e) { _o->legs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->legs[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; +} + +inline flatbuffers::Offset RouteObject::Pack(flatbuffers::FlatBufferBuilder &_fbb, const RouteObjectT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateRouteObject(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateRouteObject(flatbuffers::FlatBufferBuilder &_fbb, const RouteObjectT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const RouteObjectT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _distance = _o->distance; + auto _duration = _o->duration; + auto _weight = _o->weight; + auto _weight_name = _o->weight_name.empty() ? 0 : _fbb.CreateString(_o->weight_name); + auto _confidence = _o->confidence; + auto _polyline = _o->polyline.empty() ? 0 : _fbb.CreateString(_o->polyline); + auto _coordinates = _o->coordinates.size() ? _fbb.CreateVectorOfStructs(_o->coordinates) : 0; + auto _legs = _o->legs.size() ? _fbb.CreateVector> (_o->legs.size(), [](size_t i, _VectorArgs *__va) { return CreateLeg(*__va->__fbb, __va->__o->legs[i].get(), __va->__rehasher); }, &_va ) : 0; + return osrm::engine::api::fbresult::CreateRouteObject( + _fbb, + _distance, + _duration, + _weight, + _weight_name, + _confidence, + _polyline, + _coordinates, + _legs); +} + +inline TableT *Table::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new TableT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Table::UnPackTo(TableT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = durations(); if (_e) { _o->durations.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->durations[_i] = _e->Get(_i); } } }; + { auto _e = rows(); _o->rows = _e; }; + { auto _e = cols(); _o->cols = _e; }; + { auto _e = distances(); if (_e) { _o->distances.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->distances[_i] = _e->Get(_i); } } }; + { auto _e = destinations(); if (_e) { _o->destinations.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->destinations[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; + { auto _e = fallback_speed_cells(); if (_e) { _o->fallback_speed_cells.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->fallback_speed_cells[_i] = _e->Get(_i); } } }; +} + +inline flatbuffers::Offset
Table::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TableT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateTable(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset
CreateTable(flatbuffers::FlatBufferBuilder &_fbb, const TableT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TableT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _durations = _o->durations.size() ? _fbb.CreateVector(_o->durations) : 0; + auto _rows = _o->rows; + auto _cols = _o->cols; + auto _distances = _o->distances.size() ? _fbb.CreateVector(_o->distances) : 0; + auto _destinations = _o->destinations.size() ? _fbb.CreateVector> (_o->destinations.size(), [](size_t i, _VectorArgs *__va) { return CreateWaypoint(*__va->__fbb, __va->__o->destinations[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _fallback_speed_cells = _o->fallback_speed_cells.size() ? _fbb.CreateVector(_o->fallback_speed_cells) : 0; + return osrm::engine::api::fbresult::CreateTable( + _fbb, + _durations, + _rows, + _cols, + _distances, + _destinations, + _fallback_speed_cells); +} + +inline ErrorT *Error::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new ErrorT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void Error::UnPackTo(ErrorT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = code(); if (_e) _o->code = _e->str(); }; + { auto _e = message(); if (_e) _o->message = _e->str(); }; +} + +inline flatbuffers::Offset Error::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ErrorT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateError(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateError(flatbuffers::FlatBufferBuilder &_fbb, const ErrorT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ErrorT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _code = _o->code.empty() ? 0 : _fbb.CreateString(_o->code); + auto _message = _o->message.empty() ? 0 : _fbb.CreateString(_o->message); + return osrm::engine::api::fbresult::CreateError( + _fbb, + _code, + _message); +} + +inline FBResultT *FBResult::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new FBResultT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void FBResult::UnPackTo(FBResultT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = error(); _o->error = _e; }; + { auto _e = code(); if (_e) _o->code = std::unique_ptr(_e->UnPack(_resolver)); }; + { auto _e = data_version(); if (_e) _o->data_version = _e->str(); }; + { auto _e = waypoints(); if (_e) { _o->waypoints.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->waypoints[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; + { auto _e = routes(); if (_e) { _o->routes.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->routes[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } }; + { auto _e = table(); if (_e) _o->table = std::unique_ptr(_e->UnPack(_resolver)); }; +} + +inline flatbuffers::Offset FBResult::Pack(flatbuffers::FlatBufferBuilder &_fbb, const FBResultT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateFBResult(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateFBResult(flatbuffers::FlatBufferBuilder &_fbb, const FBResultT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const FBResultT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _error = _o->error; + auto _code = _o->code ? CreateError(_fbb, _o->code.get(), _rehasher) : 0; + auto _data_version = _o->data_version.empty() ? 0 : _fbb.CreateString(_o->data_version); + auto _waypoints = _o->waypoints.size() ? _fbb.CreateVector> (_o->waypoints.size(), [](size_t i, _VectorArgs *__va) { return CreateWaypoint(*__va->__fbb, __va->__o->waypoints[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _routes = _o->routes.size() ? _fbb.CreateVector> (_o->routes.size(), [](size_t i, _VectorArgs *__va) { return CreateRouteObject(*__va->__fbb, __va->__o->routes[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _table = _o->table ? CreateTable(_fbb, _o->table.get(), _rehasher) : 0; + return osrm::engine::api::fbresult::CreateFBResult( + _fbb, + _error, + _code, + _data_version, + _waypoints, + _routes, + _table); +} + +inline const osrm::engine::api::fbresult::FBResult *GetFBResult(const void *buf) { + return flatbuffers::GetRoot(buf); +} + +inline const osrm::engine::api::fbresult::FBResult *GetSizePrefixedFBResult(const void *buf) { + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline bool VerifyFBResultBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(nullptr); +} + +inline bool VerifySizePrefixedFBResultBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(nullptr); +} + +inline void FinishFBResultBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedFBResultBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +inline std::unique_ptr UnPackFBResult( + const void *buf, + const flatbuffers::resolver_function_t *res = nullptr) { + return std::unique_ptr(GetFBResult(buf)->UnPack(res)); +} + +inline std::unique_ptr UnPackSizePrefixedFBResult( + const void *buf, + const flatbuffers::resolver_function_t *res = nullptr) { + return std::unique_ptr(GetSizePrefixedFBResult(buf)->UnPack(res)); +} + +} // namespace fbresult +} // namespace api +} // namespace engine +} // namespace osrm + +#endif // FLATBUFFERS_GENERATED_FBRESULT_OSRM_ENGINE_API_FBRESULT_H_ diff --git a/include/engine/api/flatbuffers/position.fbs b/include/engine/api/flatbuffers/position.fbs new file mode 100644 index 000000000..e78f02c67 --- /dev/null +++ b/include/engine/api/flatbuffers/position.fbs @@ -0,0 +1,6 @@ +namespace osrm.engine.api.fbresult; + +struct Position { + longitude: float; + latitude: float; +} \ No newline at end of file diff --git a/include/engine/api/flatbuffers/route.fbs b/include/engine/api/flatbuffers/route.fbs new file mode 100644 index 000000000..902bfa199 --- /dev/null +++ b/include/engine/api/flatbuffers/route.fbs @@ -0,0 +1,110 @@ +include "waypoint.fbs"; +namespace osrm.engine.api.fbresult; + +table Metadata { + datasource_names: [string]; +} + +table Annotation { + distance: [uint]; + duration: [uint]; + datasources: [uint]; + nodes: [uint]; + weight: [uint]; + speed: [float]; + metadata: Metadata; +} + +enum ManeuverType: byte { + Turn, + NewName, + Depart, + Arrive, + Merge, + OnRamp, + OffRamp, + Fork, + EndOfRoad, + Continue, + Roundabout, + Rotary, + RoundaboutTurn, + Notification, + ExitRoundabout, + ExitRotary +} + +enum Turn: byte { + None, + UTurn, + SharpRight, + Right, + SlightRight, + Straight, + SlightLeft, + Left, + SharpLeft +} + +table StepManeuver { + location: Position; + bearing_before: ushort; + bearing_after: ushort; + type: ManeuverType; + modifier: Turn; + exit: ubyte; +} + +table Lane { + indications: [Turn]; + valid: bool; +} + +table Intersection { + location: Position; + bearings: [short]; + classes: [string]; + entry: [bool]; + in_bearing: uint; + out_bearing: uint; + lanes: [Lane]; +} + +table Step { + distance: float; + duration: float; + polyline: string; + coordinates: [Position]; + weight: float; + name: string; + ref: string; + pronunciation: string; + destinations: string; + exits: string; + mode: string; + maneuver: StepManeuver; + intersections: [Intersection]; + rotary_name: string; + rotary_pronunciation: string; + driving_side: bool; //Where true stands for the left side. +} + +table Leg { + distance: double; + duration: double; + weight: double; + summary: string; + annotations: Annotation; + steps: [Step]; +} + +table RouteObject { + distance: float; + duration: float; + weight: float; + weight_name: string; + confidence: float; //Used only by 'Match' service + polyline: string; + coordinates: [Position]; + legs: [Leg]; +} \ No newline at end of file diff --git a/include/engine/api/flatbuffers/table.fbs b/include/engine/api/flatbuffers/table.fbs new file mode 100644 index 000000000..caf1855e6 --- /dev/null +++ b/include/engine/api/flatbuffers/table.fbs @@ -0,0 +1,11 @@ +include "waypoint.fbs"; +namespace osrm.engine.api.fbresult; + +table Table { + durations: [float]; + rows: ushort; + cols: ushort; + distances: [float]; + destinations: [Waypoint]; + fallback_speed_cells: [uint]; +} \ No newline at end of file diff --git a/include/engine/api/flatbuffers/waypoint.fbs b/include/engine/api/flatbuffers/waypoint.fbs new file mode 100644 index 000000000..4991f72e6 --- /dev/null +++ b/include/engine/api/flatbuffers/waypoint.fbs @@ -0,0 +1,19 @@ +include "position.fbs"; +namespace osrm.engine.api.fbresult; + +struct Uint64Pair { + first: uint64; + second: uint64; +} + +table Waypoint { + hint: string; + distance: float; + name: string; + location: Position; + nodes: Uint64Pair; //Used only by 'Nearest' service + matchings_index: uint; //Used only by 'Match' service + waypoint_index: uint; //Used by 'Match' and 'Trip' services + alternatives_count: uint; //Used only by 'Match' service + trips_index: uint; //Used only by 'Trip' service +} \ No newline at end of file diff --git a/include/engine/api/json_factory.hpp b/include/engine/api/json_factory.hpp index 8754e4cf5..f92dba16a 100644 --- a/include/engine/api/json_factory.hpp +++ b/include/engine/api/json_factory.hpp @@ -1,8 +1,8 @@ #ifndef ENGINE_RESPONSE_OBJECTS_HPP_ #define ENGINE_RESPONSE_OBJECTS_HPP_ -#include "extractor/guidance/turn_instruction.hpp" #include "extractor/travel_mode.hpp" +#include "guidance/turn_instruction.hpp" #include "engine/guidance/leg_geometry.hpp" #include "engine/guidance/route.hpp" #include "engine/guidance/route_leg.hpp" @@ -33,21 +33,19 @@ namespace json namespace detail { -std::string instructionTypeToString(extractor::guidance::TurnType::Enum type); -std::string instructionModifierToString(extractor::guidance::DirectionModifier::Enum modifier); +// Check whether to include a modifier in the result of the API +inline bool isValidModifier(const guidance::StepManeuver maneuver) +{ + return (maneuver.waypoint_type == guidance::WaypointType::None || + maneuver.instruction.direction_modifier != osrm::guidance::DirectionModifier::UTurn); +} -/** - * Returns a string representing all instruction types (including internal types that - * are normally not exposed in route responses) - * - * @param type the TurnType value to convert into a string - * @return a string representing the turn type (e.g. `turn` or `continue`) - */ -std::string internalInstructionTypeToString(extractor::guidance::TurnType::Enum type); +inline bool hasValidLanes(const guidance::IntermediateIntersection &intersection) +{ + return intersection.lanes.lanes_in_turn > 0; +} -util::json::Array coordinateToLonLat(const util::Coordinate coordinate); - -std::string modeToString(const extractor::TravelMode mode); +util::json::Array coordinateToLonLat(const util::Coordinate &coordinate); /** * Ensures that a bearing value is a whole number, and clamped to the range 0-359 @@ -100,19 +98,22 @@ 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); util::json::Array makeRouteLegs(std::vector legs, std::vector step_geometries, std::vector annotations); -} -} +} // namespace json +} // namespace api } // namespace engine } // namespace osrm diff --git a/include/engine/api/match_api.hpp b/include/engine/api/match_api.hpp index c06297941..d7899817d 100644 --- a/include/engine/api/match_api.hpp +++ b/include/engine/api/match_api.hpp @@ -29,6 +29,44 @@ class MatchAPI final : public RouteAPI { } + void MakeResponse(const std::vector &sub_matchings, + const std::vector &sub_routes, + osrm::engine::api::ResultT &response) const + { + BOOST_ASSERT(sub_matchings.size() == sub_routes.size()); + if (response.is()) + { + auto &fb_result = response.get(); + MakeResponse(sub_matchings, sub_routes, fb_result); + } + else + { + auto &json_result = response.get(); + MakeResponse(sub_matchings, sub_routes, json_result); + } + } + void MakeResponse(const std::vector &sub_matchings, + const std::vector &sub_routes, + flatbuffers::FlatBufferBuilder &fb_result) const + { + auto data_timestamp = facade.GetTimestamp(); + flatbuffers::Offset data_version_string; + if (!data_timestamp.empty()) + { + data_version_string = fb_result.CreateString(data_timestamp); + } + + auto response = MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_matchings]() { + return MakeTracepoints(fb_result, sub_matchings); + }); + + if (!data_timestamp.empty()) + { + response->add_data_version(data_version_string); + } + + fb_result.Finish(response->Finish()); + } void MakeResponse(const std::vector &sub_matchings, const std::vector &sub_routes, util::json::Object &response) const @@ -36,63 +74,117 @@ class MatchAPI final : public RouteAPI auto number_of_routes = sub_matchings.size(); util::json::Array routes; routes.values.reserve(number_of_routes); - BOOST_ASSERT(sub_matchings.size() == sub_routes.size()); for (auto index : util::irange(0UL, sub_matchings.size())) { - auto route = MakeRoute(sub_routes[index].segment_end_coordinates, + auto route = MakeRoute(sub_routes[index].leg_endpoints, sub_routes[index].unpacked_path_segments, sub_routes[index].source_traversed_in_reverse, sub_routes[index].target_traversed_in_reverse); route.values["confidence"] = sub_matchings[index].confidence; routes.values.push_back(std::move(route)); } - response.values["tracepoints"] = MakeTracepoints(sub_matchings); + if (!parameters.skip_waypoints) + { + response.values["tracepoints"] = MakeTracepoints(sub_matchings); + } response.values["matchings"] = std::move(routes); response.values["code"] = "Ok"; + auto data_timestamp = facade.GetTimestamp(); + if (!data_timestamp.empty()) + { + response.values["data_version"] = data_timestamp; + } } protected: // FIXME this logic is a little backwards. We should change the output format of the // map_matching // routing algorithm to be easier to consume here. + struct MatchingIndex + { + MatchingIndex() = default; + MatchingIndex(unsigned sub_matching_index_, unsigned point_index_) + : sub_matching_index(sub_matching_index_), point_index(point_index_) + { + } + + unsigned sub_matching_index = std::numeric_limits::max(); + unsigned point_index = std::numeric_limits::max(); + + bool NotMatched() + { + return sub_matching_index == std::numeric_limits::max() && + point_index == std::numeric_limits::max(); + } + }; + + flatbuffers::Offset>> + MakeTracepoints(flatbuffers::FlatBufferBuilder &fb_result, + const std::vector &sub_matchings) const + { + std::vector> waypoints; + waypoints.reserve(parameters.coordinates.size()); + + auto trace_idx_to_matching_idx = MakeMatchingIndices(sub_matchings); + + BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1); + + std::size_t was_waypoint_idx = 0; + for (auto trace_index : util::irange(0UL, parameters.coordinates.size())) + { + + if (tidy_result.can_be_removed[trace_index]) + { + waypoints.push_back(fbresult::WaypointBuilder(fb_result).Finish()); + continue; + } + auto matching_index = trace_idx_to_matching_idx[trace_index]; + if (matching_index.NotMatched()) + { + waypoints.push_back(fbresult::WaypointBuilder(fb_result).Finish()); + continue; + } + const auto &phantom = + sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index]; + auto waypoint = BaseAPI::MakeWaypoint(&fb_result, {phantom}); + waypoint->add_matchings_index(matching_index.sub_matching_index); + waypoint->add_alternatives_count(sub_matchings[matching_index.sub_matching_index] + .alternatives_count[matching_index.point_index]); + // waypoint indices need to be adjusted if route legs were collapsed + // waypoint parameter assumes there is only one match object + if (!parameters.waypoints.empty()) + { + if (tidy_result.was_waypoint[trace_index]) + { + waypoint->add_waypoint_index(was_waypoint_idx); + was_waypoint_idx++; + } + else + { + waypoint->add_waypoint_index(0); + } + } + else + { + waypoint->add_waypoint_index(matching_index.point_index); + } + waypoints.push_back(waypoint->Finish()); + } + + return fb_result.CreateVector(waypoints); + } + util::json::Array MakeTracepoints(const std::vector &sub_matchings) const { util::json::Array waypoints; waypoints.values.reserve(parameters.coordinates.size()); - struct MatchingIndex - { - MatchingIndex() = default; - MatchingIndex(unsigned sub_matching_index_, unsigned point_index_) - : sub_matching_index(sub_matching_index_), point_index(point_index_) - { - } + auto trace_idx_to_matching_idx = MakeMatchingIndices(sub_matchings); - unsigned sub_matching_index = std::numeric_limits::max(); - unsigned point_index = std::numeric_limits::max(); - - bool NotMatched() - { - return sub_matching_index == std::numeric_limits::max() && - point_index == std::numeric_limits::max(); - } - }; - - std::vector trace_idx_to_matching_idx(parameters.coordinates.size()); - for (auto sub_matching_index : - util::irange(0u, static_cast(sub_matchings.size()))) - { - for (auto point_index : util::irange( - 0u, static_cast(sub_matchings[sub_matching_index].indices.size()))) - { - trace_idx_to_matching_idx[tidy_result - .tidied_to_original[sub_matchings[sub_matching_index] - .indices[point_index]]] = - MatchingIndex{sub_matching_index, point_index}; - } - } + BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1); + std::size_t was_waypoint_idx = 0; for (auto trace_index : util::irange(0UL, parameters.coordinates.size())) { if (tidy_result.can_be_removed[trace_index]) @@ -108,24 +200,61 @@ class MatchAPI final : public RouteAPI } const auto &phantom = sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index]; - auto waypoint = BaseAPI::MakeWaypoint(phantom); + auto waypoint = BaseAPI::MakeWaypoint({phantom}); waypoint.values["matchings_index"] = matching_index.sub_matching_index; waypoint.values["waypoint_index"] = matching_index.point_index; waypoint.values["alternatives_count"] = sub_matchings[matching_index.sub_matching_index] .alternatives_count[matching_index.point_index]; + // waypoint indices need to be adjusted if route legs were collapsed + // waypoint parameter assumes there is only one match object + if (!parameters.waypoints.empty()) + { + if (tidy_result.was_waypoint[trace_index]) + { + waypoint.values["waypoint_index"] = was_waypoint_idx; + was_waypoint_idx++; + } + else + { + waypoint.values["waypoint_index"] = util::json::Null(); + } + } waypoints.values.push_back(std::move(waypoint)); } return waypoints; } + std::vector + MakeMatchingIndices(const std::vector &sub_matchings) const + { + std::vector trace_idx_to_matching_idx(parameters.coordinates.size()); + for (auto sub_matching_index : + util::irange(0u, static_cast(sub_matchings.size()))) + { + for (auto point_index : util::irange( + 0u, static_cast(sub_matchings[sub_matching_index].indices.size()))) + { + // tidied_to_original: index of the input coordinate that a tidied coordinate + // corresponds to. + // sub_matching indices: index of the coordinate passed to map matching plugin that + // a matched node corresponds to. + trace_idx_to_matching_idx[tidy_result + .tidied_to_original[sub_matchings[sub_matching_index] + .indices[point_index]]] = + MatchingIndex{sub_matching_index, point_index}; + } + } + return trace_idx_to_matching_idx; + } + const MatchParameters ¶meters; const tidy::Result &tidy_result; }; -} // ns api -} // ns engine -} // ns osrm +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/match_parameters.hpp b/include/engine/api/match_parameters.hpp index 4e037fb45..774a2c09d 100644 --- a/include/engine/api/match_parameters.hpp +++ b/include/engine/api/match_parameters.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -68,8 +68,22 @@ struct MatchParameters : public RouteParameters } template - MatchParameters(std::vector timestamps_, GapsType gaps_, bool tidy_, Args... args_) - : RouteParameters{std::forward(args_)...}, timestamps{std::move(timestamps_)}, + MatchParameters(const std::vector ×tamps_, + GapsType gaps_, + bool tidy_, + Args &&... args_) + : MatchParameters(timestamps_, gaps_, tidy_, {}, std::forward(args_)...) + { + } + + template + MatchParameters(std::vector timestamps_, + GapsType gaps_, + bool tidy_, + const std::vector &waypoints_, + Args &&... args_) + : RouteParameters{std::forward(args_)..., waypoints_}, timestamps{std::move( + timestamps_)}, gaps(gaps_), tidy(tidy_) { } @@ -84,8 +98,8 @@ struct MatchParameters : public RouteParameters (timestamps.empty() || timestamps.size() == coordinates.size()); } }; -} -} -} +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/match_parameters_tidy.hpp b/include/engine/api/match_parameters_tidy.hpp index b4e3a2fea..694dd6885 100644 --- a/include/engine/api/match_parameters_tidy.hpp +++ b/include/engine/api/match_parameters_tidy.hpp @@ -37,6 +37,9 @@ struct Result Mask can_be_removed; // Maps the MatchParameter's original items to items which should not be removed. Mapping tidied_to_original; + // Masking the MatchParameter coordinates for items whose indices were present in the + // `waypoints` parameter. + Mask was_waypoint; }; inline Result keep_all(const MatchParameters ¶ms) @@ -44,6 +47,17 @@ inline Result keep_all(const MatchParameters ¶ms) Result result; result.can_be_removed.resize(params.coordinates.size(), false); + result.was_waypoint.resize(params.coordinates.size(), true); + // by default all input coordinates are treated as waypoints + if (!params.waypoints.empty()) + { + for (const auto p : params.waypoints) + { + result.was_waypoint.set(p, false); + } + // logic is a little funny, uses inversion to set the bitfield + result.was_waypoint.flip(); + } result.tidied_to_original.reserve(params.coordinates.size()); for (std::size_t current = 0; current < params.coordinates.size(); ++current) { @@ -61,6 +75,8 @@ inline Result keep_all(const MatchParameters ¶ms) { result.parameters.coordinates.push_back(params.coordinates[i]); + if (result.was_waypoint[i]) + result.parameters.waypoints.push_back(result.parameters.coordinates.size() - 1); if (!params.hints.empty()) result.parameters.hints.push_back(params.hints[i]); @@ -74,6 +90,8 @@ inline Result keep_all(const MatchParameters ¶ms) result.parameters.timestamps.push_back(params.timestamps[i]); } } + if (params.waypoints.empty()) + result.parameters.waypoints.clear(); return result; } @@ -85,6 +103,15 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5}) Result result; result.can_be_removed.resize(params.coordinates.size(), false); + result.was_waypoint.resize(params.coordinates.size(), true); + if (!params.waypoints.empty()) + { + for (const auto p : params.waypoints) + { + result.was_waypoint.set(p, false); + } + result.was_waypoint.flip(); + } result.tidied_to_original.push_back(0); @@ -95,7 +122,7 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5}) // Walk over adjacent (coord, ts)-pairs, with rhs being the candidate to discard or keep for (std::size_t current = 0, next = 1; next < params.coordinates.size() - 1; ++current, ++next) { - auto distance_delta = util::coordinate_calculation::haversineDistance( + auto distance_delta = util::coordinate_calculation::greatCircleDistance( params.coordinates[current], params.coordinates[next]); running.distance_in_meters += distance_delta; const auto over_distance = running.distance_in_meters >= cfg.distance_in_meters; @@ -138,13 +165,14 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5}) // We have to filter parallel arrays that may be empty or the exact same size. // result.parameters contains an empty MatchParameters at this point: conditionally fill. - for (std::size_t i = 0; i < result.can_be_removed.size(); ++i) { if (!result.can_be_removed[i]) { result.parameters.coordinates.push_back(params.coordinates[i]); + if (result.was_waypoint[i]) + result.parameters.waypoints.push_back(result.parameters.coordinates.size() - 1); if (!params.hints.empty()) result.parameters.hints.push_back(params.hints[i]); @@ -157,15 +185,24 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5}) if (!params.timestamps.empty()) result.parameters.timestamps.push_back(params.timestamps[i]); } + else + { + // one of the coordinates meant to be used as a waypoint was marked for removal + // update the original waypoint index to the new representative coordinate + const auto last_idx = result.parameters.coordinates.size() - 1; + if (result.was_waypoint[i] && (result.parameters.waypoints.back() != last_idx)) + { + result.parameters.waypoints.push_back(last_idx); + } + } } - BOOST_ASSERT(result.tidied_to_original.size() == result.parameters.coordinates.size()); return result; } -} // ns tidy -} // ns api -} // ns engine -} // ns osrm +} // namespace tidy +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/nearest_api.hpp b/include/engine/api/nearest_api.hpp index c0c2c8077..43c42de29 100644 --- a/include/engine/api/nearest_api.hpp +++ b/include/engine/api/nearest_api.hpp @@ -2,6 +2,7 @@ #define ENGINE_API_NEAREST_API_HPP #include "engine/api/base_api.hpp" +#include "engine/api/base_result.hpp" #include "engine/api/nearest_parameters.hpp" #include "engine/api/json_factory.hpp" @@ -27,31 +28,144 @@ class NearestAPI final : public BaseAPI } void MakeResponse(const std::vector> &phantom_nodes, - util::json::Object &response) const + osrm::engine::api::ResultT &response) const { BOOST_ASSERT(phantom_nodes.size() == 1); BOOST_ASSERT(parameters.coordinates.size() == 1); - util::json::Array waypoints; - waypoints.values.resize(phantom_nodes.front().size()); - std::transform(phantom_nodes.front().begin(), - phantom_nodes.front().end(), - waypoints.values.begin(), - [this](const PhantomNodeWithDistance &phantom_with_distance) { - auto waypoint = MakeWaypoint(phantom_with_distance.phantom_node); - waypoint.values["distance"] = phantom_with_distance.distance; - return waypoint; - }); + if (response.is()) + { + auto &fb_result = response.get(); + MakeResponse(phantom_nodes, fb_result); + } + else + { + auto &json_result = response.get(); + MakeResponse(phantom_nodes, json_result); + } + } + + void MakeResponse(const std::vector> &phantom_nodes, + flatbuffers::FlatBufferBuilder &fb_result) const + { + auto data_timestamp = facade.GetTimestamp(); + boost::optional> data_version_string = boost::none; + if (!data_timestamp.empty()) + { + data_version_string = fb_result.CreateString(data_timestamp); + } + + flatbuffers::Offset>> + waypoints_vector; + if (!parameters.skip_waypoints) + { + std::vector> waypoints; + waypoints.resize(phantom_nodes.front().size()); + std::transform( + phantom_nodes.front().begin(), + phantom_nodes.front().end(), + waypoints.begin(), + [this, &fb_result](const PhantomNodeWithDistance &phantom_with_distance) { + auto &phantom_node = phantom_with_distance.phantom_node; + + auto node_values = MakeNodes(phantom_node); + fbresult::Uint64Pair nodes{node_values.first, node_values.second}; + + auto waypoint = MakeWaypoint(&fb_result, {phantom_node}); + waypoint->add_nodes(&nodes); + return waypoint->Finish(); + }); + + waypoints_vector = fb_result.CreateVector(waypoints); + } + + fbresult::FBResultBuilder response(fb_result); + + response.add_waypoints(waypoints_vector); + if (data_version_string) + { + response.add_data_version(*data_version_string); + } + fb_result.Finish(response.Finish()); + } + void MakeResponse(const std::vector> &phantom_nodes, + util::json::Object &response) const + { + if (!parameters.skip_waypoints) + { + util::json::Array waypoints; + waypoints.values.resize(phantom_nodes.front().size()); + std::transform(phantom_nodes.front().begin(), + phantom_nodes.front().end(), + waypoints.values.begin(), + [this](const PhantomNodeWithDistance &phantom_with_distance) { + auto &phantom_node = phantom_with_distance.phantom_node; + auto waypoint = MakeWaypoint({phantom_node}); + + util::json::Array nodes; + + auto node_values = MakeNodes(phantom_node); + + nodes.values.push_back(node_values.first); + nodes.values.push_back(node_values.second); + waypoint.values["nodes"] = std::move(nodes); + + return waypoint; + }); + response.values["waypoints"] = std::move(waypoints); + } response.values["code"] = "Ok"; - response.values["waypoints"] = std::move(waypoints); + auto data_timestamp = facade.GetTimestamp(); + if (!data_timestamp.empty()) + { + response.values["data_version"] = data_timestamp; + } } const NearestParameters ¶meters; + + protected: + std::pair MakeNodes(const PhantomNode &phantom_node) const + { + std::uint64_t from_node = 0; + std::uint64_t to_node = 0; + + datafacade::BaseDataFacade::NodeForwardRange forward_geometry; + if (phantom_node.forward_segment_id.enabled) + { + auto segment_id = phantom_node.forward_segment_id.id; + const auto geometry_id = facade.GetGeometryIndex(segment_id).id; + forward_geometry = facade.GetUncompressedForwardGeometry(geometry_id); + + auto osm_node_id = + facade.GetOSMNodeIDOfNode(forward_geometry(phantom_node.fwd_segment_position)); + to_node = static_cast(osm_node_id); + } + + if (phantom_node.reverse_segment_id.enabled) + { + auto segment_id = phantom_node.reverse_segment_id.id; + const auto geometry_id = facade.GetGeometryIndex(segment_id).id; + const auto geometry = facade.GetUncompressedForwardGeometry(geometry_id); + auto osm_node_id = + facade.GetOSMNodeIDOfNode(geometry(phantom_node.fwd_segment_position + 1)); + from_node = static_cast(osm_node_id); + } + else if (phantom_node.forward_segment_id.enabled && phantom_node.fwd_segment_position > 0) + { + // In the case of one way, rely on forward segment only + auto osm_node_id = + facade.GetOSMNodeIDOfNode(forward_geometry(phantom_node.fwd_segment_position - 1)); + from_node = static_cast(osm_node_id); + } + + return std::make_pair(from_node, to_node); + } }; -} // ns api -} // ns engine -} // ns osrm +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/nearest_parameters.hpp b/include/engine/api/nearest_parameters.hpp index 6a6dad7f1..576e75352 100644 --- a/include/engine/api/nearest_parameters.hpp +++ b/include/engine/api/nearest_parameters.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -52,8 +52,8 @@ struct NearestParameters : public BaseParameters bool IsValid() const { return BaseParameters::IsValid() && number_of_results >= 1; } }; -} -} -} +} // namespace api +} // namespace engine +} // namespace osrm #endif // ENGINE_API_NEAREST_PARAMETERS_HPP diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index 3f278b9b6..044ea0b1b 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -1,7 +1,9 @@ #ifndef ENGINE_API_ROUTE_HPP #define ENGINE_API_ROUTE_HPP +#include "extractor/maneuver_override.hpp" #include "engine/api/base_api.hpp" +#include "engine/api/base_result.hpp" #include "engine/api/json_factory.hpp" #include "engine/api/route_parameters.hpp" @@ -19,11 +21,14 @@ #include "engine/internal_route_result.hpp" +#include "guidance/turn_instruction.hpp" + #include "util/coordinate.hpp" #include "util/integer_range.hpp" #include "util/json_util.hpp" #include +#include #include namespace osrm @@ -41,11 +46,58 @@ class RouteAPI : public BaseAPI { } - void MakeResponse(const InternalManyRoutesResult &raw_routes, - util::json::Object &response) const + void + MakeResponse(const InternalManyRoutesResult &raw_routes, + const std::vector + &waypoint_candidates, // all used coordinates, ignoring waypoints= parameter + osrm::engine::api::ResultT &response) const { BOOST_ASSERT(!raw_routes.routes.empty()); + if (response.is()) + { + auto &fb_result = response.get(); + MakeResponse(raw_routes, waypoint_candidates, fb_result); + } + else + { + auto &json_result = response.get(); + MakeResponse(raw_routes, waypoint_candidates, json_result); + } + } + + void + MakeResponse(const InternalManyRoutesResult &raw_routes, + const std::vector + &waypoint_candidates, // all used coordinates, ignoring waypoints= parameter + flatbuffers::FlatBufferBuilder &fb_result) const + { + + auto data_timestamp = facade.GetTimestamp(); + flatbuffers::Offset data_version_string; + if (!data_timestamp.empty()) + { + data_version_string = fb_result.CreateString(data_timestamp); + } + + auto response = + MakeFBResponse(raw_routes, fb_result, [this, &waypoint_candidates, &fb_result]() { + return BaseAPI::MakeWaypoints(&fb_result, waypoint_candidates); + }); + + if (!data_timestamp.empty()) + { + response->add_data_version(data_version_string); + } + fb_result.Finish(response->Finish()); + } + + void + MakeResponse(const InternalManyRoutesResult &raw_routes, + const std::vector + &waypoint_candidates, // all used coordinates, ignoring waypoints= parameter + util::json::Object &response) const + { util::json::Array jsRoutes; for (const auto &route : raw_routes.routes) @@ -53,34 +105,121 @@ class RouteAPI : public BaseAPI if (!route.is_valid()) continue; - jsRoutes.values.push_back(MakeRoute(route.segment_end_coordinates, + jsRoutes.values.push_back(MakeRoute(route.leg_endpoints, route.unpacked_path_segments, route.source_traversed_in_reverse, route.target_traversed_in_reverse)); } - response.values["waypoints"] = - BaseAPI::MakeWaypoints(raw_routes.routes[0].segment_end_coordinates); + if (!parameters.skip_waypoints) + { + response.values["waypoints"] = BaseAPI::MakeWaypoints(waypoint_candidates); + } 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: + template + std::unique_ptr + MakeFBResponse(const InternalManyRoutesResult &raw_routes, + flatbuffers::FlatBufferBuilder &fb_result, + GetWptsFn getWaypoints) const + { + + std::vector> routes; + for (const auto &raw_route : raw_routes.routes) + { + if (!raw_route.is_valid()) + continue; + + routes.push_back(MakeRoute(fb_result, + raw_route.leg_endpoints, + raw_route.unpacked_path_segments, + raw_route.source_traversed_in_reverse, + raw_route.target_traversed_in_reverse)); + } + + auto routes_vector = fb_result.CreateVector(routes); + flatbuffers::Offset>> + waypoints_vector; + if (!parameters.skip_waypoints) + { + waypoints_vector = getWaypoints(); + } + + auto response = std::make_unique(fb_result); + response->add_routes(routes_vector); + response->add_waypoints(waypoints_vector); + + return response; + } + template - util::json::Value MakeGeometry(ForwardIter begin, ForwardIter end) const + mapbox::util::variant, + flatbuffers::Offset>> + MakeGeometry(flatbuffers::FlatBufferBuilder &builder, ForwardIter begin, ForwardIter end) const { if (parameters.geometries == RouteParameters::GeometriesType::Polyline) { - return json::makePolyline<100000>(begin, end); + return builder.CreateString(encodePolyline<100000>(begin, end)); } - - if (parameters.geometries == RouteParameters::GeometriesType::Polyline6) + else if (parameters.geometries == RouteParameters::GeometriesType::Polyline6) { - return json::makePolyline<1000000>(begin, end); + return builder.CreateString(encodePolyline<1000000>(begin, end)); + } + std::vector coordinates; + coordinates.resize(std::distance(begin, end)); + std::transform(begin, end, coordinates.begin(), [](const Coordinate &c) { + return fbresult::Position{static_cast(util::toFloating(c.lon).__value), + static_cast(util::toFloating(c.lat).__value)}; + }); + return builder.CreateVectorOfStructs(coordinates); + } + + boost::optional + MakeGeometry(boost::optional> &&annotations) const + { + boost::optional json_geometry; + if (annotations) + { + auto begin = annotations->begin(); + auto end = annotations->end(); + if (parameters.geometries == RouteParameters::GeometriesType::Polyline) + { + json_geometry = json::makePolyline<100000>(begin, end); + } + else if (parameters.geometries == RouteParameters::GeometriesType::Polyline6) + { + json_geometry = json::makePolyline<1000000>(begin, end); + } + else + { + BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON); + json_geometry = json::makeGeoJSONGeometry(begin, end); + } + } + return json_geometry; + } + + template + flatbuffers::Offset> GetAnnotations( + flatbuffers::FlatBufferBuilder &fb_result, guidance::LegGeometry &leg, GetFn Get) const + { + std::vector annotations_store; + annotations_store.reserve(leg.annotations.size()); + + for (const auto &step : leg.annotations) + { + annotations_store.push_back(Get(step)); } - BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON); - return json::makeGeoJSONGeometry(begin, end); + return fb_result.CreateVector(annotations_store); } template @@ -88,126 +227,512 @@ class RouteAPI : public BaseAPI { util::json::Array annotations_store; annotations_store.values.reserve(leg.annotations.size()); - std::for_each(leg.annotations.begin(), - leg.annotations.end(), - [Get, &annotations_store](const auto &step) { - annotations_store.values.push_back(Get(step)); - }); + + for (const auto &step : leg.annotations) + { + annotations_store.values.push_back(Get(step)); + } + return annotations_store; } - util::json::Object MakeRoute(const std::vector &segment_end_coordinates, + fbresult::ManeuverType WaypointTypeToFB(guidance::WaypointType type) const + { + switch (type) + { + case guidance::WaypointType::Arrive: + return fbresult::ManeuverType_Arrive; + case guidance::WaypointType::Depart: + return fbresult::ManeuverType_Depart; + default: + return fbresult::ManeuverType_Notification; + } + } + + fbresult::ManeuverType TurnTypeToFB(osrm::guidance::TurnType::Enum turn) const + { + static std::map mappings = { + {osrm::guidance::TurnType::Invalid, fbresult::ManeuverType_Notification}, + {osrm::guidance::TurnType::NewName, fbresult::ManeuverType_NewName}, + {osrm::guidance::TurnType::Continue, fbresult::ManeuverType_Continue}, + {osrm::guidance::TurnType::Turn, fbresult::ManeuverType_Turn}, + {osrm::guidance::TurnType::Merge, fbresult::ManeuverType_Merge}, + {osrm::guidance::TurnType::OnRamp, fbresult::ManeuverType_OnRamp}, + {osrm::guidance::TurnType::OffRamp, fbresult::ManeuverType_OffRamp}, + {osrm::guidance::TurnType::Fork, fbresult::ManeuverType_Fork}, + {osrm::guidance::TurnType::EndOfRoad, fbresult::ManeuverType_EndOfRoad}, + {osrm::guidance::TurnType::Notification, fbresult::ManeuverType_Notification}, + {osrm::guidance::TurnType::EnterRoundabout, fbresult::ManeuverType_Roundabout}, + {osrm::guidance::TurnType::EnterAndExitRoundabout, + fbresult::ManeuverType_ExitRoundabout}, + {osrm::guidance::TurnType::EnterRotary, fbresult::ManeuverType_Rotary}, + {osrm::guidance::TurnType::EnterAndExitRotary, fbresult::ManeuverType_ExitRotary}, + {osrm::guidance::TurnType::EnterRoundaboutIntersection, + fbresult::ManeuverType_Roundabout}, + {osrm::guidance::TurnType::EnterAndExitRoundaboutIntersection, + fbresult::ManeuverType_ExitRoundabout}, + {osrm::guidance::TurnType::NoTurn, fbresult::ManeuverType_Notification}, + {osrm::guidance::TurnType::Suppressed, fbresult::ManeuverType_Notification}, + {osrm::guidance::TurnType::EnterRoundaboutAtExit, fbresult::ManeuverType_Roundabout}, + {osrm::guidance::TurnType::ExitRoundabout, fbresult::ManeuverType_ExitRoundabout}, + {osrm::guidance::TurnType::EnterRotaryAtExit, fbresult::ManeuverType_Rotary}, + {osrm::guidance::TurnType::ExitRotary, fbresult::ManeuverType_ExitRotary}, + {osrm::guidance::TurnType::EnterRoundaboutIntersectionAtExit, + fbresult::ManeuverType_Roundabout}, + {osrm::guidance::TurnType::ExitRoundaboutIntersection, + fbresult::ManeuverType_ExitRoundabout}, + {osrm::guidance::TurnType::StayOnRoundabout, fbresult::ManeuverType_RoundaboutTurn}, + {osrm::guidance::TurnType::Sliproad, fbresult::ManeuverType_Notification}, + {osrm::guidance::TurnType::MaxTurnType, fbresult::ManeuverType_Notification}}; + return mappings[turn]; + } + + fbresult::Turn TurnModifierToFB(osrm::guidance::DirectionModifier::Enum modifier) const + { + static std::map mappings = { + {osrm::guidance::DirectionModifier::UTurn, fbresult::Turn_UTurn}, + {osrm::guidance::DirectionModifier::SharpRight, fbresult::Turn_SharpRight}, + {osrm::guidance::DirectionModifier::Right, fbresult::Turn_Right}, + {osrm::guidance::DirectionModifier::SlightRight, fbresult::Turn_SlightRight}, + {osrm::guidance::DirectionModifier::Straight, fbresult::Turn_Straight}, + {osrm::guidance::DirectionModifier::SlightLeft, fbresult::Turn_SlightLeft}, + {osrm::guidance::DirectionModifier::Left, fbresult::Turn_Left}, + {osrm::guidance::DirectionModifier::SharpLeft, fbresult::Turn_SharpLeft}, + }; + return mappings[modifier]; + } + + std::vector TurnLaneTypeToFB(const extractor::TurnLaneType::Mask lane_type) const + { + const static fbresult::Turn mapping[] = {fbresult::Turn_None, + fbresult::Turn_Straight, + fbresult::Turn_SharpLeft, + fbresult::Turn_Left, + fbresult::Turn_SlightLeft, + fbresult::Turn_SlightRight, + fbresult::Turn_Right, + fbresult::Turn_SharpRight, + fbresult::Turn_UTurn, + fbresult::Turn_SlightLeft, + fbresult::Turn_SlightRight}; + std::vector result; + std::bitset<8 * sizeof(extractor::TurnLaneType::Mask)> mask(lane_type); + for (auto index : util::irange(0, extractor::TurnLaneType::NUM_TYPES)) + { + if (mask[index]) + { + result.push_back(mapping[index]); + } + } + return result; + } + + flatbuffers::Offset + MakeRoute(flatbuffers::FlatBufferBuilder &fb_result, + const std::vector &leg_endpoints, + const std::vector> &unpacked_path_segments, + const std::vector &source_traversed_in_reverse, + const std::vector &target_traversed_in_reverse) const + { + auto legs_info = MakeLegs(leg_endpoints, + unpacked_path_segments, + source_traversed_in_reverse, + target_traversed_in_reverse); + std::vector legs = legs_info.first; + std::vector leg_geometries = legs_info.second; + auto route = guidance::assembleRoute(legs); + + // Fill legs + std::vector> routeLegs; + routeLegs.reserve(legs.size()); + for (const auto idx : util::irange(0UL, legs.size())) + { + auto leg = legs[idx]; + auto &leg_geometry = leg_geometries[idx]; + + // Fill steps + std::vector> legSteps; + if (!leg.steps.empty()) + { + legSteps.resize(leg.steps.size()); + std::transform(leg.steps.begin(), + leg.steps.end(), + legSteps.begin(), + [this, &fb_result, &leg_geometry](auto &step) { + return this->MakeFBStep(fb_result, leg_geometry, step); + }); + } + auto steps_vector = fb_result.CreateVector(legSteps); + + // Fill annotations + // To maintain support for uses of the old default constructors, we check + // if annotations property was set manually after default construction + auto requested_annotations = parameters.annotations_type; + if (parameters.annotations && + (parameters.annotations_type == RouteParameters::AnnotationsType::None)) + { + requested_annotations = RouteParameters::AnnotationsType::All; + } + + flatbuffers::Offset annotation_buffer; + if (requested_annotations != RouteParameters::AnnotationsType::None) + { + annotation_buffer = + MakeFBAnnotations(fb_result, leg_geometry, requested_annotations); + } + + flatbuffers::Offset summary_string; + if (!leg.summary.empty()) + { + summary_string = fb_result.CreateString(leg.summary); + } + + fbresult::LegBuilder legBuilder(fb_result); + legBuilder.add_distance(leg.distance); + legBuilder.add_duration(leg.duration); + legBuilder.add_weight(leg.weight); + if (!leg.summary.empty()) + { + legBuilder.add_summary(summary_string); + } + legBuilder.add_steps(steps_vector); + + if (requested_annotations != RouteParameters::AnnotationsType::None) + { + legBuilder.add_annotations(annotation_buffer); + } + routeLegs.emplace_back(legBuilder.Finish()); + } + auto legs_vector = fb_result.CreateVector(routeLegs); + + // Fill geometry + auto overview = MakeOverview(leg_geometries); + mapbox::util::variant, + flatbuffers::Offset>> + geometry; + if (overview) + { + geometry = MakeGeometry(fb_result, overview->begin(), overview->end()); + } + + auto weight_name_string = fb_result.CreateString(facade.GetWeightName()); + + fbresult::RouteObjectBuilder routeObject(fb_result); + routeObject.add_distance(route.distance); + routeObject.add_duration(route.duration); + routeObject.add_weight(route.weight); + routeObject.add_weight_name(weight_name_string); + routeObject.add_legs(legs_vector); + if (overview) + { + mapbox::util::apply_visitor(GeometryVisitor(routeObject), + geometry); + } + + return routeObject.Finish(); + } + + flatbuffers::Offset + MakeFBAnnotations(flatbuffers::FlatBufferBuilder &fb_result, + guidance::LegGeometry &leg_geometry, + const RouteParameters::AnnotationsType &requested_annotations) const + { + // AnnotationsType uses bit flags, & operator checks if a property is set + flatbuffers::Offset> speed; + if (requested_annotations & RouteParameters::AnnotationsType::Speed) + { + double prev_speed = 0; + speed = + GetAnnotations(fb_result, + leg_geometry, + [&prev_speed](const guidance::LegGeometry::Annotation &anno) { + if (anno.duration < std::numeric_limits::min()) + { + return prev_speed; + } + else + { + auto speed = + round(anno.distance / anno.duration * 10.) / 10.; + prev_speed = speed; + return util::json::clamp_float(speed); + } + }); + } + + flatbuffers::Offset> duration; + if (requested_annotations & RouteParameters::AnnotationsType::Duration) + { + duration = GetAnnotations( + fb_result, leg_geometry, [](const guidance::LegGeometry::Annotation &anno) { + return anno.duration; + }); + } + + flatbuffers::Offset> distance; + if (requested_annotations & RouteParameters::AnnotationsType::Distance) + { + distance = GetAnnotations( + fb_result, leg_geometry, [](const guidance::LegGeometry::Annotation &anno) { + return anno.distance; + }); + } + + flatbuffers::Offset> weight; + if (requested_annotations & RouteParameters::AnnotationsType::Weight) + { + weight = GetAnnotations( + fb_result, leg_geometry, [](const guidance::LegGeometry::Annotation &anno) { + return anno.weight; + }); + } + + flatbuffers::Offset> datasources; + if (requested_annotations & RouteParameters::AnnotationsType::Datasources) + { + datasources = GetAnnotations( + fb_result, leg_geometry, [](const guidance::LegGeometry::Annotation &anno) { + return anno.datasource; + }); + } + std::vector nodes; + if (requested_annotations & RouteParameters::AnnotationsType::Nodes) + { + nodes.reserve(leg_geometry.node_ids.size()); + for (const auto node_id : leg_geometry.node_ids) + { + nodes.emplace_back(static_cast(facade.GetOSMNodeIDOfNode(node_id))); + } + } + auto nodes_vector = fb_result.CreateVector(nodes); + // Add any supporting metadata, if needed + bool use_metadata = requested_annotations & RouteParameters::AnnotationsType::Datasources; + flatbuffers::Offset metadata_buffer; + if (use_metadata) + { + const auto MAX_DATASOURCE_ID = 255u; + std::vector> names; + for (auto i = 0u; i < MAX_DATASOURCE_ID; i++) + { + const auto name = facade.GetDatasourceName(i); + // Length of 0 indicates the first empty name, so we can stop here + if (name.empty()) + break; + names.emplace_back( + fb_result.CreateString(std::string(facade.GetDatasourceName(i)))); + } + metadata_buffer = fbresult::CreateMetadataDirect(fb_result, &names); + } + fbresult::AnnotationBuilder annotation(fb_result); + annotation.add_speed(speed); + annotation.add_duration(duration); + annotation.add_distance(distance); + annotation.add_weight(weight); + annotation.add_datasources(datasources); + annotation.add_nodes(nodes_vector); + if (use_metadata) + { + annotation.add_metadata(metadata_buffer); + } + + return annotation.Finish(); + } + + template class GeometryVisitor + { + public: + GeometryVisitor(Builder &builder) : builder(builder) {} + + void operator()(const flatbuffers::Offset &value) + { + builder.add_polyline(value); + } + void operator()( + const flatbuffers::Offset> &value) + { + builder.add_coordinates(value); + } + + private: + Builder &builder; + }; + + flatbuffers::Offset MakeFBStep(flatbuffers::FlatBufferBuilder &builder, + const guidance::LegGeometry &leg_geometry, + const guidance::RouteStep &step) const + { + auto name_string = builder.CreateString(step.name); + + flatbuffers::Offset ref_string; + if (!step.ref.empty()) + { + ref_string = builder.CreateString(step.ref); + } + + flatbuffers::Offset pronunciation_string; + if (!step.pronunciation.empty()) + { + pronunciation_string = builder.CreateString(step.pronunciation); + } + + flatbuffers::Offset destinations_string; + if (!step.destinations.empty()) + { + destinations_string = builder.CreateString(step.destinations); + } + + flatbuffers::Offset exists_string; + if (!step.exits.empty()) + { + exists_string = builder.CreateString(step.exits); + } + + flatbuffers::Offset rotary_name_string; + flatbuffers::Offset rotary_pronunciation_string; + if (!step.rotary_name.empty()) + { + rotary_name_string = builder.CreateString(step.rotary_name); + if (!step.rotary_pronunciation.empty()) + { + rotary_pronunciation_string = builder.CreateString(step.rotary_pronunciation); + } + } + auto mode_string = builder.CreateString(extractor::travelModeToString(step.mode)); + + // Geometry + auto geometry = MakeGeometry(builder, + leg_geometry.locations.begin() + step.geometry_begin, + leg_geometry.locations.begin() + step.geometry_end); + // Maneuver + fbresult::StepManeuverBuilder maneuver(builder); + fbresult::Position maneuverPosition{ + static_cast(util::toFloating(step.maneuver.location.lon).__value), + static_cast(util::toFloating(step.maneuver.location.lat).__value)}; + maneuver.add_location(&maneuverPosition); + maneuver.add_bearing_before(step.maneuver.bearing_before); + maneuver.add_bearing_after(step.maneuver.bearing_after); + if (step.maneuver.waypoint_type == guidance::WaypointType::None) + maneuver.add_type(TurnTypeToFB(step.maneuver.instruction.type)); + else + maneuver.add_type(WaypointTypeToFB(step.maneuver.waypoint_type)); + if (osrm::engine::api::json::detail::isValidModifier(step.maneuver)) + { + maneuver.add_modifier(TurnModifierToFB(step.maneuver.instruction.direction_modifier)); + } + if (step.maneuver.exit != 0) + { + maneuver.add_exit(step.maneuver.exit); + } + auto maneuver_buffer = maneuver.Finish(); + + // intersections + auto intersections_vector = MakeFBIntersections(builder, step); + + fbresult::StepBuilder stepBuilder(builder); + stepBuilder.add_duration(step.duration); + stepBuilder.add_distance(step.distance); + stepBuilder.add_weight(step.weight); + stepBuilder.add_name(name_string); + stepBuilder.add_mode(mode_string); + stepBuilder.add_driving_side(step.is_left_hand_driving); + stepBuilder.add_ref(ref_string); + stepBuilder.add_pronunciation(pronunciation_string); + stepBuilder.add_destinations(destinations_string); + stepBuilder.add_exits(exists_string); + stepBuilder.add_rotary_name(rotary_name_string); + stepBuilder.add_rotary_pronunciation(rotary_pronunciation_string); + stepBuilder.add_intersections(intersections_vector); + stepBuilder.add_maneuver(maneuver_buffer); + mapbox::util::apply_visitor(GeometryVisitor(stepBuilder), geometry); + return stepBuilder.Finish(); + }; + + flatbuffers::Offset>> + MakeFBIntersections(flatbuffers::FlatBufferBuilder &fb_result, + const guidance::RouteStep &step) const + { + std::vector> intersections; + intersections.resize(step.intersections.size()); + std::transform( + step.intersections.begin(), + step.intersections.end(), + intersections.begin(), + [&fb_result, this](const guidance::IntermediateIntersection &intersection) { + std::vector> lanes; + if (json::detail::hasValidLanes(intersection)) + { + BOOST_ASSERT(intersection.lanes.lanes_in_turn >= 1); + lanes.reserve(intersection.lane_description.size()); + LaneID lane_id = intersection.lane_description.size(); + + for (const auto &lane_desc : intersection.lane_description) + { + --lane_id; + auto indications = TurnLaneTypeToFB(lane_desc); + + auto lane_valid = lane_id >= intersection.lanes.first_lane_from_the_right && + lane_id < intersection.lanes.first_lane_from_the_right + + intersection.lanes.lanes_in_turn; + lanes.push_back( + fbresult::CreateLaneDirect(fb_result, &indications, lane_valid)); + } + } + auto lanes_vector = fb_result.CreateVector(lanes); + + fbresult::Position maneuverPosition{ + static_cast(util::toFloating(intersection.location.lon).__value), + static_cast(util::toFloating(intersection.location.lat).__value)}; + auto bearings_vector = fb_result.CreateVector(intersection.bearings); + std::vector> classes; + classes.resize(intersection.classes.size()); + std::transform( + intersection.classes.begin(), + intersection.classes.end(), + classes.begin(), + [&fb_result](const std::string &cls) { return fb_result.CreateString(cls); }); + auto classes_vector = fb_result.CreateVector(classes); + auto entry_vector = fb_result.CreateVector(intersection.entry); + + fbresult::IntersectionBuilder intersectionBuilder(fb_result); + intersectionBuilder.add_location(&maneuverPosition); + intersectionBuilder.add_bearings(bearings_vector); + intersectionBuilder.add_classes(classes_vector); + intersectionBuilder.add_entry(entry_vector); + intersectionBuilder.add_in_bearing(intersection.in); + intersectionBuilder.add_out_bearing(intersection.out); + intersectionBuilder.add_lanes(lanes_vector); + return intersectionBuilder.Finish(); + }); + return fb_result.CreateVector(intersections); + } + + util::json::Object MakeRoute(const std::vector &leg_endpoints, const std::vector> &unpacked_path_segments, const std::vector &source_traversed_in_reverse, const std::vector &target_traversed_in_reverse) const { - std::vector legs; - std::vector leg_geometries; - auto number_of_legs = segment_end_coordinates.size(); - legs.reserve(number_of_legs); - leg_geometries.reserve(number_of_legs); - - for (auto idx : util::irange(0UL, number_of_legs)) - { - const auto &phantoms = segment_end_coordinates[idx]; - const auto &path_data = unpacked_path_segments[idx]; - - const bool reversed_source = source_traversed_in_reverse[idx]; - const bool reversed_target = target_traversed_in_reverse[idx]; - - auto leg_geometry = guidance::assembleGeometry(BaseAPI::facade, - path_data, - phantoms.source_phantom, - phantoms.target_phantom, - reversed_source, - reversed_target); - auto leg = guidance::assembleLeg(facade, - path_data, - leg_geometry, - phantoms.source_phantom, - phantoms.target_phantom, - reversed_target, - parameters.steps); - - if (parameters.steps) - { - auto steps = guidance::assembleSteps(BaseAPI::facade, - path_data, - leg_geometry, - phantoms.source_phantom, - phantoms.target_phantom, - reversed_source, - reversed_target); - - /* Perform step-based post-processing. - * - * Using post-processing on basis of route-steps for a single leg at a time - * comes at the cost that we cannot count the correct exit for roundabouts. - * We can only emit the exit nr/intersections up to/starting at a part of the leg. - * If a roundabout is not terminated in a leg, we will end up with a - *enter-roundabout - * and exit-roundabout-nr where the exit nr is out of sync with the previous enter. - * - * | S | - * * * - * ----* * ---- - * T - * ----* * ---- - * V * * - * | | - * | | - * - * Coming from S via V to T, we end up with the legs S->V and V->T. V-T will say to - *take - * the second exit, even though counting from S it would be the third. - * For S, we only emit `roundabout` without an exit number, showing that we enter a - *roundabout - * to find a via point. - * The same exit will be emitted, though, if we should start routing at S, making - * the overall response consistent. - * - * âš  CAUTION: order of post-processing steps is important - * - handleRoundabouts must be called before collapseTurnInstructions that - * expects post-processed roundabouts - */ - - guidance::trimShortSegments(steps, leg_geometry); - leg.steps = guidance::handleRoundabouts(std::move(steps)); - leg.steps = guidance::collapseTurnInstructions(std::move(leg.steps)); - leg.steps = guidance::anticipateLaneChange(std::move(leg.steps)); - leg.steps = guidance::buildIntersections(std::move(leg.steps)); - leg.steps = guidance::suppressShortNameSegments(std::move(leg.steps)); - leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), - leg_geometry, - phantoms.source_phantom, - phantoms.target_phantom); - leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps); - } - - leg_geometries.push_back(std::move(leg_geometry)); - legs.push_back(std::move(leg)); - } + auto legs_info = MakeLegs(leg_endpoints, + unpacked_path_segments, + source_traversed_in_reverse, + target_traversed_in_reverse); + std::vector legs = legs_info.first; + std::vector leg_geometries = legs_info.second; auto route = guidance::assembleRoute(legs); - boost::optional json_overview; - if (parameters.overview != RouteParameters::OverviewType::False) - { - const auto use_simplification = - parameters.overview == RouteParameters::OverviewType::Simplified; - BOOST_ASSERT(use_simplification || - parameters.overview == RouteParameters::OverviewType::Full); - - auto overview = guidance::assembleOverview(leg_geometries, use_simplification); - json_overview = MakeGeometry(overview.begin(), overview.end()); - } + boost::optional json_overview = + MakeGeometry(MakeOverview(leg_geometries)); std::vector step_geometries; + const auto total_step_count = + std::accumulate(legs.begin(), legs.end(), 0, [](const auto &v, const auto &leg) { + return v + leg.steps.size(); + }); + step_geometries.reserve(total_step_count); + for (const auto idx : util::irange(0UL, legs.size())) { auto &leg_geometry = leg_geometries[idx]; - step_geometries.reserve(step_geometries.size() + legs[idx].steps.size()); - std::transform( legs[idx].steps.begin(), legs[idx].steps.end(), @@ -239,7 +764,7 @@ class RouteAPI : public BaseAPI // To maintain support for uses of the old default constructors, we check // if annotations property was set manually after default construction auto requested_annotations = parameters.annotations_type; - if ((parameters.annotations == true) && + if (parameters.annotations && (parameters.annotations_type == RouteParameters::AnnotationsType::None)) { requested_annotations = RouteParameters::AnnotationsType::All; @@ -253,12 +778,21 @@ class RouteAPI : public BaseAPI util::json::Object annotation; // AnnotationsType uses bit flags, & operator checks if a property is set - if (parameters.annotations_type & RouteParameters::AnnotationsType::Speed) + if (requested_annotations & RouteParameters::AnnotationsType::Speed) { + double prev_speed = 0; annotation.values["speed"] = GetAnnotations( - leg_geometry, [](const guidance::LegGeometry::Annotation &anno) { - auto val = std::round(anno.distance / anno.duration * 10.) / 10.; - return util::json::clamp_float(val); + leg_geometry, [&prev_speed](const guidance::LegGeometry::Annotation &anno) { + if (anno.duration < std::numeric_limits::min()) + { + return prev_speed; + } + else + { + auto speed = std::round(anno.distance / anno.duration * 10.) / 10.; + prev_speed = speed; + return util::json::clamp_float(speed); + } }); } @@ -292,14 +826,31 @@ class RouteAPI : public BaseAPI if (requested_annotations & RouteParameters::AnnotationsType::Nodes) { util::json::Array nodes; - nodes.values.reserve(leg_geometry.osm_node_ids.size()); - std::for_each(leg_geometry.osm_node_ids.begin(), - leg_geometry.osm_node_ids.end(), - [this, &nodes](const OSMNodeID &node_id) { - nodes.values.push_back(static_cast(node_id)); - }); + nodes.values.reserve(leg_geometry.node_ids.size()); + for (const auto node_id : leg_geometry.node_ids) + { + nodes.values.push_back( + static_cast(facade.GetOSMNodeIDOfNode(node_id))); + } annotation.values["nodes"] = std::move(nodes); } + // Add any supporting metadata, if needed + if (requested_annotations & RouteParameters::AnnotationsType::Datasources) + { + const auto MAX_DATASOURCE_ID = 255u; + util::json::Object metadata; + util::json::Array datasource_names; + for (auto i = 0u; i < MAX_DATASOURCE_ID; i++) + { + const auto name = facade.GetDatasourceName(i); + // Length of 0 indicates the first empty name, so we can stop here + if (name.empty()) + break; + datasource_names.values.push_back(std::string(facade.GetDatasourceName(i))); + } + metadata.values["datasource_names"] = datasource_names; + annotation.values["metadata"] = metadata; + } annotations.push_back(std::move(annotation)); } @@ -316,10 +867,142 @@ class RouteAPI : public BaseAPI } const RouteParameters ¶meters; + + std::pair, std::vector> + MakeLegs(const std::vector &leg_endpoints, + const std::vector> &unpacked_path_segments, + const std::vector &source_traversed_in_reverse, + const std::vector &target_traversed_in_reverse) const + { + auto result = + std::make_pair(std::vector(), std::vector()); + auto &legs = result.first; + auto &leg_geometries = result.second; + auto number_of_legs = leg_endpoints.size(); + legs.reserve(number_of_legs); + leg_geometries.reserve(number_of_legs); + + for (auto idx : util::irange(0UL, number_of_legs)) + { + const auto &phantoms = leg_endpoints[idx]; + const auto &path_data = unpacked_path_segments[idx]; + + const bool reversed_source = source_traversed_in_reverse[idx]; + const bool reversed_target = target_traversed_in_reverse[idx]; + + auto leg = guidance::assembleLeg(facade, + path_data, + phantoms.source_phantom, + phantoms.target_phantom, + reversed_target); + + guidance::LegGeometry leg_geometry; + + // Generate additional geometry data if request includes turn-by-turn steps, + // overview geometry or route geometry annotations. + // Note that overview geometry and route geometry annotations can return different + // results depending on whether turn-by-turn steps are also requested. + if (parameters.steps || parameters.annotations || + parameters.overview != RouteParameters::OverviewType::False) + { + + leg_geometry = guidance::assembleGeometry(BaseAPI::facade, + path_data, + phantoms.source_phantom, + phantoms.target_phantom, + reversed_source, + reversed_target); + + util::Log(logDEBUG) << "Assembling steps " << std::endl; + if (parameters.steps) + { + leg.summary = guidance::assembleSummary( + facade, path_data, phantoms.target_phantom, reversed_target); + + auto steps = guidance::assembleSteps(BaseAPI::facade, + path_data, + leg_geometry, + phantoms.source_phantom, + phantoms.target_phantom, + reversed_source, + reversed_target); + + // Apply maneuver overrides before any other post + // processing is performed + guidance::applyOverrides(BaseAPI::facade, steps, leg_geometry); + + // Collapse segregated steps before others + steps = guidance::collapseSegregatedTurnInstructions(std::move(steps)); + + /* Perform step-based post-processing. + * + * Using post-processing on basis of route-steps for a single leg at a time + * comes at the cost that we cannot count the correct exit for roundabouts. + * We can only emit the exit nr/intersections up to/starting at a part of the + *leg. If a roundabout is not terminated in a leg, we will end up with a + *enter-roundabout + * and exit-roundabout-nr where the exit nr is out of sync with the previous + *enter. + * + * | S | + * * * + * ----* * ---- + * T + * ----* * ---- + * V * * + * | | + * | | + * + * Coming from S via V to T, we end up with the legs S->V and V->T. V-T will say + *to take the second exit, even though counting from S it would be the third. + * For S, we only emit `roundabout` without an exit number, showing that we + *enter a roundabout to find a via point. The same exit will be emitted, though, + *if we should start routing at S, making the overall response consistent. + * + * âš  CAUTION: order of post-processing steps is important + * - handleRoundabouts must be called before collapseTurnInstructions that + * expects post-processed roundabouts + */ + + guidance::trimShortSegments(steps, leg_geometry); + leg.steps = guidance::handleRoundabouts(std::move(steps)); + leg.steps = guidance::collapseTurnInstructions(std::move(leg.steps)); + leg.steps = guidance::anticipateLaneChange(std::move(leg.steps)); + leg.steps = guidance::buildIntersections(std::move(leg.steps)); + leg.steps = guidance::suppressShortNameSegments(std::move(leg.steps)); + leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), + leg_geometry, + phantoms.source_phantom, + phantoms.target_phantom); + leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps); + } + } + + leg_geometries.push_back(std::move(leg_geometry)); + legs.push_back(std::move(leg)); + } + return result; + } + + boost::optional> + MakeOverview(const std::vector &leg_geometries) const + { + boost::optional> overview; + if (parameters.overview != RouteParameters::OverviewType::False) + { + const auto use_simplification = + parameters.overview == RouteParameters::OverviewType::Simplified; + BOOST_ASSERT(use_simplification || + parameters.overview == RouteParameters::OverviewType::Full); + + overview = guidance::assembleOverview(leg_geometries, use_simplification); + } + return overview; + } }; -} // ns api -} // ns engine -} // ns osrm +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/route_parameters.hpp b/include/engine/api/route_parameters.hpp index 115a557af..8d5dd9ae4 100644 --- a/include/engine/api/route_parameters.hpp +++ b/include/engine/api/route_parameters.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -87,18 +87,13 @@ struct RouteParameters : public BaseParameters const GeometriesType geometries_, const OverviewType overview_, const boost::optional continue_straight_, - Args... args_) + Args &&... args_) // Once we perfectly-forward `args` (see #2990) this constructor can delegate to the one // below. - : BaseParameters{std::forward(args_)...}, - steps{steps_}, - alternatives{alternatives_}, - number_of_alternatives{alternatives_ ? 1u : 0u}, - annotations{false}, - annotations_type{AnnotationsType::None}, - geometries{geometries_}, - overview{overview_}, - continue_straight{continue_straight_} + : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, + number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{false}, + annotations_type{AnnotationsType::None}, geometries{geometries_}, overview{overview_}, + continue_straight{continue_straight_}, waypoints() { } @@ -110,11 +105,13 @@ struct RouteParameters : public BaseParameters const GeometriesType geometries_, const OverviewType overview_, const boost::optional continue_straight_, - Args... args_) + Args &&... args_) : BaseParameters{std::forward(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() + { } @@ -126,12 +123,48 @@ struct RouteParameters : public BaseParameters const GeometriesType geometries_, const OverviewType overview_, const boost::optional continue_straight_, - Args... args_) + Args &&... args_) : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, number_of_alternatives{alternatives_ ? 1u : 0u}, - annotations{annotations_ == AnnotationsType::None ? false : true}, + annotations{annotations_ != AnnotationsType::None}, annotations_type{annotations_}, + geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_}, + waypoints() + { + } + + // RouteParameters constructor adding the `waypoints` parameter + template + RouteParameters(const bool steps_, + const bool alternatives_, + const bool annotations_, + const GeometriesType geometries_, + const OverviewType overview_, + const boost::optional continue_straight_, + std::vector waypoints_, + const Args &&... args_) + : BaseParameters{std::forward(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{std::move(waypoints_)} + { + } + + // RouteParameters constructor adding the `waypoints` parameter + template + RouteParameters(const bool steps_, + const bool alternatives_, + const AnnotationsType annotations_, + const GeometriesType geometries_, + const OverviewType overview_, + const boost::optional continue_straight_, + std::vector waypoints_, + Args &&... args_) + : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, + number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_ != + AnnotationsType::None}, annotations_type{annotations_}, geometries{geometries_}, overview{overview_}, - continue_straight{continue_straight_} + continue_straight{continue_straight_}, waypoints{std::move(waypoints_)} { } @@ -144,12 +177,17 @@ struct RouteParameters : public BaseParameters GeometriesType geometries = GeometriesType::Polyline; OverviewType overview = OverviewType::Simplified; boost::optional continue_straight; + std::vector 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 +211,8 @@ inline RouteParameters::AnnotationsType operator|=(RouteParameters::AnnotationsT { return lhs = lhs | rhs; } -} -} -} +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/table_api.hpp b/include/engine/api/table_api.hpp index 2ff667404..cf6bac1db 100644 --- a/include/engine/api/table_api.hpp +++ b/include/engine/api/table_api.hpp @@ -2,6 +2,7 @@ #define ENGINE_API_TABLE_HPP #include "engine/api/base_api.hpp" +#include "engine/api/base_result.hpp" #include "engine/api/json_factory.hpp" #include "engine/api/table_parameters.hpp" @@ -31,14 +32,147 @@ namespace api class TableAPI final : public BaseAPI { public: + virtual ~TableAPI() = default; + + 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 &durations, - const std::vector &phantoms, - util::json::Object &response) const + virtual void + MakeResponse(const std::pair, std::vector> &tables, + const std::vector &candidates, + const std::vector &fallback_speed_cells, + osrm::engine::api::ResultT &response) const + { + if (response.is()) + { + auto &fb_result = response.get(); + MakeResponse(tables, candidates, fallback_speed_cells, fb_result); + } + else + { + auto &json_result = response.get(); + MakeResponse(tables, candidates, fallback_speed_cells, json_result); + } + } + + virtual void + MakeResponse(const std::pair, std::vector> &tables, + const std::vector &candidates, + const std::vector &fallback_speed_cells, + flatbuffers::FlatBufferBuilder &fb_result) const + { + auto number_of_sources = parameters.sources.size(); + auto number_of_destinations = parameters.destinations.size(); + + auto data_timestamp = facade.GetTimestamp(); + flatbuffers::Offset data_version_string; + if (!data_timestamp.empty()) + { + data_version_string = fb_result.CreateString(data_timestamp); + } + + // symmetric case + flatbuffers::Offset>> sources; + if (parameters.sources.empty()) + { + if (!parameters.skip_waypoints) + { + sources = MakeWaypoints(fb_result, candidates); + } + number_of_sources = candidates.size(); + } + else + { + if (!parameters.skip_waypoints) + { + sources = MakeWaypoints(fb_result, candidates, parameters.sources); + } + } + + flatbuffers::Offset>> + destinations; + if (parameters.destinations.empty()) + { + if (!parameters.skip_waypoints) + { + destinations = MakeWaypoints(fb_result, candidates); + } + number_of_destinations = candidates.size(); + } + else + { + if (!parameters.skip_waypoints) + { + destinations = MakeWaypoints(fb_result, candidates, parameters.destinations); + } + } + + bool use_durations = parameters.annotations & TableParameters::AnnotationsType::Duration; + flatbuffers::Offset> durations; + if (use_durations) + { + durations = MakeDurationTable(fb_result, tables.first); + } + + bool use_distances = parameters.annotations & TableParameters::AnnotationsType::Distance; + flatbuffers::Offset> distances; + if (use_distances) + { + distances = MakeDistanceTable(fb_result, tables.second); + } + + bool have_speed_cells = + parameters.fallback_speed != INVALID_FALLBACK_SPEED && parameters.fallback_speed > 0; + flatbuffers::Offset> speed_cells; + if (have_speed_cells) + { + speed_cells = MakeEstimatesTable(fb_result, fallback_speed_cells); + } + + fbresult::TableBuilder table(fb_result); + table.add_destinations(destinations); + table.add_rows(number_of_sources); + table.add_cols(number_of_destinations); + if (use_durations) + { + table.add_durations(durations); + } + if (use_distances) + { + table.add_distances(distances); + } + if (have_speed_cells) + { + table.add_fallback_speed_cells(speed_cells); + } + auto table_buffer = table.Finish(); + + fbresult::FBResultBuilder response(fb_result); + if (!data_timestamp.empty()) + { + response.add_data_version(data_version_string); + } + response.add_table(table_buffer); + response.add_waypoints(sources); + fb_result.Finish(response.Finish()); + } + + virtual void + MakeResponse(const std::pair, std::vector> &tables, + const std::vector &candidates, + const std::vector &fallback_speed_cells, + util::json::Object &response) const { auto number_of_sources = parameters.sources.size(); auto number_of_destinations = parameters.destinations.size(); @@ -46,60 +180,176 @@ class TableAPI final : public BaseAPI // symmetric case if (parameters.sources.empty()) { - response.values["sources"] = MakeWaypoints(phantoms); - number_of_sources = phantoms.size(); + if (!parameters.skip_waypoints) + { + response.values["sources"] = MakeWaypoints(candidates); + } + number_of_sources = candidates.size(); } else { - response.values["sources"] = MakeWaypoints(phantoms, parameters.sources); + if (!parameters.skip_waypoints) + { + response.values["sources"] = MakeWaypoints(candidates, parameters.sources); + } } if (parameters.destinations.empty()) { - response.values["destinations"] = MakeWaypoints(phantoms); - number_of_destinations = phantoms.size(); + if (!parameters.skip_waypoints) + { + response.values["destinations"] = MakeWaypoints(candidates); + } + number_of_destinations = candidates.size(); } else { - response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations); + if (!parameters.skip_waypoints) + { + response.values["destinations"] = + MakeWaypoints(candidates, parameters.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["durations"] = - MakeTable(durations, number_of_sources, number_of_destinations); response.values["code"] = "Ok"; + auto data_timestamp = facade.GetTimestamp(); + if (!data_timestamp.empty()) + { + response.values["data_version"] = data_timestamp; + } } protected: - virtual util::json::Array MakeWaypoints(const std::vector &phantoms) const + virtual flatbuffers::Offset>> + MakeWaypoints(flatbuffers::FlatBufferBuilder &builder, + const std::vector &candidates) const + { + std::vector> waypoints; + waypoints.reserve(candidates.size()); + BOOST_ASSERT(candidates.size() == parameters.coordinates.size()); + + boost::range::transform(candidates, + std::back_inserter(waypoints), + [this, &builder](const PhantomNodeCandidates &candidates) { + return BaseAPI::MakeWaypoint(&builder, candidates)->Finish(); + }); + return builder.CreateVector(waypoints); + } + + virtual flatbuffers::Offset>> + MakeWaypoints(flatbuffers::FlatBufferBuilder &builder, + const std::vector &candidates, + const std::vector &indices) const + { + std::vector> waypoints; + waypoints.reserve(indices.size()); + boost::range::transform( + indices, + std::back_inserter(waypoints), + [this, &builder, &candidates](const std::size_t idx) { + BOOST_ASSERT(idx < candidates.size()); + return BaseAPI::MakeWaypoint(&builder, candidates[idx])->Finish(); + }); + return builder.CreateVector(waypoints); + } + + virtual flatbuffers::Offset> + MakeDurationTable(flatbuffers::FlatBufferBuilder &builder, + const std::vector &values) const + { + std::vector distance_table; + distance_table.resize(values.size()); + std::transform( + values.begin(), values.end(), distance_table.begin(), [](const EdgeWeight duration) { + if (duration == MAXIMAL_EDGE_DURATION) + { + return 0.; + } + return duration / 10.; + }); + return builder.CreateVector(distance_table); + } + + virtual flatbuffers::Offset> + MakeDistanceTable(flatbuffers::FlatBufferBuilder &builder, + const std::vector &values) const + { + std::vector duration_table; + duration_table.resize(values.size()); + std::transform( + values.begin(), values.end(), duration_table.begin(), [](const EdgeDistance distance) { + if (distance == INVALID_EDGE_DISTANCE) + { + return 0.; + } + return std::round(distance * 10) / 10.; + }); + return builder.CreateVector(duration_table); + } + + virtual flatbuffers::Offset> + MakeEstimatesTable(flatbuffers::FlatBufferBuilder &builder, + const std::vector &fallback_speed_cells) const + { + std::vector fb_table; + fb_table.reserve(fallback_speed_cells.size()); + std::for_each( + fallback_speed_cells.begin(), fallback_speed_cells.end(), [&](const auto &cell) { + fb_table.push_back(cell.row); + fb_table.push_back(cell.column); + }); + return builder.CreateVector(fb_table); + } + + virtual util::json::Array + MakeWaypoints(const std::vector &candidates) const { util::json::Array json_waypoints; - json_waypoints.values.reserve(phantoms.size()); - BOOST_ASSERT(phantoms.size() == parameters.coordinates.size()); + json_waypoints.values.reserve(candidates.size()); + BOOST_ASSERT(candidates.size() == parameters.coordinates.size()); - boost::range::transform( - phantoms, - std::back_inserter(json_waypoints.values), - [this](const PhantomNode &phantom) { return BaseAPI::MakeWaypoint(phantom); }); + boost::range::transform(candidates, + std::back_inserter(json_waypoints.values), + [this](const PhantomNodeCandidates &candidates) { + return BaseAPI::MakeWaypoint(candidates); + }); return json_waypoints; } - virtual util::json::Array MakeWaypoints(const std::vector &phantoms, + virtual util::json::Array MakeWaypoints(const std::vector &candidates, const std::vector &indices) const { util::json::Array json_waypoints; json_waypoints.values.reserve(indices.size()); boost::range::transform(indices, std::back_inserter(json_waypoints.values), - [this, phantoms](const std::size_t idx) { - BOOST_ASSERT(idx < phantoms.size()); - return BaseAPI::MakeWaypoint(phantoms[idx]); + [this, &candidates](const std::size_t idx) { + BOOST_ASSERT(idx < candidates.size()); + return BaseAPI::MakeWaypoint(candidates[idx]); }); return json_waypoints; } - virtual util::json::Array MakeTable(const std::vector &values, - std::size_t number_of_rows, - std::size_t number_of_columns) const + virtual util::json::Array MakeDurationTable(const std::vector &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(0UL, number_of_rows)) @@ -116,6 +366,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,11 +374,53 @@ class TableAPI final : public BaseAPI return json_table; } + virtual util::json::Array MakeDistanceTable(const std::vector &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(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 &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; }; -} // ns api -} // ns engine -} // ns osrm +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/table_parameters.hpp b/include/engine/api/table_parameters.hpp index 78f17b1e1..30e17900b 100644 --- a/include/engine/api/table_parameters.hpp +++ b/include/engine/api/table_parameters.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -59,36 +59,76 @@ struct TableParameters : public BaseParameters { std::vector sources; std::vector 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 TableParameters(std::vector sources_, std::vector destinations_, - Args... args_) + Args &&... args_) : BaseParameters{std::forward(args_)...}, sources{std::move(sources_)}, destinations{std::move(destinations_)} { } + template + TableParameters(std::vector sources_, + std::vector destinations_, + const AnnotationsType annotations_, + Args &&... args_) + : BaseParameters{std::forward(args_)...}, sources{std::move(sources_)}, + destinations{std::move(destinations_)}, annotations{annotations_} + { + } + + template + TableParameters(std::vector sources_, + std::vector destinations_, + const AnnotationsType annotations_, + double fallback_speed_, + FallbackCoordinateType fallback_coordinate_type_, + double scale_factor_, + Args &&... args_) + : BaseParameters{std::forward(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()) return false; - // Distance Table makes only sense with 2+ coodinates + // Distance Table makes only sense with 2+ coordinates 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,11 +137,37 @@ 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( + static_cast>(lhs) & + static_cast>(rhs)); } +inline TableParameters::AnnotationsType operator|(TableParameters::AnnotationsType lhs, + TableParameters::AnnotationsType rhs) +{ + return (TableParameters::AnnotationsType)( + static_cast>(lhs) | + static_cast>(rhs)); +} + +inline TableParameters::AnnotationsType &operator|=(TableParameters::AnnotationsType &lhs, + TableParameters::AnnotationsType rhs) +{ + return lhs = lhs | rhs; +} +} // namespace api +} // namespace engine +} // namespace osrm + #endif // ENGINE_API_TABLE_PARAMETERS_HPP diff --git a/include/engine/api/tile_parameters.hpp b/include/engine/api/tile_parameters.hpp index b62e1036f..e5328e7c7 100644 --- a/include/engine/api/tile_parameters.hpp +++ b/include/engine/api/tile_parameters.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -70,8 +70,8 @@ struct TileParameters final return valid_x && valid_y && valid_z; } }; -} -} -} +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/trip_api.hpp b/include/engine/api/trip_api.hpp index b65ac1970..fb8e5598b 100644 --- a/include/engine/api/trip_api.hpp +++ b/include/engine/api/trip_api.hpp @@ -24,56 +24,147 @@ class TripAPI final : public RouteAPI : RouteAPI(facade_, parameters_), parameters(parameters_) { } - void MakeResponse(const std::vector> &sub_trips, const std::vector &sub_routes, - const std::vector &phantoms, + const std::vector &candidates, + osrm::engine::api::ResultT &response) const + { + BOOST_ASSERT(sub_trips.size() == sub_routes.size()); + + if (response.is()) + { + auto &fb_result = response.get(); + MakeResponse(sub_trips, sub_routes, candidates, fb_result); + } + else + { + auto &json_result = response.get(); + MakeResponse(sub_trips, sub_routes, candidates, json_result); + } + } + void MakeResponse(const std::vector> &sub_trips, + const std::vector &sub_routes, + const std::vector &candidates, + flatbuffers::FlatBufferBuilder &fb_result) const + { + auto data_timestamp = facade.GetTimestamp(); + flatbuffers::Offset data_version_string; + if (!data_timestamp.empty()) + { + data_version_string = fb_result.CreateString(data_timestamp); + } + + auto response = + MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &candidates]() { + return MakeWaypoints(fb_result, sub_trips, candidates); + }); + + if (!data_timestamp.empty()) + { + response->add_data_version(data_version_string); + } + fb_result.Finish(response->Finish()); + } + void MakeResponse(const std::vector> &sub_trips, + const std::vector &sub_routes, + const std::vector &candidates, util::json::Object &response) const { auto number_of_routes = sub_trips.size(); util::json::Array routes; routes.values.reserve(number_of_routes); - BOOST_ASSERT(sub_trips.size() == sub_routes.size()); for (auto index : util::irange(0UL, sub_trips.size())) { - auto route = MakeRoute(sub_routes[index].segment_end_coordinates, + auto route = MakeRoute(sub_routes[index].leg_endpoints, sub_routes[index].unpacked_path_segments, sub_routes[index].source_traversed_in_reverse, sub_routes[index].target_traversed_in_reverse); routes.values.push_back(std::move(route)); } - response.values["waypoints"] = MakeWaypoints(sub_trips, phantoms); + if (!parameters.skip_waypoints) + { + response.values["waypoints"] = MakeWaypoints(sub_trips, candidates); + } response.values["trips"] = std::move(routes); response.values["code"] = "Ok"; + auto data_timestamp = facade.GetTimestamp(); + if (!data_timestamp.empty()) + { + response.values["data_version"] = data_timestamp; + } } protected: // FIXME this logic is a little backwards. We should change the output format of the // trip plugin routing algorithm to be easier to consume here. + + struct TripIndex + { + TripIndex() = default; + + TripIndex(unsigned sub_trip_index_, unsigned point_index_) + : sub_trip_index(sub_trip_index_), point_index(point_index_) + { + } + + unsigned sub_trip_index = std::numeric_limits::max(); + unsigned point_index = std::numeric_limits::max(); + + bool NotUsed() + { + return sub_trip_index == std::numeric_limits::max() && + point_index == std::numeric_limits::max(); + } + }; + + flatbuffers::Offset>> + MakeWaypoints(flatbuffers::FlatBufferBuilder &fb_result, + const std::vector> &sub_trips, + const std::vector &candidates) const + { + std::vector> waypoints; + waypoints.reserve(parameters.coordinates.size()); + + auto input_idx_to_trip_idx = MakeTripIndices(sub_trips); + + for (auto input_index : util::irange(0UL, parameters.coordinates.size())) + { + auto trip_index = input_idx_to_trip_idx[input_index]; + BOOST_ASSERT(!trip_index.NotUsed()); + + auto waypoint = BaseAPI::MakeWaypoint(&fb_result, candidates[input_index]); + waypoint->add_waypoint_index(trip_index.point_index); + waypoint->add_trips_index(trip_index.sub_trip_index); + waypoints.push_back(waypoint->Finish()); + } + + return fb_result.CreateVector(waypoints); + } + util::json::Array MakeWaypoints(const std::vector> &sub_trips, - const std::vector &phantoms) const + const std::vector &candidates) const { util::json::Array waypoints; waypoints.values.reserve(parameters.coordinates.size()); - struct TripIndex + auto input_idx_to_trip_idx = MakeTripIndices(sub_trips); + + for (auto input_index : util::irange(0UL, parameters.coordinates.size())) { - TripIndex() = default; - TripIndex(unsigned sub_trip_index_, unsigned point_index_) - : sub_trip_index(sub_trip_index_), point_index(point_index_) - { - } + auto trip_index = input_idx_to_trip_idx[input_index]; + BOOST_ASSERT(!trip_index.NotUsed()); - unsigned sub_trip_index = std::numeric_limits::max(); - unsigned point_index = std::numeric_limits::max(); + auto waypoint = BaseAPI::MakeWaypoint(candidates[input_index]); + waypoint.values["trips_index"] = trip_index.sub_trip_index; + waypoint.values["waypoint_index"] = trip_index.point_index; + waypoints.values.push_back(std::move(waypoint)); + } - bool NotUsed() - { - return sub_trip_index == std::numeric_limits::max() && - point_index == std::numeric_limits::max(); - } - }; + return waypoints; + } + std::vector MakeTripIndices(const std::vector> &sub_trips) const + { std::vector input_idx_to_trip_idx(parameters.coordinates.size()); for (auto sub_trip_index : util::irange(0u, sub_trips.size())) { @@ -83,26 +174,14 @@ class TripAPI final : public RouteAPI TripIndex{sub_trip_index, point_index}; } } - - for (auto input_index : util::irange(0UL, parameters.coordinates.size())) - { - auto trip_index = input_idx_to_trip_idx[input_index]; - BOOST_ASSERT(!trip_index.NotUsed()); - - auto waypoint = BaseAPI::MakeWaypoint(phantoms[input_index]); - waypoint.values["trips_index"] = trip_index.sub_trip_index; - waypoint.values["waypoint_index"] = trip_index.point_index; - waypoints.values.push_back(std::move(waypoint)); - } - - return waypoints; + return input_idx_to_trip_idx; } const TripParameters ¶meters; }; -} // ns api -} // ns engine -} // ns osrm +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/api/trip_parameters.hpp b/include/engine/api/trip_parameters.hpp index 0164dbb02..84d6b861a 100644 --- a/include/engine/api/trip_parameters.hpp +++ b/include/engine/api/trip_parameters.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -65,8 +65,8 @@ struct TripParameters : public RouteParameters DestinationType destination_, bool roundtrip_, Args &&... args_) - : RouteParameters{std::forward(args_)...}, source{source_}, destination{destination_}, - roundtrip{roundtrip_} + : RouteParameters{std::forward(args_)...}, source{source_}, + destination{destination_}, roundtrip{roundtrip_} { } @@ -76,8 +76,8 @@ struct TripParameters : public RouteParameters bool IsValid() const { return RouteParameters::IsValid(); } }; -} -} -} +} // namespace api +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/approach.hpp b/include/engine/approach.hpp index 55ed5a50c..f7d671a9c 100644 --- a/include/engine/approach.hpp +++ b/include/engine/approach.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -42,5 +42,5 @@ enum class Approach : std::uint8_t }; } -} +} // namespace osrm #endif diff --git a/include/engine/base64.hpp b/include/engine/base64.hpp index 2cb7d3b50..d1fa8753c 100644 --- a/include/engine/base64.hpp +++ b/include/engine/base64.hpp @@ -38,7 +38,7 @@ using BinaryFromBase64 = boost::archive::iterators::transform_width< 8, // get a view of 8 bit 6 // from a sequence of 6 bit >; -} // ns detail +} // namespace detail namespace engine { @@ -87,7 +87,7 @@ inline std::string encodeBase64(const std::string &x) { return encodeBase64(x.da // Encode any sufficiently trivial object to Base64. template std::string encodeBase64Bytewise(const T &x) { -#if not defined __GNUC__ or __GNUC__ > 4 +#if !defined(__GNUC__) || (__GNUC__ > 4) static_assert(std::is_trivially_copyable::value, "requires a trivially copyable type"); #endif @@ -124,7 +124,7 @@ inline std::string decodeBase64(const std::string &encoded) // Decodes from Base 64 to any sufficiently trivial object. template T decodeBase64Bytewise(const std::string &encoded) { -#if not defined __GNUC__ or __GNUC__ > 4 +#if !defined(__GNUC__) || (__GNUC__ > 4) static_assert(std::is_trivially_copyable::value, "requires a trivially copyable type"); #endif @@ -135,7 +135,7 @@ template T decodeBase64Bytewise(const std::string &encoded) return x; } -} // ns engine -} // ns osrm +} // namespace engine +} // namespace osrm #endif /* OSRM_BASE64_HPP */ diff --git a/include/engine/bearing.hpp b/include/engine/bearing.hpp index 3b999622b..54e24f57f 100644 --- a/include/engine/bearing.hpp +++ b/include/engine/bearing.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2016, Project OSRM contributors +Copyright (c) 2017, Project OSRM contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -46,7 +46,7 @@ inline bool operator==(const Bearing lhs, const Bearing rhs) return lhs.bearing == rhs.bearing && lhs.range == rhs.range; } inline bool operator!=(const Bearing lhs, const Bearing rhs) { return !(lhs == rhs); } -} -} +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/data_watchdog.hpp b/include/engine/data_watchdog.hpp index 91349eb2a..29fb93443 100644 --- a/include/engine/data_watchdog.hpp +++ b/include/engine/data_watchdog.hpp @@ -32,20 +32,38 @@ template class DataWatchdogImpl; template class DataWatchdogImpl> final { - using mutex_type = typename storage::SharedMonitor::mutex_type; + using mutex_type = typename storage::SharedMonitor::mutex_type; using Facade = datafacade::ContiguousInternalMemoryDataFacade; public: - DataWatchdogImpl() : active(true), timestamp(0) + DataWatchdogImpl(const std::string &dataset_name) : dataset_name(dataset_name), active(true) { // create the initial facade before launching the watchdog thread { boost::interprocess::scoped_lock current_region_lock(barrier.get_mutex()); - facade_factory = - DataFacadeFactory( - std::make_shared(barrier.data().region)); - timestamp = barrier.data().timestamp; + auto &shared_register = barrier.data(); + auto static_region_id = shared_register.Find(dataset_name + "/static"); + auto updatable_region_id = shared_register.Find(dataset_name + "/updatable"); + if (static_region_id == storage::SharedRegionRegister::INVALID_REGION_ID || + updatable_region_id == storage::SharedRegionRegister::INVALID_REGION_ID) + { + throw util::exception("Could not find shared memory region for \"" + dataset_name + + "/data\". Did you run osrm-datastore?"); + } + static_shared_region = &shared_register.GetRegion(static_region_id); + updatable_shared_region = &shared_register.GetRegion(updatable_region_id); + static_region = *static_shared_region; + updatable_region = *updatable_shared_region; + + { + boost::unique_lock swap_lock(factory_mutex); + facade_factory = + DataFacadeFactory( + std::make_shared( + std::vector{ + static_region.shm_key, updatable_region.shm_key})); + } } watcher = std::thread(&DataWatchdogImpl::Run, this); @@ -60,10 +78,14 @@ class DataWatchdogImpl Get(const api::BaseParameters ¶ms) const { + // make sure facade_factory stays stable while we call Get() + boost::shared_lock swap_lock(factory_mutex); return facade_factory.Get(params); } std::shared_ptr Get(const api::TileParameters ¶ms) const { + // make sure facade_factory stays stable while we call Get() + boost::shared_lock swap_lock(factory_mutex); return facade_factory.Get(params); } @@ -74,40 +96,60 @@ class DataWatchdogImpl current_region_lock(barrier.get_mutex()); - while (active && timestamp == barrier.data().timestamp) + while (active && static_region.timestamp == static_shared_region->timestamp && + updatable_region.timestamp == updatable_shared_region->timestamp) { barrier.wait(current_region_lock); } - if (timestamp != barrier.data().timestamp) + if (!active) + break; + + if (static_region.timestamp != static_shared_region->timestamp) { - auto region = barrier.data().region; + static_region = *static_shared_region; + } + if (updatable_region.timestamp != updatable_shared_region->timestamp) + { + updatable_region = *updatable_shared_region; + } + + util::Log() << "updated facade to regions " << (int)static_region.shm_key << " and " + << (int)updatable_region.shm_key << " with timestamps " + << static_region.timestamp << " and " << updatable_region.timestamp; + + { + boost::unique_lock swap_lock(factory_mutex); facade_factory = DataFacadeFactory( - std::make_shared(region)); - timestamp = barrier.data().timestamp; - util::Log() << "updated facade to region " << region << " with timestamp " - << timestamp; + std::make_shared( + std::vector{ + static_region.shm_key, updatable_region.shm_key})); } } util::Log() << "DataWatchdog thread stopped"; } - storage::SharedMonitor barrier; + mutable boost::shared_mutex factory_mutex; + const std::string dataset_name; + storage::SharedMonitor barrier; std::thread watcher; bool active; - unsigned timestamp; + storage::SharedRegion static_region; + storage::SharedRegion updatable_region; + storage::SharedRegion *static_shared_region; + storage::SharedRegion *updatable_shared_region; DataFacadeFactory facade_factory; }; -} +} // namespace detail // This class monitors the shared memory region that contains the pointers to // the data and layout regions that should be used. This region is updated // once a new dataset arrives. template class FacadeT> using DataWatchdog = detail::DataWatchdogImpl>; -} -} +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/datafacade.hpp b/include/engine/datafacade.hpp index 76068a472..f0f8e9e5b 100644 --- a/include/engine/datafacade.hpp +++ b/include/engine/datafacade.hpp @@ -11,7 +11,7 @@ namespace engine using DataFacadeBase = datafacade::ContiguousInternalMemoryDataFacadeBase; template using DataFacade = datafacade::ContiguousInternalMemoryDataFacade; -} -} +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/datafacade/algorithm_datafacade.hpp b/include/engine/datafacade/algorithm_datafacade.hpp index 6036bb331..c9337f079 100644 --- a/include/engine/datafacade/algorithm_datafacade.hpp +++ b/include/engine/datafacade/algorithm_datafacade.hpp @@ -2,11 +2,12 @@ #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" -#include "partition/cell_storage.hpp" -#include "partition/multi_level_partition.hpp" +#include "partitioner/cell_storage.hpp" +#include "partitioner/multi_level_partition.hpp" #include "util/filtered_graph.hpp" #include "util/integer_range.hpp" @@ -20,7 +21,6 @@ namespace datafacade // Namespace local aliases for algorithms using CH = routing_algorithms::ch::Algorithm; -using CoreCH = routing_algorithms::corech::Algorithm; using MLD = routing_algorithms::mld::Algorithm; template class AlgorithmDataFacade; @@ -31,72 +31,86 @@ template <> class AlgorithmDataFacade using EdgeData = contractor::QueryEdge::EdgeData; using EdgeRange = util::filtered_range>; + virtual ~AlgorithmDataFacade() = default; + // search graph access virtual unsigned GetNumberOfNodes() const = 0; virtual unsigned GetNumberOfEdges() const = 0; - virtual unsigned GetOutDegree(const NodeID n) const = 0; + virtual unsigned GetOutDegree(const NodeID edge_based_node_id) const = 0; - virtual NodeID GetTarget(const EdgeID e) const = 0; + virtual NodeID GetTarget(const EdgeID edge_based_edge_id) const = 0; - virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0; + virtual const EdgeData &GetEdgeData(const EdgeID edge_based_edge_id) const = 0; - virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0; + virtual EdgeRange GetAdjacentEdgeRange(const NodeID edge_based_node_id) const = 0; // searches for a specific edge - virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0; + virtual EdgeID FindEdge(const NodeID edge_based_node_from, + const NodeID edge_based_node_to) const = 0; - virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0; + virtual EdgeID FindEdgeInEitherDirection(const NodeID edge_based_node_from, + const NodeID edge_based_node_to) const = 0; - virtual EdgeID - FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0; + virtual EdgeID FindEdgeIndicateIfReverse(const NodeID edge_based_node_from, + const NodeID edge_based_node_to, + bool &result) const = 0; - virtual EdgeID FindSmallestEdge(const NodeID from, - const NodeID to, + virtual EdgeID FindSmallestEdge(const NodeID edge_based_node_from, + const NodeID edge_based_node_to, const std::function filter) const = 0; }; -template <> class AlgorithmDataFacade -{ - public: - using EdgeData = contractor::QueryEdge::EdgeData; - - virtual bool IsCoreNode(const NodeID id) const = 0; -}; - template <> class AlgorithmDataFacade { public: - using EdgeData = extractor::EdgeBasedEdge::EdgeData; + using EdgeData = customizer::EdgeBasedGraphEdgeData; using EdgeRange = util::range; + virtual ~AlgorithmDataFacade() = default; + // search graph access virtual unsigned GetNumberOfNodes() const = 0; + virtual unsigned GetMaxBorderNodeID() const = 0; + virtual unsigned GetNumberOfEdges() const = 0; - virtual unsigned GetOutDegree(const NodeID n) const = 0; + virtual unsigned GetOutDegree(const NodeID edge_based_node_id) const = 0; - virtual NodeID GetTarget(const EdgeID e) const = 0; + virtual EdgeRange GetAdjacentEdgeRange(const NodeID edge_based_node_id) const = 0; - virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0; + virtual EdgeWeight GetNodeWeight(const NodeID edge_based_node_id) const = 0; - virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0; + virtual EdgeWeight + GetNodeDuration(const NodeID edge_based_node_id) const = 0; // TODO: to be removed - virtual const partition::MultiLevelPartitionView &GetMultiLevelPartition() const = 0; + virtual EdgeDistance GetNodeDistance(const NodeID edge_based_node_id) const = 0; - virtual const partition::CellStorageView &GetCellStorage() const = 0; + virtual bool IsForwardEdge(EdgeID edge_based_edge_id) const = 0; + + virtual bool IsBackwardEdge(EdgeID edge_based_edge_id) const = 0; + + virtual NodeID GetTarget(const EdgeID edge_based_edge_id) const = 0; + + virtual const EdgeData &GetEdgeData(const EdgeID edge_based_edge_id) const = 0; + + virtual const partitioner::MultiLevelPartitionView &GetMultiLevelPartition() const = 0; + + virtual const partitioner::CellStorageView &GetCellStorage() const = 0; virtual const customizer::CellMetricView &GetCellMetric() const = 0; - virtual EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const = 0; + virtual EdgeRange GetBorderEdgeRange(const LevelID level, + const NodeID edge_based_node_id) const = 0; // searches for a specific edge - virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0; + virtual EdgeID FindEdge(const NodeID edge_based_node_from, + const NodeID edge_based_node_to) const = 0; }; -} -} -} +} // namespace datafacade +} // namespace engine +} // namespace osrm #endif diff --git a/include/engine/datafacade/contiguous_block_allocator.hpp b/include/engine/datafacade/contiguous_block_allocator.hpp index 0a1852025..0af5b310b 100644 --- a/include/engine/datafacade/contiguous_block_allocator.hpp +++ b/include/engine/datafacade/contiguous_block_allocator.hpp @@ -1,7 +1,7 @@ #ifndef OSRM_ENGINE_DATAFACADE_CONTIGUOUS_BLOCK_ALLOCATOR_HPP_ #define OSRM_ENGINE_DATAFACADE_CONTIGUOUS_BLOCK_ALLOCATOR_HPP_ -#include "storage/shared_datatype.hpp" +#include "storage/shared_data_index.hpp" namespace osrm { @@ -16,8 +16,7 @@ class ContiguousBlockAllocator virtual ~ContiguousBlockAllocator() = default; // interface to give access to the datafacades - virtual storage::DataLayout &GetLayout() = 0; - virtual char *GetMemory() = 0; + virtual const storage::SharedDataIndex &GetIndex() = 0; }; } // namespace datafacade diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 5824d7fa7..0548e0569 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -9,41 +9,13 @@ #include "engine/approach.hpp" #include "engine/geospatial_query.hpp" -#include "customizer/edge_based_graph.hpp" - -#include "extractor/datasources.hpp" -#include "extractor/guidance/turn_instruction.hpp" -#include "extractor/guidance/turn_lane_types.hpp" -#include "extractor/intersection_bearings_container.hpp" -#include "extractor/node_data_container.hpp" -#include "extractor/packed_osm_ids.hpp" -#include "extractor/profile_properties.hpp" -#include "extractor/segment_data_container.hpp" -#include "extractor/turn_data_container.hpp" - -#include "contractor/query_graph.hpp" - -#include "partition/cell_storage.hpp" -#include "partition/multi_level_partition.hpp" - #include "storage/shared_datatype.hpp" #include "storage/shared_memory_ownership.hpp" +#include "storage/view_factory.hpp" #include "util/exception.hpp" #include "util/exception_utils.hpp" -#include "util/filtered_graph.hpp" -#include "util/guidance/bearing_class.hpp" -#include "util/guidance/entry_class.hpp" -#include "util/guidance/turn_bearing.hpp" -#include "util/guidance/turn_lanes.hpp" #include "util/log.hpp" -#include "util/name_table.hpp" -#include "util/packed_vector.hpp" -#include "util/range_table.hpp" -#include "util/rectangle.hpp" -#include "util/static_graph.hpp" -#include "util/static_rtree.hpp" -#include "util/typedefs.hpp" #include @@ -78,44 +50,22 @@ class ContiguousInternalMemoryAlgorithmDataFacade : public datafacade::Algor // allocator that keeps the allocation data std::shared_ptr allocator; - void InitializeGraphPointer(storage::DataLayout &data_layout, - char *memory_block, - const std::size_t exclude_index) - { - auto graph_nodes_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::CH_GRAPH_NODE_LIST); - - auto graph_edges_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::CH_GRAPH_EDGE_LIST); - - auto filter_block_id = static_cast( - storage::DataLayout::CH_EDGE_FILTER_0 + exclude_index); - - auto edge_filter_ptr = data_layout.GetBlockPtr(memory_block, filter_block_id); - - util::vector_view node_list( - graph_nodes_ptr, data_layout.num_entries[storage::DataLayout::CH_GRAPH_NODE_LIST]); - util::vector_view edge_list( - graph_edges_ptr, data_layout.num_entries[storage::DataLayout::CH_GRAPH_EDGE_LIST]); - - util::vector_view edge_filter(edge_filter_ptr, - data_layout.num_entries[filter_block_id]); - m_query_graph = QueryGraph({node_list, edge_list}, edge_filter); - } - public: ContiguousInternalMemoryAlgorithmDataFacade( - std::shared_ptr allocator_, std::size_t exclude_index) + std::shared_ptr allocator_, + const std::string &metric_name, + std::size_t exclude_index) : allocator(std::move(allocator_)) { - InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory(), exclude_index); + InitializeInternalPointers(allocator->GetIndex(), metric_name, exclude_index); } - void InitializeInternalPointers(storage::DataLayout &data_layout, - char *memory_block, + void InitializeInternalPointers(const storage::SharedDataIndex &index, + const std::string &metric_name, const std::size_t exclude_index) { - InitializeGraphPointer(data_layout, memory_block, exclude_index); + m_query_graph = + make_filtered_graph_view(index, "/ch/metrics/" + metric_name, exclude_index); } // search graph access @@ -123,89 +73,52 @@ class ContiguousInternalMemoryAlgorithmDataFacade : public datafacade::Algor unsigned GetNumberOfEdges() const override final { return m_query_graph.GetNumberOfEdges(); } - unsigned GetOutDegree(const NodeID n) const override final + unsigned GetOutDegree(const NodeID edge_based_node_id) const override final { - return m_query_graph.GetOutDegree(n); + return m_query_graph.GetOutDegree(edge_based_node_id); } - NodeID GetTarget(const EdgeID e) const override final { return m_query_graph.GetTarget(e); } - - const EdgeData &GetEdgeData(const EdgeID e) const override final + NodeID GetTarget(const EdgeID edge_based_edge_id) const override final { - return m_query_graph.GetEdgeData(e); + return m_query_graph.GetTarget(edge_based_edge_id); } - EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final + const EdgeData &GetEdgeData(const EdgeID edge_based_edge_id) const override final { - return m_query_graph.GetAdjacentEdgeRange(node); + return m_query_graph.GetEdgeData(edge_based_edge_id); + } + + EdgeRange GetAdjacentEdgeRange(const NodeID edge_based_node_id) const override final + { + return m_query_graph.GetAdjacentEdgeRange(edge_based_node_id); } // searches for a specific edge - EdgeID FindEdge(const NodeID from, const NodeID to) const override final + EdgeID FindEdge(const NodeID edge_based_node_from, + const NodeID edge_based_node_to) const override final { - return m_query_graph.FindEdge(from, to); + return m_query_graph.FindEdge(edge_based_node_from, edge_based_node_to); } - EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final + EdgeID FindEdgeInEitherDirection(const NodeID edge_based_node_from, + const NodeID edge_based_node_to) const override final { - return m_query_graph.FindEdgeInEitherDirection(from, to); + return m_query_graph.FindEdgeInEitherDirection(edge_based_node_from, edge_based_node_to); } - EdgeID - FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final + EdgeID FindEdgeIndicateIfReverse(const NodeID edge_based_node_from, + const NodeID edge_based_node_to, + bool &result) const override final { - return m_query_graph.FindEdgeIndicateIfReverse(from, to, result); + return m_query_graph.FindEdgeIndicateIfReverse( + edge_based_node_from, edge_based_node_to, result); } - EdgeID FindSmallestEdge(const NodeID from, - const NodeID to, + EdgeID FindSmallestEdge(const NodeID edge_based_node_from, + const NodeID edge_based_node_to, std::function filter) const override final { - return m_query_graph.FindSmallestEdge(from, to, filter); - } -}; - -template <> -class ContiguousInternalMemoryAlgorithmDataFacade - : public datafacade::AlgorithmDataFacade -{ - private: - util::vector_view m_is_core_node; - - // allocator that keeps the allocation data - std::shared_ptr allocator; - - void InitializeCoreInformationPointer(storage::DataLayout &data_layout, - char *memory_block, - const std::size_t exclude_index) - { - auto core_block_id = static_cast( - storage::DataLayout::CH_CORE_MARKER_0 + exclude_index); - auto core_marker_ptr = data_layout.GetBlockPtr(memory_block, core_block_id); - util::vector_view is_core_node(core_marker_ptr, - data_layout.num_entries[core_block_id]); - m_is_core_node = std::move(is_core_node); - } - - public: - ContiguousInternalMemoryAlgorithmDataFacade( - std::shared_ptr allocator_, const std::size_t exclude_index) - : allocator(std::move(allocator_)) - { - InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory(), exclude_index); - } - - void InitializeInternalPointers(storage::DataLayout &data_layout, - char *memory_block, - const std::size_t exclude_index) - { - InitializeCoreInformationPointer(data_layout, memory_block, exclude_index); - } - - bool IsCoreNode(const NodeID id) const override final - { - BOOST_ASSERT(m_is_core_node.empty() || id < m_is_core_node.size()); - return !m_is_core_node.empty() || m_is_core_node[id]; + return m_query_graph.FindSmallestEdge(edge_based_node_from, edge_based_node_to, filter); } }; @@ -220,40 +133,41 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade { private: using super = BaseDataFacade; - using IndexBlock = util::RangeTable<16, storage::Ownership::View>::BlockT; using RTreeLeaf = super::RTreeLeaf; using SharedRTree = util::StaticRTree; using SharedGeospatialQuery = GeospatialQuery; - using RTreeNode = SharedRTree::TreeNode; extractor::ClassData exclude_mask; - std::string m_timestamp; extractor::ProfileProperties *m_profile_properties; extractor::Datasources *m_datasources; - unsigned m_check_sum; + std::uint32_t m_check_sum; + StringView m_data_timestamp; util::vector_view m_coordinate_list; extractor::PackedOSMIDsView m_osmnodeid_list; util::vector_view m_lane_description_offsets; - util::vector_view m_lane_description_masks; + util::vector_view m_lane_description_masks; util::vector_view m_turn_weight_penalties; util::vector_view m_turn_duration_penalties; extractor::SegmentDataView segment_data; - extractor::TurnDataView turn_data; extractor::EdgeBasedNodeDataView edge_based_node_data; + guidance::TurnDataView turn_data; util::vector_view m_datasource_name_data; util::vector_view m_datasource_name_offsets; util::vector_view m_datasource_name_lengths; util::vector_view m_lane_tupel_id_pairs; - std::unique_ptr m_static_rtree; + util::vector_view m_maneuver_overrides; + util::vector_view m_maneuver_override_node_sequences; + + SharedRTree m_static_rtree; std::unique_ptr m_geospatial_query; boost::filesystem::path file_index_path; extractor::IntersectionBearingsView intersection_bearings_view; - util::NameTable m_name_table; + extractor::NameTableView m_name_table; // the look-up table for entry classes. An entry class lists the possibility of entry for all // available turns. Such a class id is stored with every edge. util::vector_view m_entry_class_table; @@ -261,417 +175,141 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade // allocator that keeps the allocation data std::shared_ptr allocator; - void InitializeProfilePropertiesPointer(storage::DataLayout &data_layout, - char *memory_block, - const std::size_t exclude_index) - { - m_profile_properties = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::PROPERTIES); - - exclude_mask = m_profile_properties->excludable_classes[exclude_index]; - } - - void InitializeTimestampPointer(storage::DataLayout &data_layout, char *memory_block) - { - auto timestamp_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::TIMESTAMP); - m_timestamp.resize(data_layout.GetBlockSize(storage::DataLayout::TIMESTAMP)); - std::copy(timestamp_ptr, - timestamp_ptr + data_layout.GetBlockSize(storage::DataLayout::TIMESTAMP), - m_timestamp.begin()); - } - - void InitializeChecksumPointer(storage::DataLayout &data_layout, char *memory_block) - { - m_check_sum = - *data_layout.GetBlockPtr(memory_block, storage::DataLayout::HSGR_CHECKSUM); - util::Log() << "set checksum: " << m_check_sum; - } - - void InitializeRTreePointers(storage::DataLayout &data_layout, char *memory_block) - { - BOOST_ASSERT_MSG(!m_coordinate_list.empty(), "coordinates must be loaded before r-tree"); - - const auto file_index_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::FILE_INDEX_PATH); - file_index_path = boost::filesystem::path(file_index_ptr); - if (!boost::filesystem::exists(file_index_path)) - { - util::Log(logDEBUG) << "Leaf file name " << file_index_path.string(); - throw util::exception("Could not load " + file_index_path.string() + - "Is any data loaded into shared memory?" + SOURCE_REF); - } - - auto tree_nodes_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::R_SEARCH_TREE); - auto tree_level_sizes_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::R_SEARCH_TREE_LEVELS); - m_static_rtree.reset( - new SharedRTree(tree_nodes_ptr, - data_layout.num_entries[storage::DataLayout::R_SEARCH_TREE], - tree_level_sizes_ptr, - data_layout.num_entries[storage::DataLayout::R_SEARCH_TREE_LEVELS], - file_index_path, - m_coordinate_list)); - m_geospatial_query.reset( - new SharedGeospatialQuery(*m_static_rtree, m_coordinate_list, *this)); - } - - void InitializeNodeInformationPointers(storage::DataLayout &layout, char *memory_ptr) - { - const auto coordinate_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::COORDINATE_LIST); - m_coordinate_list.reset(coordinate_list_ptr, - layout.num_entries[storage::DataLayout::COORDINATE_LIST]); - - const auto osmnodeid_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::OSM_NODE_ID_LIST); - m_osmnodeid_list = extractor::PackedOSMIDsView( - util::vector_view( - osmnodeid_ptr, layout.num_entries[storage::DataLayout::OSM_NODE_ID_LIST]), - // We (ab)use the number of coordinates here because we know we have the same amount of - // ids - layout.num_entries[storage::DataLayout::COORDINATE_LIST]); - } - - void InitializeEdgeBasedNodeDataInformationPointers(storage::DataLayout &layout, - char *memory_ptr) - { - const auto via_geometry_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::GEOMETRY_ID_LIST); - util::vector_view geometry_ids( - via_geometry_list_ptr, layout.num_entries[storage::DataLayout::GEOMETRY_ID_LIST]); - - const auto name_id_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::NAME_ID_LIST); - util::vector_view name_ids(name_id_list_ptr, - layout.num_entries[storage::DataLayout::NAME_ID_LIST]); - - const auto component_id_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::COMPONENT_ID_LIST); - util::vector_view component_ids( - component_id_list_ptr, layout.num_entries[storage::DataLayout::COMPONENT_ID_LIST]); - - const auto travel_mode_list_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::TRAVEL_MODE_LIST); - util::vector_view travel_modes( - travel_mode_list_ptr, layout.num_entries[storage::DataLayout::TRAVEL_MODE_LIST]); - - const auto classes_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::CLASSES_LIST); - util::vector_view classes( - classes_list_ptr, layout.num_entries[storage::DataLayout::CLASSES_LIST]); - - edge_based_node_data = extractor::EdgeBasedNodeDataView(std::move(geometry_ids), - std::move(name_ids), - std::move(component_ids), - std::move(travel_modes), - std::move(classes)); - } - - void InitializeEdgeInformationPointers(storage::DataLayout &layout, char *memory_ptr) - { - const auto lane_data_id_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::LANE_DATA_ID); - util::vector_view lane_data_ids( - lane_data_id_ptr, layout.num_entries[storage::DataLayout::LANE_DATA_ID]); - - const auto turn_instruction_list_ptr = - layout.GetBlockPtr( - memory_ptr, storage::DataLayout::TURN_INSTRUCTION); - util::vector_view turn_instructions( - turn_instruction_list_ptr, layout.num_entries[storage::DataLayout::TURN_INSTRUCTION]); - - const auto entry_class_id_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::ENTRY_CLASSID); - util::vector_view entry_class_ids( - entry_class_id_list_ptr, layout.num_entries[storage::DataLayout::ENTRY_CLASSID]); - - const auto pre_turn_bearing_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::PRE_TURN_BEARING); - util::vector_view pre_turn_bearings( - pre_turn_bearing_ptr, layout.num_entries[storage::DataLayout::PRE_TURN_BEARING]); - - const auto post_turn_bearing_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::POST_TURN_BEARING); - util::vector_view post_turn_bearings( - post_turn_bearing_ptr, layout.num_entries[storage::DataLayout::POST_TURN_BEARING]); - - turn_data = extractor::TurnDataView(std::move(turn_instructions), - std::move(lane_data_ids), - std::move(entry_class_ids), - std::move(pre_turn_bearings), - std::move(post_turn_bearings)); - } - - void InitializeNamePointers(storage::DataLayout &data_layout, char *memory_block) - { - auto name_data_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::NAME_CHAR_DATA); - const auto name_data_size = data_layout.num_entries[storage::DataLayout::NAME_CHAR_DATA]; - m_name_table.reset(name_data_ptr, name_data_ptr + name_data_size); - } - - void InitializeTurnLaneDescriptionsPointers(storage::DataLayout &data_layout, - char *memory_block) - { - auto offsets_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::LANE_DESCRIPTION_OFFSETS); - util::vector_view offsets( - offsets_ptr, data_layout.num_entries[storage::DataLayout::LANE_DESCRIPTION_OFFSETS]); - m_lane_description_offsets = std::move(offsets); - - auto masks_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::LANE_DESCRIPTION_MASKS); - - util::vector_view masks( - masks_ptr, data_layout.num_entries[storage::DataLayout::LANE_DESCRIPTION_MASKS]); - m_lane_description_masks = std::move(masks); - - const auto lane_tupel_id_pair_ptr = - data_layout.GetBlockPtr( - memory_block, storage::DataLayout::TURN_LANE_DATA); - util::vector_view lane_tupel_id_pair( - lane_tupel_id_pair_ptr, data_layout.num_entries[storage::DataLayout::TURN_LANE_DATA]); - m_lane_tupel_id_pairs = std::move(lane_tupel_id_pair); - } - - void InitializeTurnPenalties(storage::DataLayout &data_layout, char *memory_block) - { - auto turn_weight_penalties_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::TURN_WEIGHT_PENALTIES); - m_turn_weight_penalties = util::vector_view( - turn_weight_penalties_ptr, - data_layout.num_entries[storage::DataLayout::TURN_WEIGHT_PENALTIES]); - auto turn_duration_penalties_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::TURN_DURATION_PENALTIES); - m_turn_duration_penalties = util::vector_view( - turn_duration_penalties_ptr, - data_layout.num_entries[storage::DataLayout::TURN_DURATION_PENALTIES]); - } - - void InitializeGeometryPointers(storage::DataLayout &data_layout, char *memory_block) - { - auto geometries_index_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::GEOMETRIES_INDEX); - util::vector_view geometry_begin_indices( - geometries_index_ptr, data_layout.num_entries[storage::DataLayout::GEOMETRIES_INDEX]); - - auto num_entries = data_layout.num_entries[storage::DataLayout::GEOMETRIES_NODE_LIST]; - - auto geometries_node_list_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::GEOMETRIES_NODE_LIST); - util::vector_view geometry_node_list(geometries_node_list_ptr, num_entries); - - auto geometries_fwd_weight_list_ptr = - data_layout.GetBlockPtr( - memory_block, storage::DataLayout::GEOMETRIES_FWD_WEIGHT_LIST); - extractor::SegmentDataView::SegmentWeightVector geometry_fwd_weight_list( - util::vector_view( - geometries_fwd_weight_list_ptr, - data_layout.num_entries[storage::DataLayout::GEOMETRIES_FWD_WEIGHT_LIST]), - num_entries); - - auto geometries_rev_weight_list_ptr = - data_layout.GetBlockPtr( - memory_block, storage::DataLayout::GEOMETRIES_REV_WEIGHT_LIST); - extractor::SegmentDataView::SegmentWeightVector geometry_rev_weight_list( - util::vector_view( - geometries_rev_weight_list_ptr, - data_layout.num_entries[storage::DataLayout::GEOMETRIES_REV_WEIGHT_LIST]), - num_entries); - - auto geometries_fwd_duration_list_ptr = - data_layout.GetBlockPtr( - memory_block, storage::DataLayout::GEOMETRIES_FWD_DURATION_LIST); - extractor::SegmentDataView::SegmentDurationVector geometry_fwd_duration_list( - util::vector_view( - geometries_fwd_duration_list_ptr, - data_layout.num_entries[storage::DataLayout::GEOMETRIES_FWD_DURATION_LIST]), - num_entries); - - auto geometries_rev_duration_list_ptr = - data_layout.GetBlockPtr( - memory_block, storage::DataLayout::GEOMETRIES_REV_DURATION_LIST); - extractor::SegmentDataView::SegmentDurationVector geometry_rev_duration_list( - util::vector_view( - geometries_rev_duration_list_ptr, - data_layout.num_entries[storage::DataLayout::GEOMETRIES_REV_DURATION_LIST]), - num_entries); - - auto geometries_fwd_datasources_list_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::GEOMETRIES_FWD_DATASOURCES_LIST); - util::vector_view geometry_fwd_datasources_list( - geometries_fwd_datasources_list_ptr, - data_layout.num_entries[storage::DataLayout::GEOMETRIES_FWD_DATASOURCES_LIST]); - - auto geometries_rev_datasources_list_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::GEOMETRIES_REV_DATASOURCES_LIST); - util::vector_view geometry_rev_datasources_list( - geometries_rev_datasources_list_ptr, - data_layout.num_entries[storage::DataLayout::GEOMETRIES_REV_DATASOURCES_LIST]); - - segment_data = extractor::SegmentDataView{std::move(geometry_begin_indices), - std::move(geometry_node_list), - std::move(geometry_fwd_weight_list), - std::move(geometry_rev_weight_list), - std::move(geometry_fwd_duration_list), - std::move(geometry_rev_duration_list), - std::move(geometry_fwd_datasources_list), - std::move(geometry_rev_datasources_list)}; - - m_datasources = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::DATASOURCES_NAMES); - } - - void InitializeIntersectionClassPointers(storage::DataLayout &data_layout, char *memory_block) - { - auto bearing_class_id_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::BEARING_CLASSID); - util::vector_view bearing_class_id( - bearing_class_id_ptr, data_layout.num_entries[storage::DataLayout::BEARING_CLASSID]); - - auto bearing_values_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::BEARING_VALUES); - util::vector_view bearing_values( - bearing_values_ptr, data_layout.num_entries[storage::DataLayout::BEARING_VALUES]); - - auto offsets_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::BEARING_OFFSETS); - auto blocks_ptr = - data_layout.GetBlockPtr(memory_block, storage::DataLayout::BEARING_BLOCKS); - util::vector_view bearing_offsets( - offsets_ptr, data_layout.num_entries[storage::DataLayout::BEARING_OFFSETS]); - util::vector_view bearing_blocks( - blocks_ptr, data_layout.num_entries[storage::DataLayout::BEARING_BLOCKS]); - - util::RangeTable<16, storage::Ownership::View> bearing_range_table( - bearing_offsets, bearing_blocks, static_cast(bearing_values.size())); - - intersection_bearings_view = extractor::IntersectionBearingsView{ - std::move(bearing_values), std::move(bearing_class_id), std::move(bearing_range_table)}; - - auto entry_class_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::ENTRY_CLASS); - util::vector_view entry_class_table( - entry_class_ptr, data_layout.num_entries[storage::DataLayout::ENTRY_CLASS]); - m_entry_class_table = std::move(entry_class_table); - } - - void InitializeInternalPointers(storage::DataLayout &data_layout, - char *memory_block, + void InitializeInternalPointers(const storage::SharedDataIndex &index, + const std::string &metric_name, const std::size_t exclude_index) { - InitializeChecksumPointer(data_layout, memory_block); - InitializeNodeInformationPointers(data_layout, memory_block); - InitializeEdgeBasedNodeDataInformationPointers(data_layout, memory_block); - InitializeEdgeInformationPointers(data_layout, memory_block); - InitializeTurnPenalties(data_layout, memory_block); - InitializeGeometryPointers(data_layout, memory_block); - InitializeTimestampPointer(data_layout, memory_block); - InitializeNamePointers(data_layout, memory_block); - InitializeTurnLaneDescriptionsPointers(data_layout, memory_block); - InitializeProfilePropertiesPointer(data_layout, memory_block, exclude_index); - InitializeRTreePointers(data_layout, memory_block); - InitializeIntersectionClassPointers(data_layout, memory_block); + // TODO: For multi-metric support we need to have separate exclude classes per metric + (void)metric_name; + + m_profile_properties = + index.GetBlockPtr("/common/properties"); + + exclude_mask = m_profile_properties->excludable_classes[exclude_index]; + + m_check_sum = *index.GetBlockPtr("/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"); + + m_static_rtree = make_search_tree_view(index, "/common/rtree"); + m_geospatial_query.reset( + new SharedGeospatialQuery(m_static_rtree, m_coordinate_list, *this)); + + edge_based_node_data = make_ebn_data_view(index, "/common/ebg_node_data"); + + turn_data = make_turn_data_view(index, "/common/turn_data"); + + m_name_table = make_name_table_view(index, "/common/names"); + + std::tie(m_lane_description_offsets, m_lane_description_masks) = + make_turn_lane_description_views(index, "/common/turn_lanes"); + m_lane_tupel_id_pairs = make_lane_data_view(index, "/common/turn_lanes"); + + m_turn_weight_penalties = make_turn_weight_view(index, "/common/turn_penalty"); + m_turn_duration_penalties = make_turn_duration_view(index, "/common/turn_penalty"); + + segment_data = make_segment_data_view(index, "/common/segment_data"); + + m_datasources = index.GetBlockPtr("/common/data_sources_names"); + + intersection_bearings_view = + make_intersection_bearings_view(index, "/common/intersection_bearings"); + + m_entry_class_table = make_entry_classes_view(index, "/common/entry_classes"); + + std::tie(m_maneuver_overrides, m_maneuver_override_node_sequences) = + make_maneuver_overrides_views(index, "/common/maneuver_overrides"); } public: // allows switching between process_memory/shared_memory datafacade, based on the type of // allocator ContiguousInternalMemoryDataFacadeBase(std::shared_ptr allocator_, + const std::string &metric_name, const std::size_t exclude_index) : allocator(std::move(allocator_)) { - InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory(), exclude_index); + InitializeInternalPointers(allocator->GetIndex(), metric_name, exclude_index); } // node and edge information access - util::Coordinate GetCoordinateOfNode(const NodeID id) const override final + util::Coordinate GetCoordinateOfNode(const NodeID node_based_node_id) const override final { - return m_coordinate_list[id]; + return m_coordinate_list[node_based_node_id]; } - OSMNodeID GetOSMNodeIDOfNode(const NodeID id) const override final + OSMNodeID GetOSMNodeIDOfNode(const NodeID node_based_node_id) const override final { - return m_osmnodeid_list[id]; + return m_osmnodeid_list[node_based_node_id]; } - std::vector GetUncompressedForwardGeometry(const EdgeID id) const override final + NodeForwardRange GetUncompressedForwardGeometry(const PackedGeometryID id) const override final { - - auto range = segment_data.GetForwardGeometry(id); - return std::vector{range.begin(), range.end()}; + return segment_data.GetForwardGeometry(id); } - virtual std::vector GetUncompressedReverseGeometry(const EdgeID id) const override final + NodeReverseRange GetUncompressedReverseGeometry(const PackedGeometryID id) const override final { - auto range = segment_data.GetReverseGeometry(id); - return std::vector{range.begin(), range.end()}; + return segment_data.GetReverseGeometry(id); } - virtual std::vector - GetUncompressedForwardDurations(const EdgeID id) const override final + DurationForwardRange + GetUncompressedForwardDurations(const PackedGeometryID id) const override final { - auto range = segment_data.GetForwardDurations(id); - return std::vector{range.begin(), range.end()}; + return segment_data.GetForwardDurations(id); } - virtual std::vector - GetUncompressedReverseDurations(const EdgeID id) const override final + DurationReverseRange + GetUncompressedReverseDurations(const PackedGeometryID id) const override final { - auto range = segment_data.GetReverseDurations(id); - return std::vector{range.begin(), range.end()}; + return segment_data.GetReverseDurations(id); } - virtual std::vector - GetUncompressedForwardWeights(const EdgeID id) const override final + WeightForwardRange GetUncompressedForwardWeights(const PackedGeometryID id) const override final { - auto range = segment_data.GetForwardWeights(id); - return std::vector{range.begin(), range.end()}; + return segment_data.GetForwardWeights(id); } - virtual std::vector - GetUncompressedReverseWeights(const EdgeID id) const override final + WeightReverseRange GetUncompressedReverseWeights(const PackedGeometryID id) const override final { - auto range = segment_data.GetReverseWeights(id); - return std::vector{range.begin(), range.end()}; + return segment_data.GetReverseWeights(id); } // Returns the data source ids that were used to supply the edge // weights. - virtual std::vector - GetUncompressedForwardDatasources(const EdgeID id) const override final + DatasourceForwardRange + GetUncompressedForwardDatasources(const PackedGeometryID id) const override final { - auto range = segment_data.GetForwardDatasources(id); - return std::vector{range.begin(), range.end()}; + return segment_data.GetForwardDatasources(id); } // Returns the data source ids that were used to supply the edge // weights. - virtual std::vector - GetUncompressedReverseDatasources(const EdgeID id) const override final + DatasourceReverseRange + GetUncompressedReverseDatasources(const PackedGeometryID id) const override final { - auto range = segment_data.GetReverseDatasources(id); - return std::vector{range.begin(), range.end()}; + return segment_data.GetReverseDatasources(id); } - virtual TurnPenalty GetWeightPenaltyForEdgeID(const unsigned id) const override final + TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID edge_based_edge_id) const override final { - BOOST_ASSERT(m_turn_weight_penalties.size() > id); - return m_turn_weight_penalties[id]; + BOOST_ASSERT(m_turn_weight_penalties.size() > edge_based_edge_id); + return m_turn_weight_penalties[edge_based_edge_id]; } - virtual TurnPenalty GetDurationPenaltyForEdgeID(const unsigned id) const override final + TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID edge_based_edge_id) const override final { - BOOST_ASSERT(m_turn_duration_penalties.size() > id); - return m_turn_duration_penalties[id]; + BOOST_ASSERT(m_turn_duration_penalties.size() > edge_based_edge_id); + return m_turn_duration_penalties[edge_based_edge_id]; } - extractor::guidance::TurnInstruction - GetTurnInstructionForEdgeID(const EdgeID id) const override final + osrm::guidance::TurnInstruction + GetTurnInstructionForEdgeID(const EdgeID edge_based_edge_id) const override final { - return turn_data.GetTurnInstruction(id); + return turn_data.GetTurnInstruction(edge_based_edge_id); } std::vector GetEdgesInBox(const util::Coordinate south_west, @@ -685,148 +323,73 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade std::vector NearestPhantomNodesInRange(const util::Coordinate input_coordinate, - const float max_distance, - const Approach approach) const override final + const double max_distance, + const boost::optional bearing, + 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); - } - - std::vector - NearestPhantomNodesInRange(const util::Coordinate input_coordinate, - const float max_distance, - const int bearing, - const int bearing_range, - const Approach approach) const override final - { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodesInRange( - input_coordinate, max_distance, bearing, bearing_range, approach); + return m_geospatial_query->NearestPhantomNodes( + input_coordinate, approach, boost::none, max_distance, bearing, use_all_edges); } std::vector NearestPhantomNodes(const util::Coordinate input_coordinate, - const unsigned max_results, - const Approach approach) const override final - { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, approach); - } - - std::vector - NearestPhantomNodes(const util::Coordinate input_coordinate, - const unsigned max_results, - const double max_distance, + const size_t max_results, + const boost::optional max_distance, + const boost::optional bearing, const Approach approach) const override final { BOOST_ASSERT(m_geospatial_query.get()); return m_geospatial_query->NearestPhantomNodes( - input_coordinate, max_results, max_distance, approach); + input_coordinate, approach, max_results, max_distance, bearing, boost::none); } - std::vector - NearestPhantomNodes(const util::Coordinate input_coordinate, - const unsigned max_results, - const int bearing, - const int bearing_range, - const Approach approach) const override final + PhantomCandidateAlternatives + NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, + const boost::optional max_distance, + const boost::optional bearing, + const Approach approach, + const bool use_all_edges) const override final { BOOST_ASSERT(m_geospatial_query.get()); - return m_geospatial_query->NearestPhantomNodes( - input_coordinate, max_results, bearing, bearing_range, approach); + return m_geospatial_query->NearestCandidatesWithAlternativeFromBigComponent( + input_coordinate, approach, max_distance, bearing, use_all_edges); } - std::vector - NearestPhantomNodes(const util::Coordinate input_coordinate, - const unsigned max_results, - const double max_distance, - const int bearing, - const int bearing_range, - const Approach approach) const override final - { - BOOST_ASSERT(m_geospatial_query.get()); + std::uint32_t GetCheckSum() const override final { return m_check_sum; } - return m_geospatial_query->NearestPhantomNodes( - input_coordinate, max_results, max_distance, bearing, bearing_range, approach); + std::string GetTimestamp() const override final + { + return std::string(m_data_timestamp.begin(), m_data_timestamp.end()); } - std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const Approach approach) const override final + GeometryID GetGeometryIndex(const NodeID edge_based_node_id) const override final { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate, approach); + return edge_based_node_data.GetGeometryID(edge_based_node_id); } - std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const double max_distance, - const Approach approach) const override final + ComponentID GetComponentID(const NodeID edge_based_node_id) const override final { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate, max_distance, approach); + return edge_based_node_data.GetComponentID(edge_based_node_id); } - std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const double max_distance, - const int bearing, - const int bearing_range, - const Approach approach) const override final + extractor::TravelMode GetTravelMode(const NodeID edge_based_node_id) const override final { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate, max_distance, bearing, bearing_range, approach); + return edge_based_node_data.GetTravelMode(edge_based_node_id); } - std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const int bearing, - const int bearing_range, - const Approach approach) const override final + extractor::ClassData GetClassData(const NodeID edge_based_node_id) const override final { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate, bearing, bearing_range, approach); + return edge_based_node_data.GetClassData(edge_based_node_id); } - unsigned GetCheckSum() const override final { return m_check_sum; } - - GeometryID GetGeometryIndex(const NodeID id) const override final + bool ExcludeNode(const NodeID edge_based_node_id) const override final { - return edge_based_node_data.GetGeometryID(id); - } - - ComponentID GetComponentID(const NodeID id) const override final - { - return edge_based_node_data.GetComponentID(id); - } - - extractor::TravelMode GetTravelMode(const NodeID id) const override final - { - return edge_based_node_data.GetTravelMode(id); - } - - extractor::ClassData GetClassData(const NodeID id) const override final - { - return edge_based_node_data.GetClassData(id); - } - - bool ExcludeNode(const NodeID id) const override final - { - return (edge_based_node_data.GetClassData(id) & exclude_mask) > 0; + return (edge_based_node_data.GetClassData(edge_based_node_id) & exclude_mask) > 0; } std::vector GetClasses(const extractor::ClassData class_data) const override final @@ -840,9 +403,9 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade return classes; } - NameID GetNameIndex(const NodeID id) const override final + NameID GetNameIndex(const NodeID edge_based_node_id) const override final { - return edge_based_node_data.GetNameID(id); + return edge_based_node_data.GetNameID(edge_based_node_id); } StringView GetNameForID(const NameID id) const override final @@ -875,8 +438,6 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade return m_datasources->GetSourceName(id); } - std::string GetTimestamp() const override final { return m_timestamp; } - bool GetContinueStraightDefault() const override final { return m_profile_properties->continue_straight_at_waypoint; @@ -899,49 +460,93 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade return m_profile_properties->GetWeightMultiplier(); } - util::guidance::BearingClass GetBearingClass(const NodeID node) const override final + util::guidance::BearingClass + GetBearingClass(const NodeID node_based_node_id) const override final { - return intersection_bearings_view.GetBearingClass(node); + return intersection_bearings_view.GetBearingClass(node_based_node_id); } - util::guidance::TurnBearing PreTurnBearing(const EdgeID eid) const override final + guidance::TurnBearing PreTurnBearing(const EdgeID edge_based_edge_id) const override final { - return turn_data.GetPreTurnBearing(eid); + return turn_data.GetPreTurnBearing(edge_based_edge_id); } - util::guidance::TurnBearing PostTurnBearing(const EdgeID eid) const override final + guidance::TurnBearing PostTurnBearing(const EdgeID edge_based_edge_id) const override final { - return turn_data.GetPostTurnBearing(eid); + return turn_data.GetPostTurnBearing(edge_based_edge_id); } - util::guidance::EntryClass GetEntryClass(const EdgeID turn_id) const override final + util::guidance::EntryClass GetEntryClass(const EdgeID edge_based_edge_id) const override final { - auto entry_class_id = turn_data.GetEntryClassID(turn_id); + auto entry_class_id = turn_data.GetEntryClassID(edge_based_edge_id); return m_entry_class_table.at(entry_class_id); } - bool HasLaneData(const EdgeID id) const override final { return turn_data.HasLaneData(id); } - - util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const override final + bool HasLaneData(const EdgeID edge_based_edge_id) const override final { - BOOST_ASSERT(HasLaneData(id)); - return m_lane_tupel_id_pairs.at(turn_data.GetLaneDataID(id)); + return turn_data.HasLaneData(edge_based_edge_id); } - extractor::guidance::TurnLaneDescription + util::guidance::LaneTupleIdPair + GetLaneData(const EdgeID edge_based_edge_id) const override final + { + BOOST_ASSERT(HasLaneData(edge_based_edge_id)); + return m_lane_tupel_id_pairs.at(turn_data.GetLaneDataID(edge_based_edge_id)); + } + + extractor::TurnLaneDescription GetTurnDescription(const LaneDescriptionID lane_description_id) const override final { if (lane_description_id == INVALID_LANE_DESCRIPTIONID) return {}; else - return extractor::guidance::TurnLaneDescription( + return extractor::TurnLaneDescription( m_lane_description_masks.begin() + m_lane_description_offsets[lane_description_id], m_lane_description_masks.begin() + m_lane_description_offsets[lane_description_id + 1]); } - bool IsLeftHandDriving() const override final + bool IsLeftHandDriving(const NodeID edge_based_node_id) const override final { - return m_profile_properties->left_hand_driving; + // TODO: can be moved to a data block indexed by GeometryID + return edge_based_node_data.IsLeftHandDriving(edge_based_node_id); + } + + bool IsSegregated(const NodeID edge_based_node_id) const override final + { + return edge_based_node_data.IsSegregated(edge_based_node_id); + } + + std::vector + GetOverridesThatStartAt(const NodeID edge_based_node_id) const override final + { + std::vector results; + + // heterogeneous comparison: + struct Comp + { + bool operator()(const extractor::StorageManeuverOverride &s, NodeID i) const + { + return s.start_node < i; + } + bool operator()(NodeID i, const extractor::StorageManeuverOverride &s) const + { + return i < s.start_node; + } + }; + + auto found_range = std::equal_range( + m_maneuver_overrides.begin(), m_maneuver_overrides.end(), edge_based_node_id, Comp{}); + + std::for_each(found_range.first, found_range.second, [&](const auto &override) { + std::vector sequence( + m_maneuver_override_node_sequences.begin() + override.node_sequence_offset_begin, + m_maneuver_override_node_sequences.begin() + override.node_sequence_offset_end); + results.push_back(extractor::ManeuverOverride{std::move(sequence), + override.instruction_node, + override.override_type, + override.direction}); + }); + return results; } }; @@ -953,26 +558,11 @@ class ContiguousInternalMemoryDataFacade public ContiguousInternalMemoryAlgorithmDataFacade { public: - ContiguousInternalMemoryDataFacade(std::shared_ptr allocator, + ContiguousInternalMemoryDataFacade(const std::shared_ptr &allocator, + const std::string &metric_name, const std::size_t exclude_index) - : ContiguousInternalMemoryDataFacadeBase(allocator, exclude_index), - ContiguousInternalMemoryAlgorithmDataFacade(allocator, exclude_index) - - { - } -}; - -template <> -class ContiguousInternalMemoryDataFacade final - : public ContiguousInternalMemoryDataFacade, - public ContiguousInternalMemoryAlgorithmDataFacade -{ - public: - ContiguousInternalMemoryDataFacade(std::shared_ptr allocator, - const std::size_t exclude_index) - : ContiguousInternalMemoryDataFacade(allocator, exclude_index), - ContiguousInternalMemoryAlgorithmDataFacade(allocator, exclude_index) - + : ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index), + ContiguousInternalMemoryAlgorithmDataFacade(allocator, metric_name, exclude_index) { } }; @@ -980,8 +570,8 @@ class ContiguousInternalMemoryDataFacade final template <> class ContiguousInternalMemoryAlgorithmDataFacade : public AlgorithmDataFacade { // MLD data - partition::MultiLevelPartitionView mld_partition; - partition::CellStorageView mld_cell_storage; + partitioner::MultiLevelPartitionView mld_partition; + partitioner::CellStorageView mld_cell_storage; customizer::CellMetricView mld_cell_metric; using QueryGraph = customizer::MultiLevelEdgeBasedGraphView; using GraphNode = QueryGraph::NodeArrayEntry; @@ -989,122 +579,15 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade : public Algo QueryGraph query_graph; - void InitializeInternalPointers(storage::DataLayout &data_layout, - char *memory_block, + void InitializeInternalPointers(const storage::SharedDataIndex &index, + const std::string &metric_name, const std::size_t exclude_index) { - InitializeMLDDataPointers(data_layout, memory_block, exclude_index); - InitializeGraphPointer(data_layout, memory_block); - } - - void InitializeMLDDataPointers(storage::DataLayout &data_layout, - char *memory_block, - const std::size_t exclude_index) - { - if (data_layout.GetBlockSize(storage::DataLayout::MLD_PARTITION) > 0) - { - BOOST_ASSERT(data_layout.GetBlockSize(storage::DataLayout::MLD_LEVEL_DATA) > 0); - BOOST_ASSERT(data_layout.GetBlockSize(storage::DataLayout::MLD_CELL_TO_CHILDREN) > 0); - - auto level_data = - data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_LEVEL_DATA); - - auto mld_partition_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_PARTITION); - auto partition_entries_count = - data_layout.GetBlockEntries(storage::DataLayout::MLD_PARTITION); - util::vector_view partition(mld_partition_ptr, partition_entries_count); - - auto mld_chilren_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_CELL_TO_CHILDREN); - auto children_entries_count = - data_layout.GetBlockEntries(storage::DataLayout::MLD_CELL_TO_CHILDREN); - util::vector_view cell_to_children(mld_chilren_ptr, children_entries_count); - - mld_partition = - partition::MultiLevelPartitionView{level_data, partition, cell_to_children}; - } - - const auto weights_block_id = static_cast( - storage::DataLayout::MLD_CELL_WEIGHTS_0 + exclude_index); - const auto durations_block_id = static_cast( - storage::DataLayout::MLD_CELL_DURATIONS_0 + exclude_index); - - if (data_layout.GetBlockSize(weights_block_id) > 0) - { - auto mld_cell_weights_ptr = - data_layout.GetBlockPtr(memory_block, weights_block_id); - auto mld_cell_durations_ptr = - data_layout.GetBlockPtr(memory_block, durations_block_id); - auto weight_entries_count = - data_layout.GetBlockEntries(storage::DataLayout::MLD_CELL_WEIGHTS_0); - auto duration_entries_count = - data_layout.GetBlockEntries(storage::DataLayout::MLD_CELL_DURATIONS_0); - BOOST_ASSERT(weight_entries_count == duration_entries_count); - util::vector_view weights(mld_cell_weights_ptr, weight_entries_count); - util::vector_view durations(mld_cell_durations_ptr, - duration_entries_count); - - mld_cell_metric = customizer::CellMetricView{std::move(weights), std::move(durations)}; - } - - if (data_layout.GetBlockSize(storage::DataLayout::MLD_CELLS) > 0) - { - - auto mld_source_boundary_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_CELL_SOURCE_BOUNDARY); - auto mld_destination_boundary_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_CELL_DESTINATION_BOUNDARY); - auto mld_cells_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_CELLS); - auto mld_cell_level_offsets_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_CELL_LEVEL_OFFSETS); - - auto source_boundary_entries_count = - data_layout.GetBlockEntries(storage::DataLayout::MLD_CELL_SOURCE_BOUNDARY); - auto destination_boundary_entries_count = - data_layout.GetBlockEntries(storage::DataLayout::MLD_CELL_DESTINATION_BOUNDARY); - auto cells_entries_counts = data_layout.GetBlockEntries(storage::DataLayout::MLD_CELLS); - auto cell_level_offsets_entries_count = - data_layout.GetBlockEntries(storage::DataLayout::MLD_CELL_LEVEL_OFFSETS); - - util::vector_view source_boundary(mld_source_boundary_ptr, - source_boundary_entries_count); - util::vector_view destination_boundary(mld_destination_boundary_ptr, - destination_boundary_entries_count); - util::vector_view cells(mld_cells_ptr, - cells_entries_counts); - util::vector_view level_offsets(mld_cell_level_offsets_ptr, - cell_level_offsets_entries_count); - - mld_cell_storage = partition::CellStorageView{std::move(source_boundary), - std::move(destination_boundary), - std::move(cells), - std::move(level_offsets)}; - } - } - void InitializeGraphPointer(storage::DataLayout &data_layout, char *memory_block) - { - auto graph_nodes_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_GRAPH_NODE_LIST); - - auto graph_edges_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_GRAPH_EDGE_LIST); - - auto graph_node_to_offset_ptr = data_layout.GetBlockPtr( - memory_block, storage::DataLayout::MLD_GRAPH_NODE_TO_OFFSET); - - util::vector_view node_list( - graph_nodes_ptr, data_layout.num_entries[storage::DataLayout::MLD_GRAPH_NODE_LIST]); - util::vector_view edge_list( - graph_edges_ptr, data_layout.num_entries[storage::DataLayout::MLD_GRAPH_EDGE_LIST]); - util::vector_view node_to_offset( - graph_node_to_offset_ptr, - data_layout.num_entries[storage::DataLayout::MLD_GRAPH_NODE_TO_OFFSET]); - - query_graph = - QueryGraph(std::move(node_list), std::move(edge_list), std::move(node_to_offset)); + mld_partition = make_partition_view(index, "/mld/multilevelpartition"); + mld_cell_metric = + make_filtered_cell_metric_view(index, "/mld/metrics/" + metric_name, exclude_index); + mld_cell_storage = make_cell_storage_view(index, "/mld/cellstorage"); + query_graph = make_multi_level_graph_view(index, "/mld/multilevelgraph"); } // allocator that keeps the allocation data @@ -1112,52 +595,86 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade : public Algo public: ContiguousInternalMemoryAlgorithmDataFacade( - std::shared_ptr allocator_, const std::size_t exclude_index) + std::shared_ptr allocator_, + const std::string &metric_name, + const std::size_t exclude_index) : allocator(std::move(allocator_)) { - InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory(), exclude_index); + InitializeInternalPointers(allocator->GetIndex(), metric_name, exclude_index); } - const partition::MultiLevelPartitionView &GetMultiLevelPartition() const override + const partitioner::MultiLevelPartitionView &GetMultiLevelPartition() const override { return mld_partition; } - const partition::CellStorageView &GetCellStorage() const override { return mld_cell_storage; } + const partitioner::CellStorageView &GetCellStorage() const override { return mld_cell_storage; } const customizer::CellMetricView &GetCellMetric() const override { return mld_cell_metric; } // search graph access unsigned GetNumberOfNodes() const override final { return query_graph.GetNumberOfNodes(); } + unsigned GetMaxBorderNodeID() const override final { return query_graph.GetMaxBorderNodeID(); } + unsigned GetNumberOfEdges() const override final { return query_graph.GetNumberOfEdges(); } - unsigned GetOutDegree(const NodeID n) const override final + unsigned GetOutDegree(const NodeID edge_based_node_id) const override final { - return query_graph.GetOutDegree(n); + return query_graph.GetOutDegree(edge_based_node_id); } - NodeID GetTarget(const EdgeID e) const override final { return query_graph.GetTarget(e); } - - const EdgeData &GetEdgeData(const EdgeID e) const override final + EdgeRange GetAdjacentEdgeRange(const NodeID edge_based_node_id) const override final { - return query_graph.GetEdgeData(e); + return query_graph.GetAdjacentEdgeRange(edge_based_node_id); } - EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final + EdgeWeight GetNodeWeight(const NodeID edge_based_node_id) const override final { - return query_graph.GetAdjacentEdgeRange(node); + return query_graph.GetNodeWeight(edge_based_node_id); } - EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const override final + EdgeDuration GetNodeDuration(const NodeID edge_based_node_id) const override final { - return query_graph.GetBorderEdgeRange(level, node); + return query_graph.GetNodeDuration(edge_based_node_id); + } + + EdgeDistance GetNodeDistance(const NodeID edge_based_node_id) const override final + { + return query_graph.GetNodeDistance(edge_based_node_id); + } + + bool IsForwardEdge(const NodeID edge_based_node_id) const override final + { + return query_graph.IsForwardEdge(edge_based_node_id); + } + + bool IsBackwardEdge(const NodeID edge_based_node_id) const override final + { + return query_graph.IsBackwardEdge(edge_based_node_id); + } + + NodeID GetTarget(const EdgeID edge_based_edge_id) const override final + { + return query_graph.GetTarget(edge_based_edge_id); + } + + const EdgeData &GetEdgeData(const EdgeID edge_based_edge_id) const override final + { + return query_graph.GetEdgeData(edge_based_edge_id); + } + + EdgeRange GetBorderEdgeRange(const LevelID level, + const NodeID edge_based_node_id) const override final + { + return query_graph.GetBorderEdgeRange(level, edge_based_node_id); } // searches for a specific edge - EdgeID FindEdge(const NodeID from, const NodeID to) const override final + EdgeID FindEdge(const NodeID edge_based_node_from, + const NodeID edge_based_node_to) const override final { - return query_graph.FindEdge(from, to); + return query_graph.FindEdge(edge_based_node_from, edge_based_node_to); } }; @@ -1168,16 +685,16 @@ class ContiguousInternalMemoryDataFacade final { private: public: - ContiguousInternalMemoryDataFacade(std::shared_ptr allocator, + ContiguousInternalMemoryDataFacade(const std::shared_ptr &allocator, + const std::string &metric_name, const std::size_t exclude_index) - : ContiguousInternalMemoryDataFacadeBase(allocator, exclude_index), - ContiguousInternalMemoryAlgorithmDataFacade(allocator, exclude_index) - + : ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index), + ContiguousInternalMemoryAlgorithmDataFacade(allocator, metric_name, exclude_index) { } }; -} -} -} +} // namespace datafacade +} // namespace engine +} // namespace osrm #endif // CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 1011d853e..936ccf0c2 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -10,26 +10,32 @@ #include "extractor/class_data.hpp" #include "extractor/edge_based_node_segment.hpp" -#include "extractor/guidance/turn_instruction.hpp" -#include "extractor/guidance/turn_lane_types.hpp" -#include "extractor/original_edge_data.hpp" +#include "extractor/maneuver_override.hpp" #include "extractor/query_node.hpp" +#include "extractor/segment_data_container.hpp" #include "extractor/travel_mode.hpp" +#include "extractor/turn_lane_types.hpp" + +#include "guidance/turn_bearing.hpp" +#include "guidance/turn_instruction.hpp" #include "util/exception.hpp" #include "util/guidance/bearing_class.hpp" #include "util/guidance/entry_class.hpp" -#include "util/guidance/turn_bearing.hpp" #include "util/guidance/turn_lanes.hpp" #include "util/integer_range.hpp" +#include "util/packed_vector.hpp" #include "util/string_util.hpp" #include "util/string_view.hpp" #include "util/typedefs.hpp" #include "osrm/coordinate.hpp" +#include +#include #include +#include #include #include #include @@ -47,54 +53,76 @@ class BaseDataFacade { public: using RTreeLeaf = extractor::EdgeBasedNodeSegment; + + using NodeForwardRange = + boost::iterator_range; + using NodeReverseRange = boost::reversed_range; + + using WeightForwardRange = + boost::iterator_range; + using WeightReverseRange = boost::reversed_range; + + using DurationForwardRange = + boost::iterator_range; + using DurationReverseRange = boost::reversed_range; + + using DatasourceForwardRange = + boost::iterator_range; + using DatasourceReverseRange = boost::reversed_range; + BaseDataFacade() {} virtual ~BaseDataFacade() {} - virtual unsigned GetCheckSum() const = 0; + 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; + virtual util::Coordinate GetCoordinateOfNode(const NodeID node_based_node_id) const = 0; - virtual OSMNodeID GetOSMNodeIDOfNode(const NodeID id) const = 0; + virtual OSMNodeID GetOSMNodeIDOfNode(const NodeID node_based_node_id) const = 0; - virtual GeometryID GetGeometryIndex(const NodeID id) const = 0; + virtual GeometryID GetGeometryIndex(const NodeID edge_based_node_id) const = 0; - virtual ComponentID GetComponentID(const NodeID id) const = 0; + virtual ComponentID GetComponentID(const NodeID edge_based_node_id) const = 0; - virtual std::vector GetUncompressedForwardGeometry(const EdgeID id) const = 0; + virtual NodeForwardRange GetUncompressedForwardGeometry(const PackedGeometryID id) const = 0; + virtual NodeReverseRange GetUncompressedReverseGeometry(const PackedGeometryID id) const = 0; - virtual std::vector GetUncompressedReverseGeometry(const EdgeID id) const = 0; + virtual TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID edge_based_edge_id) const = 0; - virtual TurnPenalty GetWeightPenaltyForEdgeID(const unsigned id) const = 0; - - virtual TurnPenalty GetDurationPenaltyForEdgeID(const unsigned id) const = 0; + virtual TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID edge_based_edge_id) const = 0; // Gets the weight values for each segment in an uncompressed geometry. // Should always be 1 shorter than GetUncompressedGeometry - virtual std::vector GetUncompressedForwardWeights(const EdgeID id) const = 0; - virtual std::vector GetUncompressedReverseWeights(const EdgeID id) const = 0; + virtual WeightForwardRange GetUncompressedForwardWeights(const PackedGeometryID id) const = 0; + virtual WeightReverseRange GetUncompressedReverseWeights(const PackedGeometryID id) const = 0; // Gets the duration values for each segment in an uncompressed geometry. // Should always be 1 shorter than GetUncompressedGeometry - virtual std::vector GetUncompressedForwardDurations(const EdgeID id) const = 0; - virtual std::vector GetUncompressedReverseDurations(const EdgeID id) const = 0; + virtual DurationForwardRange + GetUncompressedForwardDurations(const PackedGeometryID id) const = 0; + virtual DurationReverseRange + GetUncompressedReverseDurations(const PackedGeometryID id) const = 0; // Returns the data source ids that were used to supply the edge // weights. Will return an empty array when only the base profile is used. - virtual std::vector GetUncompressedForwardDatasources(const EdgeID id) const = 0; - virtual std::vector GetUncompressedReverseDatasources(const EdgeID id) const = 0; + virtual DatasourceForwardRange + GetUncompressedForwardDatasources(const PackedGeometryID id) const = 0; + virtual DatasourceReverseRange + GetUncompressedReverseDatasources(const PackedGeometryID id) const = 0; // Gets the name of a datasource virtual StringView GetDatasourceName(const DatasourceID id) const = 0; - virtual extractor::guidance::TurnInstruction - GetTurnInstructionForEdgeID(const EdgeID id) const = 0; + virtual osrm::guidance::TurnInstruction + GetTurnInstructionForEdgeID(const EdgeID edge_based_edge_id) const = 0; - virtual extractor::TravelMode GetTravelMode(const NodeID id) const = 0; + virtual extractor::TravelMode GetTravelMode(const NodeID edge_based_node_id) const = 0; - virtual extractor::ClassData GetClassData(const NodeID id) const = 0; + virtual extractor::ClassData GetClassData(const NodeID edge_based_node_id) const = 0; - virtual bool ExcludeNode(const NodeID id) const = 0; + virtual bool ExcludeNode(const NodeID edge_based_node_id) const = 0; virtual std::vector GetClasses(const extractor::ClassData class_data) const = 0; @@ -103,63 +131,31 @@ class BaseDataFacade virtual std::vector NearestPhantomNodesInRange(const util::Coordinate input_coordinate, - const float max_distance, - const int bearing, - const int bearing_range, - const Approach approach) const = 0; - virtual std::vector - NearestPhantomNodesInRange(const util::Coordinate input_coordinate, - const float max_distance, - const Approach approach) const = 0; + const double max_distance, + const boost::optional bearing, + const Approach approach, + const bool use_all_edges) const = 0; virtual std::vector NearestPhantomNodes(const util::Coordinate input_coordinate, - const unsigned max_results, - const double max_distance, - const int bearing, - const int bearing_range, - const Approach approach) const = 0; - virtual std::vector - NearestPhantomNodes(const util::Coordinate input_coordinate, - const unsigned max_results, - const int bearing, - const int bearing_range, - const Approach approach) const = 0; - virtual std::vector - NearestPhantomNodes(const util::Coordinate input_coordinate, - const unsigned max_results, - const Approach approach) const = 0; - virtual std::vector - NearestPhantomNodes(const util::Coordinate input_coordinate, - const unsigned max_results, - const double max_distance, + const size_t max_results, + const boost::optional max_distance, + const boost::optional bearing, const Approach approach) const = 0; - virtual std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const Approach approach) const = 0; - virtual std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const double max_distance, - const Approach approach) const = 0; - virtual std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const double max_distance, - const int bearing, - const int bearing_range, - const Approach approach) const = 0; - virtual std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const int bearing, - const int bearing_range, - const Approach approach) const = 0; + virtual PhantomCandidateAlternatives + NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, + const boost::optional max_distance, + const boost::optional bearing, + const Approach approach, + const bool use_all_edges) const = 0; - virtual bool HasLaneData(const EdgeID id) const = 0; - virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0; - virtual extractor::guidance::TurnLaneDescription + virtual bool HasLaneData(const EdgeID edge_based_edge_id) const = 0; + virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID edge_based_edge_id) const = 0; + virtual extractor::TurnLaneDescription GetTurnDescription(const LaneDescriptionID lane_description_id) const = 0; - virtual NameID GetNameIndex(const NodeID id) const = 0; + virtual NameID GetNameIndex(const NodeID edge_based_node_id) const = 0; virtual StringView GetNameForID(const NameID id) const = 0; @@ -171,8 +167,6 @@ class BaseDataFacade virtual StringView GetExitsForID(const NameID id) const = 0; - virtual std::string GetTimestamp() const = 0; - virtual bool GetContinueStraightDefault() const = 0; virtual double GetMapMatchingMaxSpeed() const = 0; @@ -183,17 +177,22 @@ class BaseDataFacade virtual double GetWeightMultiplier() const = 0; - virtual util::guidance::TurnBearing PreTurnBearing(const EdgeID eid) const = 0; - virtual util::guidance::TurnBearing PostTurnBearing(const EdgeID eid) const = 0; + virtual osrm::guidance::TurnBearing PreTurnBearing(const EdgeID edge_based_edge_id) const = 0; + virtual osrm::guidance::TurnBearing PostTurnBearing(const EdgeID edge_based_edge_id) const = 0; - virtual util::guidance::BearingClass GetBearingClass(const NodeID node) const = 0; + virtual util::guidance::BearingClass GetBearingClass(const NodeID node_based_node_id) const = 0; - virtual util::guidance::EntryClass GetEntryClass(const EdgeID turn_id) const = 0; + virtual util::guidance::EntryClass GetEntryClass(const EdgeID edge_based_edge_id) const = 0; - virtual bool IsLeftHandDriving() const = 0; + virtual bool IsLeftHandDriving(const NodeID edge_based_node_id) const = 0; + + virtual bool IsSegregated(const NodeID edge_based_node_id) const = 0; + + virtual std::vector + GetOverridesThatStartAt(const NodeID edge_based_node_id) const = 0; }; -} -} -} +} // namespace datafacade +} // namespace engine +} // namespace osrm #endif // DATAFACADE_BASE_HPP diff --git a/include/engine/datafacade/mmap_memory_allocator.hpp b/include/engine/datafacade/mmap_memory_allocator.hpp new file mode 100644 index 000000000..817fcf9db --- /dev/null +++ b/include/engine/datafacade/mmap_memory_allocator.hpp @@ -0,0 +1,44 @@ +#ifndef OSRM_ENGINE_DATAFACADE_MMAP_MEMORY_ALLOCATOR_HPP_ +#define OSRM_ENGINE_DATAFACADE_MMAP_MEMORY_ALLOCATOR_HPP_ + +#include "engine/datafacade/contiguous_block_allocator.hpp" + +#include "storage/storage_config.hpp" + +#include "util/vector_view.hpp" + +#include + +#include +#include + +namespace osrm +{ +namespace engine +{ +namespace datafacade +{ + +/** + * This allocator uses file backed mmap memory block as the data location. + */ +class MMapMemoryAllocator final : public ContiguousBlockAllocator +{ + public: + explicit MMapMemoryAllocator(const storage::StorageConfig &config); + ~MMapMemoryAllocator() override final; + + // interface to give access to the datafacades + const storage::SharedDataIndex &GetIndex() override final; + + private: + storage::SharedDataIndex index; + std::vector mapped_memory_files; + std::string rtree_filename; +}; + +} // namespace datafacade +} // namespace engine +} // namespace osrm + +#endif // OSRM_ENGINE_DATAFACADE_SHARED_MEMORY_ALLOCATOR_HPP_ diff --git a/include/engine/datafacade/process_memory_allocator.hpp b/include/engine/datafacade/process_memory_allocator.hpp index aa41dd6e4..742f20e36 100644 --- a/include/engine/datafacade/process_memory_allocator.hpp +++ b/include/engine/datafacade/process_memory_allocator.hpp @@ -20,19 +20,18 @@ namespace datafacade * This class holds a unique_ptr to the memory block, so it * is auto-freed upon destruction. */ -class ProcessMemoryAllocator : public ContiguousBlockAllocator +class ProcessMemoryAllocator final : public ContiguousBlockAllocator { public: explicit ProcessMemoryAllocator(const storage::StorageConfig &config); ~ProcessMemoryAllocator() override final; // interface to give access to the datafacades - storage::DataLayout &GetLayout() override final; - char *GetMemory() override final; + const storage::SharedDataIndex &GetIndex() override final; private: + storage::SharedDataIndex index; std::unique_ptr internal_memory; - std::unique_ptr internal_layout; }; } // namespace datafacade diff --git a/include/engine/datafacade/shared_memory_allocator.hpp b/include/engine/datafacade/shared_memory_allocator.hpp index 2cef60e19..5b0a0989a 100644 --- a/include/engine/datafacade/shared_memory_allocator.hpp +++ b/include/engine/datafacade/shared_memory_allocator.hpp @@ -3,7 +3,7 @@ #include "engine/datafacade/contiguous_block_allocator.hpp" -#include "storage/shared_datatype.hpp" +#include "storage/shared_data_index.hpp" #include "storage/shared_memory.hpp" #include @@ -16,22 +16,23 @@ namespace datafacade { /** -* This allocator uses an IPC shared memory block as the data location. -* Many SharedMemoryDataFacade objects can be created that point to the same shared -* memory block. -*/ -class SharedMemoryAllocator : public ContiguousBlockAllocator + * This allocator uses an IPC shared memory block as the data location. + * Many SharedMemoryDataFacade objects can be created that point to the same shared + * memory block. + */ +class SharedMemoryAllocator final : public ContiguousBlockAllocator { public: - explicit SharedMemoryAllocator(storage::SharedDataType data_region); + explicit SharedMemoryAllocator( + const std::vector &shm_keys); ~SharedMemoryAllocator() override final; // interface to give access to the datafacades - storage::DataLayout &GetLayout() override final; - char *GetMemory() override final; + const storage::SharedDataIndex &GetIndex() override final; private: - std::unique_ptr m_large_memory; + storage::SharedDataIndex index; + std::vector> memory_regions; }; } // namespace datafacade diff --git a/include/engine/datafacade_factory.hpp b/include/engine/datafacade_factory.hpp index 92efcf7ee..e01c70f72 100644 --- a/include/engine/datafacade_factory.hpp +++ b/include/engine/datafacade_factory.hpp @@ -33,6 +33,7 @@ template