diff --git a/.babelrc b/.babelrc index fd234626aba..21e2dd7fd15 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 de4303bf8db..495e4fc6af4 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,4 +1,101 @@ --- -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, + -bugprone-chained-comparison, + -bugprone-incorrect-enable-if, + -bugprone-switch-missing-default-case, + -bugprone-empty-catch, + -bugprone-unchecked-optional-access, + -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-const-correctness, + -misc-non-private-member-variables-in-classes, + -misc-unconventional-assign-operator, + -misc-no-recursion, + -misc-misplaced-const, + -misc-definitions-in-headers, + -misc-unused-parameters, + -misc-include-cleaner, + modernize-concat-nested-namespaces, + modernize-use-using, + performance-*, + -performance-no-int-to-ptr, + -performance-enum-size, + -performance-avoid-endl, + 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-redundant-inline-specifier, + -readability-avoid-nested-conditional-operator, + -readability-avoid-return-with-void-value, + -readability-redundant-casting, + -readability-static-accessed-through-instance + +WarningsAsErrors: '*' +HeaderFilterRegex: '.*' + diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index d6d517dcc6c..00000000000 --- a/.eslintrc +++ /dev/null @@ -1,28 +0,0 @@ -{ - "rules": { - "indent": [ - 2, - 4 - ], - "quotes": [ - 1, - "single" - ], - "linebreak-style": [ - 2, - "unix" - ], - "semi": [ - 2, - "always" - ], - "no-console": [ - 1 - ] - }, - "env": { - "es6": true, - "node": true - }, - "extends": "eslint:recommended" -} diff --git a/.gitattributes b/.gitattributes index 37ce36f9b89..c426721cb9b 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 00000000000..e223dc636d2 --- /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 00000000000..ea79a1f9053 --- /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/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1d5fbec2d70..a9f0a816063 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,10 +9,10 @@ If your PR is still work in progress please attach the relevant label. - [ ] 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 tests (see [testing documentation](https://github.com/Project-OSRM/osrm-backend/blob/master/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 diff --git a/.github/workflows/osrm-backend-docker.yml b/.github/workflows/osrm-backend-docker.yml new file mode 100644 index 00000000000..499731f90b7 --- /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: + strategy: + matrix: + docker-base-image: ["debian", "alpine"] + 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-${{ matrix.docker-base-image }} + tags: ${{ steps.metadebug.outputs.tags }} + build-args: | + DOCKER_TAG=${{ join(steps.metadebug.outputs.tags ) }}-${{ matrix.docker-base-image }} + + + - name: Build container image - assertions + uses: docker/build-push-action@v2 + with: + push: true + platforms: linux/amd64,linux/arm64 + file: ./docker/Dockerfile-${{ matrix.docker-base-image }} + tags: ${{ steps.metaassertions.outputs.tags }} + build-args: | + DOCKER_TAG=${{ join(steps.metaassertions.outputs.tags ) }}-${{ matrix.docker-base-image }} + + # 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-${{ matrix.docker-base-image }} + tags: ${{ steps.meta.outputs.tags }} + build-args: | + DOCKER_TAG=${{ join(steps.meta.outputs.tags ) }}-${{ matrix.docker-base-image }} diff --git a/.github/workflows/osrm-backend.yml b/.github/workflows/osrm-backend.yml new file mode 100644 index 00000000000..7375b2cf021 --- /dev/null +++ b/.github/workflows/osrm-backend.yml @@ -0,0 +1,608 @@ +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 + CMAKE_VERSION: 3.21.2 + ENABLE_NODE_BINDINGS: "ON" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + conan-windows-release-node: + needs: format-taginfo-docs + runs-on: windows-2025 + continue-on-error: false + env: + BUILD_TYPE: Release + steps: + - uses: actions/checkout@v4 + - run: cmake --version + - uses: actions/setup-node@v4 + with: + node-version: 18 + - 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 + - name: Build + shell: bash + run: | + mkdir build + cd build + + python3 -m venv .venv + source .venv/Scripts/Activate + python3 -m pip install conan==2.15.1 + conan profile detect --force + + cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_CONAN=ON -DENABLE_NODE_BINDINGS=ON .. + cmake --build . --config Release + + # TODO: MSVC goes out of memory when building our tests + # - name: Run tests + # shell: bash + # run: | + # cd build + # cmake --build . --config Release --target tests + # # TODO: run tests + # - name: Run node tests + # shell: bash + # run: | + # ./lib/binding/osrm-extract.exe -p profiles/car.lua test/data/monaco.osm.pbf + + # mkdir -p test/data/ch + # cp test/data/monaco.osrm* test/data/ch/ + # ./lib/binding/osrm-contract.exe test/data/ch/monaco.osrm + + # ./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-22.04 + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + - name: Enable Node.js cache + uses: actions/cache@v4 + 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-15 --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 + npm audit --production + + docker-image-matrix: + strategy: + matrix: + docker-base-image: ["debian", "alpine"] + needs: format-taginfo-docs + runs-on: ubuntu-22.04 + continue-on-error: false + steps: + - name: Check out the repo + uses: actions/checkout@v4 + - name: Enable osm.pbf cache + uses: actions/cache@v4 + 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-${{ matrix.docker-base-image }} . + - 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-matrix: + needs: format-taginfo-docs + strategy: + matrix: + include: + - name: gcc-13-debug-cov + continue-on-error: false + node: 22 + runs-on: ubuntu-24.04 + BUILD_TYPE: Debug + CCOMPILER: gcc-13 + CUCUMBER_TIMEOUT: 20000 + CXXCOMPILER: g++-13 + ENABLE_COVERAGE: ON + + - name: clang-18-debug-asan-ubsan + continue-on-error: false + node: 22 + runs-on: ubuntu-24.04 + BUILD_TYPE: Debug + CCOMPILER: clang-18 + CUCUMBER_TIMEOUT: 20000 + CXXCOMPILER: clang++-18 + ENABLE_SANITIZER: ON + TARGET_ARCH: x86_64-asan-ubsan + OSRM_CONNECTION_RETRIES: 10 + OSRM_CONNECTION_EXP_BACKOFF_COEF: 1.5 + + - name: clang-18-release + continue-on-error: false + node: 22 + runs-on: ubuntu-24.04 + BUILD_TYPE: Release + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 + CUCUMBER_TIMEOUT: 60000 + ENABLE_LTO: OFF + + - name: clang-18-debug + continue-on-error: false + node: + runs-on: ubuntu-24.04 + BUILD_TYPE: Debug + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 + CUCUMBER_TIMEOUT: 60000 + ENABLE_LTO: OFF + + - name: clang-18-debug-clang-tidy + continue-on-error: false + node: 18 + runs-on: ubuntu-24.04 + BUILD_TYPE: Debug + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 + CUCUMBER_TIMEOUT: 60000 + ENABLE_CLANG_TIDY: ON + NODE_PACKAGE_TESTS_ONLY: ON + ENABLE_LTO: OFF + + - name: clang-17-release + continue-on-error: false + node: 18 + runs-on: ubuntu-24.04 + BUILD_TYPE: Release + CCOMPILER: clang-17 + CXXCOMPILER: clang++-17 + CUCUMBER_TIMEOUT: 60000 + ENABLE_LTO: OFF + + - name: clang-16-release + continue-on-error: false + node: 18 + runs-on: ubuntu-24.04 + BUILD_TYPE: Release + CCOMPILER: clang-16 + CXXCOMPILER: clang++-16 + CUCUMBER_TIMEOUT: 60000 + ENABLE_LTO: OFF + + - name: conan-linux-debug-asan-ubsan + continue-on-error: false + node: 18 + runs-on: ubuntu-24.04 + BUILD_TYPE: Release + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 + ENABLE_CONAN: ON + ENABLE_SANITIZER: ON + ENABLE_LTO: OFF + + - name: conan-linux-release + continue-on-error: false + node: 18 + runs-on: ubuntu-24.04 + BUILD_TYPE: Release + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 + ENABLE_CONAN: ON + ENABLE_LTO: OFF + + - name: gcc-14-release + continue-on-error: false + node: 22 + runs-on: ubuntu-24.04 + BUILD_TYPE: Release + CCOMPILER: gcc-14 + CXXCOMPILER: g++-14 + CXXFLAGS: '-Wno-array-bounds -Wno-uninitialized' + + - name: gcc-13-release + continue-on-error: false + node: 22 + runs-on: ubuntu-24.04 + BUILD_TYPE: Release + CCOMPILER: gcc-13 + CXXCOMPILER: g++-13 + CXXFLAGS: '-Wno-array-bounds -Wno-uninitialized' + + - name: gcc-12-release + continue-on-error: false + node: 22 + runs-on: ubuntu-22.04 + BUILD_TYPE: Release + CCOMPILER: gcc-12 + CXXCOMPILER: g++-12 + CXXFLAGS: '-Wno-array-bounds -Wno-uninitialized' + + - name: conan-linux-release-node + build_node_package: true + continue-on-error: false + node: 22 + runs-on: ubuntu-24.04 + BUILD_TYPE: Release + CCOMPILER: clang-16 + CXXCOMPILER: clang++-16 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: conan-linux-debug-node + build_node_package: true + continue-on-error: false + node: 22 + runs-on: ubuntu-24.04 + BUILD_TYPE: Debug + CCOMPILER: clang-16 + CXXCOMPILER: clang++-16 + ENABLE_CONAN: ON + NODE_PACKAGE_TESTS_ONLY: ON + + - name: conan-macos-x64-release-node + build_node_package: true + continue-on-error: true + node: 22 + runs-on: macos-13 # x86_64 + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + + - name: conan-macos-arm64-release-node + build_node_package: true + continue-on-error: true + node: 22 + runs-on: macos-15 # arm64 + BUILD_TYPE: Release + CCOMPILER: clang + CXXCOMPILER: clang++ + CUCUMBER_TIMEOUT: 60000 + ENABLE_ASSERTIONS: ON + ENABLE_CONAN: ON + + name: ${{ matrix.name}} + continue-on-error: ${{ matrix.continue-on-error }} + runs-on: ${{ matrix.runs-on }} + env: + 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 }} + TARGET_ARCH: ${{ matrix.TARGET_ARCH }} + OSRM_CONNECTION_RETRIES: ${{ matrix.OSRM_CONNECTION_RETRIES }} + OSRM_CONNECTION_EXP_BACKOFF_COEF: ${{ matrix.OSRM_CONNECTION_EXP_BACKOFF_COEF }} + ENABLE_LTO: ${{ matrix.ENABLE_LTO }} + steps: + - uses: actions/checkout@v4 + - name: Build machine architecture + run: uname -m + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + - name: Enable Node.js cache + uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Enable compiler cache + uses: actions/cache@v4 + with: + path: ~/.ccache + key: ccache-${{ matrix.name }}-${{ github.sha }} + restore-keys: | + ccache-${{ matrix.name }}- + - name: Enable Conan cache + uses: actions/cache@v4 + with: + path: ~/.conan2 + key: v10-conan-${{ matrix.name }}-${{ github.sha }} + restore-keys: | + v10-conan-${{ matrix.name }}- + - name: Enable test cache + uses: actions/cache@v4 + with: + path: ${{github.workspace}}/test/cache + key: v4-test-${{ matrix.name }}-${{ github.sha }} + restore-keys: | + v4-test-${{ matrix.name }}- + - name: Prepare environment + run: | + echo "CCACHE_DIR=$HOME/.ccache" >> $GITHUB_ENV + mkdir -p $HOME/.ccache + + 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 + echo "ASAN_OPTIONS=print_suppressions=0:suppressions=${GITHUB_WORKSPACE}/scripts/ci/addresssanitizer.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 + # See: https://github.com/actions/toolkit/issues/946#issuecomment-1590016041 + # We need it to be able to access system folders while restoring cached Boost below + - name: Give tar root ownership + if: runner.os == 'Linux' && matrix.ENABLE_CONAN != 'ON' + run: sudo chown root /bin/tar && sudo chmod u+s /bin/tar + + - name: Install boost + if: ${{ matrix.ENABLE_CONAN != 'ON' }} + uses: MarkusJx/install-boost@v2 + id: install-boost + with: + boost_version: 1.85.0 + + - name: Install dev dependencies + run: | + # workaround for issue that GitHub Actions seems to not adding it to PATH after https://github.com/actions/runner-images/pull/6499 + # and that's why CI cannot find conan executable installed above + if [[ "${RUNNER_OS}" == "macOS" ]]; then + echo "/Library/Frameworks/Python.framework/Versions/Current/bin" >> $GITHUB_PATH + fi + + # 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 + + # Linux dev packages + if [ "${ENABLE_CONAN}" != "ON" ]; then + sudo apt-get update -y + sudo apt-get install -y libbz2-dev libxml2-dev libzip-dev liblua5.2-dev + if [[ "${CCOMPILER}" != clang-* ]]; then + sudo apt-get install -y ${CXXCOMPILER} + fi + if [[ "${ENABLE_COVERAGE}" == "ON" ]]; then + sudo apt-get install -y lcov + fi + fi + + # TBB + TBB_VERSION=2021.12.0 + if [[ "${RUNNER_OS}" == "Linux" ]]; then + TBB_URL="https://github.com/oneapi-src/oneTBB/releases/download/v$%7BTBB_VERSION%7D/oneapi-tbb-$%7BTBB_VERSION%7D-lin.tgz" + elif [[ "${RUNNER_OS}" == "macOS" ]]; then + TBB_URL="https://github.com/oneapi-src/oneTBB/releases/download/v$%7BTBB_VERSION%7D/oneapi-tbb-$%7BTBB_VERSION%7D-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 + if [[ "${RUNNER_OS}" == "macOS" ]]; then + # missing from GCC path, needed for conan builds of libiconv, for example. + sudo xcode-select --switch /Library/Developer/CommandLineTools + echo "LIBRARY_PATH=${LIBRARY_PATH}:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib" >> $GITHUB_ENV + echo "CPATH=${CPATH}:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include" >> $GITHUB_ENV + fi + + - name: Build and install OSRM + run: | + echo "Using ${JOBS} jobs" + pushd ${OSRM_BUILD_DIR} + + if [[ "${ENABLE_CONAN}" == "ON" ]]; then + python3 -m venv .venv + source .venv/bin/activate + python3 -m pip install conan==2.15.1 + conan profile detect --force + fi + + ccache --zero-stats + 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} \ + -DENABLE_CCACHE=ON \ + -DENABLE_LTO=${ENABLE_LTO:-ON} \ + -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} + + make --jobs=${JOBS} + + if [[ "${NODE_PACKAGE_TESTS_ONLY}" != "ON" ]]; then + make tests --jobs=${JOBS} + make benchmarks --jobs=${JOBS} + + 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 + env: + Boost_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }} + - name: Run all tests + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY != '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 }} + + # 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}" ]; then + npm run nodejs-tests + fi + popd + npm test + + - name: Use Node 18 + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' }} + uses: actions/setup-node@v4 + with: + node-version: 18 + - name: Run Node package tests on Node 18 + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' }} + run: | + node --version + npm run nodejs-tests + - name: Use Node 22 + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' }} + uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Run Node package tests on Node 22 + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' }} + run: | + node --version + npm run nodejs-tests + - name: Use Node latest + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' }} + uses: actions/setup-node@v4 + with: + node-version: latest + - name: Run Node package tests on Node-latest + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' }} + run: | + node --version + npm run nodejs-tests + + - name: Upload test logs + uses: actions/upload-artifact@v4 + if: failure() + with: + name: logs + path: test/logs/ + + - 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 }} + - name: Show CCache statistics + run: | + ccache -p + ccache -s + + ci-complete: + runs-on: ubuntu-latest + needs: [build-matrix, conan-windows-release-node, docker-image-matrix] + steps: + - run: echo "CI complete" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000000..5a31f5f6db2 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,29 @@ +name: 'Close stale issues' +on: + # NOTE: uncomment if you want to test changes to this file in PRs CI + # pull_request: + # branches: + # - master + schedule: + - cron: '30 1 * * *' # every day at 1:30am +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-24.04 + steps: + - uses: actions/stale@v9 + with: + operations-per-run: 3000 + stale-issue-message: 'This issue seems to be stale. It will be closed in 30 days if no further activity occurs.' + stale-pr-message: 'This PR seems to be stale. Is it still relevant?' + days-before-issue-stale: 180 # 6 months + days-before-issue-close: 30 # 1 month + days-before-pr-stale: 180 # 6 months + days-before-pr-close: -1 # never close PRs + exempt-issue-labels: 'Do Not Stale,Feature Request,Performance,Bug Report,CI,Starter Task,Refactor,Guidance' + + + diff --git a/.gitignore b/.gitignore index 69b0c2afcd8..a98ae2b44c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ -# mason # -######### -/.mason -/mason_packages - # pre compiled dependencies # ############################# osrm-deps @@ -48,10 +43,8 @@ Thumbs.db ####################### /_build* /build/ -/example/build/ -/test/data/monaco* +/test/data/monaco.osrm* /test/data/ch -/test/data/corech /test/data/mld /cmake/postinst @@ -67,17 +60,12 @@ Thumbs.db /.vs* /*.local.bat /CMakeSettings.json +/.cache # Jetbrains related files # ########################### .idea/ -# stxxl related files # -####################### -.stxxl -stxxl.log -stxxl.errlog - # Compiled Binary Files # #################################### /osrm-extract @@ -115,3 +103,4 @@ debug.lua # node-osrm artifacts lib/binding + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 91e8ce14cde..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,520 +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: - npm: 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="10" - -stages: - - core - - optional - -matrix: - fast_finish: true - - # We override the compiler names here to yield better ccache behavior, which uses this as key - include: - - # Debug Builds - - stage: core - os: linux - compiler: "format-taginfo-docs" - env: NODE=10 - sudo: false - before_install: - install: - - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash - - source $NVM_DIR/nvm.sh - - nvm install $NODE - - nvm use $NODE - - npm --version - - npm ci --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 - - node ./scripts/validate_changelog.js - # See issue 4043 - #- npm run docs && ./scripts/error_on_dirty.sh - after_success: - - - os: linux - compiler: "gcc-7-debug-cov" - addons: &gcc7 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-7', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev', 'lcov'] - env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Debug' ENABLE_COVERAGE=ON CUCUMBER_TIMEOUT=20000 - before_script: - - cd ${TRAVIS_BUILD_DIR} - - lcov --directory . --zerocounters # clean cached da files - after_success: - # Creating report - - cd ${TRAVIS_BUILD_DIR} - - 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 - - bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports" - - - os: linux - compiler: "gcc-7-debug-asan" - addons: &gcc7 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-7', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Debug' TARGET_ARCH='x86_64-asan' ENABLE_SANITIZER=ON CUCUMBER_TIMEOUT=20000 LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/scripts/travis/leaksanitizer.conf" - - - os: linux - compiler: "clang-5.0-debug" - addons: &clang50 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-5-dev', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' CUCUMBER_TIMEOUT=60000 - - - os: linux - compiler: "mason-linux-debug-asan" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_SANITIZER=ON LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/scripts/travis/leaksanitizer.conf" - - # Release Builds - - os: linux - compiler: "mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON RUN_CLANG_FORMAT=ON ENABLE_LTO=ON - - - os: linux - compiler: "gcc-8-release" - addons: &gcc8 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-8', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-8' CXXCOMPILER='g++-8' BUILD_TYPE='Release' CXXFLAGS='-Wno-cast-function-type' - - - os: linux - compiler: "gcc-7-release" - addons: &gcc7 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-7', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Release' - - - os: linux - compiler: "gcc-7-release-i686" - env: > - TARGET_ARCH='i686' CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Release' - CFLAGS='-m32 -msse2 -mfpmath=sse' CXXFLAGS='-m32 -msse2 -mfpmath=sse' - - - os: linux - compiler: "gcc-7-stxxl" - addons: &gcc7 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-7', 'libbz2-dev', 'libstxxl-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Release' ENABLE_STXXL=On - - - os: linux - compiler: "gcc-5-release" - addons: &gcc49 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-5', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev', 'ccache'] - env: CCOMPILER='gcc-5' CXXCOMPILER='g++-5' BUILD_TYPE='Release' - - - os: linux - compiler: "gcc-6-release" - addons: &gcc49 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev', 'ccache'] - env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release' - - - os: osx - osx_image: xcode9.2 - compiler: "mason-osx-release-node-10" - # we use the xcode provides clang and don't install our own - env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="10" - after_success: - - ./scripts/travis/publish.sh - - - os: osx - osx_image: xcode9.2 - compiler: "mason-osx-release-node-8" - # we use the xcode provides clang and don't install our own - env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="8" - after_success: - - ./scripts/travis/publish.sh - - # Shared Library - - os: linux - compiler: "gcc-7-release-shared" - addons: &gcc7 - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-7', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev'] - env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON - - # Node build jobs. These skip running the tests. - - os: linux - sudo: false - compiler: "node-8-mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="8" - install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ - -DENABLE_GLIBC_WORKAROUND=ON - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-8-mason-linux-debug" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="8" - install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ - -DENABLE_GLIBC_WORKAROUND=ON - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-10-mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="10" - install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ - -DENABLE_GLIBC_WORKAROUND=ON - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-10-mason-linux-debug" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="10" - install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ - -DENABLE_GLIBC_WORKAROUND=ON - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: osx - stage: optional - osx_image: xcode9.2 - compiler: "mason-osx-release-node-latest" - # we use the xcode provides clang and don't install our own - env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="node" - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-latest-mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="node" - install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ - -DENABLE_GLIBC_WORKAROUND=ON - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-latest-mason-linux-debug" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="node" - install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ - -DENABLE_GLIBC_WORKAROUND=ON - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: osx - osx_image: xcode9.2 - compiler: "mason-osx-release-node-lts" - # we use the xcode provides clang and don't install our own - env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="--lts" - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-lts-mason-linux-release" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="--lts" - install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ - -DENABLE_GLIBC_WORKAROUND=ON - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - - os: linux - sudo: false - compiler: "node-lts-mason-linux-debug" - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['libstdc++-4.9-dev'] - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="--lts" - install: - - pushd ${OSRM_BUILD_DIR} - - | - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ - -DENABLE_MASON=${ENABLE_MASON:-OFF} \ - -DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \ - -DENABLE_CCACHE=ON \ - -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \ - -DENABLE_GLIBC_WORKAROUND=ON - - make --jobs=${JOBS} - - popd - script: - - npm run nodejs-tests - after_success: - - ./scripts/travis/publish.sh - - allow_failures: - - compiler: "mason-osx-release-node-latest" - env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="node" - - compiler: "node-latest-mason-linux-release" - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="node" - - compiler: "node-latest-mason-linux-debug" - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="node" - - compiler: "mason-osx-release-node-lts" - env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="--lts" - - compiler: "node-lts-mason-linux-release" - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="--lts" - - compiler: "node-lts-mason-linux-debug" - env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="--lts" - -before_install: - - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash - - source $NVM_DIR/nvm.sh - - nvm install $NODE - - nvm use $NODE - - 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 - - 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" - - npm ci --ignore-scripts - # Bootstrap cmake to be able to run mason - - CMAKE_URL="https://mason-binaries.s3.amazonaws.com/$%7BTRAVIS_OS_NAME%7D-x86_64/cmake/$%7BCMAKE_VERSION%7D.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} \ - -DENABLE_GLIBC_WORKAROUND=${ENABLE_GLIBC_WORKAROUND:-OFF} - - 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/mld/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/partitioner-tests - - | - if [ -z "${ENABLE_SANITIZER}" ] && [ "$TARGET_ARCH" != "i686" ]; then - npm run nodejs-tests - fi - - | - - popd - - npm test diff --git a/CHANGELOG.md b/CHANGELOG.md index baee7fcf5a8..e97f8cc878c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,288 @@ # Unreleased - - Changes from 5.21.0 + - Changes from 6.0.0 + +# 6.0.0 + - Changes from 6.0.0 RC2: None + +# 6.0.0 RC2 + - Changes from 6.0.0 RC1 - Build: - - ADDED: optionally build Node `lts` and `latest` bindings [#5347](https://github.com/Project-OSRM/osrm-backend/pull/5347) + - CHANGED: Updated Conan to v2.15.0 [#7148](https://github.com/Project-OSRM/osrm-backend/pull/7148) + - CHANGED: Back to installing header files and lib [#7140](https://github.com/Project-OSRM/osrm-backend/pull/7140) + - Misc: + - CHANGED: Updated documentation library [#6677](https://github.com/Project-OSRM/osrm-backend/pull/6677) + +# 6.0.0 RC1 + - Changes from 5.27.1 + - Features + - ADDED: Add generic support for obstacles [#7130](https://github.com/Project-OSRM/osrm-backend/pull/7130) + - ADDED: Route pedestrians over highway=platform [#6993](https://github.com/Project-OSRM/osrm-backend/pull/6993) + - REMOVED: Remove all core-CH left-overs [#6920](https://github.com/Project-OSRM/osrm-backend/pull/6920) + - ADDED: Add support for a keepalive_timeout flag. [#6674](https://github.com/Project-OSRM/osrm-backend/pull/6674) + - ADDED: Add support for a default_radius flag. [#6575](https://github.com/Project-OSRM/osrm-backend/pull/6575) + - ADDED: Add support for disabling feature datasets. [#6666](https://github.com/Project-OSRM/osrm-backend/pull/6666) + - ADDED: Add support for opposite approach request parameter. [#6842](https://github.com/Project-OSRM/osrm-backend/pull/6842) + - ADDED: Add support for accessing edge flags in `process_segment` [#6658](https://github.com/Project-OSRM/osrm-backend/pull/6658) + - Build: + - CHANGED: Fix compilation with upcoming Boost 1.87.0 [#7073](https://github.com/Project-OSRM/osrm-backend/pull/7073) + - CHANGED: Upgrade clang-format to version 15. [#6919](https://github.com/Project-OSRM/osrm-backend/pull/6919) + - CHANGED: Use Debian Bookworm as base Docker image [#6904](https://github.com/Project-OSRM/osrm-backend/pull/6904) + - CHANGED: Upgrade CI actions to latest versions [#6893](https://github.com/Project-OSRM/osrm-backend/pull/6893) + - CHANGED: Remove outdated warnings #6894 [#6894](https://github.com/Project-OSRM/osrm-backend/pull/6894) + - ADDED: Add CI job which builds OSRM with gcc 12. [#6455](https://github.com/Project-OSRM/osrm-backend/pull/6455) + - CHANGED: Upgrade to clang-tidy 15. [#6439](https://github.com/Project-OSRM/osrm-backend/pull/6439) + - CHANGED: Update actions/cache to v3. [#6420](https://github.com/Project-OSRM/osrm-backend/pull/6420) + - REMOVED: Drop support of Node 12 & 14. [#6431](https://github.com/Project-OSRM/osrm-backend/pull/6431) + - ADDED: Add 'load directly' mode to default Cucumber test suite. [#6663](https://github.com/Project-OSRM/osrm-backend/pull/6663) + - CHANGED: Fix compilation for Boost 1.85.0 [#6856](https://github.com/Project-OSRM/osrm-backend/pull/6856) + - CHANGED: Drop support for Node 16 [#6855](https://github.com/Project-OSRM/osrm-backend/pull/6855) + - REMOVED: Remove unused AppVeyor files [#6860](https://github.com/Project-OSRM/osrm-backend/pull/6860) + - CHANGED: Upgrade clang-format to version 15 [#6859](https://github.com/Project-OSRM/osrm-backend/pull/6859) + - NodeJS: + - CHANGED: Use node-api instead of NAN. [#6452](https://github.com/Project-OSRM/osrm-backend/pull/6452) + - Misc: + - CHANGED: Migrate to Conan 2.x. [#7042](https://github.com/Project-OSRM/osrm-backend/pull/7042) + - CHANGED: Use std::string_view for key type in json::Object. [#7062](https://github.com/Project-OSRM/osrm-backend/pull/7062) + - CHANGED: Use thread_local instead of boost::thread_specific_ptr. [#6991](https://github.com/Project-OSRM/osrm-backend/pull/6991) + - CHANGED: Bump flatbuffers to v24.3.25 version. [#6988](https://github.com/Project-OSRM/osrm-backend/pull/6988) + - CHANGED: Add .reserve(...) to assembleGeometry function. [#6983](https://github.com/Project-OSRM/osrm-backend/pull/6983) + - CHANGED: Get rid of boost::optional leftovers. [#6977](https://github.com/Project-OSRM/osrm-backend/pull/6977) + - CHANGED: Use Link Time Optimisation whenever possible. [#6967](https://github.com/Project-OSRM/osrm-backend/pull/6967) + - CHANGED: Use struct instead of tuple to define UnpackedPath. [#6974](https://github.com/Project-OSRM/osrm-backend/pull/6974) + - CHANGED: Micro performance optimisation in map matching. [#6976](https://github.com/Project-OSRM/osrm-backend/pull/6976) + - CHANGED: Re-use priority queue in StaticRTree. [#6952](https://github.com/Project-OSRM/osrm-backend/pull/6952) + - CHANGED: Optimise encodePolyline function. [#6940](https://github.com/Project-OSRM/osrm-backend/pull/6940) + - CHANGED: Avoid reallocations in base64 encoding. [#6951](https://github.com/Project-OSRM/osrm-backend/pull/6951) + - CHANGED: Get rid of unused Boost dependencies. [#6960](https://github.com/Project-OSRM/osrm-backend/pull/6960) + - CHANGED: Apply micro-optimisation for Table & Trip APIs. [#6949](https://github.com/Project-OSRM/osrm-backend/pull/6949) + - CHANGED: Apply micro-optimisation for Route API. [#6948](https://github.com/Project-OSRM/osrm-backend/pull/6948) + - CHANGED: Apply micro-optimisation for Match API. [#6945](https://github.com/Project-OSRM/osrm-backend/pull/6945) + - CHANGED: Apply micro-optimisation for Nearest API. [#6944](https://github.com/Project-OSRM/osrm-backend/pull/6944) + - CHANGED: Avoid copy of intersection in totalTurnAngle. [#6938](https://github.com/Project-OSRM/osrm-backend/pull/6938) + - CHANGED: Use std::unordered_map::emplace instead of operator[] when producing JSONs. [#6936](https://github.com/Project-OSRM/osrm-backend/pull/6936) + - CHANGED: Avoid copy of vectors in MakeRoute function. [#6939](https://github.com/Project-OSRM/osrm-backend/pull/6939) + - FIXED: Fix bugprone-unused-return-value clang-tidy warning. [#6934](https://github.com/Project-OSRM/osrm-backend/pull/6934) + - FIXED: Fix performance-noexcept-move-constructor clang-tidy warning. [#6931](https://github.com/Project-OSRM/osrm-backend/pull/6933) + - FIXED: Fix performance-noexcept-swap clang-tidy warning. [#6931](https://github.com/Project-OSRM/osrm-backend/pull/6931) + - CHANGED: Use custom struct instead of std::pair in QueryHeap. [#6921](https://github.com/Project-OSRM/osrm-backend/pull/6921) + - CHANGED: Use std::string_view::starts_with instead of boost::starts_with. [#6918](https://github.com/Project-OSRM/osrm-backend/pull/6918) + - CHANGED: Get rid of boost::math::constants::* and M_PI in favor of std::numbers. [#6916](https://github.com/Project-OSRM/osrm-backend/pull/6916) + - CHANGED: Make constants in PackedVector constexpr. [#6917](https://github.com/Project-OSRM/osrm-backend/pull/6917) + - CHANGED: Use std::variant instead of mapbox::util::variant. [#6903](https://github.com/Project-OSRM/osrm-backend/pull/6903) + - CHANGED: Bump rapidjson to version f9d53419e912910fd8fa57d5705fa41425428c35 [#6906](https://github.com/Project-OSRM/osrm-backend/pull/6906) + - CHANGED: Bump mapbox/variant to version 1.2.0 [#6898](https://github.com/Project-OSRM/osrm-backend/pull/6898) + - CHANGED: Avoid copy of std::function-based callback in path unpacking [#6895](https://github.com/Project-OSRM/osrm-backend/pull/6895) + - CHANGED: Replace boost::hash by std::hash [#6892](https://github.com/Project-OSRM/osrm-backend/pull/6892) + - CHANGED: Partial fix migration from boost::optional to std::optional [#6551](https://github.com/Project-OSRM/osrm-backend/issues/6551) + - CHANGED: Replace boost::filesystem with std::filesystem [#6432](https://github.com/Project-OSRM/osrm-backend/pull/6432) + - CHANGED: Update Conan Boost version to 1.85.0. [#6868](https://github.com/Project-OSRM/osrm-backend/pull/6868) + - FIXED: Fix an error in a RouteParameters AnnotationsType operator overload. [#6646](https://github.com/Project-OSRM/osrm-backend/pull/6646) + - ADDED: Add support for "unlimited" to be passed as a value for the default-radius and max-matching-radius flags. [#6599](https://github.com/Project-OSRM/osrm-backend/pull/6599) + - CHANGED: Allow -1.0 as unlimited for default_radius value. [#6599](https://github.com/Project-OSRM/osrm-backend/pull/6599) + - CHANGED: keep libosrm* in the docker image for downstream linking [#6602](https://github.com/Project-OSRM/osrm-backend/pull/6602) + - CHANGED: Move vector in CSVFilesParser instead copying it. [#6470](https://github.com/Project-OSRM/osrm-backend/pull/6470) + - REMOVED: Get rid of unused functions in util/json_util.hpp. [#6446](https://github.com/Project-OSRM/osrm-backend/pull/6446) + - FIXED: Apply workaround for Conan installation issue on CI. [#6442](https://github.com/Project-OSRM/osrm-backend/pull/6442) + - FIXED: Fix `npm audit` warnings in NPM package. [#6437](https://github.com/Project-OSRM/osrm-backend/pull/6437) + - 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) + - CHANGED: Make edge metrics strongly typed [#6420](https://github.com/Project-OSRM/osrm-backend/pull/6420) + - FIXED: Typo in file name src/util/timed_historgram.cpp -> src/util/timed_histogram.cpp [#6428](https://github.com/Project-OSRM/osrm-backend/issues/6428) + - CHANGED: Replace boost::string_ref with std::string_view [#6433](https://github.com/Project-OSRM/osrm-backend/pull/6433) + - ADDED: Print tracebacks for Lua runtime errors [#6564](https://github.com/Project-OSRM/osrm-backend/pull/6564) + - FIXED: Added a variable to preprocessor guard in file osrm-backend/include/util/range_table.hpp to solve build error. [#6596](https://github.com/Project-OSRM/osrm-backend/pull/6596) + - FIXED: Ensure required file check in osrm-routed is correctly enforced. [#6655](https://github.com/Project-OSRM/osrm-backend/pull/6655) + - FIXED: Correct HTTP docs to reflect summary output dependency on steps parameter. [#6655](https://github.com/Project-OSRM/osrm-backend/pull/6655) + - ADDED: Extract prerelease/build information from package semver [#6839](https://github.com/Project-OSRM/osrm-backend/pull/6839) + - FIXED: Segfault in `UnresolvedManeuverOverride::Turns()` on Australia extracts [#7112](https://github.com/Project-OSRM/osrm-backend/pull/7112) + - CHANGED: Replaced PL:trunk with PL:expressway to match the latest changes in Polish tagging [#7079](https://github.com/Project-OSRM/osrm-backend/pull/7079) + - FIXED: Remove unused C++ headers [#7105](https://github.com/Project-OSRM/osrm-backend/pull/7105) + - Profiles: + - FIXED: Bicycle and foot profiles now don't route on proposed ways [#6615](https://github.com/Project-OSRM/osrm-backend/pull/6615) + - ADDED: Add optional support of cargo bike exclusion and width to bicyle profile [#7044](https://github.com/Project-OSRM/osrm-backend/pull/7044) + - Routing: + - FIXED: Fix adding traffic signal penalties during compression [#6419](https://github.com/Project-OSRM/osrm-backend/pull/6419) + - FIXED: Correctly handle compressed traffic signals. [#6724](https://github.com/Project-OSRM/osrm-backend/pull/6724) + - FIXED: Fix bug when searching for maneuver overrides [#6739](https://github.com/Project-OSRM/osrm-backend/pull/6739) + - FIXED: Remove force-loop checks for routes with u-turns [#6858](https://github.com/Project-OSRM/osrm-backend/pull/6858) + - FIXED: Correctly check runtime search conditions for forcing routing steps [#6866](https://github.com/Project-OSRM/osrm-backend/pull/6866) + - Map Matching: + - CHANGED: Optimise path distance calculation in MLD map matching even more. [#6884](https://github.com/Project-OSRM/osrm-backend/pull/6884) + - CHANGED: Optimise path distance calculation in MLD map matching. [#6876](https://github.com/Project-OSRM/osrm-backend/pull/6876) + - CHANGED: Optimise R-tree queries in the case of map matching. [#6881](https://github.com/Project-OSRM/osrm-backend/pull/6876) + - Debug tiles: + - FIXED: Ensure speed layer features have unique ids. [#6726](https://github.com/Project-OSRM/osrm-backend/pull/6726) + +# 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: + - 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 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) - 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 @@ -57,7 +329,7 @@ ](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] + - 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: diff --git a/CMakeLists.txt b/CMakeLists.txt index e1767b961d9..15447a31c9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,8 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.18) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR AND NOT MSVC_IDE) message(FATAL_ERROR "In-source builds are not allowed. @@ -18,59 +22,90 @@ 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_CCACHE "Speed up incremental rebuilds via ccache" ON) -option(BUILD_TOOLS "Build OSRM tools" OFF) option(BUILD_PACKAGE "Build OSRM package" OFF) option(ENABLE_ASSERTIONS "Use assertions in release mode" OFF) +option(ENABLE_CCACHE "Speed up incremental rebuilds via ccache" ON) +option(ENABLE_CLANG_TIDY "Enables clang-tidy checks" OFF) +option(ENABLE_CONAN "Use conan for dependencies" 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_DEBUG_LOGGING "Use debug logging in release mode" OFF) option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF) -option(ENABLE_GOLD_LINKER "Use GNU gold linker if available" ON) +option(ENABLE_LTO "Use Link Time Optimisation" ON) option(ENABLE_NODE_BINDINGS "Build NodeJs bindings" OFF) -option(ENABLE_GLIBC_WORKAROUND "Workaround GLIBC symbol exports" OFF) +option(ENABLE_SANITIZER "Use memory sanitizer for Debug build" OFF) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +if (ENABLE_CONAN) + message(STATUS "Installing Conan packages. It may take a while...") + find_program(CONAN_EXECUTABLE NAMES conan) + + if (NOT CONAN_EXECUTABLE) + message(FATAL_ERROR "Conan not found! Please install Conan 2.x and try again.") + else() + set(CMAKE_TOOLCHAIN_FILE "./conan_toolchain.cmake") + + execute_process( + COMMAND ${CONAN_EXECUTABLE} install .. --output-folder=. --build=missing --settings compiler.cppstd=20 --settings build_type=${CMAKE_BUILD_TYPE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + OUTPUT_VARIABLE conan_stdout + ERROR_VARIABLE conan_stderr + RESULT_VARIABLE conan_install_result + ) + + if (NOT conan_install_result EQUAL 0) + message(FATAL_ERROR "Conan install failed: ${conan_install_result}. Stderr: ${conan_stderr}. Stdout: ${conan_stdout}") + endif() + endif() +endif() -if(ENABLE_MASON) - # versions in use - set(MASON_BOOST_VERSION "1.65.1") - 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") +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=*;--header-filter=.*") + endif() +endif() - message(STATUS "Enabling mason") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - find_program(CURL_FOUND curl) - if(NOT CURL_FOUND) - message(FATAL_ERROR "curl command required with -DENABLE_MASON") - endif() +project(OSRM C CXX) - include(mason) +if(ENABLE_LTO AND (CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)) + include(CheckIPOSupported) + check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT error) + if(LTO_SUPPORTED) + message(STATUS "IPO / LTO enabled") + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + else() + message(FATAL_ERROR "IPO / LTO not supported: <${error}>") + endif() endif() -# be compatible with version handling before cmake 3.x -if (POLICY CMP0048) - cmake_policy(SET CMP0048 OLD) +# 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() -project(OSRM C CXX) 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}) +# This regex is not strict enough, but the correct one is too complicated for cmake matching. +# https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string +if (packagejson.version MATCHES "^([0-9]+)\.([0-9]+)\.([0-9]+)([-+][0-9a-zA-Z.-]+)?$") + set(OSRM_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(OSRM_VERSION_MINOR ${CMAKE_MATCH_2}) + set(OSRM_VERSION_PATCH ${CMAKE_MATCH_3}) + set(OSRM_VERSION_PRERELEASE_BUILD ${CMAKE_MATCH_4}) - set(OSRM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}") + set(OSRM_VERSION packagejson.version) else() - message(FATAL_ERROR "Version from package.json cannot be parsed, expected semver compatible X.Y.Z, but found ${packagejson.version}") + message(FATAL_ERROR "Version from package.json cannot be parsed, expected semver compatible label, but found ${packagejson.version}") endif() if (MSVC) @@ -102,35 +137,12 @@ include(CheckCXXCompilerFlag) include(FindPackageHandleStandardArgs) include(GNUInstallDirs) -set(bitness 32) -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(bitness 64) - message(STATUS "Building on a 64 bit system") -else() - message(STATUS "Building on a 32 bit system") -endif() - -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>=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 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) - message(FATAL_ERROR "Clang>=3.4 required. In case you are on Ubuntu upgrade via http://apt.llvm.org") - endif() -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/variant/include) +include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/generated/include/) +include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/sol2/include) -set(BOOST_COMPONENTS date_time chrono filesystem iostreams program_options regex system thread unit_test_framework) +set(BOOST_COMPONENTS date_time iostreams program_options thread unit_test_framework) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/include/util/version.hpp.in @@ -146,7 +158,6 @@ file(GLOB UpdaterGlob src/updater/*.cpp) file(GLOB StorageGlob src/storage/*.cpp) file(GLOB ServerGlob src/server/*.cpp src/server/**/*.cpp) file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp) -file(GLOB ErrorcodesGlob src/osrm/errorcodes.cpp) add_library(UTIL OBJECT ${UtilGlob}) add_library(EXTRACTOR OBJECT ${ExtractorGlob}) @@ -161,11 +172,11 @@ add_library(SERVER OBJECT ${ServerGlob}) set_target_properties(UTIL PROPERTIES LINKER_LANGUAGE CXX) +add_executable(osrm-routed src/tools/routed.cpp $ $) 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_library(osrm_contract src/osrm/contractor.cpp $ $) @@ -176,33 +187,6 @@ 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(OSRM_LDFLAGS "${OSRM_LDFLAGS} -fuse-ld=gold -Wl,--disable-new-dtags") - message(STATUS "Using GNU gold as linker.") - - # Issue 2785: check gold binutils version and don't use gc-sections for versions prior 2.25 - string(REGEX REPLACE ".*\\(GNU Binutils[^\\)0-9]+([0-9]+\\.[0-9]+)[^\\)]*\\).*" "\\1" GOLD_BINUTILS_VERSION "${LD_VERSION}") - if ("${GOLD_BINUTILS_VERSION}" VERSION_LESS "2.26") - message(STATUS "Disabling gc-sections on gold binutils < 2.26, see: https://sourceware.org/bugzilla/show_bug.cgi?id=17639") - set(LD_AVOID_GC_SECTIONS TRUE) - endif() - else() - message(WARNING "GNU gold linker isn't available.") - set(ENABLE_GOLD_LINKER OFF) - 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. @@ -227,6 +211,7 @@ endif() if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) message(STATUS "Configuring debug mode flags") set(ENABLE_ASSERTIONS ON) + set(ENABLE_DEBUG_LOGGING ON) endif() if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") @@ -239,95 +224,30 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 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 - check_cxx_compiler_flag("-Wl,-flto" LTO_AVAILABLE) - - if(ENABLE_LTO AND LTO_AVAILABLE) - set(OLD_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - # GCC in addition allows parallelizing LTO - if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - include(ProcessorCount) - ProcessorCount(NPROC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=${NPROC}") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") - endif() - set(CHECK_LTO_SRC "int main(){return 0;}") - check_cxx_source_compiles("${CHECK_LTO_SRC}" LTO_WORKS) - if(LTO_WORKS) - message(STATUS "LTO working") - set(OSRM_CXXFLAGS "${OSRM_CXXFLAGS} -flto") - set(OSRM_LDFLAGS "${OSRM_LDFLAGS} -flto") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -flto") - else() - message(STATUS "LTO broken") - set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}") - set(ENABLE_LTO Off) - endif() - - # Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools - if(CMAKE_CXX_COMPILER_ID 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") - message(WARNING "GCC specific binutils not found. In case of linker issues export env vars: AR=gcc-ar, NM=gcc-nm, RANLIB=gcc-ranlib") - else() - message(STATUS "Using GCC specific binutils for LTO:") - message(STATUS " ${GCC_AR}") - message(STATUS " ${GCC_RANLIB}") - set(CMAKE_AR ${GCC_AR}) - set(CMAKE_RANLIB ${GCC_RANLIB}) - endif() - endif() - - # Same for clang LTO requires their own toolchain - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - find_program(LLVM_AR llvm-ar) - find_program(LLVM_RANLIB llvm-ranlib) - if ("${LLVM_AR}" STREQUAL "LLVM_AR-NOTFOUND" OR "${LLVM_RANLIB}" STREQUAL "LLVM_RANLIB-NOTFOUND") - message(WARNING "LLVM specific binutils not found.") - else() - message(STATUS "Using LLVM specific binutils for LTO:") - message(STATUS " ${LLVM_AR}") - message(STATUS " ${LLVM_RANLIB}") - set(CMAKE_AR ${LLVM_AR}) - set(CMAKE_RANLIB ${LLVM_RANLIB}) - endif() - endif() - 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") -endif() - set(MAYBE_COVERAGE_LIBRARIES "") if (ENABLE_COVERAGE) if (NOT CMAKE_BUILD_TYPE MATCHES "Debug") - message(ERROR "ENABLE_COVERAGE=ON only make sense with a Debug build") + message(ERROR "ENABLE_COVERAGE=ON only makes sense with a Debug build") endif() message(STATUS "Enabling coverage") set(MAYBE_COVERAGE_LIBRARIES "-lgcov") 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 -set(OSRM_WARNING_FLAGS "-Werror=all -Werror=extra -Werror=uninitialized -Werror=unreachable-code -Werror=unused-variable -Werror=unreachable-code -Wno-error=cpp -Wpedantic") +include(cmake/warnings.cmake) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OSRM_WARNING_FLAGS} -Werror=strict-overflow=2 -Wno-error=unused-local-typedef -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) @@ -335,85 +255,33 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(COLOR_FLAG "") endif() # using GCC - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OSRM_WARNING_FLAGS} -Werror=strict-overflow=1 -Wno-error=maybe-uninitialized -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) endif() - - # -fpermissive is required for parallel_do Intel TBB internal issue with GCC < 5 - # https://github.com/Project-OSRM/osrm-backend/pull/3603#issuecomment-277688589 - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) - message(STATUS "Adding -fpermissive for GCC version < 5 bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51048). See #3603.") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") - endif() - elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") # using Intel C++ 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) add_dependency_defines(-D_CRT_SECURE_NO_WARNINGS) add_dependency_defines(-DNOMINMAX) # avoid min and max macros that can break compilation - add_dependency_defines(-D_USE_MATH_DEFINES) #needed for M_PI with cmath.h add_dependency_defines(-D_WIN32_WINNT=0x0501) add_dependency_defines(-DXML_STATIC) find_library(ws2_32_LIBRARY_PATH ws2_32) target_link_libraries(osrm-extract wsock32 ws2_32) endif() -# Configuring linker -execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-Wl,--version" ERROR_QUIET OUTPUT_VARIABLE LINKER_VERSION) -# For ld.gold and ld.bfs (the GNU linkers) we optimize hard -if("${LINKER_VERSION}" MATCHES "GNU gold" OR "${LINKER_VERSION}" MATCHES "GNU ld") - message(STATUS "Setting linker optimizations") - if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "MSVC" OR "${LD_AVOID_GC_SECTIONS}")) - # Tell compiler to put every function in separate section, linker can then match sections and functions - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections") - # Tell linker to do dead code and data eminination during link time discarding sections - set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--gc-sections") - endif() - # Default linker optimization flags - set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-O1 -Wl,--hash-style=gnu -Wl,--sort-common") - -else() - message(STATUS "Using unknown linker, not setting linker optimizations") -endif () -set(OSRM_LDFLAGS "${OSRM_LDFLAGS} ${LINKER_FLAGS}") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}") -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}") -set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") - -# 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") -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) - message(STATUS "linking against ${OSXLIBSTD}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${OSXLIBSTD}") - elseif(DARWIN_VERSION GREATER 12) - message(STATUS "linking against libc++") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") - endif() -endif() - if(UNIX AND NOT APPLE) - set(MAYBE_RT_LIBRARY -lrt) + find_library(RT_LIB rt) + if (RT_LIB) + set(MAYBE_RT_LIBRARY -lrt) + endif() endif() find_package(Threads REQUIRED) @@ -425,145 +293,104 @@ include_directories(SYSTEM ${RAPIDJSON_INCLUDE_DIR}) set(MICROTAR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src") include_directories(SYSTEM ${MICROTAR_INCLUDE_DIR}) -set(MBXGEOM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/geometry.hpp-0.9.2/include") -include_directories(SYSTEM ${MBXGEOM_INCLUDE_DIR}) -set(CHEAPRULER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/cheap-ruler-cpp-2.5.4/include") -include_directories(SYSTEM ${CHEAPRULER_INCLUDE_DIR}) - add_library(MICROTAR OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src/microtar.c") set_property(TARGET MICROTAR PROPERTY POSITION_INDEPENDENT_CODE ON) +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) -# 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") +set(FMT_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/fmt/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) 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}) - - 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(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) + find_package(TBB REQUIRED) + find_package(EXPAT REQUIRED) + find_package(BZip2 REQUIRED) + find_package(Lua 5.2 REQUIRED) - mason_use(expat VERSION ${MASON_EXPAT_VERSION}) - add_dependency_includes(${MASON_PACKAGE_expat_INCLUDE_DIRS}) - set(EXPAT_LIBRARIES ${MASON_PACKAGE_expat_STATIC_LIBS}) + add_dependency_includes(${Boost_INCLUDE_DIRS}) - mason_use(lua VERSION ${MASON_LUA_VERSION}) - add_dependency_includes(${MASON_PACKAGE_lua_INCLUDE_DIRS}) - set(USED_LUA_LIBRARIES ${MASON_PACKAGE_lua_STATIC_LIBS}) + set(BOOST_BASE_LIBRARIES ${Boost_LIBRARIES}) + set(BOOST_ENGINE_LIBRARIES ${Boost_LIBRARIES}) - mason_use(bzip2 VERSION ${MASON_BZIP2_VERSION}) - add_dependency_includes(${MASON_PACKAGE_bzip2_INCLUDE_DIRS}) - set(BZIP2_LIBRARIES ${MASON_PACKAGE_bzip2_STATIC_LIBS}) + add_dependency_includes(${TBB_INCLUDE_DIR}) + set(TBB_LIBRARIES ${TBB_LIBRARIES}) - mason_use(tbb VERSION ${MASON_TBB_VERSION}) - add_dependency_includes(${MASON_PACKAGE_tbb_INCLUDE_DIRS}) - set(TBB_LIBRARIES ${MASON_PACKAGE_tbb_LDFLAGS}) + add_dependency_includes(${expat_INCLUDE_DIRS}) + set(EXPAT_LIBRARIES ${expat_LIBRARIES}) + set(EXPAT_INCLUDE_DIRS ${expat_INCLUDE_DIRS}) - 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() + add_dependency_includes(${BZIP2_INCLUDE_DIR}) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") + set(LUA_LIBRARIES lua::lua) + if (LUA_FOUND) + message(STATUS "Using Lua ${LUA_VERSION_STRING}") + endif() - # current mason packages target -D_GLIBCXX_USE_CXX11_ABI=0 - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0") + add_dependency_includes(${lua_INCLUDE_DIRS}) # 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) else() + find_package(Boost REQUIRED CONFIG COMPONENTS ${BOOST_COMPONENTS}) + find_package(TBB REQUIRED) + find_package(EXPAT REQUIRED) + find_package(BZip2 REQUIRED) + find_package(Lua 5.2 REQUIRED) - 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") - endif() - - 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() - - 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}) + add_dependency_includes(${LUA_INCLUDE_DIR}) - find_package(Lua 5.2 REQUIRED) - if (LUA_FOUND) - message(STATUS "Using Lua ${LUA_VERSION_STRING}") - endif() + set(TBB_LIBRARIES TBB::tbb) - set(USED_LUA_LIBRARIES ${LUA_LIBRARIES}) - add_dependency_includes(${LUA_INCLUDE_DIR}) + set(BOOST_BASE_LIBRARIES + ${Boost_DATE_TIME_LIBRARY} + ${Boost_IOSTREAMS_LIBRARY} + ${Boost_THREAD_LIBRARY}) + + set(BOOST_ENGINE_LIBRARIES + ${Boost_ZLIB_LIBRARY} + ${Boost_REGEX_LIBRARY} + ${BOOST_BASE_LIBRARIES}) # add a target to generate API documentation with Doxygen find_package(Doxygen) if(DOXYGEN_FOUND) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) - add_custom_target(doc - ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen" VERBATIM - ) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) + add_custom_target(doc + ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" VERBATIM + ) endif() - # note libosmium depends on expat and bzip2 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake") if(NOT OSMIUM_INCLUDE_DIR) @@ -573,6 +400,8 @@ else() include_directories(SYSTEM ${OSMIUM_INCLUDE_DIR}) endif() + + # prefix compilation with ccache by default if available and on clang or gcc if(ENABLE_CCACHE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")) find_program(CCACHE_FOUND ccache) @@ -580,51 +409,24 @@ if(ENABLE_CCACHE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILE message(STATUS "Using ccache to speed up incremental builds") set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) - set(ENV{CCACHE_CPP2} "true") endif() endif() -# even with mason builds we want to link to system zlib +# 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() +set(ZLIB_LIBRARY ${ZLIB_LIBRARIES}) 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() + +# Workaround for https://github.com/boostorg/phoenix/issues/111 +add_dependency_defines(-DBOOST_PHOENIX_STL_TUPLE_H_) add_definitions(${OSRM_DEFINES}) include_directories(SYSTEM ${DEPENDENCIES_INCLUDE_DIRS}) -set(BOOST_BASE_LIBRARIES - ${Boost_DATE_TIME_LIBRARY} - ${Boost_CHRONO_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_IOSTREAMS_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_SYSTEM_LIBRARY}) - -set(BOOST_ENGINE_LIBRARIES - ${Boost_ZLIB_LIBRARY} - ${Boost_REGEX_LIBRARY} - ${BOOST_BASE_LIBRARIES}) # Binaries target_link_libraries(osrm-datastore osrm_store ${Boost_PROGRAM_OPTIONS_LIBRARY}) @@ -636,20 +438,18 @@ target_link_libraries(osrm-routed osrm ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPTION set(EXTRACTOR_LIBRARIES ${BZIP2_LIBRARIES} - ${Boost_REGEX_LIBRARY} ${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} - ${USED_LUA_LIBRARIES} + ${LUA_LIBRARIES} ${TBB_LIBRARIES} ${MAYBE_COVERAGE_LIBRARIES}) set(PARTITIONER_LIBRARIES @@ -657,10 +457,10 @@ set(PARTITIONER_LIBRARIES ${CMAKE_THREAD_LIBS_INIT} ${TBB_LIBRARIES} ${MAYBE_RT_LIBRARY} - ${MAYBE_COVERAGE_LIBRARIES} - ${ZLIB_LIBRARY}) + ${MAYBE_COVERAGE_LIBRARIES}) set(CUSTOMIZER_LIBRARIES ${BOOST_ENGINE_LIBRARIES} + ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${TBB_LIBRARIES} ${MAYBE_RT_LIBRARY} @@ -675,8 +475,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}) @@ -696,7 +495,6 @@ set(STORAGE_LIBRARIES set(UTIL_LIBRARIES ${BOOST_BASE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - ${MAYBE_STXXL_LIBRARY} ${TBB_LIBRARIES} ${MAYBE_COVERAGE_LIBRARIES} ${ZLIB_LIBRARY}) @@ -710,24 +508,24 @@ 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 $ $) 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}) - - install(TARGETS osrm-io-benchmark DESTINATION bin) -endif() +add_executable(osrm-io-benchmark src/tools/io-benchmark.cpp $) +target_link_libraries(osrm-io-benchmark ${BOOST_BASE_LIBRARIES} ${TBB_LIBRARIES}) +install(TARGETS osrm-io-benchmark DESTINATION bin) if (ENABLE_ASSERTIONS) message(STATUS "Enabling 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 @@ -737,9 +535,10 @@ set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) -file(GLOB VariantGlob third_party/variant/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) @@ -754,13 +553,16 @@ 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 ${VariantGlob} DESTINATION include/mapbox) +install(FILES ${ApiHeader} DESTINATION include/osrm/engine/api) +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) + install(TARGETS osrm DESTINATION lib) install(TARGETS osrm_extract DESTINATION lib) install(TARGETS osrm_partition DESTINATION lib) @@ -768,14 +570,15 @@ 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 set(DefaultProfilesDir profiles) install(DIRECTORY ${DefaultProfilesDir} DESTINATION share/osrm) -# Setup exporting variables for pkgconfig and subproject -# +# Install data geojson files to /usr/local/share/osrm/data by default +set(DefaultProfilesDir data) +install(DIRECTORY ${DefaultProfilesDir} DESTINATION share/osrm) if(BUILD_PACKAGE) include(CPackConfig) @@ -813,9 +616,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) + +if (NOT ENABLE_CONAN) + foreach(engine_lib ${ENGINE_LIBRARIES}) + if("${engine_lib}" MATCHES "^boost.*" OR "${engine_lib}" MATCHES "^TBB.*") + list(APPEND PKGCONFIG_DEPENDENT_LIBRARIES "$") + else() + list(APPEND PKGCONFIG_DEPENDENT_LIBRARIES "${engine_lib}") + endif() + endforeach(engine_lib) +endif() + +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 @@ -832,15 +653,10 @@ add_custom_target(uninstall add_subdirectory(unit_tests) add_subdirectory(src/benchmarks) -if (ENABLE_GLIBC_WORKAROUND) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLIBC_WORKAROUND") -endif() - if (ENABLE_NODE_BINDINGS) add_subdirectory(src/nodejs) endif() - if (ENABLE_FUZZING) # Requires libosrm being built with sanitizers; make configurable and default to ubsan set(FUZZ_SANITIZER "undefined" CACHE STRING "Sanitizer to be used for Fuzz testing") @@ -855,22 +671,22 @@ if (ENABLE_FUZZING) add_subdirectory(fuzz) endif () - # 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() \ No newline at end of file +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}) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 30b697e550c..2b01a4a77dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ You can add a :+1: emoji reaction to the issue if you want to express interest i # Developer -We use `clang-format` version `3.8` to consistently format the code base. There is a helper script under `scripts/format.sh`. +We use `clang-format` version `15` to consistently format the code base. There is a helper script under `scripts/format.sh`. The format is automatically checked by the `mason-linux-release` job of a Travis CI build. To save development time a local hook `.git/hooks/pre-push` ``` diff --git a/README.md b/README.md index 8435d558ffc..f0079952d83 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ ## 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) | -High performance routing engine written in C++14 designed to run on OpenStreetMap data. +[![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) [![Discord](https://img.shields.io/discord/1034487840219860992)](https://discord.gg/es9CdcCXcb) + +High performance routing engine written in C++ 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 @@ -16,12 +15,12 @@ The following services are available via HTTP API, C++ library interface and Nod To quickly try OSRM use our [demo server](http://map.project-osrm.org) which comes with both the backend and a frontend on top. -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/). +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 [the OSM wiki on routing](https://wiki.openstreetmap.org/wiki/Routing) or [this guide about mapping for navigation](https://web.archive.org/web/20221206013651/https://labs.mapbox.com/mapping/mapping-for-navigation/). Related [Project-OSRM](https://github.com/Project-OSRM) repositories: - [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 +- [osrm-backend-docker](https://github.com/project-osrm/osrm-backend/pkgs/container/osrm-backend) - Ready to use Docker images ## Documentation @@ -33,6 +32,7 @@ Related [Project-OSRM](https://github.com/Project-OSRM) repositories: ## Contact +- Discord: [join](https://discord.gg/es9CdcCXcb) - IRC: `irc.oftc.net`, channel: `#osrm` ([Webchat](https://webchat.oftc.net)) - Mailinglist: `https://lists.openstreetmap.org/listinfo/osrm-talk` @@ -50,7 +50,7 @@ If you want to use the CH pipeline instead replace `osrm-partition` and `osrm-cu ### Using Docker -We base our Docker images ([backend](https://hub.docker.com/r/osrm/osrm-backend/), [frontend](https://hub.docker.com/r/osrm/osrm-frontend/)) on Debian 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/) @@ -58,16 +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" ghcr.io/project-osrm/osrm-backend osrm-extract -p /opt/car.lua /data/berlin-latest.osm.pbf || echo "osrm-extract failed" -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. +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. Noting that this process can take a long time to complete with little changes on the terminal output, for example, a Mexico's OSM file of 550.7MB took around 30 minutes to finish extraction and generate edge-expanded graph representation. - docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-partition /data/berlin-latest.osrm - docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-customize /data/berlin-latest.osrm + docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-partition /data/berlin-latest.osrm || echo "osrm-partition failed" + docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-customize /data/berlin-latest.osrm || echo "osrm-customize failed" -Note that `berlin-latest.osrm` has a different file extension. +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" osrm/osrm-backend osrm-routed --algorithm mld /data/berlin-latest.osrm + 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 @@ -84,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 -----|------ @@ -96,7 +96,7 @@ 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 @@ -132,16 +132,16 @@ curl "https://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.38%20The%20Node.js%20bindings%20provide%20read-only%20access%20to%20the%20routing%20engine.%20We%20provide%20API%20documentation%20and%20examples%20[here](docs/nodejs/api.md).%20-You%20will%20need%20a%20modern%20%60libstdc++%60%20toolchain%20(%60%3E=%20GLIBCXX_3.4.20%60)%20for%20binary%20compatibility%20if%20you%20want%20to%20use%20the%20pre-built%20binaries.+You%20will%20need%20a%20modern%20%60libstdc++%60%20toolchain%20(%60%3E=%20GLIBCXX_3.4.26%60)%20for%20binary%20compatibility%20if%20you%20want%20to%20use%20the%20pre-built%20binaries.%20For%20older%20Ubuntu%20systems%20you%20can%20upgrade%20your%20standard%20library%20for%20example%20with:%20%20%60%60%60%20sudo%20add-apt-repository%20ppa:ubuntu-toolchain-r/test%20sudo%20apt-get%20update%20-y-sudo%20apt-get%20install%20-y%20libstdc++-5-dev+sudo%20apt-get%20install%20-y%20libstdc++-9-dev%20%60%60%60%20-You%20can%20install%20the%20Node.js%20bindings%20via%20%60npm%20install%20osrm%60%20or%20from%20this%20repository%20either%20via+You%20can%20install%20the%20Node.js%20bindings%20via%20%60npm%20install%20@project-osrm/osrm%60%20or%20from%20this%20repository%20either%20via%20%20%20%20%20%20npm%20install%20@@%20-151,7%20+151,18%20@@%20which%20will%20check%20and%20use%20pre-built%20binaries%20if%20they're available for this releas to always force building the Node.js bindings from source. -For usage details have a look [these API docs](docs/nodejs/api.md). +#### 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). diff --git a/appveyor-build.bat b/appveyor-build.bat deleted file mode 100644 index 09a2f421d42..00000000000 --- a/appveyor-build.bat +++ /dev/null @@ -1,172 +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-2017.09.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 - -: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 deleted file mode 100644 index 02e124c57fd..00000000000 --- a/appveyor.yml +++ /dev/null @@ -1,35 +0,0 @@ -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 - -# clone directory -clone_folder: c:\projects\osrm - -platform: x64 - -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 - -branches: - only: - - master - diff --git a/build-local.bat b/build-local.bat deleted file mode 100644 index 8598230f3a6..00000000000 --- a/build-local.bat +++ /dev/null @@ -1,33 +0,0 @@ -@ECHO OFF -SETLOCAL -SET EL=0 - -ECHO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %~f0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -SET PLATFORM=x64 -SET CONFIGURATION=Release -::SET LOCAL_DEV=1 - -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 -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -CALL appveyor-build.bat -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/cloudformation/ci.template b/cloudformation/ci.template deleted file mode 100644 index bb9d52829c3..00000000000 --- a/cloudformation/ci.template +++ /dev/null @@ -1,75 +0,0 @@ -{ - "AWSTemplateFormatVersion": "2010-09-09", - "Description": "user for publishing to s3://mapbox-node-binary/osrm", - "Resources": { - "User": { - "Type": "AWS::IAM::User", - "Properties": { - "Policies": [ - { - "PolicyName": "list", - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "s3:ListBucket" - ], - "Effect": "Allow", - "Resource": "arn:aws:s3:::mapbox-node-binary", - "Condition": { - "StringLike": { - "s3:prefix": [ - "osrm/*" - ] - } - } - } - ] - } - }, - { - "PolicyName": "publish", - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "s3:DeleteObject", - "s3:GetObject", - "s3:GetObjectAcl", - "s3:PutObject", - "s3:PutObjectAcl" - ], - "Effect": "Allow", - "Resource": "arn:aws:s3:::mapbox-node-binary/osrm/*" - } - ] - } - } - ] - } - }, - "AccessKey": { - "Type": "AWS::IAM::AccessKey", - "Properties": { - "UserName": { - "Ref": "User" - } - } - } - }, - "Outputs": { - "AccessKeyId": { - "Value": { - "Ref": "AccessKey" - } - }, - "SecretAccessKey": { - "Value": { - "Fn::GetAtt": [ - "AccessKey", - "SecretAccessKey" - ] - } - } - } -} diff --git a/cloudformation/ci.template.js b/cloudformation/ci.template.js deleted file mode 100644 index 719e80071ec..00000000000 --- a/cloudformation/ci.template.js +++ /dev/null @@ -1,59 +0,0 @@ -var cf = require('@mapbox/cloudfriend'); -var package_json = require('../package.json') - -module.exports = { - AWSTemplateFormatVersion: '2010-09-09', - Description: 'user for publishing to s3://mapbox-node-binary/' + package_json.name, - Resources: { - User: { - Type: 'AWS::IAM::User', - Properties: { - Policies: [ - { - PolicyName: 'list', - PolicyDocument: { - Statement: [ - { - Action: ['s3:ListBucket'], - Effect: 'Allow', - Resource: 'arn:aws:s3:::mapbox-node-binary', - Condition : { - StringLike : { - "s3:prefix": [ package_json.name + "/*"] - } - } - } - ] - } - }, - { - PolicyName: 'publish', - PolicyDocument: { - Statement: [ - { - Action: ['s3:DeleteObject', 's3:GetObject', 's3:GetObjectAcl', 's3:PutObject', 's3:PutObjectAcl'], - Effect: 'Allow', - Resource: 'arn:aws:s3:::mapbox-node-binary/' + package_json.name + '/*' - } - ] - } - } - ] - } - }, - AccessKey: { - Type: 'AWS::IAM::AccessKey', - Properties: { - UserName: cf.ref('User') - } - } - }, - Outputs: { - AccessKeyId: { - Value: cf.ref('AccessKey') - }, - SecretAccessKey: { - Value: cf.getAtt('AccessKey', 'SecretAccessKey') - } - } -}; diff --git a/cmake/CheckCXXCompilerFlag.cmake b/cmake/CheckCXXCompilerFlag.cmake deleted file mode 100644 index e396f75a92c..00000000000 --- a/cmake/CheckCXXCompilerFlag.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# - Check whether the CXX compiler supports a given flag. -# CHECK_CXX_COMPILER_FLAG( ) -# - the compiler flag -# - variable to store the result -# This internally calls the check_cxx_source_compiles macro. See help -# for CheckCXXSourceCompiles for a listing of variables that can -# modify the build. - -# Copyright (c) 2006, Alexander Neundorf, -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - - -INCLUDE(CheckCXXSourceCompiles) - -MACRO (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT) - SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") - SET(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") - CHECK_CXX_SOURCE_COMPILES("int main() { return 0;}" ${_RESULT} - # Some compilers do not fail with a bad flag - FAIL_REGEX "unrecognized .*option" # GNU - FAIL_REGEX "ignoring unknown option" # MSVC - FAIL_REGEX "[Uu]nknown option" # HP - FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro - FAIL_REGEX "command option .* is not recognized" # XL - ) - SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") -ENDMACRO (CHECK_CXX_COMPILER_FLAG) diff --git a/cmake/FindLua.cmake b/cmake/FindLua.cmake index 2b732ca210b..d8cc01e8a9d 100644 --- a/cmake/FindLua.cmake +++ b/cmake/FindLua.cmake @@ -36,7 +36,10 @@ # This is because, the lua location is not standardized and may exist in # locations other than lua/ -include(FindPkgConfig) +if(NOT PKG_CONFIG_FOUND) + include(CMakeFindDependencyMacro) + find_dependency(PkgConfig) +endif() unset(_lua_include_subdirs) unset(_lua_library_names) @@ -44,7 +47,7 @@ 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) diff --git a/cmake/FindSTXXL.cmake b/cmake/FindSTXXL.cmake deleted file mode 100644 index 473fb6a29db..00000000000 --- 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/FindTBB.cmake b/cmake/FindTBB.cmake index 09ba1655549..ca5a792ae40 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 - - -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) - -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. +# 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.) + + +#============================================================================= +# FindTBB helper functions and macros +# + +# 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) + 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 - 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) + 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) - 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) + return() +endif () -endif (NOT _TBB_INSTALL_DIR) +#============================================================================= +# Look for TBB's malloc package +set(TBB_MALLOC_LIBRARY_NAMES tbbmalloc) +get_debug_names(TBB_MALLOC_LIBRARY_NAMES) -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) +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 index e1be64e0d87..5822bf5f282 100644 --- a/cmake/JSONParser.cmake +++ b/cmake/JSONParser.cmake @@ -1,7 +1,7 @@ # 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) +cmake_minimum_required(VERSION 3.18) if (DEFINED JSonParserGuard) return() diff --git a/cmake/mason.cmake b/cmake/mason.cmake deleted file mode 100644 index d33c3439f7b..00000000000 --- a/cmake/mason.cmake +++ /dev/null @@ -1,215 +0,0 @@ -# Mason CMake - -include(CMakeParseArguments) - -function(mason_detect_platform) - # Determine platform - if(NOT MASON_PLATFORM) - # we call uname -s manually here since - # CMAKE_HOST_SYSTEM_NAME will not be defined before the project() call - execute_process( - COMMAND uname -s - OUTPUT_VARIABLE UNAME - OUTPUT_STRIP_TRAILING_WHITESPACE) - - if (UNAME STREQUAL "Darwin") - set(MASON_PLATFORM "osx" PARENT_SCOPE) - else() - set(MASON_PLATFORM "linux" PARENT_SCOPE) - endif() - endif() - - # Determine platform version string - if(NOT MASON_PLATFORM_VERSION) - execute_process( - COMMAND uname -m - OUTPUT_VARIABLE MASON_PLATFORM_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - set(MASON_PLATFORM_VERSION "${MASON_PLATFORM_VERSION}" PARENT_SCOPE) - endif() -endfunction() - -function(mason_use _PACKAGE) - if(NOT _PACKAGE) - message(FATAL_ERROR "[Mason] No package name given") - endif() - - cmake_parse_arguments("" "HEADER_ONLY" "VERSION" "" ${ARGN}) - - if(_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "[Mason] mason_use() called with unrecognized arguments: ${_UNPARSED_ARGUMENTS}") - endif() - - if(NOT _VERSION) - message(FATAL_ERROR "[Mason] Specifying a version is required") - endif() - - if(MASON_PACKAGE_${_PACKAGE}_INVOCATION STREQUAL "${MASON_INVOCATION}") - # Check that the previous invocation of mason_use didn't select another version of this package - if(NOT MASON_PACKAGE_${_PACKAGE}_VERSION STREQUAL ${_VERSION}) - message(FATAL_ERROR "[Mason] Already using ${_PACKAGE} ${MASON_PACKAGE_${_PACKAGE}_VERSION}. Cannot select version ${_VERSION}.") - endif() - else() - if(_HEADER_ONLY) - set(_PLATFORM_ID "headers") - else() - set(_PLATFORM_ID "${MASON_PLATFORM}-${MASON_PLATFORM_VERSION}") - endif() - - set(_SLUG "${_PLATFORM_ID}/${_PACKAGE}/${_VERSION}") - set(_INSTALL_PATH "${MASON_PACKAGE_DIR}/${_SLUG}") - file(RELATIVE_PATH _INSTALL_PATH_RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${_INSTALL_PATH}") - - if(NOT EXISTS "${_INSTALL_PATH}") - set(_CACHE_PATH "${MASON_PACKAGE_DIR}/.binaries/${_SLUG}.tar.gz") - if (NOT EXISTS "${_CACHE_PATH}") - # Download the package - set(_URL "${MASON_REPOSITORY}/${_SLUG}.tar.gz") - message("[Mason] Downloading package ${_URL}...") - - set(_FAILED) - set(_ERROR) - # Note: some CMake versions are compiled without SSL support - get_filename_component(_CACHE_DIR "${_CACHE_PATH}" DIRECTORY) - file(MAKE_DIRECTORY "${_CACHE_DIR}") - execute_process( - COMMAND curl --retry 3 -s -f -S -L "${_URL}" -o "${_CACHE_PATH}.tmp" - RESULT_VARIABLE _FAILED - ERROR_VARIABLE _ERROR) - if(_FAILED) - message(FATAL_ERROR "[Mason] Failed to download ${_URL}: ${_ERROR}") - else() - # We downloaded to a temporary file to prevent half-finished downloads - file(RENAME "${_CACHE_PATH}.tmp" "${_CACHE_PATH}") - endif() - endif() - - # Unpack the package - message("[Mason] Unpacking package to ${_INSTALL_PATH_RELATIVE}...") - file(MAKE_DIRECTORY "${_INSTALL_PATH}") - execute_process( - COMMAND ${CMAKE_COMMAND} -E tar xzf "${_CACHE_PATH}" - WORKING_DIRECTORY "${_INSTALL_PATH}") - endif() - - # Error out if there is no config file. - if(NOT EXISTS "${_INSTALL_PATH}/mason.ini") - message(FATAL_ERROR "[Mason] Could not find mason.ini for package ${_PACKAGE} ${_VERSION}") - endif() - - set(MASON_PACKAGE_${_PACKAGE}_PREFIX "${_INSTALL_PATH}" CACHE STRING "${_PACKAGE} ${_INSTALL_PATH}" FORCE) - mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_PREFIX) - - # Load the configuration from the ini file - file(STRINGS "${_INSTALL_PATH}/mason.ini" _CONFIG_FILE) - foreach(_LINE IN LISTS _CONFIG_FILE) - string(REGEX MATCH "^([a-z_]+) *= *" _KEY "${_LINE}") - if (_KEY) - string(LENGTH "${_KEY}" _KEY_LENGTH) - string(SUBSTRING "${_LINE}" ${_KEY_LENGTH} -1 _VALUE) - string(REGEX REPLACE ";.*$" "" _VALUE "${_VALUE}") # Trim trailing commas - string(REPLACE "{prefix}" "${_INSTALL_PATH}" _VALUE "${_VALUE}") - string(STRIP "${_VALUE}" _VALUE) - string(REPLACE "=" "" _KEY "${_KEY}") - string(STRIP "${_KEY}" _KEY) - string(TOUPPER "${_KEY}" _KEY) - if(_KEY STREQUAL "INCLUDE_DIRS" OR _KEY STREQUAL "STATIC_LIBS" ) - separate_arguments(_VALUE) - endif() - set(MASON_PACKAGE_${_PACKAGE}_${_KEY} "${_VALUE}" CACHE STRING "${_PACKAGE} ${_KEY}" FORCE) - mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_${_KEY}) - endif() - endforeach() - - # Compare version in the package to catch errors early on - if(NOT _VERSION STREQUAL MASON_PACKAGE_${_PACKAGE}_VERSION) - message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has version '${MASON_PACKAGE_${_PACKAGE}_VERSION}', but required '${_VERSION}'") - endif() - - if(NOT _PACKAGE STREQUAL MASON_PACKAGE_${_PACKAGE}_NAME) - message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has name '${MASON_PACKAGE_${_PACKAGE}_NAME}', but required '${_NAME}'") - endif() - - if(NOT _HEADER_ONLY) - if(NOT MASON_PLATFORM STREQUAL MASON_PACKAGE_${_PACKAGE}_PLATFORM) - message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has platform '${MASON_PACKAGE_${_PACKAGE}_PLATFORM}', but required '${MASON_PLATFORM}'") - endif() - - if(NOT MASON_PLATFORM_VERSION STREQUAL MASON_PACKAGE_${_PACKAGE}_PLATFORM_VERSION) - message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has platform version '${MASON_PACKAGE_${_PACKAGE}_PLATFORM_VERSION}', but required '${MASON_PLATFORM_VERSION}'") - endif() - endif() - - # Concatenate the static libs and libraries - set(_LIBRARIES) - list(APPEND _LIBRARIES ${MASON_PACKAGE_${_PACKAGE}_STATIC_LIBS} ${MASON_PACKAGE_${_PACKAGE}_LDFLAGS}) - set(MASON_PACKAGE_${_PACKAGE}_LIBRARIES "${_LIBRARIES}" CACHE STRING "${_PACKAGE} _LIBRARIES" FORCE) - mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_LIBRARIES) - - if(NOT _HEADER_ONLY) - string(REGEX MATCHALL "(^| +)-L *([^ ]+)" MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LDFLAGS}") - string(REGEX REPLACE "(^| +)-L *" "\\1" MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}") - set(MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}" CACHE STRING "${_PACKAGE} ${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}" FORCE) - mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS) - endif() - - # Store invocation ID to prevent different versions of the same package in one invocation - set(MASON_PACKAGE_${_PACKAGE}_INVOCATION "${MASON_INVOCATION}" CACHE INTERNAL "${_PACKAGE} invocation ID" FORCE) - endif() -endfunction() - -macro(target_add_mason_package _TARGET _VISIBILITY _PACKAGE) - if (NOT MASON_PACKAGE_${_PACKAGE}_INVOCATION) - message(FATAL_ERROR "[Mason] Package ${_PACKAGE} has not been initialized yet") - endif() - - target_include_directories(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_INCLUDE_DIRS}") - target_compile_definitions(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_DEFINITIONS}") - target_compile_options(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_OPTIONS}") - target_link_libraries(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_LIBRARIES}") -endmacro() - -# Setup - -string(RANDOM LENGTH 16 MASON_INVOCATION) - -# Read environment variables if CMake is run in command mode -if (CMAKE_ARGC) - set(MASON_PLATFORM "$ENV{MASON_PLATFORM}") - set(MASON_PLATFORM_VERSION "$ENV{MASON_PLATFORM_VERSION}") - set(MASON_PACKAGE_DIR "$ENV{MASON_PACKAGE_DIR}") - set(MASON_REPOSITORY "$ENV{MASON_REPOSITORY}") -endif() - -# Directory where Mason packages are located; typically ends with mason_packages -if (NOT MASON_PACKAGE_DIR) - set(MASON_PACKAGE_DIR "${CMAKE_SOURCE_DIR}/mason_packages") -endif() - -# URL prefix of where packages are located. -if (NOT MASON_REPOSITORY) - set(MASON_REPOSITORY "https://mason-binaries.s3.amazonaws.com/") -endif() - -mason_detect_platform() - -# Execute commands if CMake is run in command mode -if (CMAKE_ARGC) - # Collect remaining arguments for passing to mason_use - set(_MASON_ARGS) - if (${CMAKE_ARGC} LESS 5) - message(FATAL_ERROR "Usage: mason.sh [install|prefix] PACKAGE VERSION") - endif() - - if (${CMAKE_ARGV3} STREQUAL "install") - # Install the package - mason_use(${CMAKE_ARGV4} VERSION ${CMAKE_ARGV5}) - elseif (${CMAKE_ARGV3} STREQUAL "prefix") - set(PKG_PREFIX "${MASON_PACKAGE_DIR}/${MASON_PLATFORM}-${MASON_PLATFORM_VERSION}/${CMAKE_ARGV4}/${CMAKE_ARGV5}") - # CMake can't write to stdout with message() - execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${PKG_PREFIX}") - else() - message(FATAL_ERROR "Usage: mason.sh [install|prefix] PACKAGE VERSION") - endif() - -endif() diff --git a/cmake/warnings.cmake b/cmake/warnings.cmake new file mode 100644 index 00000000000..fa52d6279e9 --- /dev/null +++ b/cmake/warnings.cmake @@ -0,0 +1,88 @@ +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 "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(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) +# these warnings are not enabled by default +# no_warning(name-of-warning) +no_warning(deprecated-comma-subscript) +no_warning(comma-subscript) +no_warning(ambiguous-reversed-operator) +no_warning(restrict) +no_warning(free-nonheap-object) +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + no_warning(stringop-overflow) +endif() \ No newline at end of file diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index 7750fa78575..00000000000 --- a/codecov.yml +++ /dev/null @@ -1,6 +0,0 @@ -coverage: - - ignore: - - third_party/.* - -comment: off diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 00000000000..8f0011705b9 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,36 @@ +from conan import ConanFile +from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps + +class OsrmConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "CMakeDeps" + + def requirements(self): + self.requires("boost/1.85.0") + self.requires("bzip2/1.0.8") + self.requires("expat/2.6.2") + self.requires("lua/5.4.6") + self.requires("onetbb/2021.12.0") + self.requires("xz_utils/5.4.5") + self.requires("zlib/1.3.1") + + def configure(self): + self.options["boost"].without_python = True + self.options["boost"].without_coroutine = True + self.options["boost"].without_stacktrace = True + self.options["boost"].without_cobalt = True + self.options["bzip2"].shared = True + self.options["xz-utils"].shared = True + + def generate(self): + tc = CMakeToolchain(self) + tc.variables["CMAKE_CXX_STANDARD"] = "20" + tc.variables["Bzip2_ROOT"] = "${CMAKE_BINARY_DIR}" + tc.variables["LZMA_ROOT"] = "${CMAKE_BINARY_DIR}" + tc.variables["TBB_ROOT"] = "${CONAN_ONETBB_ROOT}" + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() diff --git a/cucumber.js b/cucumber.js index 288e3ba5aea..9cec411756b 100644 --- a/cucumber.js +++ b/cucumber.js @@ -1,6 +1,6 @@ module.exports = { - 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', + default: '--strict --tags ~@stress --tags ~@todo --tags ~@mld --require features/support --require features/step_definitions', + ch: '--strict --tags ~@stress --tags ~@todo --tags ~@mld -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 ~@ch --require features/support --require features/step_definitions -f progress' diff --git a/data/driving_side.geojson b/data/driving_side.geojson index 6ae14ceac27..9dc8e765203 100644 --- a/data/driving_side.geojson +++ b/data/driving_side.geojson @@ -11,348 +11,321 @@ "coordinates": [ [ [ - 159.78515624999997, - -21.943045533438166 + 113.573, + 22.186 ], [ - 163.828125, - -7.710991655433217 + 114, + 22.5 ], [ - 154.8632597923279, - 1.230288366531784 + 114.05534, + 22.503 ], [ - 130.49558401107788, - 5.900103419579043 + 114.0595, + 22.51422 ], [ - 122.8710722923279, - 4.5653879923552605 + 114.07345, + 22.51934 ], [ - 120.7177519798279, - 5.315150278601077 + 114.0786, + 22.53012 ], [ - 120.5749297142029, - 5.697896578851922 + 114.08512, + 22.53228 ], [ - 120.3277373313904, - 5.531158894311544 + 114.09034, + 22.53717 ], [ - 119.5312285423279, - 5.484682580410128 + 114.09611, + 22.53486 ], [ - 118.9105010032654, - 7.275207196686071 + 114.10602, + 22.53472 ], [ - 117.7734160423279, - 7.710906600862094 + 114.1115, + 22.52929 ], [ - 102.6562285423279, - 8.059144644195047 + 114.11522, + 22.5308 ], [ - 102.91990041732791, - 11.652152342254183 + 114.11649, + 22.53418 ], [ - 102.90481567382812, - 11.766536924462363 + 114.11979, + 22.53511 ], [ - 102.82928466796874, - 11.884821555123915 + 114.1244, + 22.5393 ], [ - 102.7716064453125, - 12.052751072179356 + 114.12729, + 22.53947 ], [ - 102.70843505859375, - 12.181649710171742 + 114.13018, + 22.54132 ], [ - 102.72628784179688, - 12.352075625709524 + 114.13807, + 22.5432 ], [ - 102.78533935546875, - 12.412436216375175 + 114.14429, + 22.54176 ], [ - 102.56423950195311, - 12.656417878339736 + 114.14441, + 22.54114 ], [ - 102.49008178710938, - 12.981809528732812 + 114.14846, + 22.54179 ], [ - 102.381591796875, - 13.18914225554674 + 114.14855, + 22.54397 ], [ - 102.34725952148438, - 13.352209751204438 + 114.15042, + 22.54593 ], [ - 102.37058401107791, - 13.539117223464746 + 114.14964, + 22.54954 ], [ - 103.11765432357788, - 14.243003670396702 + 114.15166, + 22.55168 ], [ - 103.53515625, - 14.424040444354699 + 114.15192, + 22.55438 ], [ - 104.1064453125, - 14.370833973406821 + 114.15642, + 22.55495 ], [ - 105.1391386985779, - 14.285594123582854 + 114.15841, + 22.55909 ], [ - 105.5126953125, - 14.530415228007362 + 114.16032, + 22.56153 ], [ - 105.46875, - 15.114552871944115 + 114.16162, + 22.56187 ], [ - 105.6005859375, - 15.559544421458103 + 114.1634, + 22.55931 ], [ - 105.413818359375, - 16.003575733881327 + 114.16553, + 22.5593 ], [ - 105.062255859375, - 16.06692895745012 + 114.16733, + 22.56119 ], [ - 104.75463867187499, - 16.488764934242077 + 114.16934, + 22.56093 ], [ - 104.7656035423279, - 17.308605942846185 + 114.17061, + 22.5597 ], [ - 103.95261526107788, - 18.25013846381984 + 114.17702, + 22.56 ], [ - 103.2934355735779, - 18.3752976396967 + 114.17798, + 22.55546 ], [ - 102.67820119857791, - 17.85320841659695 + 114.18401, + 22.5552 ], [ - 102.1069121360779, - 18.166648857895012 + 114.18673, + 22.55468 ], [ - 101.0302519798279, - 17.56016467227813 + 114.1878, + 22.55545 ], [ - 101.326904296875, - 18.999802829053262 + 114.18979, + 22.55446 ], [ - 101.2060546875, - 19.611543503814232 + 114.1955, + 22.55564 ], [ - 100.7666015625, - 19.476950206488414 + 114.19674, + 22.55691 ], [ - 100.404052734375, - 19.72534224805787 + 114.20005, + 22.55717 ], [ - 100.546875, - 20.148784632164155 + 114.20376, + 22.55623 ], [ - 100.14038085937499, - 20.396123272467616 + 114.20884, + 22.55672 ], [ - 99.052734375, - 20.16941122761028 + 114.22438, + 22.55055 ], [ - 99.03076171875, - 19.735683578629445 + 114.2264, + 22.5476 ], [ - 98.59130859375, - 19.663280219987662 + 114.22545, + 22.54528 ], [ - 98.0419921875, - 19.797717490704738 + 114.22661, + 22.54339 ], [ - 97.75634765625, - 19.155546551403607 + 114.32, + 22.576 ], [ - 97.3828125, - 18.510865709091377 + 114.45, + 22.43 ], [ - 97.9541015625, - 17.612610761099077 + 114.45, + 22.14 ], [ - 98.89892578125, - 16.351767849269347 + 113.9, + 22.14 ], [ - 98.59130859375, - 16.014136002085912 + 113.75, + 22.22 ], [ - 98.5693359375, - 15.368949896534705 + 113.553, + 22.095 ], [ - 98.19580078125, - 15.231189704767242 + 113.54678, + 22.1207 ], [ - 98.382568359375, - 14.732386081418454 + 113.5456, + 22.1207 ], [ - 99.16257619857791, - 13.560478307112557 + 113.54076, + 22.12373 ], [ - 99.58142995834352, - 11.918331814112104 + 113.54016, + 22.13618 ], [ - 99.64872121810917, - 11.805501728366703 + 113.54701, + 22.13651 ], [ - 99.64111447334291, - 11.789853455395441 + 113.5475, + 22.14583 ], [ - 99.64106082916263, - 11.788918731650105 + 113.52456, + 22.17978 ], [ - 99.64245557785038, - 11.778699577993807 + 113.53623, + 22.20191 ], [ - 99.64048147201542, - 11.753071252426949 + 113.53299, + 22.21232 ], [ - 99.28342580795291, - 11.210712717455792 + 113.53497, + 22.21351 ], [ - 99.02662038803102, - 10.888581271040938 + 113.53735, + 22.21377 ], [ - 98.80277395248417, - 10.711866898462292 + 113.54156, + 22.21315 ], [ - 98.80826711654666, - 10.521547650627832 + 113.54385, + 22.21709 ], [ - 98.75196218490605, - 10.381094932405219 + 113.55849, + 22.21565 ], [ - 98.67231130599978, - 10.18246297848021 - ], - [ - 98.57343435287478, - 9.971534577962496 - ], - [ - 98.48417043685916, - 9.955303622625479 - ], - [ - 98.34615468978888, - 9.917428257015372 - ], - [ - 98.27405691146853, - 9.575000723804276 - ], - [ - 97.960946559906, - 9.493741474485672 - ], - [ - 97.13147878646853, - 9.786183416123238 - ], - [ - 92.56116628646856, - 15.147674168282906 - ], - [ - 90.71546316146853, - 0.759386240320313 - ], - [ - 109.34827566146853, - -15.46296618728526 - ], - [ - 107.23890066146849, - -38.418107244191766 - ], + 113.573, + 22.186 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "driving_side": "left" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ [ - 130.4420256614686, - -41.64727816306098 + -75, + 18 ], [ - 160.67640066146856, - -53.96175413197849 + -80, + 20.5 ], [ - 185.81311941146856, - -48.23109085729586 + -83, + 19 ], [ - 184.93421316146848, - -33.73235247373941 + -77, + 16 ], [ - 159.78515624999997, - -21.943045533438166 + -75, + 18 ] ] ] @@ -368,490 +341,440 @@ "coordinates": [ [ [ - 147.15087890625003, - 44.13885576756881 - ], - [ - 145.52490234375, - 43.50075243569041 - ], - [ - 145.20629882812497, - 43.8186748554532 - ], - [ - 145.70068359375, - 44.55916341529182 - ], - [ - 141.48193359375, - 45.836454050187726 + -64.33594, + 32.86113 ], [ - 135.0439453125, - 37.71859032558816 + -79.39819, + 27.21067 ], [ - 127.88085937500001, - 32.565333160841035 + -80.63965, + 23.71998 ], [ - 125.61767578124999, - 27.196014383173306 + -73.39966, + 20.40642 ], [ - 122.54150390625, - 24.70691524106633 + -65.1709, + 19.20743 ], [ - 123.64013671874999, - 22.411028521558706 + -65.09399, + 16.23577 ], [ - 131.66015625, - 25.284437746983055 + -59.13391, + 16.80454 ], [ - 141.36108398437503, - 33.394759218577995 + -62.64404, + 15.16228 ], [ - 147.15087890625003, - 44.13885576756881 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 1.9116210937499998, - 61.19621314083867 + -59.43054, + 14.85985 ], [ - -2.0654296875, - 61.990587736204105 + -62.83081, + 13.64599 ], [ - -12.54638671875, - 55.94919982336746 + -61.80359, + 10.73752 ], [ - -12.260742187500002, - 50.62507306341437 + -62.08649, + 10.04729 ], [ - -1.9445800781249998, - 48.93693495409401 + -61.06201, + 9.85522 ], [ - -1.768798828125, - 49.210420445650286 + -59.81369, + 8.31274 ], [ - -2.142333984375, - 49.50380954152213 + -59.8027, + 8.27469 ], [ - -1.966552734375, - 49.930008124606886 + -59.83498, + 8.22712 ], [ - -0.3515625, - 49.69606181911566 + -59.94141, + 8.21149 ], [ - 2.5048828125, - 51.6180165487737 + -59.99771, + 8.15576 ], [ - 1.9116210937499998, - 61.19621314083867 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 92.39501953125, - 21.514406720030294 + -59.97986, + 8.13265 ], [ - 92.74658203125, - 21.248422235627014 + -59.99771, + 8.12041 ], [ - 92.65869140625, - 22.06527806776582 + -60.00183, + 8.07147 ], [ - 93.1640625, - 22.30942584120019 + -60.05127, + 8.02524 ], [ - 93.2080078125, - 23.059516273509303 + -60.09933, + 8.03747 ], [ - 93.36181640625, - 24.066528197726857 + -60.12268, + 8.02388 ], [ - 94.21875, - 23.905926927314724 + -60.14053, + 7.98988 ], [ - 94.76806640624999, - 25.06569718553588 + -60.36163, + 7.83345 ], [ - 94.52636718749999, - 25.284437746983055 + -60.53467, + 7.81713 ], [ - 95.16357421875, - 26.13571361317392 + -60.5896, + 7.6375 ], [ - 95.1416015625, - 26.56887654795065 + -60.72144, + 7.54493 ], [ - 95.97656249999999, - 27.059125784374068 + -60.5896, + 7.31888 ], [ - 96.8115234375, - 27.332735136859146 + -60.63904, + 7.24532 ], [ - 97.18505859374999, - 27.15692045688088 + -60.54703, + 7.12542 ], [ - 96.92138671875, - 27.6251403350933 + -60.46875, + 7.20309 ], [ - 97.36083984375, - 27.955591004642553 + -60.37262, + 7.18401 ], [ - 97.3828125, - 28.285033294640684 + -60.29984, + 7.1445 ], [ - 96.7236328125, - 28.5941685062326 + -60.2916, + 7.06819 ], [ - 95.97656249999999, - 29.401319510041485 + -60.39871, + 6.95097 ], [ - 95.29541015625, - 29.075375179558346 + -60.66513, + 6.83235 ], [ - 94.7021484375, - 29.267232865200878 + -60.71869, + 6.75053 ], [ - 92.10937499999999, - 27.800209937418252 + -60.91232, + 6.81735 ], [ - 91.669921875, - 27.858503954841247 + -60.94254, + 6.72053 ], [ - 91.1865234375, - 28.110748760633534 + -61.14441, + 6.72326 ], [ - 90.4833984375, - 28.07198030177986 + -61.23093, + 6.5773 ], [ - 90.52734374999999, - 28.246327971048842 + -61.1554, + 6.45314 ], [ - 89.75830078125, - 28.323724553546015 + -61.14441, + 6.20199 ], [ - 88.9013671875, - 27.31321389856826 + -61.39709, + 5.95619 ], [ - 88.9013671875, - 27.89734922968426 + -60.71045, + 5.20036 ], [ - 88.5498046875, - 28.130127737874005 + -60.21606, + 5.23319 ], [ - 87.29736328125, - 27.877928333679495 + -59.99634, + 5.06906 ], [ - 85.14404296875, - 28.536274512989916 + -60.13916, + 4.51071 ], [ - 82.001953125, - 30.35391637229704 + -59.69971, + 4.40118 ], [ - 81.45263671875, - 30.41078179084589 + -59.5459, + 3.93002 ], [ - 81.18896484375, - 30.031055426540206 + -59.87549, + 3.56825 ], [ - 79.40917968749999, - 31.090574094954192 + -59.7876, + 3.37086 ], [ - 78.75, - 31.555133721172034 + -60.01831, + 2.83332 ], [ - 78.5357666015625, - 32.60698915452777 + -59.90845, + 2.38335 ], [ - 79.002685546875, - 32.33355894864106 + -59.69971, + 2.2626 ], [ - 79.4146728515625, - 32.532920675187846 + -59.77661, + 1.87833 ], [ - 79.21142578125, - 33.18813395605041 + -59.65302, + 1.85087 ], [ - 78.8104248046875, - 33.829356907739296 + -59.69147, + 1.75754 ], [ - 79.024658203125, - 34.30260622622907 + -59.61456, + 1.71361 ], [ - 78.0908203125, - 34.912962495216966 + -59.55139, + 1.73283 ], [ - 78.134765625, - 35.505400093441324 + -59.36188, + 1.49123 ], [ - 76.761474609375, - 35.65729624809628 + -59.26575, + 1.39238 ], [ - 76.552734375, - 35.92464453144099 + -58.92242, + 1.30726 ], [ - 76.0693359375, - 35.97800618085566 + -58.83728, + 1.17271 ], [ - 75.69580078125, - 36.80928470205937 + -58.71918, + 1.23037 ], [ - 74.55322265625, - 37.10776507118514 + -58.71094, + 1.29902 ], [ - 73.10302734375, - 36.86204269508728 + -58.49121, + 1.26058 ], [ - 71.56494140625, - 36.38591277287651 + -58.461, + 1.37591 ], [ - 71.2353515625, - 36.01356058518153 + -58.50494, + 1.38689 ], [ - 71.5869140625, - 35.15584570226544 + -58.51044, + 1.46102 ], [ - 70.9716796875, - 34.470335121217474 + -58.38135, + 1.4775 ], [ - 71.12548828125, - 34.27083595165 + -58.32642, + 1.57359 ], [ - 70.927734375, - 33.99802726234877 + -58.00507, + 1.49946 ], [ - 69.85107421874999, - 34.016241889667015 + -57.99133, + 1.65321 ], [ - 70.3125, - 33.32134852669881 + -57.79907, + 1.69165 ], [ - 69.521484375, - 33.063924198120645 + -57.70844, + 1.71087 ], [ - 69.23583984375, - 31.970803930433096 + -57.54364, + 1.68341 ], [ - 68.84033203125, - 31.541089879585808 + -57.41455, + 1.94421 ], [ - 68.48876953125, - 31.80289258670676 + -57.10693, + 1.97715 ], [ - 68.13720703125, - 31.82156451492074 + -56.8103, + 1.85636 ], [ - 67.5439453125, - 31.541089879585808 + -56.48071, + 1.92225 ], [ - 67.82958984375, - 31.372399104880525 + -55.90942, + 1.81244 ], [ - 67.12646484375, - 31.22219703210317 + -55.90942, + 2.04302 ], [ - 66.81884765625, - 31.297327991404266 + -56.14014, + 2.26534 ], [ - 66.4453125, - 30.939924331023445 + -55.94788, + 2.53701 ], [ - 66.3134765625, - 29.859701442126756 + -55.70892, + 2.39981 ], [ - 65.126953125, - 29.57345707301757 + -55.37933, + 2.43274 ], [ - 64.44580078125, - 29.592565403314087 + -55.19257, + 2.53976 ], [ - 64.072265625, - 29.401319510041485 + -54.98108, + 2.57268 ], [ - 62.4462890625, - 29.420460341013133 + -54.88495, + 2.43548 ], [ - 60.88623046875001, - 29.84064389983441 + -54.71191, + 2.46293 ], [ - 61.36962890625001, - 29.34387539941801 + -54.69543, + 2.34767 ], [ - 61.58935546875, - 28.9023972285585 + -54.58832, + 2.32846 ], [ - 61.89697265624999, - 28.51696944040106 + -54.43451, + 2.43548 ], [ - 62.77587890625, - 28.246327971048842 + -54.20654, + 2.76748 ], [ - 62.7978515625, - 27.254629577800063 + -54.17358, + 3.12955 ], [ - 63.25927734375, - 27.235094607795503 + -53.96484, + 3.57921 ], [ - 63.19335937499999, - 26.686729520004036 + -54.33838, + 4.00674 ], [ - 62.2705078125, - 26.509904531413927 + -54.44412, + 4.52577 ], [ - 62.24853515624999, - 26.31311263768267 + -54.46884, + 4.91036 ], [ - 61.85302734375001, - 26.27371402440643 + -54.36653, + 5.13061 ], [ - 61.58935546875, - 25.224820176765036 + -54.27727, + 5.26191 ], [ - 74.970703125, - 7.580327791330129 + -54.19968, + 5.3084 ], [ - 67.6318359375, - 4.521666342614804 + -54.01222, + 5.54457 ], [ - 72.4658203125, - -2.986927393334863 + -54.0239, + 5.64605 ], [ - 85.86914062500001, - 5.5941182188847876 + -53.86322, + 5.94936 ], [ - 92.39501953125, - 21.514406720030294 + -64.33594, + 32.86113 ] ] ] @@ -867,904 +790,736 @@ "coordinates": [ [ [ - 43.57177734375001, - -4.390228926463384 + -14.5, + -6 ], [ - 41.0009765625, - -0.8129610018708315 + 11.79657, + -17.27197 ], [ - 40.97900390625, - 2.7235830833483856 + 12.03415, + -17.14866 ], [ - 41.90185546875, - 3.995780512963038 + 12.38159, + -17.22213 ], [ - 41.15478515624999, - 3.9738609758391017 + 12.58484, + -17.22476 ], [ - 40.75927734375, - 4.3464112753331925 + 13.01193, + -16.97405 ], [ - 39.814453125, - 3.8423316311549156 + 13.24951, + -17.00098 ], [ - 39.55078125, - 3.447624666646865 + 13.38135, + -16.98522 ], [ - 38.14453125, - 3.6230713262356864 + 13.93341, + -17.38734 ], [ - 36.9580078125, - 4.477856485570586 + 18.42476, + -17.38996 ], [ - 35.9912109375, - 4.477856485570586 + 18.47763, + -17.46857 ], [ - 35.947265625, - 4.696879026871425 + 18.62663, + -17.64599 ], [ - 34.43115234375, - 4.631179340411012 + 18.79211, + -17.76177 ], [ - 33.94775390625, - 4.171115454867424 + 18.92944, + -17.82061 ], [ - 34.43115234375, - 3.6449998008920375 + 19.33044, + -17.84806 ], [ - 32.01416015625, - 3.601142320158735 + 19.66278, + -17.8644 ], [ - 31.81640625, - 3.8642546157214084 + 19.74792, + -17.90557 ], [ - 30.871582031249996, - 3.6230713262356864 + 19.85161, + -17.87486 ], [ - 30.78369140625, - 2.3943223575350774 + 20.10361, + -17.90296 ], [ - 31.289062500000004, - 2.152813583128846 + 20.18394, + -17.88401 ], [ - 30.454101562499996, - 1.1644706071806057 + 20.34737, + -17.88466 ], [ - 29.860839843749996, - 0.4833927027896987 + 20.44693, + -17.91733 ], [ - 29.553222656249996, - -1.2962761196418089 + 20.51697, + -17.96698 ], [ - 30.454101562499996, - -1.0546279422758742 + 20.83008, + -18.03032 ], [ - 30.91552734375, - -1.8014609294680355 + 20.95711, + -17.97285 ], [ - 30.871582031249996, - -2.3943223575350774 + 21.16997, + -17.93497 ], [ - 30.563964843750004, - -2.4162756547063857 + 21.42677, + -18.0264 ], [ - 30.43212890625, - -2.921097018708451 + 23.45032, + -17.63879 ], [ - 30.827636718749996, - -2.921097018708451 + 22.00012, + -16.38866 ], [ - 30.827636718749996, - -3.2502085616531686 + 21.99944, + -13.00523 ], [ - 30.322265625000004, - -3.864254615721396 + 24.03809, + -12.99118 ], [ - 29.970703124999996, - -4.3245014930191905 + 24.03809, + -10.91962 ], [ - 29.443359375, - -4.412136788910181 + 24.43359, + -11.09217 ], [ - 29.355468750000004, - -4.872047700241915 + 24.45557, + -11.48002 ], [ - 29.663085937499996, - -5.7690358661221355 + 25.37842, + -11.19996 ], [ - 29.729003906249996, - -6.620957270326323 + 25.42236, + -11.60919 ], [ - 31.09130859375, - -8.581021215641842 + 26.96045, + -11.97484 ], [ - 28.894042968749996, - -8.472372282909127 + 27.18018, + -11.60919 ], [ - 28.410644531249996, - -9.297306856327596 + 28.125, + -12.42048 ], [ - 28.67431640625, - -9.925565912405494 + 29.11377, + -13.36824 ], [ - 28.652343749999996, - -10.703791711680724 + 29.1687, + -13.43771 ], [ - 28.36669921875, - -11.695272733029402 + 29.55872, + -13.19716 ], [ - 29.02587890625, - -12.340001834116316 + 29.68506, + -13.2239 ], [ - 29.77294921875, - -12.146745814539685 + 29.62463, + -13.41099 ], [ - 29.838867187500004, - -13.432366575813747 + 29.80591, + -13.44305 ], [ - 29.597167968750004, - -13.17577122442339 + 29.81415, + -12.14809 ], [ - 28.54248046875, - -12.790374787613588 + 29.31152, + -12.55456 ], [ - 27.9052734375, - -12.254127737657369 + 28.41064, + -11.78133 ], [ - 27.0703125, - -11.630715737981474 + 28.63037, + -10.70379 ], [ - 26.69677734375, - -11.953349393643416 + 28.65234, + -9.73071 ], [ - 25.356445312499996, - -11.566143767762844 + 28.37219, + -9.24309 ], [ - 25.356445312499996, - -11.199956869621811 + 28.89748, + -8.47916 ], [ - 24.41162109375, - -11.372338792141125 + 30.78644, + -8.26857 ], [ - 24.0380859375, - -10.898042159726009 + 29.39941, + -6.05316 ], [ - 23.994140624999996, - -12.961735843534306 + 29.4873, + -4.45595 ], [ - 21.97265625, - -13.025965926333539 + 29.75922, + -4.46759 ], [ - 21.9287109375, - -16.13026201203474 + 29.81415, + -4.36421 ], [ - 23.48876953125, - -17.644022027872712 + 29.88007, + -4.36832 ], [ - 21.4013671875, - -18.041421221891937 + 30.04074, + -4.26699 ], [ - 18.45703125, - -17.392579271057766 + 30.07919, + -4.1629 ], [ - 14.23828125, - -17.392579271057766 + 30.18356, + -4.08311 ], [ - 13.359375, - -16.951724234434423 + 30.1918, + -4.05126 ], [ - 12.5244140625, - -17.224758206624628 + 30.21566, + -4.04595 ], [ - 9.77783203125, - -17.245744208007117 + 30.22923, + -4.01136 ], [ - 13.359375, - -38.54816542304657 + 30.21326, + -3.99612 ], [ - 36.03515625, - -34.74161249883172 + 30.25978, + -3.88755 ], [ - 43.57177734375001, - -4.390228926463384 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 56.35986328125, - -21.125497636606266 + 30.29274, + -3.86288 ], [ - 59.23828124999999, - -21.125497636606266 + 30.34424, + -3.77245 ], [ - 59.23828124999999, - -19.642587534013032 + 30.39848, + -3.79095 ], [ - 56.35986328125, - -19.642587534013032 + 30.40878, + -3.76765 ], [ - 56.35986328125, - -21.125497636606266 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 70.42236328125, - -7.896029593273104 + 30.39548, + -3.7304 ], [ - 73.2623291015625, - -7.896029593273104 + 30.39054, + -3.72821 ], [ - 73.2623291015625, - -5.78543165536185 + 30.3896, + -3.71918 ], [ - 70.42236328125, - -5.78543165536185 + 30.39093, + -3.7101 ], [ - 70.42236328125, - -7.896029593273104 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 49.39453125, - -8.146242825034385 + 30.39514, + -3.70444 ], [ - 60.6005859375, - -8.146242825034385 + 30.42028, + -3.64963 ], [ - 60.6005859375, - -2.67968661580376 + 30.46886, + -3.53501 ], [ - 49.39453125, - -2.67968661580376 + 30.67108, + -3.41335 ], [ - 49.39453125, - -8.146242825034385 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 30.63297, + -3.34892 + ], [ - -53.9208984375, - 6.096859818887948 + 30.84206, + -3.25535 ], [ - -55.72265625, - 7.863381805309173 + 30.84549, + -3.16108 ], [ - -60.13916015625, - 8.86336203355168 + 30.83485, + -3.09698 ], [ - -59.83154296874999, - 8.276727101164047 + 30.7933, + -3.06235 ], [ - -60.53466796874999, - 7.863381805309173 + 30.82111, + -3.02258 ], [ - -60.71044921875, - 7.558546606093156 + 30.84515, + -2.9739 ], [ - -60.57861328125, - 7.18810087117902 + 30.74764, + -2.99618 ], [ - -60.2490234375, - 7.18810087117902 + 30.7037, + -2.97013 ], [ - -60.5126953125, - 6.860985433763661 + 30.66422, + -2.98967 ], [ - -60.88623046875001, - 6.860985433763661 + 30.57632, + -2.90738 ], [ - -61.19384765625, - 6.68643125265198 + 30.49393, + -2.94441 ], [ - -61.10595703125, - 6.227933930268672 + 30.41016, + -2.87172 ], [ - -61.41357421874999, - 5.987606891658272 + 30.52002, + -2.39432 ], [ - -60.732421875, - 5.222246513227375 + 30.77545, + -2.38883 ], [ - -60.18310546874999, - 5.331644153439766 + 30.8606, + -2.31199 ], [ - -59.96337890624999, - 5.0690578267840465 + 30.84961, + -2.19398 ], [ - -60.20507812499999, - 4.54357027937176 + 30.89081, + -2.07322 ], [ - -59.61181640625, - 4.324501493019203 + 30.81116, + -1.96068 ], [ - -59.5458984375, - 3.9300201571114752 + 30.83862, + -1.6587 ], [ - -59.87548828125, - 3.5572827265412794 + 30.73425, + -1.4418 ], [ - -60.029296875, - 2.767477951092084 + 30.56259, + -1.33884 ], [ - -59.765625, - 2.2625953010152453 + 30.4541, + -1.05737 ], [ - -59.47998046874999, - 1.6037944300589855 + 30.35797, + -1.06287 ], [ - -58.86474609374999, - 1.1864386394452024 + 30.34149, + -1.13152 ], [ - -57.919921875, - 1.6477220517969353 + 30.16571, + -1.34296 ], [ - -57.1728515625, - 2.0210651187669897 + 29.91852, + -1.48024 ], [ - -56.5576171875, - 1.9771465537125772 + 29.83887, + -1.31824 ], [ - -55.8984375, - 1.8234225930141614 + 29.58344, + -1.39238 ], [ - -56.1181640625, - 2.3504147112508176 + 29.729, + 0.05493 ], [ - -55.96435546875, - 2.5040852618529215 + 29.96796, + 0.5136 ], [ - -54.99755859375, - 2.591888984149953 + 29.9707, + 0.8569 ], [ - -54.51416015625, - 2.28455066023697 + 30.22339, + 0.92281 ], [ - -53.94287109375, - 3.5572827265412794 + 30.24536, + 1.15349 ], [ - -54.38232421875, - 4.039617826768437 + 30.47745, + 1.20772 ], [ - -54.4482421875, - 4.893940608902113 + 31.30966, + 2.15693 ], [ - -54.0087890625, - 5.506639674354886 + 31.20255, + 2.22211 ], [ - -53.9208984375, - 6.096859818887948 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 31.20255, + 2.29278 + ], [ - -62.60009765624999, - -53.409531853086435 + 31.16409, + 2.27906 ], [ - -55.70068359375, - -53.409531853086435 + 31.13937, + 2.28318 ], [ - -55.70068359375, - -50.247204901392664 + 31.13113, + 2.26534 ], [ - -62.60009765624999, - -50.247204901392664 + 31.07826, + 2.30033 ], [ - -62.60009765624999, - -53.409531853086435 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 31.0714, + 2.34767 + ], [ - -41.220703125, - -57.70414723434192 + 31.00479, + 2.4005 ], [ - -29.091796875, - -57.70414723434192 + 30.97183, + 2.40461 ], [ - -29.091796875, - -52.74959372674114 + 30.94711, + 2.38746 ], [ - -41.220703125, - -52.74959372674114 + 30.94849, + 2.36276 ], [ - -41.220703125, - -57.70414723434192 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 30.9375, + 2.33532 + ], [ - -46.845703125, - -60.95444387929966 + 30.88531, + 2.34012 ], [ - -43.81347656249999, - -60.95444387929966 + 30.83038, + 2.42176 ], [ - -43.81347656249999, - -60.329667021005825 + 30.74112, + 2.43274 ], [ - -46.845703125, - -60.329667021005825 + 30.76035, + 2.5864 ], [ - -46.845703125, - -60.95444387929966 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 30.90179, + 2.88132 + ], [ - -65.489501953125, - 31.840232667909365 + 30.76447, + 3.04178 ], [ - -64.00634765625, - 31.840232667909365 + 30.93613, + 3.40239 ], [ - -64.00634765625, - 32.76418137510082 + 30.94059, + 3.50588 ], [ - -65.489501953125, - 32.76418137510082 + 30.85236, + 3.48601 ], [ - -65.489501953125, - 31.840232667909365 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 30.90866, + 3.5936 + ], [ - -78.90380859375, - 16.867633616803836 + 30.95055, + 3.63918 ], [ - -75.6298828125, - 16.867633616803836 + 30.94677, + 3.65391 ], [ - -75.6298828125, - 18.979025953255267 + 30.9866, + 3.70187 ], [ - -78.90380859375, - 18.979025953255267 + 31.00582, + 3.70701 ], [ - -78.90380859375, - 16.867633616803836 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 31.02058, + 3.69708 + ], [ - -81.67236328125001, - 19.03875247795316 + 31.16547, + 3.7954 ], [ - -79.76898193359376, - 19.48989674307901 + 31.28838, + 3.79643 ], [ - -79.48333740234375, - 19.888140273126222 + 31.52699, + 3.66282 ], [ - -81.45263671875001, - 19.46400263520258 + 31.7038, + 3.72449 ], [ - -81.67236328125001, - 19.03875247795316 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 31.82671, + 3.82794 + ], [ - 13.90869140625, - 35.6126508187567 + 31.96198, + 3.65596 ], [ - 15.00732421875, - 35.505400093441324 + 31.95854, + 3.57099 ], [ - 15.029296875, - 36.32397712011264 + 32.04987, + 3.59155 ], [ - 13.831787109375, - 36.36822190085111 + 32.07733, + 3.57099 ], [ - 13.90869140625, - 35.6126508187567 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 32.0842, + 3.53672 + ], [ - 113.53256464004518, - 22.17096258989228 + 32.20093, + 3.50657 ], [ - 113.53754281997682, - 22.16047023983672 + 32.21672, + 3.56448 ], [ - 113.54106187820436, - 22.154587822430837 + 32.19578, + 3.59977 ], [ - 113.54878664016725, - 22.14703570986906 + 32.41516, + 3.74504 ], [ - 113.54990243911743, - 22.141947742446394 + 32.72055, + 3.76782 ], [ - 113.54792833328247, - 22.118731558535227 + 32.89307, + 3.81219 ], [ - 113.54852914810182, - 22.11006426296891 + 33.02782, + 3.89371 ], [ - 113.56088876724245, - 22.105531611874294 + 33.18146, + 3.7793 ], [ - 113.5914444923401, - 22.117300298747207 + 33.51173, + 3.75258 ], [ - 113.60217332839966, - 22.136303063467075 + 33.98758, + 4.23309 ], [ - 113.58766794204713, - 22.183520585503548 + 34.05762, + 4.28342 ], [ - 113.57015848159791, - 22.189083895743767 + 34.38721, + 4.61065 ], [ - 113.56621026992799, - 22.189163370008256 + 35.94452, + 4.62023 ], [ - 113.56406450271608, - 22.190514425625366 + 35.95688, + 4.53467 ], [ - 113.56380701065065, - 22.19941517306984 + 36.04134, + 4.44568 ], [ - 113.56191873550418, - 22.2050573189853 + 36.89621, + 4.4491 ], [ - 113.56088876724245, - 22.21260631441281 + 38.14728, + 3.62992 ], [ - 113.55256319046022, - 22.217294433458783 + 38.55927, + 3.62033 ], [ - 113.54850769042969, - 22.21683754739093 + 38.92181, + 3.51068 ], [ - 113.5441303253174, - 22.217056058304685 + 39.56039, + 3.43392 ], [ - 113.54318618774415, - 22.216479983343337 + 39.87076, + 3.87522 ], [ - 113.5415554046631, - 22.213242000752253 + 40.76752, + 4.28753 ], [ - 113.54114770889284, - 22.213003618712484 + 41.16371, + 3.94372 ], [ - 113.53824019432068, - 22.213659168347313 + 41.89774, + 3.97797 ], [ - 113.53728532791139, - 22.21367903343993 + 41.31271, + 3.14463 ], [ - 113.53571891784668, - 22.213559842841935 + 40.98896, + 2.82869 ], [ - 113.53435635566713, - 22.213182405280275 + 40.99548, + -0.84042 ], [ - 113.53312253952026, - 22.212367931293002 + 41.7, + -1.8 ], [ - 113.53496789932252, - 22.20616982803302 + 41.7, + -49 ], [ - 113.53222131729127, - 22.19401121511328 + -27, + -60 ], [ - 113.52681398391725, - 22.184792218694355 + -65.7, + -52.5 ], [ - 113.53256464004518, - 22.17096258989228 + -14.5, + -6 ] ] ] @@ -1780,56 +1535,20 @@ "coordinates": [ [ [ - 114.1398811340332, - 22.298308554808454 - ], - [ - 114.1146469116211, - 22.295926164040363 + 31.33301, + 35.47856 ], [ - 114.10280227661133, - 22.2808367460213 + 33.0249, + 33.75175 ], [ - 114.1505241394043, - 22.226342457476385 + 35.44189, + 36.02245 ], [ - 114.20768737792969, - 22.188199741518677 - ], - [ - 114.26794052124023, - 22.199325771045544 - ], - [ - 114.26673889160155, - 22.257008033931445 - ], - [ - 114.24699783325194, - 22.278295210101668 - ], - [ - 114.22657012939453, - 22.29354373265189 - ], - [ - 114.20408248901367, - 22.29973796977008 - ], - [ - 114.184513092041, - 22.290843594643704 - ], - [ - 114.16563034057617, - 22.28925525380013 - ], - [ - 114.1398811340332, - 22.298308554808454 + 31.33301, + 35.47856 ] ] ] @@ -1845,24 +1564,20 @@ "coordinates": [ [ [ - -79.82666015625001, - 25.035838555635017 - ], - [ - -73.55346679687501, - 20.324023603422518 + 14, + 36.5 ], [ - -70.82336425781251, - 21.307287323905406 + 15, + 36 ], [ - -78.38745117187501, - 28.304380682962783 + 14, + 35 ], [ - -79.82666015625001, - 25.035838555635017 + 14, + 36.5 ] ] ] @@ -1878,32 +1593,28 @@ "coordinates": [ [ [ - -59.06250000000001, - 13.378931658431565 - ], - [ - -61.02905273437501, - 14.216463756160174 + 0, + 62 ], [ - -61.92443847656251, - 12.350734120814016 + 2.5, + 51.3 ], [ - -61.71569824218751, - 10.935798432254105 + -2, + 50 ], [ - -62.06176757812501, - 10.028357677443571 + -1.9, + 49 ], [ - -61.13891601562501, - 9.855216086088848 + -20, + 53 ], [ - -59.06250000000001, - 13.378931658431565 + 0, + 62 ] ] ] @@ -1919,265 +1630,1494 @@ "coordinates": [ [ [ - -61.43829345703126, - 17.17228278169308 + 180, + -35 ], [ - -61.80358886718751, - 17.882045302279195 + 161, + -19 ], [ - -62.91870117187501, - 17.403062993328938 + 167, + -12 ], [ - -62.149658203125, - 16.52826534972986 + 180, + -22 ], [ - -61.43829345703126, - 17.17228278169308 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 180, + 4 + ], [ - -61.33392333984376, - 15.731457491108594 + 170, + 3.7 ], [ - -61.63604736328126, - 15.570127852659427 + 127, + 5.7 ], [ - -61.36138916015626, - 15.10394633500913 + 118, + 2.7 ], [ - -61.13342285156251, - 15.257689080778713 + 119.5, + 5.4 ], [ - -61.33392333984376, - 15.731457491108594 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 117.2, + 7.5 + ], [ - -63.46664428710938, - 18.672267305093758 + 102.6, + 8 ], [ - -64.5604705810547, - 18.78736737706614 + 102.9158, + 11.74099 ], [ - -64.8845672607422, - 18.40665471391907 + 102.76268, + 12.07357 ], [ - -64.6593475341797, - 18.365604299215338 + 102.70226, + 12.17158 ], [ - -64.61608886718751, - 18.114529138838503 + 102.74139, + 12.46474 ], [ - -63.30596923828126, - 18.108002884854656 + 102.53128, + 12.68857 ], [ - -62.79235839843751, - 18.231960055191504 + 102.49557, + 12.9256 ], [ - -63.46664428710938, - 18.672267305093758 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 102.49763, + 13.0064 + ], [ - 31.898803710937504, - 35.29943548054545 + 102.4597, + 13.08199 ], [ - 32.38220214843751, - 34.43409789359469 + 102.43412, + 13.09026 ], [ - 34.69482421875001, - 34.74161249883172 + 102.39155, + 13.16407 ], [ - 34.74975585937501, - 35.79999392988527 + 102.35481, + 13.29341 ], [ - 31.898803710937504, - 35.29943548054545 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 102.35893, + 13.30945 + ], [ - 166.53076171875003, - -0.7140928403610857 + 102.34503, + 13.34837 ], [ - 172.81494140625009, - 0.4751532449748611 + 102.35928, + 13.39797 ], [ - 176.50634765625003, - -17.245744208007117 + 102.3567, + 13.48095 ], [ - 177.82470703125009, - -19.36038488536514 + 102.36168, + 13.50582 ], [ - 180.0439453125002, - -19.67103928897615 + 102.33559, + 13.53787 ], [ - 180.1098632812502, - -13.333502655583224 + 102.33971, + 13.56023 ], [ - 189.00878906250003, - -9.760490714194388 + 102.35498, + 13.5649 ], [ - 189.931640625, - -4.726989319952657 + 102.36511, + 13.5785 ], [ - 199.62158203125003, - 2.583657640731887 + 102.40047, + 13.5679 ], [ - 201.04980468750003, - -0.6014904163878395 + 102.42537, + 13.56891 ], [ - 193.31542968750003, - -9.543874794137526 + 102.44614, + 13.56123 ], [ - 193.42529296875003, - -14.95274576245613 + 102.48047, + 13.57091 ], [ - 183.7353515625, - -14.846576365691352 + 102.53849, + 13.56757 ], [ - 180.3295898437502, - -24.27450874986185 + 102.5699, + 13.58526 ], [ - 203.46679687500003, - -22.662175307872086 + 102.57806, + 13.60486 ], [ - 203.2470703125, - -13.247966096402816 + 102.62501, + 13.60845 ], [ - 211.33300781250003, - -11.35887518924762 + 102.62132, + 13.61295 ], [ - 200.65429687500003, - 6.468151012664214 + 102.60767, + 13.61562 ], [ - 179.8461914062502, - -4.836470204221701 + 102.57231, + 13.63331 ], [ - 173.1445312500001, - 4.162897490667403 + 102.56922, + 13.64082 ], [ - 166.53076171875003, - -0.7140928403610857 - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "driving_side": "left" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ + 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 + ], [ - -127.33154296875001, - -24.166802085303225 + -171.5, + -10.75 ], [ - -131.17675781250003, - -23.60426184707018 + -171, + -16 ], [ - -130.34179687500003, - -25.324166525738384 + -152, + -19 ], [ - -123.49731445312501, - -24.716895455859337 + -180, + -55 ], [ - -127.33154296875001, - -24.166802085303225 + -180, + 7 ] ] ] @@ -2193,24 +3133,24 @@ "coordinates": [ [ [ - -5.976562500000001, - -15.728813770533979 + -130.21, + -25.16 ], [ - -5.949096679687501, - -16.13026201203474 + -129.99, + -25.16 ], [ - -5.482177734375001, - -16.156644815257152 + -129.99, + -24.98 ], [ - -5.465698242187501, - -15.760536148501288 + -130.21, + -24.98 ], [ - -5.976562500000001, - -15.728813770533979 + -130.21, + -25.16 ] ] ] diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 056f8c7b6ef..00000000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -FROM debian:stretch-slim as builder -ARG DOCKER_TAG -ARG BUILD_CONCURRENCY -RUN mkdir -p /src && mkdir -p /opt -COPY . /src -WORKDIR /src - -RUN NPROC=${BUILD_CONCURRENCY:-$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1)} && \ - apt-get update && \ - apt-get -y --no-install-recommends install cmake make git gcc g++ libbz2-dev libxml2-dev \ - libzip-dev libboost1.62-all-dev lua5.2 liblua5.2-dev libtbb-dev -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 && \ - echo "Building OSRM ${DOCKER_TAG}" && \ - git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \ - echo "Building OSRM gitsha $(cat /opt/OSRM_GITSHA)" && \ - mkdir -p build && \ - cd build && \ - BUILD_TYPE="Release" && \ - ENABLE_ASSERTIONS="Off" && \ - BUILD_TOOLS="Off" && \ - case ${DOCKER_TAG} in *"-debug"*) BUILD_TYPE="Debug";; esac && \ - case ${DOCKER_TAG} in *"-assertions"*) BUILD_TYPE="RelWithDebInfo" && ENABLE_ASSERTIONS="On" && BUILD_TOOLS="On";; esac && \ - echo "Building ${BUILD_TYPE} with ENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} BUILD_TOOLS=${BUILD_TOOLS}" && \ - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} -DBUILD_TOOLS=${BUILD_TOOLS} -DENABLE_LTO=On && \ - make -j${NPROC} install && \ - cd ../profiles && \ - cp -r * /opt && \ - strip /usr/local/bin/* && \ - rm -rf /src /usr/local/lib/libosrm* - - -# Multistage build to reduce image size - https://docs.docker.com/engine/userguide/eng-image/multistage-build/#use-multi-stage-builds -# Only the content below ends up in the image, this helps remove /src from the image (which is large) -FROM debian:stretch-slim as runstage -RUN mkdir -p /src && mkdir -p /opt -RUN apt-get update && \ - apt-get install -y --no-install-recommends libboost-program-options1.62.0 libboost-regex1.62.0 \ - libboost-date-time1.62.0 libboost-chrono1.62.0 libboost-filesystem1.62.0 \ - libboost-iostreams1.62.0 libboost-thread1.62.0 expat liblua5.2-0 libtbb2 &&\ - rm -rf /var/lib/apt/lists/* -COPY --from=builder /usr/local /usr/local -COPY --from=builder /opt /opt -RUN /usr/local/bin/osrm-extract --help && \ - /usr/local/bin/osrm-routed --help && \ - /usr/local/bin/osrm-contract --help && \ - /usr/local/bin/osrm-partition --help && \ - /usr/local/bin/osrm-customize --help -WORKDIR /opt - -EXPOSE 5000 diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 120000 index 00000000000..4407bedc545 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1 @@ +Dockerfile-debian \ No newline at end of file diff --git a/docker/Dockerfile-alpine b/docker/Dockerfile-alpine new file mode 100644 index 00000000000..497c71514f7 --- /dev/null +++ b/docker/Dockerfile-alpine @@ -0,0 +1,77 @@ +FROM alpine:3.21.2 AS alpine-mimalloc + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache \ + boost-iostreams \ + boost-program_options \ + boost-thread \ + mimalloc + +ENV LD_PRELOAD=/usr/lib/libmimalloc.so.2 +ENV MIMALLOC_LARGE_OS_PAGES=1 + + +FROM alpine-mimalloc AS builder +ARG DOCKER_TAG +ARG BUILD_CONCURRENCY + +RUN mkdir -p /src /opt && \ + apk add --no-cache \ + boost-dev \ + boost-filesystem \ + clang \ + cmake \ + expat-dev \ + git \ + libbz2 \ + libxml2 \ + lua5.4-dev \ + make \ + onetbb-dev + +COPY . /src +WORKDIR /src + +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 -p build && \ + cd build && \ + BUILD_TYPE="Release" && \ + ENABLE_ASSERTIONS="Off" && \ + case ${DOCKER_TAG} in *"-debug"*) BUILD_TYPE="Debug";; esac && \ + case ${DOCKER_TAG} in *"-assertions"*) BUILD_TYPE="RelWithDebInfo" && ENABLE_ASSERTIONS="On";; esac && \ + echo "Building ${BUILD_TYPE} with ENABLE_ASSERTIONS=${ENABLE_ASSERTIONS}" && \ + cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} -DENABLE_LTO=OFF && \ + make -j${NPROC} install && \ + cd ../profiles && \ + cp -r * /opt && \ + strip /usr/local/bin/* && \ + rm -rf /src + + +# Multistage build to reduce image size - https://docs.docker.com/build/building/multi-stage/#use-multi-stage-builds +# Only the content below ends up in the image, this helps remove /src from the image (which is large) +FROM alpine-mimalloc AS runstage + +COPY --from=builder /usr/local /usr/local +COPY --from=builder /opt /opt + +RUN apk add --no-cache \ + boost-date_time \ + expat \ + lua5.4 \ + onetbb && \ + 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/Dockerfile-debian b/docker/Dockerfile-debian new file mode 100644 index 00000000000..43500e5115a --- /dev/null +++ b/docker/Dockerfile-debian @@ -0,0 +1,74 @@ +FROM debian:bookworm-slim AS builder +ARG DOCKER_TAG +ARG BUILD_CONCURRENCY + +RUN mkdir -p /src /opt && \ + apt-get update && \ + apt-get -y --no-install-recommends --no-install-suggests install \ + ca-certificates \ + cmake \ + g++ \ + gcc \ + git \ + libboost1.81-all-dev \ + libbz2-dev \ + liblua5.4-dev \ + libtbb-dev \ + libxml2-dev \ + libzip-dev \ + lua5.4 \ + make \ + pkg-config + +COPY . /src +WORKDIR /src + +RUN NPROC=${BUILD_CONCURRENCY:-$(nproc)} && \ + export CXXFLAGS="-Wno-array-bounds -Wno-uninitialized -Wno-stringop-overflow" && \ + echo "Building OSRM ${DOCKER_TAG}" && \ + git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \ + echo "Building OSRM gitsha $(cat /opt/OSRM_GITSHA)" && \ + mkdir -p build && \ + cd build && \ + BUILD_TYPE="Release" && \ + ENABLE_ASSERTIONS="Off" && \ + case ${DOCKER_TAG} in *"-debug"*) BUILD_TYPE="Debug";; esac && \ + case ${DOCKER_TAG} in *"-assertions"*) BUILD_TYPE="RelWithDebInfo" && ENABLE_ASSERTIONS="On";; esac && \ + echo "Building ${BUILD_TYPE} with ENABLE_ASSERTIONS=${ENABLE_ASSERTIONS}" && \ + cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} -DENABLE_LTO=On && \ + make -j${NPROC} install && \ + cd ../profiles && \ + cp -r * /opt && \ + strip /usr/local/bin/* && \ + rm -rf /src + + +# Multistage build to reduce image size - https://docs.docker.com/build/building/multi-stage/#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:bookworm-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 --no-install-suggests \ + expat \ + libboost-date-time1.81.0 \ + libboost-iostreams1.81.0 \ + libboost-program-options1.81.0 \ + libboost-thread1.81.0 \ + liblua5.4-0 \ + libtbb12 && \ + 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 \ No newline at end of file diff --git a/docker/hooks/build b/docker/hooks/build old mode 100644 new mode 100755 index c27c851ad94..8756e3e9329 --- a/docker/hooks/build +++ b/docker/hooks/build @@ -6,4 +6,8 @@ # 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 BUILD_CONCURRENCY=${CONCURRENCY:-1} --build-arg DOCKER_TAG=${DOCKER_TAG} -t $IMAGE_NAME -f Dockerfile .. + +DOCKER_BUILD="docker build --build-arg BUILD_CONCURRENCY=${CONCURRENCY} --build-arg DOCKER_TAG=${DOCKER_TAG:?unset} -t ${IMAGE_NAME:?unset} -f" + +$DOCKER_BUILD Dockerfile .. +$DOCKER_BUILD Dockerfile-alpine .. diff --git a/docs/developing.md b/docs/developing.md index 9bb661a9109..badbca9caba 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -32,9 +32,9 @@ For outputting data into our file (debug.geojson), we simply need to call the ma ### Possible Scopeguard Location Think of the scopeguard as you would do of any reference. If you wan't to access to logging during a call, the guard object must be alive and valid. -As an example: a good location to create the a scopeguard to log decisions in the edge-based-graph-factory would be right before we run it ([here](https://github.com/Project-OSRM/osrm-backend/blob/a933b5d94943bf3edaf42c84a614a99650d23cba/src/extractor/extractor.cpp#L497)). If you put `util::ScopedGeojsonLoggerGuard geojson_guard( "debug.geojson", node_coordinate_vector);` at that location, you can then print `util::ScopedGeojsonLoggerGuard::Write(list_of_node_ids);` anywhere within the `edge-based-graph-factory`. +As an example: a good location to create a scopeguard to log decisions in the edge-based-graph-factory would be right before we run it ([here](https://github.com/Project-OSRM/osrm-backend/blob/a933b5d94943bf3edaf42c84a614a99650d23cba/src/extractor/extractor.cpp#L497)). If you put `util::ScopedGeojsonLoggerGuard geojson_guard( "debug.geojson", node_coordinate_vector);` at that location, you can then print `util::ScopedGeojsonLoggerGuard::Write(list_of_node_ids);` anywhere within the `edge-based-graph-factory`. -This location would enable call for all guidance related pre-processing which is called in the edge-based-graph-factory. +This location would enable calls for all guidance related pre-processing which is called in the edge-based-graph-factory. Logging any turn-handler decisions, for example, would now be possible. ## Limitations diff --git a/docs/http.md b/docs/http.md index ff4b2460297..9e6649d7317 100644 --- a/docs/http.md +++ b/docs/http.md @@ -1,7 +1,7 @@ # OSRM HTTP server -Built-in HTTP server is a basic HTTP/1.0 server that supports 'keep-alive' extension. Persistent connections are limited to 512 requests per -connection and allow no more then 5 seconds between requests. +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 @@ -21,23 +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. | -|snapping |`default` (default), `any` |Default snapping avoids is_startpoint (see profile) edges, `any` will snap to any edge in the graph | +| 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} ...]` |Restrict the direction on the road network at a waypoint, relative to the input coordinate. | +|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: @@ -46,7 +47,7 @@ Where the elements follow the following format: |bearing |`{value},{range}` `integer 0 .. 360,integer 0 .. 180` | |radius |`double >= 0` or `unlimited` (default) | |hint |Base64 `string` | -|approach |`curb` or `unrestricted` (default) | +|approach |`curb`, `opposite` or `unrestricted` (default) | |class |A class name determined by the profile or `none`. | ``` @@ -55,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} @@ -87,17 +88,18 @@ 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. | +| `DisabledDataset` | The request tried to access a disabled dataset. | -- `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` propetry containing timestamp from the original OpenStreetMap file. This field is optional. It can be ommited if data_version parametr was not set on osrm-extract stage or OSM file has not `osmosis_replication_timestamp` section. +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 @@ -128,6 +130,9 @@ 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. @@ -143,7 +148,7 @@ curl 'http://router.project-osrm.org/nearest/v1/driving/13.388860,52.517037?numb%20%20####%20Example%20Response%20-%60%60%60json+%60%60%60JSON%20{"waypoints" : [ { @@ -207,8 +212,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. | -|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. | +|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. @@ -235,7 +240,7 @@ curl 'http://router.project-osrm.org/route/v1/driving/13.388860,52.517037;13.397%20%20###%20Table%20service%20-Computes%20the%20duration%20of%20the%20fastest%20route%20between%20all%20pairs%20of%20supplied%20coordinates.%20Returns%20the%20durations%20or%20distances%20or%20both%20between%20the%20coordinate%20pairs.%20Note%20that%20the%20distances%20are%20not%20the%20shortest%20distance%20between%20two%20coordinates,%20but%20rather%20the%20distances%20of%20the%20fastest%20routes.%20Duration%20is%20in%20seconds%20and%20distances%20is%20in%20meters.+Computes%20the%20duration%20of%20the%20fastest%20route%20between%20all%20pairs%20of%20supplied%20coordinates.%20Returns%20durations%20or%20distances%20or%20both%20between%20the%20coordinate%20pairs.%20Note%20that%20the%20distances%20are%20not%20the%20shortest%20distance%20between%20two%20coordinates,%20but%20rather%20the%20distances%20of%20the%20fastest%20routes.%20Durations%20are%20in%20seconds%20and%20distances%20are%20in%20meters.%20%20%60%60%60endpoint%20GET%20/table/v1/{profile}/{coordinates}?{sources}=[{elem}...];&{destinations}=[{elem}...]&annotations={duration|distance|duration,distance}@@%20-257,6%20+262,8%20@@%20In%20addition%20to%20the%20[general%20options](#general-options)%20the%20following%20options%20are%20Unlike%20other%20array%20encoded%20options,%20the%20length%20of%20%60sources%60%20and%20%60destinations%60%20can%20be%20**smaller%20or%20equal**%20to%20number%20of%20input%20locations;%20+With%20%60skip_waypoints%60%20set%20to%20%60true%60,%20both%20%60sources%60%20and%20%60destinations%60%20arrays%20will%20be%20skipped.+%20**Example:**%20%20%60%60%60@@%20-293,9%20+300,9%20@@%20curl'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397 - `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 waypoint to the j-th waypoint. Values are given in meters. 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 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. @@ -411,7 +418,7 @@ All other properties might be undefined. ### 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 @@ -446,11 +453,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. @@ -465,7 +472,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 @@ -486,12 +493,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 | @@ -501,8 +508,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 @@ -570,7 +577,7 @@ 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: @@ -595,13 +602,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. | @@ -642,12 +649,12 @@ Represents a route between two waypoints. - `distance`: The distance traveled by this route leg, in `float` meters. - `duration`: The estimated travel time, in `float` number of seconds. - `weight`: The calculated weight of the route leg. -- `summary`: Summary of the route taken as `string`. Depends on the `summary` parameter: +- `summary`: Summary of the route taken as `string`. Depends on the `steps` parameter: -| summary | | -|--------------|-----------------------------------------------------------------------| -| true | Names of the two major roads used. Can be empty if route is too short.| -| false | empty `string` | +| steps | | +|-------|-----------------------------------------------------------------------| +| true | Names of the two major roads used. Can be empty if the route is too short.| +| false | empty `string` | - `steps`: Depends on the `steps` parameter. @@ -656,11 +663,11 @@ 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 weights. | +| true | An `Annotation` object containing node ids, durations, distances, and weights. | | false | `undefined` | #### Example @@ -690,14 +697,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` or `osrm-customize`. String-like names are in the `metadata.datasource_names` array. +- `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 datasources used for the speed between each pair of coordinates. `lua profile` is the default profile, other values arethe filenames supplied via `--segment-speed-file` to `osrm-contract` or `osrm-customize` + - `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 @@ -756,8 +763,8 @@ step. { "bearings" : [ 10, 92, 184, 270 ], "lanes" : [ { "indications" : [ "left", "straight" ], - "valid" : "false" }, - { "valid" : "true", + "valid" : false }, + { "valid" : true, "indications" : [ "right" ] } ], "out" : 2, @@ -768,9 +775,9 @@ step. { "out" : 1, "lanes" : [ { "indications" : [ "straight" ], - "valid" : "true" }, + "valid" : true }, { "indications" : [ "right" ], - "valid" : "false" } + "valid" : false } ], "bearings" : [ 60, 240, 330 ], "in" : 0, @@ -797,11 +804,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 | @@ -815,9 +822,9 @@ step. | `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). | -| `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 @@ -827,7 +834,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 | @@ -845,8 +852,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. @@ -857,7 +864,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 | |------------------------|---------------------------------------------------------------------------------------------------------------------------| @@ -878,13 +885,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** @@ -913,22 +920,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 metres, from the input coordinate to 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 @@ -944,3 +951,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/libosrm.md b/docs/libosrm.md deleted file mode 100644 index 9b84180f1f3..00000000000 --- a/docs/libosrm.md +++ /dev/null @@ -1,33 +0,0 @@ -## Introduction - -OSRM can be used as a library (libosrm) via C++ instead of using it through the HTTP interface and `osrm-routed`. This allows for fine-tuning OSRM and has much less overhead. Here is a quick introduction into how to use `libosrm` in the upcoming v5 release. - -Take a look at the example code that lives in the [example directory](https://github.com/Project-OSRM/osrm-backend/tree/master/example). Here is all you ever wanted to know about `libosrm`, that is a short description of what the types do and where to find documentation on it: - -## Important interface objects - -- [`EngineConfig`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/engine/engine_config.hpp) - for initializing an OSRM instance we can configure certain properties and constraints. E.g. the storage config is the base path such as `france.osm.osrm` from which we derive and load `france.osm.osrm.*` auxiliary files. This also lets you set constraints such as the maximum number of locations allowed for specific services. - -- [`OSRM`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/osrm/osrm.hpp) - this is the main Routing Machine type with functions such as `Route` and `Table`. You initialize it with a `EngineConfig`. It does all the heavy lifting for you. Each function takes its own parameters, e.g. the `Route` function takes `RouteParameters`, and a out-reference to a JSON result that gets filled. The return value is a `Status`, indicating error or success. - -- [`Status`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/engine/status.hpp) - this is a type wrapping `Error` or `Ok` for indicating error or success, respectively. - -- [`TableParameters`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/engine/api/table_parameters.hpp) - this is an example of parameter types the Routing Machine functions expect. In this case `Table` expects its own parameters as `TableParameters`. You can see it wrapping two vectors, sources and destinations --- these are indices into your coordinates for the table service to construct a matrix from (empty sources or destinations means: use all of them). If you ask yourself where coordinates come from, you can see `TableParameters` inheriting from `BaseParameters`. - -- [`BaseParameter`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/engine/api/base_parameters.hpp) - this most importantly holds coordinates (and a few other optional properties that you don't need for basic usage); the specific parameter types inherit from `BaseParameters` to get these member attributes. That means your `TableParameters` type has `coordinates`, `sources` and `destination` member attributes (and a few other that we ignore for now). - -- [`Coordinate`](https://github.com/Project-OSRM/osrm-backend/blob/master/include/util/coordinate.hpp) - this is a wrapper around a (longitude, latitude) pair. We really don't care about (lon,lat) vs (lat, lon) but we don't want you to accidentally mix them up, so both latitude and longitude are strictly typed wrappers around integers (fixed notation such as `13423240`) and floating points (floating notation such as `13.42324`). - -- [Parameters for other services](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api) - here are all other `*Parameters` you need for other Routing Machine services. - -- [JSON](https://github.com/Project-OSRM/osrm-backend/blob/master/include/util/json_container.hpp) - this is a sum type resembling JSON. The Routing Machine service functions take a out-ref to a JSON result and fill it accordingly. It is currently implemented using [mapbox/variant](https://github.com/mapbox/variant) which is similar to [Boost.Variant](http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html). There are two ways to work with this sum type: either provide a visitor that acts on each type on visitation or use the `get` function in case you're sure about the structure. The JSON structure is written down in the [HTTP API](#http-api). - -## Example - -See [the example folder](https://github.com/Project-OSRM/osrm-backend/tree/master/example) in the OSRM repository. - -## Workflow - - - Create an `OSRM` instance initialized with a `EngineConfig` - - Call the service function on the `OSRM` object providing service specific `*Parameters` - - Check the return code and use the JSON result diff --git a/docs/nodejs/api.md b/docs/nodejs/api.md index 01fa41fb07e..a87452cbc67 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,23 +20,26 @@ 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', 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.dataset_name` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Connects to the persistent shared memory datastore defined by `--dataset_name` option when running `osrm-datastore` + - `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/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** *DEPRECATED* + - `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/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Map on-disk files to virtual memory addresses (mmap), rather than loading into RAM. - - `options.path` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true. - - `options.max_locations_trip` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in trip query (default: unlimited). - - `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query (default: unlimited). - - `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.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.disable_feature_dataset` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Disables a feature dataset from being loaded into memory if not needed. Options: `ROUTE_STEPS`, `ROUTE_GEOMETRY`. + - `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). + - `options.default_radius` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Default radius for queries (default: unlimited). ### route @@ -44,38 +47,42 @@ 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.waypoints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index. + - `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)?** Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. `null`/`true`/`false` - - `options.snapping` **[String](https://developer.mozilla.org/en-US/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/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** ```javascript var osrm = new OSRM("berlin-latest.osrm"); -osrm.route({coordinates: [[13.438640,52.519930], [13.415852,52.513191]]}, function(err, result) { +osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, result) { if(err) throw err; console.log(result.waypoints); // array of Waypoint objects representing all waypoints in order console.log(result.routes); // array of Route objects ordered by descending recommendation rank }); ``` -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 @@ -85,17 +92,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`. - - `options.snapping` **[String](https://developer.mozilla.org/en-US/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/en-US/docs/Web/JavaScript/Reference/Statements/function)** + - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. + - `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** @@ -111,34 +120,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 table for the given locations. Allows for both symmetric and asymmetric -tables. Optionally returns distance table. +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`. - - `options.fallback_speed` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second. - - `options.fallback_coordinate` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies diestance between two points. - - `options.scale_factor` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Multiply the table duration values in the table by this number for more controlled input into a route optimization solver. - - `options.snapping` **[String](https://developer.mozilla.org/en-US/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/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)?** Restrict the direction on the road network at a waypoint, relative to the input coordinate.. Can be `null` (unrestricted, default), `curb` or `opposite`. + - `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** @@ -153,14 +162,17 @@ 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. @@ -176,10 +188,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** @@ -203,22 +215,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`). - - `options.waypoints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index. - - `options.snapping` **[String](https://developer.mozilla.org/en-US/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/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** @@ -235,12 +248,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 + If the trace point was omitted by map matching because it is an outlier, the entry will be null. + 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. @@ -268,22 +284,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`. - - `options.snapping` **[String](https://developer.mozilla.org/en-US/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/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)?** Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. + - `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** @@ -305,19 +322,31 @@ 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. -## Plugin behaviour +## Configuration -All plugins support a second additional object that is available to configure some NodeJS specific behaviours. +All plugins support a second additional object that is available to configure some NodeJS +specific behaviours. -- `plugin_config` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query. - - `plugin_config.format` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The format of the result object to various API calls. Valid options are `object` (default), which returns a standard Javascript object, as described above, and `json_buffer`, which will return a NodeJS **[Buffer](https://nodejs.org/api/buffer.html)** object, containing a JSON string. The latter has the advantage that it can be immediately serialized to disk/sent over the network, and the generation of the string is performed outside the main NodeJS event loop. This option is ignored by the `tile` plugin. +**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** @@ -329,7 +358,7 @@ var options = { [13.374481201171875, 52.506191342034576] ] }; -osrm.route(options, { format: "json_buffer" }, function(err, response) { +osrm.route(options, { format: "buffer" }, function(err, response) { if (err) throw err; console.log(response.toString("utf-8")); }); @@ -343,7 +372,7 @@ Represents a route through (potentially multiple) waypoints. **Parameters** -- **documentation** in +- `external` **documentation** in [`osrm-backend`](../http.md#route-object) ### RouteLeg @@ -352,7 +381,7 @@ Represents a route between two waypoints. **Parameters** -- **documentation** in +- `external` **documentation** in [`osrm-backend`](../http.md#routeleg-object) ### RouteStep @@ -362,14 +391,14 @@ single way to the subsequent step. **Parameters** -- **documentation** in +- `external` **documentation** in [`osrm-backend`](../http.md#routestep-object) ### StepManeuver **Parameters** -- **documentation** in +- `external` **documentation** in [`osrm-backend`](../http.md#stepmaneuver-object) ### Waypoint @@ -378,5 +407,5 @@ Object used to describe waypoint on a route. **Parameters** -- **documentation** in +- `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 63c49f5cbc3..00000000000 --- 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 090c5c36bd5..b6c29056899 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -1,7 +1,7 @@ # OSRM profiles OSRM supports "profiles". Profiles representing routing behavior for different transport modes like car, bike and foot. You can also create profiles for variations like a fastest/shortest car profile or fastest/safest/greenest bicycles profile. - A profile describes whether or not it's possible to route along a particular type of way, whether we can pass a particular node, and how quickly we'll be traveling when we do. This feeds into the way the routing graph is created and thus influences the output routes. +A profile describes whether or not it's possible to route along a particular type of way, whether we can pass a particular node, and how quickly we'll be traveling when we do. This feeds into the way the routing graph is created and thus influences the output routes. ## 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. @@ -89,7 +89,7 @@ They all return a table of functions when you use `require` to load them. You ca ### 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 its 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,7 +98,7 @@ 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 @@ -113,10 +113,10 @@ excludable | Sequence of Sets | Determines which class 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 +relation_types | Sequence | Determines which 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. +Process an OSM node to determine whether this node is an obstacle, if it can be passed at all and whether passing it incurs a delay. Argument | Description ---------|------------------------------------------------------- @@ -126,12 +126,177 @@ result | The output that you will modify. relations| Storage of relations to access relations, where `node` is a member. The following attributes can be set on `result`: +(Note: for new code use the `obstacle_map`. Attribute | Type | Notes ----------------|---------|--------------------------------------------------------- barrier | Boolean | Is it an impassable barrier? traffic_lights | Boolean | Is it a traffic light (incurs delay in `process_turn`)? +### Obstacle +A user type that represents an obstacle on the road or a place where you can turn +around. + +This may be a completely impassable obstacle like a barrier, a temporary obstacle like a +traffic light or a stop sign, or an obstacle that just slows you down like a +traffic_calming. The obstacle may be present in both directions or in one direction +only. + +This also represents a good turning point like a mini_roundabout, turning_loop, or +turning_circle. + +An object of this type is immutable once constructed. + +```lua +local obs = Obstacle.new( + obstacle_type.traffic_signals, + obstacle_direction.forward, + 2.5, + 0 +) +assert(obs.duration == 2.5) +``` + +Member | Mode | Type | Notes +----------|-----------|--------------------|---------------------------------- +type | read-only | obstacle_type | eg. `obstacle_type.barrier` +direction | read-only | obstacle_direction | eg. `obstacle_direction.forward` +duration | read-only | float | The expected delay in seconds +weight | read-only | float | The weight + +#### obstacle_type +An enum with the following keys: + +Keys | +----------------| +none | +barrier | +traffic_signals | +stop | +give_way | +crossing | +traffic_calming | +mini_roundabout | +turning_loop | +turning_circle | + +#### obstacle_direction +An enum with the following keys: + +Keys | +---------| +none | +forward | +backward | +both | + +### obstacle_map +A global user type. It stores obstacles. + +The canonical workflow is: to store obstacles in `process_node()` and retrieve them in +`process_turn()`. + +Note: In the course of processing, between the `process_node()` stage and the +`process_turn()` stage, the extractor switches from using OSM nodes to using +internal nodes. Both types have different ids. You can only store OSM nodes and only +retrieve internal nodes. This implies that, in `process_node()`, you cannot retrieve an +obstacle you have just stored. + +#### obstacle_map:add(node, obstacle) +Call this function inside `process_node()` to register an obstacle on a node. You can +register as many different obstacles as you wish on any given node. It is your +responsibility to register the same obstacle only once. + +In a following step -- likely in `process_turn()` -- you can retrieve all obstacles +registered at any given node. This function works with OSM nodes. + +Argument | Type | Notes +---------|----------|-------------------------------------------- +node | OSMNode | The same node as passed to `process_node`. +obstacle | Obstacle | The obstacle + +Usage example: + +```lua +function process_node(profile, node, result, relations) + ... + obstacle_map:add(node, + Obstacle.new( + obstacle_type.traffic_signal, + obstacle_direction.forward, + 2, 0)) +end +``` + +#### obstacle_map:any(from, to, type) +Return true if there are any obstacles at node `to` when coming from node +`from` and having the type `type`. + +You will likely call this function inside `process_turn()`. +Note that this works only with internal nodes, not with OSM nodes. + +```lua +bool obstacle_map:any(to) +bool obstacle_map:any(from, to) +bool obstacle_map:any(from, to, type) +``` + +Argument | Type | Notes +---------|---------------|------------------------------------------------------------------------------------- +from | Node | The leading node. Optional. +to | Node | The node with the obstacle. +type | obstacle_type | The obstacle type. Defaults to all types. May be a bitwise-or combination of types. +returns | bool | True if there are any obstacles satisfiying the given criteria. + +Usage examples: + +```lua +function process_turn(profile, turn) + if obstacle_map:any(turn.via) then + ... + end + if obstacle_map:any(turn.from, turn.via, obstacle_type.traffic_signal) then + turn.duration = turn.duration + 2 + end +end +``` + +#### obstacle_map:get(from, to, type) +This function retrieves all registered obstacles at node `to` when coming from the node +`from` and having the type `type`. + +You will likely call this function inside `process_turn()`. +Note that this works only with internal nodes, not with OSM nodes. + +```lua +obstacle_map:get(to) +obstacle_map:get(from, to) +obstacle_map:get(from, to, type) +``` + +Argument | Type | Notes +---------|---------------|------------------------------------------------------------------------------------- +from | Node | The leading node. Optional. +to | Node | The node with the obstacle. +type | obstacle_type | The obstacle type. Defaults to all types. May be a bitwise-or combination of types. +returns | table | A table of `Obstacle`s. + +Usage examples: + +```lua +function process_turn(profile, turn) + for _, obs in pairs(obstacle_map:get(turn.via)) do + if obs.type == obstacle_type.barrier then + turn.duration = turn.duration + obs.duration + end + end + for _, obs in pairs(obstacle_map:get( + turn.from, turn.via, obstacle_type.traffic_signal)) do + turn.duration = turn.duration + obs.duration + end +end +``` + ### process_way(profile, way, result, relations) Given an OpenStreetMap way, the `process_way` function will either return nothing (meaning we are not going to route over this way at all), or it will set up a result hash. @@ -178,7 +343,7 @@ exits | String | The ramp's exit numbers or 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 @@ -223,7 +388,7 @@ source_number_of_lanes | Read | Integer | 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/guidance/road_classification.hpp` +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? @@ -232,15 +397,25 @@ target_number_of_lanes | Read | Integer | 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/guidance/road_classification.hpp` +target_priority_class | Read | Enum | The type of road priority class of the target. Defined in `include/extractor/road_classification.hpp` +from | Read | NodeID | The leading node +via | Read | NodeID | The intersection node +to | Read | NodeID | The trailing node +source_road | Read | ExtractionTurnLeg | The incoming road +target_road | Read | ExtractionTurnLeg | The outgoing road 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: +#### `from`, `via`, and `to` +Use these node IDs to retrieve obstacles. See: `obstacle_map:get`. + +#### `source_road`, `target_road`, `roads_on_the_right`, and `roads_on_the_left` + +The information of `source_road`, `target_road`, `roads_on_the_right`, and +`roads_on_the_left` that can be read are as follows: Attribute | Read/write? | Type | Notes --------------------- | ------------- | --------- | ------------------------------------------------------ @@ -252,7 +427,8 @@ number_of_lanes | Read | Integer | How many lanes does th 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/guidance/road_classification.hpp` +distance | Read | Double | The length of the road edge +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 @@ -349,7 +525,7 @@ The input data must an ASCII file with rows of integers. e.g.: In your `segment_function` you can then access the raster source and use `raster:query()` to query to find the nearest data point, or `raster:interpolate()` to interpolate a value based on nearby data points. -You must check whether the result is valid before use it. +You must check whether the result is valid before using it. Example: diff --git a/docs/releasing.md b/docs/releasing.md index 9a492cd495f..cd6dc9cb84e 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -44,15 +44,16 @@ We may introduce forward-compatible changes: query parameters and response prope 1. Check out the appropriate release branch `x.y` 2. Make sure `CHANGELOG.md` is up to date. 3. Make sure the `package.json` on branch `x.y` has been committed. -4. Make sure all tests are passing (e.g. Travis CI gives you a :green_apple:) +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`. + 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/src/content.js b/docs/src/content.js index 6e7844e1a29..c3eaf359d36 100644 --- a/docs/src/content.js +++ b/docs/src/content.js @@ -11,6 +11,4 @@ var fs = require('fs'); */ module.exports = '# HTTP API\n' + - fs.readFileSync('./content/http.md', 'utf8') + '\n'+ - '# libosrm C++ API\n' + - fs.readFileSync('./content/libosrm.md', 'utf8') + '\n'; + fs.readFileSync('./content/http.md', 'utf8') + '\n'; diff --git a/docs/testing.md b/docs/testing.md index 5f608fb6ef9..ed258b8050e 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -300,7 +300,7 @@ And the relations The setting looks perfectly fine at first glance. However, it is not well defined. The forbidden right turn could be either a superfluous addition, forbidding the turn `cb` to `be`, or actually refer to the turn `ab` to `bd` to say that a turn is forbidden here. -To model turn-restrictions correctly and unique, we need to split segments that contribute to the restriction into the smallest possible parts. +To model turn-restrictions correctly and uniquely, we need to split segments that contribute to the restriction into the smallest possible parts. E.g. the above scenario could correctly be expressed as: ``` @@ -360,7 +360,7 @@ When I route I should get And the test reports `turn right` for the route `a->e`, where before it said `slight right`. -If you changed the turn angles, obviously you can expect changes in the distinction between `slight right` and `right`. +If you change the turn angles, obviously you can expect changes in the distinction between `slight right` and `right`. In such a case it is, of course, reasonable to change the expected route to report `right` instead of `slight right`. You should consider inspecting the actual turn angles at `b` to see if you feel that change is justified. However, you should never adjust the test itself. @@ -390,9 +390,9 @@ In this case we would see a very slight turn angle. If your change now reports d ### Consider Post-Processing Impacts -Some changes you might see could look completely unrelated. To understand the impact of your changes, you can make use of the debugging utilities you can finde in `util/debug.hpp` (and potentially other related headers). +Some changes you might see could look completely unrelated. To understand the impact of your changes, you can make use of the debugging utilities you can find in `util/debug.hpp` (and potentially other related headers). -If your test is inspecting a series of turns (remember, a turn not necessarily equals an instruction), you could see interaction with post-processing. +If your test is inspecting a series of turns (remember, a turn does not necessarily equals an instruction), you could see interaction with post-processing. To see the unprocessed turns, you should print the steps at the end of step assembly (`assembleSteps` in `engine/guidance/assemble_steps.hpp`). If you see unexpected changes, you can consider adding the `locations` field to your test to study what location a turn is reported at. diff --git a/docs/windows-deps.md b/docs/windows-deps.md new file mode 100644 index 00000000000..f6b936e8d89 --- /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 2025](https://github.com/actions/runner-images/blob/main/images/win/Windows2025-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/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000000..02a6de828bd --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,28 @@ +const { Linter } = require("eslint"); + +/** @type {Linter.Config} */ +const config = [ + { + rules: { + indent: ["error", 2], + quotes: ["warn", "single"], + "linebreak-style": ["error", "unix"], + semi: ["error", "always"], + "no-console": ["warn"] + }, + languageOptions: { + globals: { + es6: true, + node: true + } + }, + ignores: [ + "node_modules/", + "build/", + "dist/", + "coverage/" + ] + } +]; + +module.exports = config; diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 154eda39b7f..907734b45c9 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.8) +cmake_minimum_required(VERSION 3.18) if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR AND NOT MSVC_IDE) message(FATAL_ERROR "In-source builds are not allowed. @@ -12,19 +12,19 @@ endif() project(osrm-example C CXX) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -set(bitness 32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(bitness 64) message(STATUS "Building on a 64 bit system") else() message(STATUS "Building on a 32 bit system") endif() -if(WIN32 AND MSVC_VERSION LESS 1900) - message(FATAL_ERROR "Building with Microsoft compiler needs Latest Visual Studio 2015 (Community or better)") -endif() +find_package(Boost REQUIRED CONFIG COMPONENTS date_time iostreams thread) link_directories(${LibOSRM_LIBRARY_DIRS}) add_executable(osrm-example example.cpp) diff --git a/example/cmake/FindLibOSRM.cmake b/example/cmake/FindLibOSRM.cmake deleted file mode 100644 index 50a5641a192..00000000000 --- a/example/cmake/FindLibOSRM.cmake +++ /dev/null @@ -1,63 +0,0 @@ -# - Try to find LibOSRM -# Once done this will define -# LibOSRM_FOUND - System has LibOSRM -# LibOSRM_LIBRARIES - The libraries and ldflags needed to use LibOSRM -# LibOSRM_DEPENDENT_LIBRARIES - The libraries and ldflags need to link LibOSRM dependencies -# LibOSRM_LIBRARY_DIRS - The libraries paths needed to find LibOSRM -# LibOSRM_CXXFLAGS - Compiler switches required for using LibOSRM - -find_package(PkgConfig) -pkg_search_module(PC_LibOSRM QUIET libosrm) - -function(JOIN VALUES GLUE OUTPUT) - string (REPLACE ";" "${GLUE}" _TMP_STR "${VALUES}") - set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE) -endfunction() - -list(REMOVE_ITEM PC_LibOSRM_CFLAGS " ") -JOIN("${PC_LibOSRM_CFLAGS}" " " output) - -set(LibOSRM_CXXFLAGS ${output}) -set(LibOSRM_LIBRARY_DIRS ${PC_LibOSRM_LIBRARY_DIRS}) - -find_path(LibOSRM_INCLUDE_DIR osrm/osrm.hpp - PATH_SUFFIXES osrm include/osrm include - HINTS ${PC_LibOSRM_INCLUDEDIR} ${PC_LibOSRM_INCLUDE_DIRS} - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /opt/local - /opt) - -find_library(TEST_LibOSRM_STATIC_LIBRARY Names osrm.lib libosrm.a - PATH_SUFFIXES osrm lib/osrm lib - HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS} - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /opt/local - /opt) -find_library(TEST_LibOSRM_DYNAMIC_LIBRARY Names libosrm.dylib libosrm.so - PATH_SUFFIXES osrm lib/osrm lib - HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS} - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /opt/local - /opt) - -set(LibOSRM_DEPENDENT_LIBRARIES ${PC_LibOSRM_STATIC_LDFLAGS}) -set(LibOSRM_LIBRARIES ${PC_LibOSRM_LDFLAGS}) - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set LIBOSRM_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args(LibOSRM DEFAULT_MSG - LibOSRM_LIBRARY_DIRS - LibOSRM_CXXFLAGS - LibOSRM_LIBRARIES - LibOSRM_DEPENDENT_LIBRARIES - LibOSRM_INCLUDE_DIR) diff --git a/example/cmake/FindTBB.cmake b/example/cmake/FindTBB.cmake deleted file mode 100644 index e5ca1003912..00000000000 --- 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/example.cpp b/example/example.cpp deleted file mode 100644 index 6cd6eac82bc..00000000000 --- a/example/example.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "osrm/match_parameters.hpp" -#include "osrm/nearest_parameters.hpp" -#include "osrm/route_parameters.hpp" -#include "osrm/table_parameters.hpp" -#include "osrm/trip_parameters.hpp" - -#include "osrm/coordinate.hpp" -#include "osrm/engine_config.hpp" -#include "osrm/json_container.hpp" - -#include "osrm/osrm.hpp" -#include "osrm/status.hpp" - -#include -#include -#include -#include - -#include - -int main(int argc, const char *argv[]) -{ - if (argc < 2) - { - std::cerr << "Usage: " << argv[0] << " data.osrm\n"; - return EXIT_FAILURE; - } - - using namespace osrm; - - // 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}; - - // The following shows how to use the Route service; configure this service - RouteParameters params; - - // Route in monaco - params.coordinates.push_back({util::FloatLongitude{7.419758}, util::FloatLatitude{43.731142}}); - params.coordinates.push_back({util::FloatLongitude{7.419505}, util::FloatLatitude{43.736825}}); - - // Response is in JSON format - json::Object result; - - // Execute routing request, this does the heavy lifting - const auto status = osrm.Route(params, result); - - if (status == Status::Ok) - { - auto &routes = result.values["routes"].get(); - - // Let's just use the first route - auto &route = routes.values.at(0).get(); - const auto distance = route.values["distance"].get().value; - const auto duration = route.values["duration"].get().value; - - // Warn users if extract does not contain the default coordinates from above - if (distance == 0 || duration == 0) - { - std::cout << "Note: distance or duration is zero. "; - std::cout << "You are probably doing a query outside of the OSM extract.\n\n"; - } - - std::cout << "Distance: " << distance << " meter\n"; - std::cout << "Duration: " << duration << " seconds\n"; - return EXIT_SUCCESS; - } - else if (status == Status::Error) - { - const auto code = result.values["code"].get().value; - const auto message = result.values["message"].get().value; - - std::cout << "Code: " << code << "\n"; - std::cout << "Message: " << code << "\n"; - return EXIT_FAILURE; - } -} diff --git a/features/bicycle/access.feature b/features/bicycle/access.feature index df8baa75711..787dd05e501 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 74a87b98da6..db7b624a7ea 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/exclude.feature b/features/bicycle/exclude.feature index 6fdcbfb0737..f8831540834 100644 --- a/features/bicycle/exclude.feature +++ b/features/bicycle/exclude.feature @@ -45,7 +45,7 @@ Feature: Bicycle - Exclude flags When I match I should get | trace | matchings | duration | - | abcf | abcf | 301.2 | + | abcf | abcf | 301 | When I request a travel time matrix I should get | | a | f | diff --git a/features/bicycle/maxspeed.feature b/features/bicycle/maxspeed.feature index a4fc57b3da7..72f6a0ed684 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/pushing.feature b/features/bicycle/pushing.feature index 5cd41c541df..5423859ad3d 100644 --- a/features/bicycle/pushing.feature +++ b/features/bicycle/pushing.feature @@ -78,6 +78,15 @@ Feature: Bike - Accessability of different way types | construction | yes | | | | construction | | yes | | + @proposed + Scenario: Bike - Don't allow routing on ways still being proposed + Then routability should be + | highway | foot | bicycle | proposed | bothw | + | primary | | | | x | + | proposed | | | | | + | proposed | yes | | yes | | + | proposed | | yes | yes | | + @roundabout Scenario: Bike - Don't push bikes against oneway flow on roundabouts Then routability should be diff --git a/features/bicycle/safety.feature b/features/bicycle/safety.feature index e45dae500ff..4561e1a5e5f 100644 --- a/features/bicycle/safety.feature +++ b/features/bicycle/safety.feature @@ -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 | | @@ -59,7 +59,7 @@ Feature: Bicycle - Adds penalties to unsafe roads | 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 | 4 km/h +-1 | 4.2 | 1.1 | + | 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 | @@ -67,7 +67,7 @@ Feature: Bicycle - Adds penalties to unsafe roads | 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 | 4 km/h +-1 | 15 km/h | 1.1 | 4.2 | | motorway | lane | | 15 km/h | | 4.2 | | @@ -75,7 +75,7 @@ Feature: Bicycle - Adds penalties to unsafe roads | 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.1 | - | secondary_link | lane | | 15 km/h | 15 km/h | 4.2 | 2.7 | + | 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 | @@ -84,7 +84,7 @@ Feature: Bicycle - Adds penalties to unsafe roads | 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.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 | @@ -92,7 +92,7 @@ Feature: Bicycle - Adds penalties to unsafe roads | 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.1 | - | motorway | | shared_lane | 15 km/h | | 4.2 | | + | motorway | | shared_lane | 14 km/h | | 4.2 | | | primary | | shared_lane | 15 km/h | 15 km/h | 2.1 | 4.2 | diff --git a/features/bicycle/surface.feature b/features/bicycle/surface.feature index 1a4b5763a66..5ca104fbae9 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 diff --git a/features/bicycle/turn_penalty.feature b/features/bicycle/turn_penalty.feature index d0c144e320f..7638275274f 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 47ac4e3c26a..0bebd2589e0 100644 --- a/features/car/access.feature +++ b/features/car/access.feature @@ -185,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: @@ -196,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) @@ -206,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/barrier.feature b/features/car/barrier.feature index 3f32206023e..fd7e7f834e5 100644 --- a/features/car/barrier.feature +++ b/features/car/barrier.feature @@ -46,6 +46,18 @@ Feature: Car - Barriers | 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 | diff --git a/features/car/conditional_restrictions.feature b/features/car/conditional_restrictions.feature index 23a9e1efe26..c2311067cea 100644 --- a/features/car/conditional_restrictions.feature +++ b/features/car/conditional_restrictions.feature @@ -387,217 +387,37 @@ Feature: Car - Turn restrictions | 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 - """ - a - d j b - c - """ - And the ways - | nodes | oneway | - | aj | no | - | jc | no | - | bj | yes | - | jd | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | bj | aj | j | only_right_turn @ (Mo-Su 07:00-14:00) | - - When I route I should get - | from | to | route | - | 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 - 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 - d j b - c + j + | + k - l - m + | + n """ And the ways - | nodes | oneway | - | aj | no | - | jc | no | - | bj | yes | - | jd | yes | + | nodes | + | kl | + | jl | + | ln | + | lm | And the relations | type | way:from | way:to | node:via | restriction:conditional | - | restriction | bj | aj | j | no_right_turn @ (Mo-Fr 07:00-13:00) | - - When I route I should get - | from | to | route | # | - | 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 - 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 - d j b - c - """ - - And the ways - | nodes | oneway | - | aj | no | - | jc | no | - | bj | yes | - | jd | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | bj | jc | j | only_left_turn @ (Mo-Fr 07:00-16:00) | - - When I route I should get - | from | to | route | - | 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 - 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 - d j b - c - """ - - And the ways - | nodes | oneway | - | aj | no | - | jc | no | - | bj | yes | - | jd | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | bj | jc | j | no_left_turn @ (Mo-Su 00:00-23:59) | - - When I route I should get - | from | to | route | - | 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 - 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 - d j b - c - """ - - And the ways - | nodes | oneway | - | aj | no | - | jc | no | - | bj | yes | - | jd | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | bj | aj | j | no_right_turn @ (Mo-Su 16:00-20:00) | - - When I route I should get - | from | to | route | - | b | c | bj,jc,jc | - | b | a | bj,aj,aj | - | b | d | bj,jd,jd | - - @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 - """ - a - d j b - c - """ - - And the ways - | nodes | oneway | - | aj | no | - | jc | no | - | bj | yes | - | jd | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | restriction | jb | aj | j | no_right_turn @ (Mo-Fr 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 | - | b | c | bj,jc,jc | - | b | a | bj,jc,jc,aj,aj | - | b | d | bj,jd,jd | + | k | m | kl,ln,ln,lm,lm | - @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 - """ - a - p | - \ | - j - | \ - c m - """ - - And the ways - | nodes | oneway | - | aj | no | - | jc | no | - | jp | yes | - | mj | yes | - - And the relations - | type | way:from | way:to | node:via | restriction:conditional | - | 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 | - | a | p | aj,jc,jc,jp,jp | - | m | p | mj,jp,jp | @restriction-way Scenario: Car - prohibit turn @@ -719,7 +539,7 @@ 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 nw,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 @@ -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 | @@ -1047,7 +867,7 @@ 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 | diff --git a/features/car/destination.feature b/features/car/destination.feature index 43e12386cbc..d5d3c128712 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,7 +130,7 @@ 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 diff --git a/features/car/ferry.feature b/features/car/ferry.feature index 5a8de7b1b5c..e5b7d363c54 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 @@ -117,4 +117,4 @@ Feature: Car - Handle ferry routes # Note that matching *should* work across unsnappable ferries When I match I should get | trace | geometry | duration | - | abcdef| 1,1,1.000899,1,1.000899,1,1.002697,1,1.002697,1,1.003596,1,1.003596,1,1.005394,1,1.005394,1,1.006293,1 | 610.9 | + | 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 c7169b37c3f..d2b8b4f5f64 100644 --- a/features/car/maxspeed.feature +++ b/features/car/maxspeed.feature @@ -86,57 +86,57 @@ 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 diff --git a/features/car/multi_via_restrictions.feature b/features/car/multi_via_restrictions.feature new file mode 100644 index 00000000000..5714cd45f09 --- /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/obstacle_penalties.feature b/features/car/obstacle_penalties.feature new file mode 100644 index 00000000000..1b733933004 --- /dev/null +++ b/features/car/obstacle_penalties.feature @@ -0,0 +1,227 @@ +@routing @car @obstacle +Feature: Car - Handle obstacle penalties + + Background: + Given the profile "car" + + Scenario: Car - Give-Way signs + Given the node map + """ + a-b-c d-e-f g-h-i j-k-l m-n-o + + """ + + And the ways + | nodes | highway | + | abc | primary | + | def | primary | + | ghi | primary | + | jkl | primary | + | mno | primary | + + And the nodes + | node | highway | direction | + | e | give_way | | + | h | give_way | forward | + | k | give_way | backward | + | n | give_way | both | + + When I route I should get + | from | to | time | # | + | a | c | 11s | | + | c | a | 11s | | + | d | f | 12s | give-way sign | + | f | d | 12s | give-way sign | + | g | i | 12s | give-way sign | + | i | g | 11s | | + | j | l | 11s | | + | l | j | 12s | give-way sign | + | m | o | 12s | give-way sign | + | o | m | 12s | give-way sign | + + + Scenario: Car - Stop signs + Given the node map + """ + a-b-c d-e-f g-h-i j-k-l m-n-o + + """ + + And the ways + | nodes | highway | + | abc | primary | + | def | primary | + | ghi | primary | + | jkl | primary | + | mno | primary | + + And the nodes + | node | highway | direction | + | e | stop | | + | h | stop | forward | + | k | stop | backward | + | n | stop | both | + + When I route I should get + | from | to | time | # | + | a | c | 11s | | + | c | a | 11s | | + | d | f | 13s | stop sign | + | f | d | 13s | stop sign | + | g | i | 13s | stop sign | + | i | g | 11s | | + | j | l | 11s | | + | l | j | 13s | stop sign | + | m | o | 13s | stop sign | + | o | m | 13s | stop sign | + + + Scenario: Car - Stop sign on intersection node + 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 | secondary | + | hgi | primary | + | fgj | secondary | + | lmn | primary | + | kmo | secondary | + + And the nodes + | node | highway | stop | + | g | stop | | + | m | stop | minor | + + + When I route I should get + + # No road has stop signs + | from | to | time | # | + | a | b | 14s +-1 | turn | + | a | e | 13s +-1 | no turn | + | a | d | 17s +-1 | turn | + | e | d | 14s +-1 | turn | + | e | a | 13s +-1 | no turn | + | e | b | 17s +-1 | turn | + | d | a | 14s +-1 | turn | + | d | b | 11s +-1 | no turn | + | d | e | 17s +-1 | turn | + | b | e | 14s +-1 | turn | + | b | d | 11s +-1 | no turn | + | b | a | 17s +-1 | turn | + + # All roads have stop signs - 2s penalty + | f | h | 16s +-1 | turn with stop | + | f | j | 15s +-1 | no turn with stop | + | f | i | 19s +-1 | turn with stop | + | j | i | 16s +-1 | turn with stop | + | j | f | 15s +-1 | no turn with stop | + | j | h | 19s +-1 | turn with stop | + | i | f | 16s +-1 | turn with stop | + | i | h | 13s +-1 | no turn with stop | + | i | j | 19s +-1 | turn with stop | + | h | j | 16s +-1 | turn with stop | + | h | i | 13s +-1 | no turn with stop | + | h | f | 19s +-1 | turn with stop | + + # Minor roads have stop signs - 2s penalty + | k | l | 16s +-1 | turn with minor stop | + | k | o | 15s +-1 | no turn with minor stop | + | k | n | 19s +-1 | turn with minor stop | + | o | n | 16s +-1 | turn with minor stop | + | o | k | 15s +-1 | no turn with minor stop | + | o | l | 19s +-1 | turn with minor stop | + | n | k | 14s +-1 | turn | + | n | l | 11s +-1 | no turn | + | n | o | 17s +-1 | turn | + | l | o | 14s +-1 | turn | + | l | n | 11s +-1 | no turn | + | l | k | 17s +-1 | turn | + + + Scenario: Car - Infer stop sign direction + Given a grid size of 5 meters + + Given the node map + """ + a---------sb + + c---------td + + e---------uf + + g---------vh + + """ + + And the ways + | nodes | highway | + | asb | primary | + | ctd | primary | + | euf | primary | + | gvh | primary | + + And the nodes + | node | highway | direction | + | s | stop | | + | t | stop | forward | + | u | stop | backward | + | v | stop | both | + + When I route I should get + | from | to | time | # | + | a | b | 3.5s | stop | + | b | a | 1.5s | | + | c | d | 3.5s | stop | + | d | c | 1.5s | | + | e | f | 1.5s | | + | f | e | 3.5s | stop | + | g | h | 3.5s | stop | + | h | g | 3.5s | stop | + + + Scenario: Car - Infer stop sign direction 2 + Given a grid size of 5 meters + + Given the node map + """ + + d + | + a---------sbt---------c + | + e + + """ + + And the ways + | nodes | highway | + | asbtc | primary | + | dbe | primary | + + And the nodes + | node | highway | + | s | stop | + | t | stop | + + When I route I should get + | from | to | time | # | + | a | d | 9s +- 1 | stop | + | a | c | 5s +- 1 | stop | + | a | e | 6s +- 1 | stop | + | c | e | 9s +- 1 | stop | + | c | a | 5s +- 1 | stop | + | c | d | 6s +- 1 | stop | + | d | c | 7s +- 1 | | + | d | e | 1s +- 1 | | + | d | a | 4s +- 1 | | + | e | a | 7s +- 1 | | + | e | d | 1s +- 1 | | + | e | c | 4s +- 1 | | diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature index 80cb5b95e6b..fe65994ffeb 100644 --- a/features/car/restrictions.feature +++ b/features/car/restrictions.feature @@ -115,6 +115,36 @@ Feature: Car - Turn restrictions | 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 @@ -411,7 +441,7 @@ Feature: Car - Turn restrictions y i j f b x a e g h - c d + c1 d """ And the ways @@ -438,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 @@ -798,82 +828,6 @@ Feature: Car - Turn restrictions | from | to | route | | a | d | ab,be,de,de | - @restriction-way - 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-way - 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-way Scenario: Car - prohibit turn, traffic lights Given the node map @@ -984,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 | @@ -1086,3 +1038,123 @@ Feature: Car - Turn restrictions | 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/speed.feature b/features/car/speed.feature index bbbb67b6fa0..37d9f351260 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 9e753843b60..696f1ae315e 100644 --- a/features/car/startpoint.feature +++ b/features/car/startpoint.feature @@ -53,8 +53,8 @@ Feature: Car - Allowed start/end modes When I request a travel time matrix I should get | | 2 | c | - | 1 | 59.1 | 35.1 | - | b | 35.1 | 11.1 | + | 1 | 59.1 | 35.2 | + | b | 35 | 11.1 | When I route I should get | from | to | route | @@ -121,5 +121,5 @@ Feature: Car - Allowed start/end modes When I request a travel time matrix I should get | | 2 | c | - | 1 | 59.1 | 35.1 | - | b | 35.1 | 11.1 | \ No newline at end of file + | 1 | 59.1 | 35.2 | + | b | 35 | 11.1 | \ No newline at end of file diff --git a/features/car/surface.feature b/features/car/surface.feature index 8984a8e06ad..067e56500bc 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 e5bc313a048..5311599b6df 100644 --- a/features/car/traffic_light_penalties.feature +++ b/features/car/traffic_light_penalties.feature @@ -32,14 +32,172 @@ Feature: Car - Handle traffic lights | l | traffic_signals | When I route I should get - | from | to | time | # | + | from | to | time | # | | 1 | 2 | 11.1s | no turn with no traffic light | | 3 | 4 | 13.1s | no turn with traffic light | | g | j | 18.7s | turn with no traffic light | | k | n | 20.7s | turn with traffic light | - Scenario: Tarrif Signal Geometry + Scenario: Car - Traffic signal direction straight + 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_signal_penalty = 1000 + """ + + 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 | 1033.2s | 599.9m,0m | 599.8 | goes via the expensive traffic signal | + + + + Scenario: Car - Encounters a traffic light direction + Given the node map + """ + a f k p + | | | | + b-c-d h-g-i l-m-n q-r-s + | | | | + e j o t + + """ + + And the ways + | nodes | highway | + | bcd | primary | + | ace | primary | + | hgi | primary | + | fgj | primary | + | lmn | primary | + | kmo | primary | + | qrs | primary | + | prt | primary | + + And the nodes + | node | highway | traffic_signals:direction | + | g | traffic_signals | | + | m | traffic_signals | forward | + | r | traffic_signals | backward | + + + When I route I should get + # Base case + | from | to | time | # | + | a | b | 18.7s | turn with no traffic light | + | a | e | 22.2s | no turn with no traffic light | + | a | d | 21.9s | turn with no traffic light | + | e | b | 21.9s | turn with no traffic light | + | e | a | 22.2s | no turn with no traffic light | + | e | d | 18.7s | turn with no traffic light | + | d | e | 21.9s | turn with no traffic light | + | d | b | 11s | no turn with no traffic light | + | d | a | 18.7s | turn with no traffic light | + | b | a | 21.9s | turn with no traffic light | + | b | d | 11s | no turn with no traffic light | + | b | e | 18.7s | turn with no traffic light | + # All have traffic lights - 2s penalty + | f | h | 20.7s | turn with traffic light | + | f | j | 24.2s | no turn with traffic light | + | f | i | 23.9s | turn with traffic light | + | j | h | 23.9s | turn with traffic light | + | j | f | 24.2s | no turn with traffic light | + | j | i | 20.7s | turn with traffic light | + | i | j | 23.9s | turn with traffic light | + | i | h | 13s | no turn with traffic light | + | i | f | 20.7s | turn with traffic light | + | h | f | 23.9s | turn with traffic light | + | h | i | 13s | no turn with traffic light | + | h | j | 20.7s | turn with traffic light | + # Front direction have traffic lights - 2s penalty + | k | l | 20.7s | turn with traffic light | + | k | o | 24.2s | no turn with traffic light | + | k | n | 23.9s | turn with traffic light | + | o | l | 21.9s | turn with no traffic light | + | o | k | 22.2s | no turn with no traffic light | + | o | n | 18.7s | turn with no traffic light | + | n | o | 21.9s | turn with no traffic light | + | n | l | 11s | no turn with no traffic light | + | n | k | 18.7s | turn with no traffic light | + | l | k | 23.9s | turn with traffic light | + | l | n | 13s | no turn with traffic light | + | l | o | 20.7s | turn with traffic light | + # Reverse direction have traffic lights - 2s penalty + | p | q | 18.7s | turn with no traffic light | + | p | t | 22.2s | no turn with no traffic light | + | p | s | 21.9s | turn with no traffic light | + | t | q | 23.9s | turn with traffic light | + | t | p | 24.2s | no turn with traffic light | + | t | s | 20.7s | turn with traffic light | + | s | t | 23.9s | turn with traffic light | + | s | q | 13s | no turn with traffic light | + | s | p | 20.7s | turn with traffic light | + | q | p | 21.9s | turn with no traffic light | + | q | s | 11s | no turn with no traffic light | + | q | t | 18.7s | turn with no traffic light | + + + Scenario: Traffic Signal Geometry Given the query options | overview | full | | geometries | polyline | @@ -59,7 +217,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 - backward 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 | backward | + + 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 +294,172 @@ 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 | + + + Scenario: Car - Traffic signal straight direction with edge compression + Given the node map + """ + a-1-b - c - d-2-e + + """ + + And the ways + | nodes | highway | + | abcde | primary | + + And the nodes + | node | highway | traffic_signals:direction | + | c | traffic_signals | forward | + + When I route I should get + | from | to | time | weight | # | + | 1 | 2 | 35.3s | 35.3 | no turn with traffic light | + | 2 | 1 | 33.3s | 33.3 | no turn with no traffic light | + + + Scenario: Car - Traffic signal turn direction with edge compression + Given the node map + """ + d + | + 2 + | + a-1-b - c - f + | + e + + j + | + 4 + | + g-3-h - i - k + | + l + + """ + + And the ways + | nodes | highway | + | abc | primary | + | cf | primary | + | fd | primary | + | fe | primary | + | ghi | primary | + | ik | primary | + | kj | primary | + | kl | primary | + + And the nodes + | node | highway | traffic_signals:direction | + | k | traffic_signals | forward | + + When I route I should get + | from | to | time | weight | # | + | 1 | 2 | 44.2s | 44.2 | turn with no traffic light | + | 2 | 1 | 41s | 41 | turn with no traffic light | + | 3 | 4 | 46.2s | 46.2 | turn with traffic light | + | 4 | 3 | 41s | 41 | turn with no traffic light | + + + Scenario: Car - Traffic signal turn direction with turn restriction + Given the node map + """ + d + | + 2 + | + a-1-b - c - f + | + e + + """ + + And the ways + | nodes | highway | + | abc | primary | + | cf | primary | + | fd | primary | + | fe | primary | + + And the nodes + | node | highway | traffic_signals:direction | + | f | traffic_signals | forward | + + And the relations + | type | way:from | way:to | way:via | restriction | + | restriction | abc | fe | cf | no_right_turn | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | df | fc | f | right_turn_only | + + When I route I should get + | from | to | time | weight | # | + | 1 | 2 | 46.2s | 46.2 | turn with traffic light | + | 2 | 1 | 41s | 41 | turn with no traffic light | diff --git a/features/car/turning_loop.feature b/features/car/turning_loop.feature new file mode 100644 index 00000000000..1c4d8bb0d54 --- /dev/null +++ b/features/car/turning_loop.feature @@ -0,0 +1,32 @@ +@routing @car @turning_loop +Feature: Car - Handle turning loop + + Background: + Given the profile "car" + + Scenario: Car - Must turn around at the first good opportunity + Given the node map + """ + a-b-c-d-e-f-g + """ + + And the ways + | nodes | highway | + | ab | primary | + | bc | primary | + | cd | primary | + | de | primary | + | ef | primary | + | fg | primary | + + And the nodes + | node | highway | + | b | turning_loop | + | d | turning_circle | + | f | mini_roundabout | + + When I route I should get + | waypoints | bearings | route | turns | + | a,a | 90,10 270,10 | ab,ab,ab | depart,continue uturn,arrive | + | c,a | 90,10 270,10 | cd,cd,ab | depart,continue uturn,arrive | + | e,a | 90,10 270,10 | ef,ef,ab | depart,continue uturn,arrive | diff --git a/features/car/weight.feature b/features/car/weight.feature index 6bf7a1d6efd..d7f02ac57d0 100644 --- a/features/car/weight.feature +++ b/features/car/weight.feature @@ -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/access.feature b/features/foot/access.feature index 87330ec9caf..134e02ea277 100644 --- a/features/foot/access.feature +++ b/features/foot/access.feature @@ -26,7 +26,15 @@ Feature: Foot - Access tags on ways | motorway | no | | | | motorway | no | yes | x | | motorway | no | no | | - + | platform | | | x | + | platform | | yes | x | + | platform | | no | | + | platform | yes | | x | + | platform | yes | yes | x | + | platform | yes | no | | + | platform | no | | | + | platform | no | yes | x | + | platform | no | no | | Scenario: Foot - Overwriting implied acccess on ways Then routability should be diff --git a/features/foot/intersection.feature b/features/foot/intersection.feature new file mode 100644 index 00000000000..f1ef3f6a549 --- /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 c14b00b7f46..8b8498c2622 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 5273a47b116..263aa6416c6 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/foot/way.feature b/features/foot/way.feature index ff3314f1cef..6916adece43 100644 --- a/features/foot/way.feature +++ b/features/foot/way.feature @@ -36,3 +36,9 @@ Feature: Foot - Accessability of different way types | highway | leisure | forw | | (nil) | track | x | + Scenario: Foot - Proposed ways + Then routability should be + | highway | foot | proposed | forw | + | footway | | | x | + | proposed | | | | + | proposed | yes | yes | | diff --git a/features/guidance/anticipate-lanes.feature b/features/guidance/anticipate-lanes.feature index c082dc3c19c..74f6f7d4c49 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/bugs.feature b/features/guidance/bugs.feature index aa26cb19e56..6861295f2f5 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.feature b/features/guidance/collapse.feature index e7b4dad59ad..5d790d8fa35 100644 --- a/features/guidance/collapse.feature +++ b/features/guidance/collapse.feature @@ -1061,7 +1061,7 @@ Feature: Collapse # i # """ - And the node locations + Given the node locations | node | lat | lon | #id | | a | -33.9644254 | 151.1378673 | 33226063 | | b | -33.9644373 | 151.1377172 | 1072787030 | diff --git a/features/guidance/dedicated-turn-roads.feature b/features/guidance/dedicated-turn-roads.feature index 03213bd701e..055f2af88b8 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,fork 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 diff --git a/features/guidance/maneuver-tag.feature b/features/guidance/maneuver-tag.feature index 6a4fab9f786..243090579fa 100644 --- a/features/guidance/maneuver-tag.feature +++ b/features/guidance/maneuver-tag.feature @@ -230,3 +230,100 @@ Feature: Maneuver tag support | 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 8134a2fc0c8..bb85673f7e8 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 diff --git a/features/guidance/obvious-turn-discovery.feature b/features/guidance/obvious-turn-discovery.feature index fd846aceff2..0ad8a084566 100644 --- a/features/guidance/obvious-turn-discovery.feature +++ b/features/guidance/obvious-turn-discovery.feature @@ -277,7 +277,7 @@ Feature: Simple Turns When I route I should get | from | to | route | turns | | a | c | menz,rem | depart,arrive | - | d | c | rem,rem,rem | depart,continue left,arrive | + | d | c | rem,rem | depart,arrive | | c | d | rem,rem,rem | depart,continue right,arrive | | c | a | rem,menz | depart,arrive | diff --git a/features/guidance/ramp.feature b/features/guidance/ramp.feature index a4e823dede5..560952d0b94 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-left-sided.feature b/features/guidance/roundabout-left-sided.feature index 103da754430..9555a24cae2 100644 --- a/features/guidance/roundabout-left-sided.feature +++ b/features/guidance/roundabout-left-sided.feature @@ -9,7 +9,7 @@ Feature: Basic Roundabout """ Scenario: Roundabout exit counting for left sided driving - And a grid size of 10 meters + Given a grid size of 10 meters And the node map """ a @@ -33,7 +33,7 @@ Feature: Basic Roundabout | a,h | ab,gh,gh | depart,roundabout turn right exit-3,arrive | Scenario: Mixed Entry and Exit - And a grid size of 10 meters + Given a grid size of 10 meters And the node map """ c a diff --git a/features/guidance/roundabout.feature b/features/guidance/roundabout.feature index 3b5610dcd18..5245c310ace 100644 --- a/features/guidance/roundabout.feature +++ b/features/guidance/roundabout.feature @@ -791,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 @@ -846,5 +846,5 @@ Feature: Basic Roundabout 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-lanes.feature b/features/guidance/turn-lanes.feature index f34774e9e78..1db63bfcb49 100644 --- a/features/guidance/turn-lanes.feature +++ b/features/guidance/turn-lanes.feature @@ -836,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 diff --git a/features/lib/osrm_loader.js b/features/lib/osrm_loader.js index a29d53b8e33..9a408c68033 100644 --- a/features/lib/osrm_loader.js +++ b/features/lib/osrm_loader.js @@ -2,7 +2,7 @@ const fs = require('fs'); const util = require('util'); -const Timeout = require('node-timeout'); +const { Timeout } = require('./utils'); const tryConnect = require('../lib/try_connect'); const errorReason = require('./utils').errorReason; @@ -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_IP, 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 @@ -67,8 +68,9 @@ class OSRMDirectLoader extends OSRMBaseLoader { super(scope); } - load (inputFile, callback) { - this.inputFile = inputFile; + load (ctx, callback) { + this.inputFile = ctx.inputFile; + this.loaderArgs = ctx.loaderArgs; this.shutdown(() => { this.launch(callback); }); @@ -77,7 +79,7 @@ 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 -i %s -a %s', this.inputFile, this.scope.OSRM_PORT, this.scope.OSRM_IP, this.scope.ROUTING_ALGORITHM); + const command_arguments = util.format('%s -p %d -i %s -a %s %s', this.inputFile, this.scope.OSRM_PORT, this.scope.OSRM_IP, this.scope.ROUTING_ALGORITHM, this.loaderArgs); this.child = this.scope.runBin('osrm-routed', command_arguments, this.scope.environment, (err) => { if (err && err.signal !== 'SIGINT') { this.child = null; @@ -100,8 +102,9 @@ class OSRMmmapLoader extends OSRMBaseLoader { super(scope); } - load (inputFile, callback) { - this.inputFile = inputFile; + load (ctx, callback) { + this.inputFile = ctx.inputFile; + this.loaderArgs = ctx.loaderArgs; this.shutdown(() => { this.launch(callback); }); @@ -110,7 +113,7 @@ class OSRMmmapLoader extends OSRMBaseLoader { 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); + const command_arguments = util.format('%s -p %d -i %s -a %s --mmap %s', this.inputFile, this.scope.OSRM_PORT, this.scope.OSRM_IP, this.scope.ROUTING_ALGORITHM, this.loaderArgs); this.child = this.scope.runBin('osrm-routed', command_arguments, this.scope.environment, (err) => { if (err && err.signal !== 'SIGINT') { this.child = null; @@ -133,8 +136,9 @@ class OSRMDatastoreLoader extends OSRMBaseLoader { super(scope); } - load (inputFile, callback) { - this.inputFile = inputFile; + load (ctx, callback) { + this.inputFile = ctx.inputFile; + this.loaderArgs = ctx.loaderArgs; this.loadData((err) => { if (err) return callback(err); @@ -147,7 +151,7 @@ class OSRMDatastoreLoader extends OSRMBaseLoader { } loadData (callback) { - const command_arguments = util.format('--dataset-name=%s %s', this.scope.DATASET_NAME, this.inputFile); + const command_arguments = util.format('--dataset-name=%s %s %s', this.scope.DATASET_NAME, this.inputFile, this.loaderArgs); 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(); diff --git a/features/lib/try_connect.js b/features/lib/try_connect.js index 4fa205dcbcb..be6b95c0710 100644 --- a/features/lib/try_connect.js +++ b/features/lib/try_connect.js @@ -1,7 +1,6 @@ 'use strict'; const net = require('net'); -const Timeout = require('node-timeout'); module.exports = function tryConnect(host, port, callback) { net.connect({ port: port, host: host }) diff --git a/features/lib/utils.js b/features/lib/utils.js index 32126436883..5d559019fe2 100644 --- a/features/lib/utils.js +++ b/features/lib/utils.js @@ -1,9 +1,37 @@ 'use strict'; const util = require('util'); +const { mkdir } = require('fs/promises'); + +function Timeout(ms, options) { + return function (cb) { + let called = false; + const timer = setTimeout(() => { + if (!called) { + called = true; + cb(options.err || new Error(`Operation timed out after ${ms}ms`)); + } + }, ms); + + return function (...args) { + if (!called) { + called = true; + clearTimeout(timer); + cb(...args); + } + }; + }; +} + +function createDir(dir, callback) { + mkdir(dir, { recursive: true }) + .then(() => callback(null)) + .catch(err => callback(err)); +} module.exports = { + createDir, ensureDecimal: (i) => { if (parseInt(i) === i) return i.toFixed(1); else return i; @@ -13,5 +41,6 @@ module.exports = { return err.signal ? 'killed by signal ' + err.signal : 'exited with code ' + err.code; - } + }, + Timeout }; diff --git a/features/nearest/pick.feature b/features/nearest/pick.feature index fb66ef65421..dcdf5268c30 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 3d9e6aa30b4..dc3ba94c09f 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 deleted file mode 100644 index 50269483d96..00000000000 --- a/features/options/contract/help.feature +++ /dev/null @@ -1,44 +0,0 @@ -@prepare @options @help -Feature: osrm-contract command line options: help - - Scenario: osrm-contract - Help should be shown when no options are passed - When I try to run "osrm-contract" - Then stderr should be empty - And stdout should contain /osrm-contract(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And stdout should contain "--core" - And stdout should contain "--segment-speed-file" - And it should exit with an error - - Scenario: osrm-contract - Help, short - When I run "osrm-contract -h" - Then stderr should be empty - And stdout should contain /osrm-contract(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And stdout should contain "--core" - And stdout should contain "--segment-speed-file" - And it should exit successfully - - Scenario: osrm-contract - Help, long - When I run "osrm-contract --help" - Then stderr should be empty - And stdout should contain /osrm-contract(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And stdout should contain "--core" - And stdout should contain "--segment-speed-file" - And it should exit successfully diff --git a/features/options/customize/help.feature b/features/options/customize/help.feature deleted file mode 100644 index 02a69e4ce34..00000000000 --- a/features/options/customize/help.feature +++ /dev/null @@ -1,38 +0,0 @@ -@contract @options @help -Feature: osrm-customize command line options: help - - Scenario: osrm-customize - Help should be shown when no options are passed - When I try to run "osrm-customize" - Then stderr should be empty - And stdout should contain /osrm-customize(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And it should exit with an error - - Scenario: osrm-customize - Help, short - When I run "osrm-customize -h" - Then stderr should be empty - And stdout should contain /osrm-customize(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And it should exit successfully - - Scenario: osrm-customize - Help, long - When I run "osrm-customize --help" - Then stderr should be empty - And stdout should contain /osrm-customize(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And it should exit successfully diff --git a/features/options/data/disabled_dataset.feature b/features/options/data/disabled_dataset.feature new file mode 100644 index 00000000000..0df40839483 --- /dev/null +++ b/features/options/data/disabled_dataset.feature @@ -0,0 +1,141 @@ +@routing @disable-feature-dataset +Feature: disable-feature-dataset command line options + Background: + Given the profile "testbot" + And the node map + """ + 0 + a b c + """ + And the ways + | nodes | + | ab | + | bc | + + Scenario: disable-feature-dataset - geometry disabled error + Given the data load extra arguments "--disable-feature-dataset ROUTE_GEOMETRY" + + # The default values + And the query options + | overview | simplified | + | annotations | false | + | steps | false | + | skip_waypoints | false | + + When I route I should get + | from | to | code | + | a | c | DisabledDataset | + + When I plan a trip I should get + | waypoints | code | + | a,b,c | DisabledDataset | + + When I match I should get + | trace | code | + | abc | DisabledDataset | + + Scenario: disable-feature-dataset - geometry disabled error table + Given the data load extra arguments "--disable-feature-dataset ROUTE_GEOMETRY" + + When I request nearest I should get + | in | code | + | 0 | DisabledDataset | + + When I request a travel time matrix with these waypoints I should get the response code + | waypoints | code | + | a,b,c | DisabledDataset | + + + Scenario: disable-feature-dataset - geometry disabled success + Given the data load extra arguments "--disable-feature-dataset ROUTE_GEOMETRY" + + # No geometry values returned + And the query options + | overview | false | + | annotations | false | + | steps | false | + | skip_waypoints | true | + + When I route I should get + | from | to | code | + | a | c | Ok | + + When I plan a trip I should get + | waypoints | code | + | a,b,c | Ok | + + When I match I should get + | trace | code | + | abc | Ok | + + Scenario: disable-feature-dataset - geometry disabled error table + Given the data load extra arguments "--disable-feature-dataset ROUTE_GEOMETRY" + + And the query options + | skip_waypoints | true | + + # You would never do this, but just to prove the point. + When I request nearest I should get + | in | code | + | 0 | Ok | + + When I request a travel time matrix with these waypoints I should get the response code + | waypoints | code | + | a,b,c | Ok | + + + Scenario: disable-feature-dataset - steps disabled error + Given the data load extra arguments "--disable-feature-dataset ROUTE_STEPS" + + # Default + annotations, steps + And the query options + | overview | simplified | + | annotations | true | + | steps | true | + + When I route I should get + | from | to | code | + | a | c | DisabledDataset | + + When I plan a trip I should get + | waypoints | code | + | a,b,c | DisabledDataset | + + When I match I should get + | trace | code | + | abc | DisabledDataset | + + + Scenario: disable-feature-dataset - geometry disabled error table + Given the data load extra arguments "--disable-feature-dataset ROUTE_STEPS" + + When I request nearest I should get + | in | code | + | 0 | Ok | + + When I request a travel time matrix with these waypoints I should get the response code + | waypoints | code | + | a,b,c | Ok | + + + Scenario: disable-feature-dataset - steps disabled success + Given the data load extra arguments "--disable-feature-dataset ROUTE_STEPS" + + # Default + steps + And the query options + | overview | simplified | + | annotations | true | + | steps | false | + + When I route I should get + | from | to | code | + | a | c | Ok | + + When I plan a trip I should get + | waypoints | code | + | a,b,c | Ok | + + When I match I should get + | trace | code | + | abc | Ok | + diff --git a/features/options/datastore/datastore.feature b/features/options/datastore/datastore.feature index 667f245a56f..30d19615483 100644 --- a/features/options/datastore/datastore.feature +++ b/features/options/datastore/datastore.feature @@ -33,10 +33,6 @@ Feature: osrm-datastore command line options 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." diff --git a/features/options/extract/help.feature b/features/options/extract/help.feature deleted file mode 100644 index 3d86115e5aa..00000000000 --- a/features/options/extract/help.feature +++ /dev/null @@ -1,47 +0,0 @@ -@extract @options @help -Feature: osrm-extract command line options: help - - Background: - Given the profile "testbot" - - Scenario: osrm-extract - Help should be shown when no options are passed - When I run "osrm-extract" - Then stderr should be empty - And stdout should contain /osrm-extract(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--profile" - And stdout should contain "--threads" - And stdout should contain "--small-component-size" - And it should exit successfully - - Scenario: osrm-extract - Help, short - When I run "osrm-extract -h" - Then stderr should be empty - And stdout should contain /osrm-extract(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--profile" - And stdout should contain "--threads" - And stdout should contain "--small-component-size" - And it should exit successfully - - Scenario: osrm-extract - Help, long - When I run "osrm-extract --help" - Then stderr should be empty - And stdout should contain /osrm-extract(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--profile" - And stdout should contain "--threads" - And stdout should contain "--small-component-size" - And it should exit successfully diff --git a/features/options/extract/lua.feature b/features/options/extract/lua.feature index c238cde615d..e886d710263 100644 --- a/features/options/extract/lua.feature +++ b/features/options/extract/lua.feature @@ -154,3 +154,27 @@ Feature: osrm-extract lua ways:get_nodes() Then it should exit successfully And stdout should contain "node 42" And stdout should contain "way 42" + + Scenario: osrm-extract flags accessible in process_segment function + Given the profile file + """ + functions = require('testbot') + + functions.process_segment = function (profile, segment) + print('segment forward ' .. tostring(segment.flags.forward) .. ' backward ' .. tostring(segment.flags.backward)) + end + + return functions + """ + + And the node map + """ + a b + """ + And the ways + | nodes | oneway | + | ab | 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 "segment forward true backward false" diff --git a/features/options/extract/turn_function.feature b/features/options/extract/turn_function.feature index a1db9339f92..eecb2960492 100644 --- a/features/options/extract/turn_function.feature +++ b/features/options/extract/turn_function.feature @@ -180,3 +180,30 @@ Feature: Turn Function Information 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/partition/help.feature b/features/options/partition/help.feature deleted file mode 100644 index 08fb84c35b4..00000000000 --- a/features/options/partition/help.feature +++ /dev/null @@ -1,53 +0,0 @@ -@partition @options @help -Feature: osrm-partition command line options: help - - Scenario: osrm-partition - Help should be shown when no options are passed - When I try to run "osrm-partition" - Then stderr should be empty - And stdout should contain /osrm-partition(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And stdout should contain "--balance" - And stdout should contain "--boundary" - And stdout should contain "--optimizing-cuts" - And stdout should contain "--small-component-size" - And stdout should contain "--max-cell-sizes" - And it should exit with an error - - Scenario: osrm-partition - Help, short - When I run "osrm-partition -h" - Then stderr should be empty - And stdout should contain /osrm-partition(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And stdout should contain "--balance" - And stdout should contain "--boundary" - And stdout should contain "--optimizing-cuts" - And stdout should contain "--small-component-size" - And stdout should contain "--max-cell-sizes" - And it should exit successfully - - Scenario: osrm-partition - Help, long - When I run "osrm-partition --help" - Then stderr should be empty - And stdout should contain /osrm-partition(.exe)? \[options\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "Configuration:" - And stdout should contain "--threads" - And stdout should contain "--balance" - And stdout should contain "--boundary" - And stdout should contain "--optimizing-cuts" - And stdout should contain "--small-component-size" - And stdout should contain "--max-cell-sizes" - And it should exit successfully diff --git a/features/options/routed/help.feature b/features/options/routed/help.feature deleted file mode 100644 index a581be3fed4..00000000000 --- a/features/options/routed/help.feature +++ /dev/null @@ -1,65 +0,0 @@ -@routed @options @help -Feature: osrm-routed command line options: help - - Background: - Given the profile "testbot" - - Scenario: osrm-routed - Help should be shown when no options are passed - When I run "osrm-routed" - Then stderr should be empty - And stdout should contain /osrm-routed(.exe)? \[\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "--trial" - And stdout should contain "Configuration:" - And stdout should contain "--ip" - And stdout should contain "--port" - And stdout should contain "--threads" - And stdout should contain "--shared-memory" - And stdout should contain "--max-viaroute-size" - And stdout should contain "--max-trip-size" - And stdout should contain "--max-table-size" - And stdout should contain "--max-matching-size" - And it should exit successfully - - Scenario: osrm-routed - Help, short - When I run "osrm-routed -h" - Then stderr should be empty - And stdout should contain /osrm-routed(.exe)? \[\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "--trial" - And stdout should contain "Configuration:" - And stdout should contain "--ip" - And stdout should contain "--port" - And stdout should contain "--threads" - And stdout should contain "--shared-memory" - And stdout should contain "--max-viaroute-size" - And stdout should contain "--max-trip-size" - And stdout should contain "--max-table-size" - And stdout should contain "--max-matching-size" - And it should exit successfully - - Scenario: osrm-routed - Help, long - When I run "osrm-routed --help" - Then stderr should be empty - And stdout should contain /osrm-routed(.exe)? \[\]:/ - And stdout should contain "Options:" - And stdout should contain "--version" - And stdout should contain "--help" - And stdout should contain "--verbosity" - And stdout should contain "--trial" - And stdout should contain "Configuration:" - And stdout should contain "--ip" - And stdout should contain "--port" - And stdout should contain "--threads" - And stdout should contain "--shared-memory" - And stdout should contain "--max-trip-size" - And stdout should contain "--max-table-size" - And stdout should contain "--max-table-size" - And stdout should contain "--max-matching-size" - And it should exit successfully diff --git a/features/raster/extract.feature b/features/raster/extract.feature index 8f2514aefa5..ad35b9bac98 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 0d9b76e8a37..4bcd35dfea7 100644 --- a/features/step_definitions/data.js +++ b/features/step_definitions/data.js @@ -7,310 +7,315 @@ var d3 = require('d3-queue'); var OSM = require('../lib/osm'); module.exports = function () { - this.Given(/^the profile "([^"]*)"$/, (profile, callback) => { - this.profile = this.OSRM_PROFILE || profile; - this.profileFile = path.join(this.PROFILES_PATH, this.profile + '.lua'); - callback(); + this.Given(/^the profile "([^"]*)"$/, (profile, callback) => { + this.profile = this.OSRM_PROFILE || profile; + this.profileFile = path.join(this.PROFILES_PATH, this.profile + '.lua'); + callback(); + }); + + this.Given(/^the extract extra arguments "(.*?)"$/, (args, callback) => { + this.extractArgs = this.expandOptions(args); + callback(); + }); + + this.Given(/^the contract extra arguments "(.*?)"$/, (args, callback) => { + this.contractArgs = this.expandOptions(args); + callback(); + }); + + this.Given(/^the partition extra arguments "(.*?)"$/, (args, callback) => { + this.partitionArgs = this.expandOptions(args); + callback(); + }); + + this.Given(/^the customize extra arguments "(.*?)"$/, (args, callback) => { + this.customizeArgs = this.expandOptions(args); + callback(); + }); + + this.Given(/^the data load extra arguments "(.*?)"$/, (args, callback) => { + this.loaderArgs = this.expandOptions(args); + callback(); + }); + + this.Given(/^a grid size of ([0-9.]+) meters$/, (meters, callback) => { + this.setGridSize(meters); + callback(); + }); + + this.Given(/^the origin ([-+]?[0-9]*\.?[0-9]+),([-+]?[0-9]*\.?[0-9]+)$/, (lon, lat, callback) => { + this.setOrigin([parseFloat(lon), parseFloat(lat)]); + callback(); + }); + + this.Given(/^the shortcuts$/, (table, callback) => { + let q = d3.queue(); + + let addShortcut = (row, cb) => { + this.shortcutsHash[row.key] = row.value; + cb(); + }; + + table.hashes().forEach((row) => { + q.defer(addShortcut, row); }); - this.Given(/^the extract extra arguments "(.*?)"$/, (args, callback) => { - this.extractArgs = this.expandOptions(args); - callback(); - }); - - this.Given(/^the contract extra arguments "(.*?)"$/, (args, callback) => { - this.contractArgs = this.expandOptions(args); - callback(); - }); - - this.Given(/^the partition extra arguments "(.*?)"$/, (args, callback) => { - this.partitionArgs = this.expandOptions(args); - callback(); - }); - - this.Given(/^the customize extra arguments "(.*?)"$/, (args, callback) => { - this.customizeArgs = this.expandOptions(args); - callback(); - }); - - this.Given(/^a grid size of ([0-9.]+) meters$/, (meters, callback) => { - this.setGridSize(meters); - callback(); - }); - - this.Given(/^the origin ([-+]?[0-9]*\.?[0-9]+),([-+]?[0-9]*\.?[0-9]+)$/, (lon, lat, callback) => { - this.setOrigin([parseFloat(lon), parseFloat(lat)]); - callback(); - }); - - this.Given(/^the shortcuts$/, (table, callback) => { - let q = d3.queue(); - - let addShortcut = (row, cb) => { - this.shortcutsHash[row.key] = row.value; - cb(); - }; - - table.hashes().forEach((row) => { - q.defer(addShortcut, row); - }); - - q.awaitAll(callback); - }); - - this.Given(/^the node map$/, (docstring, callback) => { - var q = d3.queue(); - - var addNode = (name, ri, ci, cb) => { - var lonLat = this.tableCoordToLonLat(ci, ri); - if (name.match(/[a-z]/) ) { - if (this.nameNodeHash[name]) throw new Error(util.format('*** duplicate node %s', name)); - this.addOSMNode(name, lonLat[0], lonLat[1], null); - } else if (name.match(/[0-9]/) ) { - if (this.locationHash[name]) throw new Error(util.format('*** duplicate node %s', name)); - this.addLocation(name, lonLat[0], lonLat[1], null); - } - cb(); - }; - - docstring.split(/\n/).forEach( (row,ri) => { - row.split('').forEach( (cell,ci) => { - if( cell.match(/[a-z0-9]/) ) { - q.defer(addNode, cell, ri, ci*0.5); - } - }); - }); - - q.awaitAll(callback); - }); - - this.Given(/^the node locations$/, (table, callback) => { - let q = d3.queue(); - - let addNodeLocations = (row, cb) => { - let name = row.node; - if (this.findNodeByName(name)) throw new Error(util.format('*** duplicate node %s', name)); - - if (name.match(/[a-z]/)) { - let id = row.id && parseInt(row.id); - this.addOSMNode(name, row.lon, row.lat, id); - } else { - this.addLocation(name, row.lon, row.lat); - } - - cb(); - }; - - table.hashes().forEach((row) => q.defer(addNodeLocations, row)); - - q.awaitAll(callback); - }); - - this.Given(/^the nodes$/, (table, callback) => { - let q = d3.queue(); - - let addNode = (row, cb) => { - let name = row.node, - node = this.findNodeByName(name); - delete row.node; - if (!node) throw new Error(util.format('*** unknown node %s', name)); - for (let key in row) { - if (key=='id') { - node.setID( row[key] ); - } else { - node.addTag(key, row[key]); - } - } - cb(); - }; - - table.hashes().forEach((row) => q.defer(addNode, row)); - - q.awaitAll(callback); + q.awaitAll(callback); + }); + + this.Given(/^the node map$/, (docstring, callback) => { + var q = d3.queue(); + + var addNode = (name, ri, ci, cb) => { + var lonLat = this.tableCoordToLonLat(ci, ri); + if (name.match(/[a-z]/) ) { + if (this.nameNodeHash[name]) throw new Error(util.format('*** duplicate node %s', name)); + this.addOSMNode(name, lonLat[0], lonLat[1], null); + } else if (name.match(/[0-9]/) ) { + if (this.locationHash[name]) throw new Error(util.format('*** duplicate node %s', name)); + this.addLocation(name, lonLat[0], lonLat[1], null); + } + cb(); + }; + + docstring.split(/\n/).forEach( (row,ri) => { + row.split('').forEach( (cell,ci) => { + if( cell.match(/[a-z0-9]/) ) { + q.defer(addNode, cell, ri, ci*0.5); + } + }); }); - 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, !!add_locations); - - let nodes = row.nodes; - if (this.nameWayHash.nodes) throw new Error(util.format('*** duplicate way %s', nodes)); - - for (let i=0; i { + let q = d3.queue(); - if (row.highway === '(nil)') delete tags.highway; + let addNodeLocations = (row, cb) => { + let name = row.node; + if (this.findNodeByName(name)) throw new Error(util.format('*** duplicate node %s', name)); - if (row.name === undefined) - tags.name = nodes; - else if (row.name === '""' || row.name === "''") // eslint-disable-line quotes - tags.name = ''; - else if (row.name === '' || row.name === '(nil)') - delete tags.name; - else - tags.name = row.name; - - way.setTags(tags); - this.OSMDB.addWay(way); - this.nameWayHash[nodes] = way; - cb(); - }; - - table.hashes().forEach((row) => q.defer(addWay, row)); - - q.awaitAll(callback); - }); - - this.Given(/^the relations$/, (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 addRelation = (headers, row, cb) => { - let relation = new OSM.Relation(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID); - - - 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) { - 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) { - 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, value); - if (key.match(/name/)) name = value; - } - } - relation.uid = this.OSM_UID; - - - if (name) { - this.nameRelationHash[name] = relation; - } - - this.OSMDB.addRelation(relation); - - cb(); - }; - - var headers = table.raw()[0]; - table.rows().forEach((row) => q.defer(addRelation, headers, row)); - - q.awaitAll(callback); - }); + if (name.match(/[a-z]/)) { + let id = row.id && parseInt(row.id); + this.addOSMNode(name, row.lon, row.lat, id); + } else { + this.addLocation(name, row.lon, row.lat); + } - this.Given(/^the input file ([^"]*)$/, (file, callback) => { - if (path.extname(file) !== '.osm') throw new Error('*** Input file must be in .osm format'); - fs.readFile(file, 'utf8', (err, data) => { - if (!err) this.osm_str = data.toString(); - callback(err); - }); - }); + cb(); + }; - this.Given(/^the raster source$/, (data, callback) => { - // TODO: Don't overwrite if it exists - fs.writeFile(this.rasterCacheFile, data, callback); - // we need this to pass it to the profiles - this.environment = Object.assign({OSRM_RASTER_SOURCE: this.rasterCacheFile}, this.environment); - }); + table.hashes().forEach((row) => q.defer(addNodeLocations, row)); - this.Given(/^the speed file$/, (data, callback) => { - // TODO: Don't overwrite if it exists - fs.writeFile(this.speedsCacheFile, data, callback); - }); + q.awaitAll(callback); + }); - this.Given(/^the turn penalty file$/, (data, callback) => { - // TODO: Don't overwrite if it exists - fs.writeFile(this.penaltiesCacheFile, data, callback); - }); + this.Given(/^the nodes$/, (table, callback) => { + let q = d3.queue(); - this.Given(/^the profile file(?: "([^"]*)" initialized with)?$/, (profile, data, callback) => { - const lua_profiles_path = this.PROFILES_PATH.split(path.sep).join('/'); - let text = 'package.path = "' + lua_profiles_path + '/?.lua;" .. package.path\n'; - if (profile == null) { - text += data + '\n'; + let addNode = (row, cb) => { + let name = row.node, + node = this.findNodeByName(name); + delete row.node; + if (!node) throw new Error(util.format('*** unknown node %s', name)); + for (let key in row) { + if (key=='id') { + node.setID( row[key] ); } else { - text += 'local functions = require("' + profile + '")\n'; - text += 'functions.setup_parent = functions.setup\n'; - text += 'functions.setup = function()\n'; - text += 'local profile = functions.setup_parent()\n'; - text += data + '\n'; - text += 'return profile\n'; - text += 'end\n'; - text += 'return functions\n'; + node.addTag(key, row[key]); } - this.profileFile = this.profileCacheFile; - // TODO: Don't overwrite if it exists - fs.writeFile(this.profileCacheFile, text, callback); - }); + } + cb(); + }; + + table.hashes().forEach((row) => q.defer(addNode, row)); + + q.awaitAll(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, !!add_locations); + + let nodes = row.nodes; + if (this.nameWayHash.nodes) throw new Error(util.format('*** duplicate way %s', nodes)); + + for (let i=0; i q.defer(addWay, row)); + + q.awaitAll(callback); + }); + + this.Given(/^the relations$/, (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 addRelation = (headers, row, cb) => { + let relation = new OSM.Relation(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID); + + + 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) { + 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) { + 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, value); + if (key.match(/name/)) name = value; + } + } + relation.uid = this.OSM_UID; - this.Given(/^the data has been saved to disk$/, (callback) => { - this.writeAndLinkOSM(callback); - }); - this.Given(/^the data has been (extract|contract|partition|customiz)ed$/, (step, callback) => { - this.reprocess(callback); - }); + if (name) { + this.nameRelationHash[name] = relation; + } - this.Given(/^osrm-routed is stopped$/, (callback) => { - this.OSRMLoader.shutdown(callback); - }); + this.OSMDB.addRelation(relation); - this.Given(/^data is loaded directly/, (callback) => { - this.osrmLoader.setLoadMethod('directly'); - callback(); - }); + cb(); + }; - this.Given(/^data is loaded with datastore$/, (callback) => { - this.osrmLoader.setLoadMethod('datastore'); - callback(); - }); + var headers = table.raw()[0]; + table.rows().forEach((row) => q.defer(addRelation, headers, row)); + + q.awaitAll(callback); + }); - this.Given(/^the HTTP method "([^"]*)"$/, (method, callback) => { - this.httpMethod = method; - callback(); + this.Given(/^the input file ([^"]*)$/, (file, callback) => { + if (path.extname(file) !== '.osm') throw new Error('*** Input file must be in .osm format'); + fs.readFile(file, 'utf8', (err, data) => { + if (!err) this.osm_str = data.toString(); + callback(err); }); + }); + + this.Given(/^the raster source$/, (data, callback) => { + // TODO: Don't overwrite if it exists + fs.writeFile(this.rasterCacheFile, data, callback); + // we need this to pass it to the profiles + this.environment = Object.assign({OSRM_RASTER_SOURCE: this.rasterCacheFile}, this.environment); + }); + + this.Given(/^the speed file$/, (data, callback) => { + // TODO: Don't overwrite if it exists + fs.writeFile(this.speedsCacheFile, data, callback); + }); + + this.Given(/^the turn penalty file$/, (data, callback) => { + // TODO: Don't overwrite if it exists + fs.writeFile(this.penaltiesCacheFile, data, callback); + }); + + this.Given(/^the profile file(?: "([^"]*)" initialized with)?$/, (profile, data, callback) => { + const lua_profiles_path = this.PROFILES_PATH.split(path.sep).join('/'); + let text = 'package.path = "' + lua_profiles_path + '/?.lua;" .. package.path\n'; + if (profile == null) { + text += data + '\n'; + } else { + text += 'local functions = require("' + profile + '")\n'; + text += 'functions.setup_parent = functions.setup\n'; + text += 'functions.setup = function()\n'; + text += 'local profile = functions.setup_parent()\n'; + text += data + '\n'; + text += 'return profile\n'; + text += 'end\n'; + text += 'return functions\n'; + } + this.profileFile = this.profileCacheFile; + // TODO: Don't overwrite if it exists + fs.writeFile(this.profileCacheFile, text, callback); + }); + + this.Given(/^the data has been saved to disk$/, (callback) => { + this.writeAndLinkOSM(callback); + }); + + this.Given(/^the data has been (extract|contract|partition|customiz)ed$/, (step, callback) => { + this.reprocess(callback); + }); + + this.Given(/^osrm-routed is stopped$/, (callback) => { + this.OSRMLoader.shutdown(callback); + }); + + this.Given(/^data is loaded directly/, (callback) => { + this.osrmLoader.setLoadMethod('directly'); + callback(); + }); + + this.Given(/^data is loaded with datastore$/, (callback) => { + this.osrmLoader.setLoadMethod('datastore'); + callback(); + }); + + this.Given(/^the HTTP method "([^"]*)"$/, (method, callback) => { + this.httpMethod = method; + callback(); + }); }; diff --git a/features/step_definitions/distance_matrix.js b/features/step_definitions/distance_matrix.js index 594268d50fa..a140a081722 100644 --- a/features/step_definitions/distance_matrix.js +++ b/features/step_definitions/distance_matrix.js @@ -1,106 +1,199 @@ var util = require('util'); -module.exports = function () { - 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 DURATIONS_NO_ROUTE = 2147483647; // MAX_INT - const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT +var flatbuffers = require('../support/flatbuffers').flatbuffers; +var FBResult = require('../support/fbresult_generated').osrm.engine.api.fbresult.FBResult; - this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', callback);}.bind(this)); - this.When(distancesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', callback);}.bind(this)); - this.When(estimatesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'fallback_speed_cells', callback);}.bind(this)); +module.exports = function () { + const durationsRegex = new RegExp(/^I request a travel time matrix I should get$/); + const durationsCodeOnlyRegex = new RegExp(/^I request a travel time matrix with these waypoints I should get the response code$/); + 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$/); + + const DURATIONS_NO_ROUTE = 2147483647; // MAX_INT + const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT + + const FORMAT_JSON = 'json'; + const FORMAT_FB = 'flatbuffers'; + + this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', FORMAT_JSON, callback);}.bind(this)); + this.When(durationsCodeOnlyRegex, function(table, callback) {tableCodeOnlyParse.call(this, table, '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)); }; const durationsParse = function(v) { return isNaN(parseInt(v)); }; const distancesParse = function(v) { return isNaN(parseFloat(v)); }; const estimatesParse = function(v) { return isNaN(parseFloat(v)); }; -function tableParse(table, noRoute, annotation, callback) { +function tableCodeOnlyParse(table, annotation, format, callback) { - const parse = annotation == 'distances' ? distancesParse : (annotation == 'durations' ? durationsParse : estimatesParse); - const params = this.queryParams; - params.annotations = ['durations','fallback_speed_cells'].indexOf(annotation) !== -1 ? 'duration' : 'distance'; + const params = this.queryParams; + params.annotations = ['durations','fallback_speed_cells'].indexOf(annotation) !== -1 ? 'duration' : 'distance'; + params.output = format; - var tableRows = table.raw(); + var got; - if (tableRows[0][0] !== '') throw new Error('*** Top-left cell of matrix table must be empty'); + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + var testRow = (row, ri, cb) => { + var afterRequest = (err, res, body) => { + if (err) return cb(err); - 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 json = JSON.parse(response.body); - - var result = {}; - if (annotation === 'fallback_speed_cells') { - result = table.raw().map(row => row.map(() => '')); - json[annotation].forEach(pair => { - result[pair[0]+1][pair[1]+1] = 'Y'; - }); - result = result.slice(1).map(row => { - var hashes = {}; - row.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; - }); + for (var k in row) { + var match = k.match(/param:(.*)/); + if (match) { + if (row[k] === '(nil)') { + params[match[1]] = null; + } else if (row[k]) { + params[match[1]] = [row[k]]; } + got[k] = row[k]; + } + } + + var json; + got.code = 'unknown'; + if (body.length) { + json = JSON.parse(body); + got.code = json.code; + } + + cb(null, got); + }; + + var params = this.queryParams, + waypoints = []; + if (row.waypoints) { + row.waypoints.split(',').forEach((n) => { + var node = this.findNodeByName(n); + if (!node) throw new Error(util.format('*** unknown waypoint node "%s"', n.trim())); + waypoints.push({ coord: node, type: 'loc' }); - var testRow = (row, ri, cb) => { - for (var k in result[ri]) { - if (this.FuzzyMatch.match(result[ri][k], row[k])) { - result[ri][k] = row[k]; - } else if (row[k] === '' && result[ri][k] === noRoute) { - result[ri][k] = ''; - } else { - result[ri][k] = result[ri][k].toString(); - } - } - - result[ri][''] = row['']; - cb(null, result[ri]); - }; - - this.processRowsAndDiff(table, testRow, callback); }); + got = { waypoints: row.waypoints }; + + this.requestTable(waypoints, params, afterRequest); + } else { + throw new Error('*** no waypoints'); + } + }; + + this.processRowsAndDiff(table, testRow, callback); + }); + +} + +function tableParse(table, noRoute, annotation, format, callback) { + + 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; + + 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' }); + }); + } + + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + // compute matrix + + this.requestTable(waypoints, params, (err, response, body) => { + if (err) return callback(err); + if (!body.length) return callback(new Error('Invalid response body')); + + var result = []; + if (format === 'json') { + var json = JSON.parse(body); + + 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 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 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]; + } + } + } + + var testRow = (row, ri, cb) => { + for (var k in result[ri]) { + if (this.FuzzyMatch.match(result[ri][k], row[k])) { + result[ri][k] = row[k]; + } else if (row[k] === '' && result[ri][k] === noRoute) { + result[ri][k] = ''; + } else { + result[ri][k] = result[ri][k].toString(); + } + } + + result[ri][''] = row['']; + cb(null, result[ri]); + }; + + this.processRowsAndDiff(table, testRow, callback); }); + }); } diff --git a/features/step_definitions/matching.js b/features/step_definitions/matching.js index d7c62ee078a..f71ca3475b9 100644 --- a/features/step_definitions/matching.js +++ b/features/step_definitions/matching.js @@ -1,277 +1,281 @@ 'use strict'; var util = require('util'); -var polyline = require('polyline'); +var polyline = require('@mapbox/polyline'); module.exports = function () { - this.When(/^I match I should get$/, (table, callback) => { - var got; - - this.reprocessAndLoadData((e) => { - if (e) return callback(e); - var testRow = (row, ri, cb) => { - var afterRequest = (err, res) => { - if (err) return cb(err); - var json; - - var headers = new Set(table.raw()[0]); - - got.code = 'unknown'; - if (res.body.length) { - json = JSON.parse(res.body); - got.code = json.code; - } - - - if (headers.has('status')) { - got.status = json.status.toString(); - } - - if (headers.has('message')) { - got.message = json.status_message; - } - - if (headers.has('#')) { - // comment column - got['#'] = row['#']; - } - - var subMatchings = [''], - turns = '', - route = '', - duration = '', - annotation = '', - geometry = '', - OSMIDs = '', - alternatives = ''; - - - if (res.statusCode === 200) { - if (headers.has('matchings')) { - subMatchings = []; - - // find the first matched - let start_index = 0; - while (start_index < json.tracepoints.length && json.tracepoints[start_index] === null) start_index++; - - var sub = []; - let prev_index = null; - for(var i = start_index; i < json.tracepoints.length; i++){ - if (json.tracepoints[i] === null) continue; - - let current_index = json.tracepoints[i].matchings_index; - - if(prev_index !== current_index) { - if (sub.length > 0) subMatchings.push(sub); - sub = []; - prev_index = current_index; - } - - sub.push(json.tracepoints[i].location); - } - subMatchings.push(sub); - } - - 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]); - } - - if (headers.has('route')) { - if (json.matchings.length != 1) throw new Error('*** Checking route only supported for matchings with one subtrace'); - route = this.wayList(json.matchings[0]); - } - - if (headers.has('duration')) { - if (json.matchings.length != 1) throw new Error('*** Checking duration only supported for matchings with one subtrace'); - duration = json.matchings[0].duration; - } - - // annotation response values are requested by 'a:{type_name}' - var found = false; - headers.forEach((h) => { if (h.match(/^a:/)) found = true; }); - if (found) { - if (json.matchings.length != 1) throw new Error('*** Checking annotation only supported for matchings with one subtrace'); - annotation = this.annotationList(json.matchings[0]); - } - - if (headers.has('geometry')) { - if (json.matchings.length != 1) throw new Error('*** Checking geometry only supported for matchings with one subtrace'); - geometry = json.matchings[0].geometry; - } - - if (headers.has('alternatives')) { - alternatives = this.alternativesList(json); - } - } - - if (headers.has('turns')) { - got.turns = turns; - } - - if (headers.has('route')) { - got.route = route; - } - - if (headers.has('duration')) { - got.duration = duration.toString(); - } - - // if header matches 'a:*', parse out the values for * - // and return in that header - headers.forEach((k) => { - let whitelist = ['duration', 'distance', 'datasources', 'nodes', 'weight']; - if (k.match(/^a:/)) { - let a_type = k.slice(2); - if (whitelist.indexOf(a_type) == -1) - return cb(new Error('Unrecognized annotation field:' + a_type)); - if (!annotation[a_type]) - return cb(new Error('Annotation not found in response: ' + a_type)); - got[k] = annotation[a_type]; - } - }); - - if (headers.has('geometry')) { - if (this.queryParams['geometries'] === 'polyline') { - got.geometry = polyline.decode(geometry).toString(); - } else if (this.queryParams['geometries'] === 'polyline6') { - got.geometry = polyline.decode(geometry,6).toString(); - } else { - got.geometry = geometry.coordinates; - } - } - - if (headers.has('OSM IDs')) { - got['OSM IDs'] = OSMIDs; - } - - if (headers.has('alternatives')) { - got['alternatives'] = alternatives; - } - var ok = true; - var encodedResult = '', - extendedTarget = '', - resultWaypoints = []; - - var testSubMatching = (sub, si) => { - var testSubNode = (ni) => { - var node = this.findNodeByName(sub[ni]), - outNode = subMatchings[si][ni]; - - if (this.FuzzyMatch.matchLocation(outNode, node)) { - encodedResult += sub[ni]; - extendedTarget += sub[ni]; - } else { - if (outNode != null) { - encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]); - } else { - encodedResult += '?'; - } - extendedTarget += util.format('%s [%d,%d]', node.lat, node.lon); - ok = false; - } - }; - - for (var i=0; i { - testSubMatching(sub, si); - }); - } - - 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; - } - - 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; - } - - cb(null, got); - }; - - if (row.request) { - got = {}; - got.request = row.request; - this.requestUrl(row.request, afterRequest); + this.When(/^I match I should get$/, (table, callback) => { + var got; + + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + var testRow = (row, ri, cb) => { + var afterRequest = (err, res, body) => { + if (err) return cb(err); + var json; + + var headers = new Set(table.raw()[0]); + + got.code = 'unknown'; + if (body.length) { + json = JSON.parse(body); + got.code = json.code; + } + + + if (headers.has('status')) { + got.status = json.status.toString(); + } + + if (headers.has('message')) { + got.message = json.status_message; + } + + if (headers.has('#')) { + // comment column + got['#'] = row['#']; + } + + var subMatchings = [''], + turns = '', + route = '', + duration = '', + annotation = '', + geometry = '', + OSMIDs = '', + alternatives = ''; + + + if (res.statusCode === 200) { + if (headers.has('matchings')) { + subMatchings = []; + + // find the first matched + let start_index = 0; + while (start_index < json.tracepoints.length && json.tracepoints[start_index] === null) start_index++; + + var sub = []; + let prev_index = null; + for(var i = start_index; i < json.tracepoints.length; i++){ + if (json.tracepoints[i] === null) continue; + + let current_index = json.tracepoints[i].matchings_index; + + if(prev_index !== current_index) { + if (sub.length > 0) subMatchings.push(sub); + sub = []; + prev_index = current_index; + } + + sub.push(json.tracepoints[i].location); + } + subMatchings.push(sub); + } + + 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]); + } + + if (headers.has('route')) { + if (json.matchings.length != 1) throw new Error('*** Checking route only supported for matchings with one subtrace'); + route = this.wayList(json.matchings[0]); + } + + if (headers.has('duration')) { + if (json.matchings.length != 1) throw new Error('*** Checking duration only supported for matchings with one subtrace'); + duration = json.matchings[0].duration; + } + + // annotation response values are requested by 'a:{type_name}' + var found = false; + headers.forEach((h) => { if (h.match(/^a:/)) found = true; }); + if (found) { + if (json.matchings.length != 1) throw new Error('*** Checking annotation only supported for matchings with one subtrace'); + annotation = this.annotationList(json.matchings[0]); + } + + if (headers.has('geometry')) { + if (json.matchings.length != 1) throw new Error('*** Checking geometry only supported for matchings with one subtrace'); + geometry = json.matchings[0].geometry; + } + + if (headers.has('alternatives')) { + alternatives = this.alternativesList(json); + } + } + + if (headers.has('turns')) { + got.turns = turns; + } + + if (headers.has('route')) { + got.route = route; + } + + if (headers.has('duration')) { + 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) => { + let whitelist = ['duration', 'distance', 'datasources', 'nodes', 'weight']; + if (k.match(/^a:/)) { + let a_type = k.slice(2); + if (whitelist.indexOf(a_type) == -1) + return cb(new Error('Unrecognized annotation field:' + a_type)); + if (!annotation[a_type]) + return cb(new Error('Annotation not found in response: ' + a_type)); + got[k] = annotation[a_type]; + } + }); + + if (headers.has('geometry')) { + if (this.queryParams['geometries'] === 'polyline') { + got.geometry = polyline.decode(geometry).toString(); + } else if (this.queryParams['geometries'] === 'polyline6') { + got.geometry = polyline.decode(geometry,6).toString(); + } else { + got.geometry = geometry.coordinates; + } + } + + if (headers.has('OSM IDs')) { + got['OSM IDs'] = OSMIDs; + } + + if (headers.has('alternatives')) { + got['alternatives'] = alternatives; + } + var ok = true; + var encodedResult = '', + extendedTarget = '', + resultWaypoints = []; + + var testSubMatching = (sub, si) => { + var testSubNode = (ni) => { + var node = this.findNodeByName(sub[ni]), + outNode = subMatchings[si][ni]; + + if (this.FuzzyMatch.matchLocation(outNode, node)) { + encodedResult += sub[ni]; + extendedTarget += sub[ni]; + } else { + if (outNode != null) { + encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]); } else { - var params = this.queryParams; - got = {}; - for (var k in row) { - var match = k.match(/param:(.*)/); - if (match) { - if (row[k] === '(nil)') { - params[match[1]] = null; - } else if (row[k]) { - params[match[1]] = [row[k]]; - } - got[k] = row[k]; - } - } - - var trace = [], - timestamps = []; - - if (row.trace) { - for (var i=0; i !!s).map(t => parseInt(t, 10)); - } - got.trace = row.trace; - this.requestMatching(trace, timestamps, params, afterRequest); - } else { - throw new Error('*** no trace'); - } + encodedResult += '?'; } + extendedTarget += util.format('%s [%d,%d]', node.lat, node.lon); + ok = false; + } }; - this.processRowsAndDiff(table, testRow, callback); - }); + for (var i=0; i { + testSubMatching(sub, si); + }); + } + + 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; + } + + 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; + } + + cb(null, got); + }; + + if (row.request) { + got = {}; + got.request = row.request; + this.requestUrl(row.request, afterRequest); + } else { + var params = this.queryParams; + got = {}; + for (var k in row) { + var match = k.match(/param:(.*)/); + if (match) { + if (row[k] === '(nil)') { + params[match[1]] = null; + } else if (row[k]) { + params[match[1]] = [row[k]]; + } + got[k] = row[k]; + } + } + + var trace = [], + timestamps = []; + + if (row.trace) { + for (var i=0; i !!s).map(t => parseInt(t, 10)); + } + got.trace = row.trace; + this.requestMatching(trace, timestamps, params, afterRequest); + } else { + throw new Error('*** no trace'); + } + } + }; + + this.processRowsAndDiff(table, testRow, callback); }); + }); }; diff --git a/features/step_definitions/nearest.js b/features/step_definitions/nearest.js index f5627b84266..b353d039b3a 100644 --- a/features/step_definitions/nearest.js +++ b/features/step_definitions/nearest.js @@ -1,46 +1,113 @@ 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)); + this.When(/^I request nearest I should get$/, (table, callback) => { + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + var testRow = (row, ri, cb) => { - var outNode = this.findNodeByName(row.out); - if (!outNode) throw new Error(util.format('*** unknown out-node "%s"', row.out)); + var inNode = this.findNodeByName(row.in); + if (!inNode) throw new Error(util.format('*** unknown in-node "%s"', row.in)); - this.requestNearest(inNode, this.queryParams, (err, response) => { - if (err) return cb(err); - var coord; + this.requestNearest(inNode, this.queryParams, (err, response, body) => { + 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); + var got = { in: row.in }; - coord = json.waypoints[0].location; + if (body.length) { + var json = JSON.parse(body); + got.code = json.code; - var got = { in: row.in, out: row.out }; + if (response.statusCode === 200) { - 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); - } - } - }); + if (headers.has('data_version')) { + got.data_version = json.data_version || ''; + } - cb(null, got); - } - else { - cb(); + if (json.waypoints && json.waypoints.length && row.out) { + coord = json.waypoints[0].location; + + got.out = row.out; + + var outNode = this.findNodeByName(row.out); + if (!outNode) throw new Error(util.format('*** unknown out-node "%s"', row.out)); + + 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); } + } }); - }; + } - this.processRowsAndDiff(table, testRow, callback); + } + 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, body) => { + if (err) return cb(err); + var coord; + + if (response.statusCode === 200 && body.length) { + 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)) { + 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); }); + }); }; diff --git a/features/step_definitions/options.js b/features/step_definitions/options.js index 79cb10e9a5a..1a713500720 100644 --- a/features/step_definitions/options.js +++ b/features/step_definitions/options.js @@ -4,97 +4,97 @@ const assert = require('assert'); const fs = require('fs'); module.exports = function () { - this.resetOptionsOutput = () => { - this.stdout = null; - this.stderr = null; - this.exitCode = null; - this.termSignal = null; - }; - - this.runAndSafeOutput = (binary, options, callback) => { - return this.runBin(binary, this.expandOptions(options), this.environment, (err, stdout, stderr) => { - this.stdout = stdout; - this.stderr = stderr; - this.exitCode = err && err.code || 0; - this.termSignal = err && err.signal || ''; - callback(err); - }); - }; - - this.When(/^I run "osrm-routed\s?(.*?)"$/, { timeout: this.TIMEOUT }, (options, callback) => { - this.runAndSafeOutput('osrm-routed', options, callback); + this.resetOptionsOutput = () => { + this.stdout = null; + this.stderr = null; + this.exitCode = null; + this.termSignal = null; + }; + + this.runAndSafeOutput = (binary, options, callback) => { + return this.runBin(binary, this.expandOptions(options), this.environment, (err, stdout, stderr) => { + this.stdout = stdout; + this.stderr = stderr; + this.exitCode = err && err.code || 0; + this.termSignal = err && err.signal || ''; + callback(err); }); + }; - 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); - fs.writeFile(stamp, 'ok', 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) => { - let child = this.runAndSafeOutput('osrm-datastore', options, callback); - if (input !== undefined) - child.stdin.write(input); - }); - - this.Then(/^it should exit successfully$/, () => { - assert.equal(this.exitCode, 0); - assert.equal(this.termSignal, ''); - }); - - this.Then(/^it should exit with an error$/, () => { - assert.ok(this.exitCode !== 0 || this.termSignal); - }); - - this.Then(/^stdout should( not)? contain "(.*?)"$/, (not, str) => { - const contains = this.stdout.indexOf(str) > -1; - assert.ok(typeof not === 'undefined' ? contains : !contains, - 'stdout ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"'); - }); - - this.Then(/^stderr should( not)? contain "(.*?)"$/, (not, str) => { - const contains = this.stderr.indexOf(str) > -1; - assert.ok(typeof not === 'undefined' ? contains : !contains, - 'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"'); - }); - - this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => { - const re = new RegExp(regexStr); - assert.ok(this.stdout.match(re)); - }); - - this.Then(/^stderr should contain \/(.*)\/$/, (regexStr) => { - const re = new RegExp(regexStr); - assert.ok(this.stdout.match(re)); - }); - - this.Then(/^stdout should be empty$/, () => { - assert.equal(this.stdout.trim(), ''); - }); - - this.Then(/^stderr should be empty$/, () => { - assert.equal(this.stderr.trim(), ''); - }); + this.When(/^I run "osrm-routed\s?(.*?)"$/, { timeout: this.TIMEOUT }, (options, callback) => { + this.runAndSafeOutput('osrm-routed', options, callback); + }); - this.Then(/^stdout should contain (\d+) lines?$/, (lines) => { - assert.equal(this.stdout.split('\n').length - 1, parseInt(lines)); + 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); + fs.writeFile(stamp, 'ok', callback); }); - - this.Then(/^stderr should contain (\d+) lines?$/, (lines) => { - assert.equal(this.stderr.split('\n').length - 1, parseInt(lines)); + }); + + 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) => { + let child = this.runAndSafeOutput('osrm-datastore', options, callback); + if (input !== undefined) + child.stdin.write(input); + }); + + this.Then(/^it should exit successfully$/, () => { + assert.equal(this.exitCode, 0); + assert.equal(this.termSignal, ''); + }); + + this.Then(/^it should exit with an error$/, () => { + assert.ok(this.exitCode !== 0 || this.termSignal); + }); + + this.Then(/^stdout should( not)? contain "(.*?)"$/, (not, str) => { + const contains = this.stdout.indexOf(str) > -1; + assert.ok(typeof not === 'undefined' ? contains : !contains, + 'stdout ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"'); + }); + + this.Then(/^stderr should( not)? contain "(.*?)"$/, (not, str) => { + const contains = this.stderr.indexOf(str) > -1; + assert.ok(typeof not === 'undefined' ? contains : !contains, + 'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"'); + }); + + this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => { + const re = new RegExp(regexStr); + assert.ok(this.stdout.match(re)); + }); + + this.Then(/^stderr should contain \/(.*)\/$/, (regexStr) => { + const re = new RegExp(regexStr); + assert.ok(this.stdout.match(re)); + }); + + this.Then(/^stdout should be empty$/, () => { + assert.equal(this.stdout.trim(), ''); + }); + + this.Then(/^stderr should be empty$/, () => { + assert.equal(this.stderr.trim(), ''); + }); + + this.Then(/^stdout should contain (\d+) lines?$/, (lines) => { + assert.equal(this.stdout.split('\n').length - 1, parseInt(lines)); + }); + + this.Then(/^stderr should contain (\d+) lines?$/, (lines) => { + assert.equal(this.stderr.split('\n').length - 1, parseInt(lines)); + }); + + this.Given(/^the query options$/, (table, callback) => { + table.raw().forEach(tuple => { + this.queryParams[tuple[0]] = tuple[1]; }); - this.Given(/^the query options$/, (table, callback) => { - table.raw().forEach(tuple => { - this.queryParams[tuple[0]] = tuple[1]; - }); - - callback(); - }); + callback(); + }); }; diff --git a/features/step_definitions/requests.js b/features/step_definitions/requests.js index 36eef830bc9..26ae8ac9ba2 100644 --- a/features/step_definitions/requests.js +++ b/features/step_definitions/requests.js @@ -1,58 +1,59 @@ var assert = require('assert'); module.exports = function () { - this.When(/^I request \/(.*)$/, (path, callback) => { - this.reprocessAndLoadData((e) => { - if (e) return callback(e); - this.requestPath(path, {}, (err, res, body) => { - this.response = res; - callback(err, res, body); - }); - }); - }); - - this.Then(/^I should get a response/, () => { - this.ShouldGetAResponse(); - }); - - this.Then(/^response should be valid JSON$/, (callback) => { - this.ShouldBeValidJSON(callback); - }); - - this.Then(/^response should be well-formed$/, () => { - this.ShouldBeWellFormed(); - }); - - this.Then(/^status code should be (\d+)$/, (code, callback) => { - try { - this.json = JSON.parse(this.response.body); - } catch(e) { - return callback(e); - } - assert.equal(this.json.status, parseInt(code)); - callback(); - }); - - this.Then(/^status message should be "(.*?)"$/, (message, callback) => { - try { - this.json = JSON.parse(this.response.body); - } catch(e) { - return callback(e); - } - assert(this.json.status_message, message); - callback(); - }); - - this.Then(/^response should be a well-formed route$/, () => { - this.ShouldBeWellFormed(); - assert.equal(this.json.code, 'ok'); - assert.ok(Array.isArray(this.json.routes)); - assert.ok(Array.isArray(this.json.waypoints)); - }); - - this.Then(/^"([^"]*)" should return code (\d+)$/, (binary, code) => { - assert.ok(this.processError instanceof Error); - assert.equal(this.processError.process, binary); - assert.equal(parseInt(this.processError.code), parseInt(code)); - }); -}; + this.When(/^I request \/(.*)$/, (path, callback) => { + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + this.requestUrl(path, (err, res, body) => { + this.response = res; + this.body = body; + callback(err, res, body); + }); + }); + }); + + this.Then(/^I should get a response/, () => { + this.ShouldGetAResponse(); + }); + + this.Then(/^response should be valid JSON$/, (callback) => { + this.ShouldBeValidJSON(callback); + }); + + this.Then(/^response should be well-formed$/, () => { + this.ShouldBeWellFormed(); + }); + + this.Then(/^status code should be (.+)$/, (code, callback) => { + try { + this.json = JSON.parse(this.body); + } catch(e) { + return callback(e); + } + assert.equal(this.json.code, code); + callback(); + }); + + this.Then(/^status message should be "(.*?)"$/, (message, callback) => { + try { + this.json = JSON.parse(this.body); + } catch(e) { + return callback(e); + } + assert(this.json.status_message, message); + callback(); + }); + + this.Then(/^response should be a well-formed route$/, () => { + this.ShouldBeWellFormed(); + assert.equal(this.json.code, 'ok'); + assert.ok(Array.isArray(this.json.routes)); + assert.ok(Array.isArray(this.json.waypoints)); + }); + + this.Then(/^"([^"]*)" should return code (\d+)$/, (binary, code) => { + assert.ok(this.processError instanceof Error); + 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 93aa9e41c7b..d7a66a98d8c 100644 --- a/features/step_definitions/routability.js +++ b/features/step_definitions/routability.js @@ -1,188 +1,191 @@ -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) => { - this.buildWaysFromTable(table, () => { - var directions = ['forw','backw','bothw'], - testedHeaders = ['forw','backw','bothw','forw_rate','backw_rate','bothw_rate'], - headers = new Set(Object.keys(table.hashes()[0])); - - if (!testedHeaders.some(k => !!headers.has(k))) { - throw new Error('*** routability table must contain either "forw", "backw", "bothw", "forw_rate" or "backw_mode" column'); - } - - this.reprocessAndLoadData((e) => { - if (e) return callback(e); - var testRow = (row, i, cb) => { - var outputRow = Object.assign({}, row); - // clear the fields that are tested for in the copied response object - for (var field in outputRow) { - if (testedHeaders.indexOf(field) != -1) - outputRow[field] = ''; - } - - testRoutabilityRow(i, (err, result) => { - if (err) return cb(err); - directions.filter(d => headers.has(d + '_rate')).forEach((direction) => { - var rate = direction + '_rate'; - var want = row[rate]; - - switch (true) { - case '' === want: - outputRow[rate] = result[direction].status ? - result[direction].status.toString() : ''; - break; - case /^\d+(\.\d+){0,1}$/.test(want): - if (result[direction].rate !== undefined && !isNaN(result[direction].rate)) { - outputRow[rate] = result[direction].rate.toString(); - } else { - outputRow[rate] = ''; - } - break; - default: - throw new Error(util.format('*** Unknown expectation format: %s for header %s', want, rate)); - } - }); - - directions.filter(d => headers.has(d)).forEach((direction) => { - var usingShortcut = false, - want = row[direction]; - // shortcuts are when a test has mapped a value like `foot` to - // a value like `5 km/h`, to represent the speed that one - // can travel by foot. we check for these and use the mapped to - // value for later comparison. - if (this.shortcutsHash[row[direction]]) { - want = this.shortcutsHash[row[direction]]; - usingShortcut = row[direction]; - } - - // TODO split out accessible/not accessible value from forw/backw headers - // rename forw/backw to forw/backw_speed - switch (true) { - case '' === want: - outputRow[direction] = result[direction].status ? - result[direction].mode : ''; - break; - case 'x' === want: - outputRow[direction] = result[direction].status ? - 'x' : ''; - break; - 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 - if (result[direction].time) { - outputRow[direction] = !isNaN(result[direction].time) ? - result[direction].time.toString()+' s' : - result[direction].time.toString() || ''; - } else { - outputRow[direction] = ''; - } - break; - case /^\d+ km\/h/.test(want): - if (result[direction].speed) { - outputRow[direction] = !isNaN(result[direction].speed) ? - result[direction].speed.toString()+' km/h' : - result[direction].speed.toString() || ''; - } else { - outputRow[direction] = ''; - } - break; - default: - outputRow[direction] = result[direction].mode || ''; - } - - if (this.FuzzyMatch.match(outputRow[direction], want)) { - outputRow[direction] = usingShortcut ? usingShortcut : row[direction]; - } - }); - - cb(null, outputRow); - }); - }; - this.processRowsAndDiff(table, testRow, callback); + this.Then(/^routability should be$/, (table, callback) => { + this.buildWaysFromTable(table, () => { + var directions = ['forw','backw','bothw'], + testedHeaders = ['forw','backw','bothw','forw_rate','backw_rate','bothw_rate'], + headers = new Set(Object.keys(table.hashes()[0])); + + if (!testedHeaders.some(k => !!headers.has(k))) { + throw new Error('*** routability table must contain either "forw", "backw", "bothw", "forw_rate" or "backw_mode" column'); + } + + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + var testRow = (row, i, cb) => { + var outputRow = Object.assign({}, row); + // clear the fields that are tested for in the copied response object + for (var field in outputRow) { + if (testedHeaders.indexOf(field) != -1) + outputRow[field] = ''; + } + + testRoutabilityRow(i, (err, result) => { + if (err) return cb(err); + directions.filter(d => headers.has(d + '_rate')).forEach((direction) => { + var rate = direction + '_rate'; + var want = row[rate]; + + switch (true) { + case '' === want: + outputRow[rate] = result[direction].status ? + result[direction].status.toString() : ''; + break; + case /^\d+(\.\d+){0,1}$/.test(want): + if (result[direction].rate !== undefined && !isNaN(result[direction].rate)) { + outputRow[rate] = result[direction].rate.toString(); + } else { + outputRow[rate] = ''; + } + break; + default: + throw new Error(util.format('*** Unknown expectation format: %s for header %s', want, rate)); + } }); - }); - }); - // makes simple a-b request using the given cucumber test routability conditions - // result is an object containing the calculated values for 'rate', 'status', - // 'time', 'distance', 'speed' and 'mode', for forwards and backwards routing, as well as - // a bothw object that diffs forwards/backwards - var testRoutabilityRow = (i, cb) => { - 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]), - r = {}; - - r.which = dir; - - this.requestRoute((dir === 'forw' ? [a, b] : [b, a]), [], [], this.queryParams, (err, res, body) => { - if (err) return callback(err); - - r.query = this.query; - r.json = JSON.parse(body); - r.code = r.json.code; - r.status = res.statusCode === 200 ? 'x' : null; - if (r.status) { - r.route = this.wayList(r.json.routes[0]); - r.summary = r.json.routes[0].legs.map(l => l.summary).join(','); - - if (r.route.split(',')[0] === util.format('w%d', i)) { - r.time = r.json.routes[0].duration; - r.distance = r.json.routes[0].distance; - r.rate = Math.round(r.distance / r.json.routes[0].weight * 10) / 10.; - r.speed = r.time > 0 ? parseInt(3.6 * r.distance / r.time) : null; - - // use the mode of the first step of the route - // for routability table test, we can assume the mode is the same throughout the route, - // since the route is just a single way - if( r.json.routes[0].legs[0] && r.json.routes[0].legs[0].steps[0] ) { - r.mode = r.json.routes[0].legs[0].steps[0].mode; - } - } else { - r.status = null; - } + directions.filter(d => headers.has(d)).forEach((direction) => { + var usingShortcut = false, + want = row[direction]; + // shortcuts are when a test has mapped a value like `foot` to + // a value like `5 km/h`, to represent the speed that one + // can travel by foot. we check for these and use the mapped to + // value for later comparison. + if (this.shortcutsHash[row[direction]]) { + want = this.shortcutsHash[row[direction]]; + usingShortcut = row[direction]; + } + + // TODO split out accessible/not accessible value from forw/backw headers + // rename forw/backw to forw/backw_speed + switch (true) { + case '' === want: + outputRow[direction] = result[direction].status ? + result[direction].mode : ''; + break; + case 'x' === want: + outputRow[direction] = result[direction].status ? + 'x' : ''; + break; + 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 + if (result[direction].time) { + outputRow[direction] = !isNaN(result[direction].time) ? + result[direction].time.toString()+' s' : + result[direction].time.toString() || ''; + } else { + outputRow[direction] = ''; } - - callback(null, r); + break; + case /^\d+ km\/h/.test(want): + if (result[direction].speed) { + outputRow[direction] = !isNaN(result[direction].speed) ? + result[direction].speed.toString()+' km/h' : + result[direction].speed.toString() || ''; + } else { + outputRow[direction] = ''; + } + break; + default: + outputRow[direction] = result[direction].mode || ''; + } + + if (this.FuzzyMatch.match(outputRow[direction], want)) { + outputRow[direction] = usingShortcut ? usingShortcut : row[direction]; + } }); + + cb(null, outputRow); + }); }; + this.processRowsAndDiff(table, testRow, callback); + }); + }); + }); + + // makes simple a-b request using the given cucumber test routability conditions + // result is an object containing the calculated values for 'rate', 'status', + // 'time', 'distance', 'speed' and 'mode', for forwards and backwards routing, as well as + // a bothw object that diffs forwards/backwards + var testRoutabilityRow = (i, cb) => { + var result = {}; + + var testDirection = (dir, callback) => { + 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; + + this.requestRoute((dir === 'forw' ? [a, b] : [b, a]), [], [], this.queryParams, (err, res, body) => { + if (err) return callback(err); + + r.query = this.query; + r.json = JSON.parse(body); + r.code = r.json.code; + r.status = res.statusCode === 200 ? 'x' : null; + if (r.status) { + r.route = this.wayList(r.json.routes[0]); + r.summary = r.json.routes[0].legs.map(l => l.summary).join(','); + + if (r.route.split(',')[0] === util.format('w%d', i)) { + r.time = r.json.routes[0].duration; + r.distance = r.json.routes[0].distance; + r.rate = Math.round(r.distance / r.json.routes[0].weight * 10) / 10.; + r.speed = r.time > 0 ? parseInt(3.6 * r.distance / r.time) : null; + + // use the mode of the first step of the route + // for routability table test, we can assume the mode is the same throughout the route, + // since the route is just a single way + if( r.json.routes[0].legs[0] && r.json.routes[0].legs[0].steps[0] ) { + r.mode = r.json.routes[0].legs[0].steps[0].mode; + } + } else { + r.status = null; + } + } - d3.queue(1) - .defer(testDirection, 'forw') - .defer(testDirection, 'backw') - .awaitAll((err, res) => { - if (err) return cb(err); - // check if forw and backw returned the same values - res.forEach((dirRes) => { - var which = dirRes.which; - delete dirRes.which; - result[which] = dirRes; - }); - - result.bothw = {}; - - var sq = d3.queue(); - - var parseRes = (key, scb) => { - if (result.forw[key] === result.backw[key]) { - result.bothw[key] = result.forw[key]; - } else { - result.bothw[key] = 'diff'; - } - scb(); - }; - - ['rate', 'status', 'time', 'distance', 'speed' ,'mode'].forEach((key) => { - sq.defer(parseRes, key); - }); - - sq.awaitAll((err) => { cb(err, result); }); - }); + callback(null, r); + }); }; + + d3.queue(1) + .defer(testDirection, 'forw') + .defer(testDirection, 'backw') + .awaitAll((err, res) => { + if (err) return cb(err); + // check if forw and backw returned the same values + res.forEach((dirRes) => { + var which = dirRes.which; + delete dirRes.which; + result[which] = dirRes; + }); + + result.bothw = {}; + + var sq = d3.queue(); + + var parseRes = (key, scb) => { + if (result.forw[key] === result.backw[key]) { + result.bothw[key] = result.forw[key]; + } else { + result.bothw[key] = 'diff'; + } + scb(); + }; + + ['rate', 'status', 'time', 'distance', 'speed' ,'mode'].forEach((key) => { + sq.defer(parseRes, key); + }); + + sq.awaitAll((err) => { cb(err, result); }); + }); + }; }; diff --git a/features/step_definitions/routing.js b/features/step_definitions/routing.js index c3e679aa5b3..b95675dd88a 100644 --- a/features/step_definitions/routing.js +++ b/features/step_definitions/routing.js @@ -1,15 +1,20 @@ var d3 = require('d3-queue'); module.exports = function () { - this.When(/^I route I should get$/, this.WhenIRouteIShouldGet); + this.When(/^I route I should get$/, this.WhenIRouteIShouldGet); - this.When(/^I route (\d+) times I should get$/, { timeout: 100 * this.TIMEOUT }, (n, table, callback) => { - var q = d3.queue(1); + this.When(/^I route (\d+) times I should get$/, { timeout: 100 * this.TIMEOUT }, (n, table, callback) => { + var q = d3.queue(1); - for (var i=0; i { + this.queryParams['skip_waypoints'] = true; + callback(); + }); }; diff --git a/features/step_definitions/timestamp.js b/features/step_definitions/timestamp.js index 55af74b5ee0..094f01f54b5 100644 --- a/features/step_definitions/timestamp.js +++ b/features/step_definitions/timestamp.js @@ -1,13 +1,13 @@ var assert = require('assert'); module.exports = function () { - this.Then(/^I should get a valid timestamp/, (callback) => { - this.ShouldGetAResponse(); - this.ShouldBeValidJSON((err) => { - this.ShouldBeWellFormed(); - assert.equal(typeof this.json.timestamp, 'string'); - assert.equal(this.json.timestamp, '2000-01-01T00:00:00Z'); - callback(err); - }); + this.Then(/^I should get a valid timestamp/, (callback) => { + this.ShouldGetAResponse(); + this.ShouldBeValidJSON((err) => { + this.ShouldBeWellFormed(); + assert.equal(typeof this.json.timestamp, 'string'); + assert.equal(this.json.timestamp, '2000-01-01T00:00:00Z'); + callback(err); }); + }); }; diff --git a/features/step_definitions/trip.js b/features/step_definitions/trip.js index e7204401890..3bc4365277e 100644 --- a/features/step_definitions/trip.js +++ b/features/step_definitions/trip.js @@ -1,175 +1,178 @@ var util = require('util'); -var polyline = require('polyline'); +var polyline = require('@mapbox/polyline'); module.exports = function () { - function add(a, b) { - return a + b; - } - - this.When(/^I plan a trip I should get$/, (table, callback) => { - var got; - - this.reprocessAndLoadData((e) => { - if (e) return callback(e); - var testRow = (row, ri, cb) => { - var afterRequest = (err, res) => { - if (err) return cb(err); - var headers = new Set(table.raw()[0]); - - for (var k in row) { - var match = k.match(/param:(.*)/); - if (match) { - if (row[k] === '(nil)') { - params[match[1]] = null; - } else if (row[k]) { - params[match[1]] = [row[k]]; - } - got[k] = row[k]; - } - } - - var json; - got.code = 'unknown'; - if (res.body.length) { - json = JSON.parse(res.body); - got.code = json.code; - } - - if (headers.has('status')) { - got.status = json.code; - } - - if (headers.has('message')) { - got.message = json.message; - } - - if (headers.has('geometry')) { - if (this.queryParams['geometries'] === 'polyline') { - got.geometry = polyline.decode(json.trips[0].geometry).toString(); - } else if (this.queryParams['geometries'] === 'polyline6') { - got.geometry = polyline.decode(json.trips[0].geometry, 6).toString(); - } else { - got.geometry = json.trips[0].geometry.coordinates; - } - } - - if (headers.has('#')) { - // comment column - got['#'] = row['#']; - } - - var subTrips; - var trip_durations; - var trip_distance; - if (res.statusCode === 200) { - 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 = []; - if (i === 0) toAdd.push(sl.steps[0].intersections[0].location); - toAdd.push(sl.steps[sl.steps.length-1].intersections[0].location); - return toAdd; - }))); - } - if(headers.has('durations')) { - var all_durations = json.trips.filter(t => !!t).map(t => t.legs).map(tl => Array.prototype.concat.apply([], tl.map(sl => { - return sl.duration; - }))); - trip_durations = all_durations.map( a => a.reduce(add, 0)); - } - if(headers.has('distance')) { - var all_distance = json.trips.filter(t => !!t).map(t => t.legs).map(tl => Array.prototype.concat.apply([], tl.map(sl => { - return sl.distance; - }))); - trip_distance = all_distance.map( a => a.reduce(add, 0)); - } - } - - var ok = true, - encodedResult = ''; - - if (json.trips) row.trips.split(',').forEach((sub, si) => { - if (si >= subTrips.length) { - ok = false; - } else { - // TODO: Check all rotations of the round trip - for (var ni=0; ni { + var got; + + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + var testRow = (row, ri, cb) => { + var afterRequest = (err, res, body) => { + if (err) return cb(err); + var headers = new Set(table.raw()[0]); + + for (var k in row) { + var match = k.match(/param:(.*)/); + if (match) { + if (row[k] === '(nil)') { + params[match[1]] = null; + } else if (row[k]) { + params[match[1]] = [row[k]]; + } + got[k] = row[k]; + } + } + + var json; + got.code = 'unknown'; + if (body.length) { + json = JSON.parse(body); + got.code = json.code; + } + + if (headers.has('status')) { + got.status = json.code; + } + + if (headers.has('message')) { + 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(); + } else if (this.queryParams['geometries'] === 'polyline6') { + got.geometry = polyline.decode(json.trips[0].geometry, 6).toString(); + } else { + got.geometry = json.trips[0].geometry.coordinates; + } + } + + if (headers.has('#')) { + // comment column + got['#'] = row['#']; + } + + var subTrips; + var trip_durations; + var trip_distance; + 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 = []; + if (i === 0) toAdd.push(sl.steps[0].intersections[0].location); + toAdd.push(sl.steps[sl.steps.length-1].intersections[0].location); + return toAdd; + }))); + } + if(headers.has('durations')) { + var all_durations = json.trips.filter(t => !!t).map(t => t.legs).map(tl => Array.prototype.concat.apply([], tl.map(sl => { + return sl.duration; + }))); + trip_durations = all_durations.map( a => a.reduce(add, 0)); + } + if(headers.has('distance')) { + var all_distance = json.trips.filter(t => !!t).map(t => t.legs).map(tl => Array.prototype.concat.apply([], tl.map(sl => { + return sl.distance; + }))); + trip_distance = all_distance.map( a => a.reduce(add, 0)); + } + } + + var encodedResult = ''; + + if (json.trips && row.trips) row.trips.split(',').forEach((sub, si) => { + if (si >= subTrips.length) { + ok = false; + } else { + // TODO: Check all rotations of the round trip + for (var ni=0; ni { - var node = this.findNodeByName(n); - if (!node) throw new Error(util.format('*** unknown waypoint node "%s"', n.trim())); - waypoints.push(node); - }); - got = { waypoints: row.waypoints }; - - if (row.source) { - params.source = got.source = row.source; - } - - if (row.destination) { - params.destination = got.destination = row.destination; - } - - if (row.hasOwnProperty('roundtrip')) { //roundtrip is a boolean so row.roundtrip alone doesn't work as a check here - params.roundtrip = got.roundtrip = row.roundtrip; - } - - this.requestTrip(waypoints, params, afterRequest); - } else { - throw new Error('*** no waypoints'); - } + ok = false; + encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]); } - }; - - this.processRowsAndDiff(table, testRow, callback); - }); + } + } + }); + + if (ok) { + got.trips = row.trips; + got.via_points = row.via_points; + } else { + got.trips = encodedResult; + } + + got.durations = trip_durations; + got.distance = trip_distance; + + for (var key in row) { + if (this.FuzzyMatch.match(got[key], row[key])) { + got[key] = row[key]; + } + } + + cb(null, got); + }; + + if (row.request) { + got.request = row.request; + this.requestUrl(row.request, afterRequest); + } else { + var params = this.queryParams, + waypoints = []; + if (row.from && row.to) { + var fromNode = this.findNodeByName(row.from); + if (!fromNode) throw new Error(util.format('*** unknown from-node "%s"', row.from)); + waypoints.push(fromNode); + + var toNode = this.findNodeByName(row.to); + if (!toNode) throw new Error(util.format('*** unknown to-node "%s"', row.to)); + waypoints.push(toNode); + + got = { from: row.from, to: row.to }; + this.requestTrip(waypoints, params, afterRequest); + } else if (row.waypoints) { + row.waypoints.split(',').forEach((n) => { + var node = this.findNodeByName(n); + if (!node) throw new Error(util.format('*** unknown waypoint node "%s"', n.trim())); + waypoints.push(node); + }); + got = { waypoints: row.waypoints }; + + if (row.source) { + params.source = got.source = row.source; + } + + if (row.destination) { + params.destination = got.destination = row.destination; + } + + if (row.hasOwnProperty('roundtrip')) { //roundtrip is a boolean so row.roundtrip alone doesn't work as a check here + params.roundtrip = got.roundtrip = row.roundtrip; + } + + this.requestTrip(waypoints, params, afterRequest); + } else { + throw new Error('*** no waypoints'); + } + } + }; + + this.processRowsAndDiff(table, testRow, callback); }); + }); }; diff --git a/features/stress/large_request.feature b/features/stress/large_request.feature new file mode 100644 index 00000000000..2211d6cce0e --- /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 2d9f99239a2..d5c4468ea1c 100644 --- a/features/support/cache.js +++ b/features/support/cache.js @@ -4,193 +4,192 @@ const d3 = require('d3-queue'); const fs = require('fs'); const util = require('util'); const path = require('path'); -const mkdirp = require('mkdirp'); const hash = require('../lib/hash'); -const rimraf = require('rimraf'); - -module.exports = function() { - this.initializeCache = (callback) => { - this.getOSRMHash((err, osrmHash) => { - if (err) return callback(err); - this.osrmHash = osrmHash; - callback(); - }); - }; - - // computes all paths for every feature - this.setupFeatures = (features, callback) => { - this.featureIDs = {}; - this.featureCacheDirectories = {}; - this.featureProcessedCacheDirectories = {}; - let queue = d3.queue(); - - function initializeFeature(feature, callback) { - let uri = feature.getUri(); - - // setup cache for feature data - // if OSRM_PROFILE is set to force a specific profile, then - // include the profile name in the hash of the profile file - 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; - this.featureCacheDirectories[uri] = featureCacheDirectory; - 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); - }); - } - - for (let i = 0; i < features.length; ++i) { - queue.defer(initializeFeature.bind(this), features[i]); - } - queue.awaitAll(callback); - }; - - this.cleanupProcessedFeatureCache = (directory, osrmHash, callback) => { - let parentPath = path.resolve(path.join(directory, '..')); - fs.readdir(parentPath, (err, files) => { - let q = d3.queue(); - function runStats(path, callback) { - fs.stat(path, (err, stat) => { - if (err) return callback(err); - callback(null, {file: path, stat: stat}); - }); - } - files.map(f => { q.defer(runStats, path.join(parentPath, f)); }); - q.awaitAll((err, results) => { - if (err) return callback(err); - let q = d3.queue(); - results.forEach(r => { - if (r.stat.isDirectory() && r.file.search(osrmHash) < 0) { - q.defer(rimraf, r.file); - } - }); - q.awaitAll(callback); - }); - }); - }; - - this.cleanupFeatureCache = (directory, featureHash, callback) => { - let parentPath = path.resolve(path.join(directory, '..')); - fs.readdir(parentPath, (err, files) => { - let q = d3.queue(); - files.filter(name => { return name !== featureHash;}) - .map((f) => { q.defer(rimraf, path.join(parentPath, f)); }); - q.awaitAll(callback); - }); - }; +const { rm } = require('fs/promises'); +const { createDir } = require('../lib/utils'); + +module.exports = function () { + this.initializeCache = (callback) => { + this.getOSRMHash((err, osrmHash) => { + if (err) return callback(err); + this.osrmHash = osrmHash; + callback(); + }); + }; + + // computes all paths for every feature + this.setupFeatures = (features, callback) => { + this.featureIDs = {}; + this.featureCacheDirectories = {}; + this.featureProcessedCacheDirectories = {}; + let queue = d3.queue(); + + function initializeFeature(feature, callback) { + let uri = feature.getUri(); + + // setup cache for feature data + // if OSRM_PROFILE is set to force a specific profile, then + // include the profile name in the hash of the profile file + 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; + this.featureCacheDirectories[uri] = featureCacheDirectory; + this.featureProcessedCacheDirectories[uri] = featureProcessedCacheDirectory; - this.setupFeatureCache = (feature) => { - let uri = feature.getUri(); - this.featureID = this.featureIDs[uri]; - this.featureCacheDirectory = this.featureCacheDirectories[uri]; - this.featureProcessedCacheDirectory = this.featureProcessedCacheDirectories[uri]; - }; - - this.setupScenarioCache = (scenarioID) => { - this.scenarioCacheFile = this.getScenarioCacheFile(this.featureCacheDirectory, scenarioID); - this.processedCacheFile = this.getProcessedCacheFile(this.featureProcessedCacheDirectory, scenarioID); - this.inputCacheFile = this.getInputCacheFile(this.featureProcessedCacheDirectory, scenarioID); - this.rasterCacheFile = this.getRasterCacheFile(this.featureProcessedCacheDirectory, scenarioID); - this.speedsCacheFile = this.getSpeedsCacheFile(this.featureProcessedCacheDirectory, scenarioID); - this.penaltiesCacheFile = this.getPenaltiesCacheFile(this.featureProcessedCacheDirectory, scenarioID); - this.profileCacheFile = this.getProfileCacheFile(this.featureProcessedCacheDirectory, scenarioID); - }; - - // returns a hash of all OSRM code side dependencies - this.getOSRMHash = (callback) => { - let dependencies = [ - this.OSRM_EXTRACT_PATH, - this.OSRM_CONTRACT_PATH, - this.LIB_OSRM_EXTRACT_PATH, - this.LIB_OSRM_GUIDANCE_PATH, - this.LIB_OSRM_CONTRACT_PATH - ]; - - var addLuaFiles = (directory, callback) => { - fs.readdir(path.normalize(directory), (err, files) => { - if (err) return callback(err); - - var luaFiles = files.filter(f => !!f.match(/\.lua$/)).map(f => path.normalize(directory + '/' + f)); - Array.prototype.push.apply(dependencies, luaFiles); - - callback(); - }); - }; - - // Note: we need a serialized queue here to ensure that the order of the files - // passed is stable. Otherwise the hash will not be stable d3.queue(1) - .defer(addLuaFiles, this.PROFILES_PATH) - .defer(addLuaFiles, this.PROFILES_PATH + '/lib') - .awaitAll(hash.hashOfFiles.bind(hash, dependencies, callback)); - }; - - // test/cache/bicycle/bollards/{HASH}/ - this.getFeatureCacheDirectory = (featureID) => { - return path.join(this.CACHE_PATH, featureID); - }; - - // converts the scenario titles in file prefixes - this.getScenarioID = (scenario) => { - 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); - }; - - // test/cache/{feature_path}/{feature_hash}/{scenario}_raster.asc - this.getRasterCacheFile = (featureCacheDirectory, scenarioID) => { - return path.join(featureCacheDirectory, scenarioID) + '_raster.asc'; - }; - - // test/cache/{feature_path}/{feature_hash}/{scenario}_speeds.csv - this.getSpeedsCacheFile = (featureCacheDirectory, scenarioID) => { - return path.join(featureCacheDirectory, scenarioID) + '_speeds.csv'; - }; - - // test/cache/{feature_path}/{feature_hash}/{scenario}_penalties.csv - this.getPenaltiesCacheFile = (featureCacheDirectory, scenarioID) => { - return path.join(featureCacheDirectory, scenarioID) + '_penalties.csv'; - }; - - // test/cache/{feature_path}/{feature_hash}/{scenario}_profile.lua - this.getProfileCacheFile = (featureCacheDirectory, scenarioID) => { - return path.join(featureCacheDirectory, scenarioID) + '_profile.lua'; - }; - - // test/cache/{feature_path}/{feature_hash}/{scenario}.osm - this.getScenarioCacheFile = (featureCacheDirectory, scenarioID) => { - return path.join(featureCacheDirectory, scenarioID) + '.osm'; - }; - - // test/cache/{feature_path}/{feature_hash}/{osrm_hash}/ - this.getFeatureProcessedCacheDirectory = (featureCacheDirectory, osrmHash) => { - return path.join(featureCacheDirectory, osrmHash); - }; - - // test/cache/{feature_path}/{feature_hash}/{osrm_hash}/{scenario}.osrm - this.getProcessedCacheFile = (featureProcessedCacheDirectory, scenarioID) => { - return path.join(featureProcessedCacheDirectory, scenarioID) + '.osrm'; - }; - - // test/cache/{feature_path}/{feature_hash}/{osrm_hash}/{scenario}.osm - this.getInputCacheFile = (featureProcessedCacheDirectory, scenarioID) => { - return path.join(featureProcessedCacheDirectory, scenarioID) + '.osm'; - }; - - - return this; + .defer(createDir, featureProcessedCacheDirectory) + .defer(this.cleanupFeatureCache.bind(this), featureCacheDirectory, hash) + .defer(this.cleanupProcessedFeatureCache.bind(this), featureProcessedCacheDirectory, this.osrmHash) + .awaitAll(callback); + }); + } + + for (let i = 0; i < features.length; ++i) { + queue.defer(initializeFeature.bind(this), features[i]); + } + queue.awaitAll(callback); + }; + + this.cleanupProcessedFeatureCache = (directory, osrmHash, callback) => { + let parentPath = path.resolve(path.join(directory, '..')); + fs.readdir(parentPath, (err, files) => { + if (err) return callback(err); + let q = d3.queue(); + files.forEach((f) => { + let filePath = path.join(parentPath, f); + fs.stat(filePath, (err, stat) => { + if (err) return callback(err); + if (stat.isDirectory() && filePath.search(osrmHash) < 0) { + rm(filePath, { recursive: true, force: true }); + } + }); + }); + q.awaitAll(callback); + }); + }; + + this.cleanupFeatureCache = (directory, featureHash, callback) => { + let parentPath = path.resolve(path.join(directory, '..')); + fs.readdir(parentPath, (err, files) => { + if (err) return callback(err); + let q = d3.queue(); + files.filter((name) => name !== featureHash).forEach((f) => { + rm(path.join(parentPath, f), { recursive: true, force: true }); + }); + q.awaitAll(callback); + }); + }; + + this.setupFeatureCache = (feature) => { + let uri = feature.getUri(); + this.featureID = this.featureIDs[uri]; + this.featureCacheDirectory = this.featureCacheDirectories[uri]; + this.featureProcessedCacheDirectory = this.featureProcessedCacheDirectories[uri]; + }; + + this.setupScenarioCache = (scenarioID) => { + this.scenarioCacheFile = this.getScenarioCacheFile(this.featureCacheDirectory, scenarioID); + this.processedCacheFile = this.getProcessedCacheFile(this.featureProcessedCacheDirectory, scenarioID); + this.inputCacheFile = this.getInputCacheFile(this.featureProcessedCacheDirectory, scenarioID); + this.rasterCacheFile = this.getRasterCacheFile(this.featureProcessedCacheDirectory, scenarioID); + this.speedsCacheFile = this.getSpeedsCacheFile(this.featureProcessedCacheDirectory, scenarioID); + this.penaltiesCacheFile = this.getPenaltiesCacheFile(this.featureProcessedCacheDirectory, scenarioID); + this.profileCacheFile = this.getProfileCacheFile(this.featureProcessedCacheDirectory, scenarioID); + }; + + // returns a hash of all OSRM code side dependencies + this.getOSRMHash = (callback) => { + 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_CUSTOMIZE_PATH, + this.LIB_OSRM_PARTITION_PATH + ]; + + var addLuaFiles = (directory, callback) => { + fs.readdir(path.normalize(directory), (err, files) => { + if (err) return callback(err); + + var luaFiles = files.filter(f => !!f.match(/\.lua$/)).map(f => path.normalize(directory + '/' + f)); + Array.prototype.push.apply(dependencies, luaFiles); + + callback(); + }); + }; + + // Note: we need a serialized queue here to ensure that the order of the files + // passed is stable. Otherwise the hash will not be stable + d3.queue(1) + .defer(addLuaFiles, this.PROFILES_PATH) + .defer(addLuaFiles, this.PROFILES_PATH + '/lib') + .awaitAll(hash.hashOfFiles.bind(hash, dependencies, callback)); + }; + + // test/cache/bicycle/bollards/{HASH}/ + this.getFeatureCacheDirectory = (featureID) => { + return path.join(this.CACHE_PATH, featureID); + }; + + // converts the scenario titles in file prefixes + this.getScenarioID = (scenario) => { + 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); + }; + + // test/cache/{feature_path}/{feature_hash}/{scenario}_raster.asc + this.getRasterCacheFile = (featureCacheDirectory, scenarioID) => { + return path.join(featureCacheDirectory, scenarioID) + '_raster.asc'; + }; + + // test/cache/{feature_path}/{feature_hash}/{scenario}_speeds.csv + this.getSpeedsCacheFile = (featureCacheDirectory, scenarioID) => { + return path.join(featureCacheDirectory, scenarioID) + '_speeds.csv'; + }; + + // test/cache/{feature_path}/{feature_hash}/{scenario}_penalties.csv + this.getPenaltiesCacheFile = (featureCacheDirectory, scenarioID) => { + return path.join(featureCacheDirectory, scenarioID) + '_penalties.csv'; + }; + + // test/cache/{feature_path}/{feature_hash}/{scenario}_profile.lua + this.getProfileCacheFile = (featureCacheDirectory, scenarioID) => { + return path.join(featureCacheDirectory, scenarioID) + '_profile.lua'; + }; + + // test/cache/{feature_path}/{feature_hash}/{scenario}.osm + this.getScenarioCacheFile = (featureCacheDirectory, scenarioID) => { + return path.join(featureCacheDirectory, scenarioID) + '.osm'; + }; + + // test/cache/{feature_path}/{feature_hash}/{osrm_hash}/ + this.getFeatureProcessedCacheDirectory = (featureCacheDirectory, osrmHash) => { + return path.join(featureCacheDirectory, osrmHash); + }; + + // test/cache/{feature_path}/{feature_hash}/{osrm_hash}/{scenario}.osrm + this.getProcessedCacheFile = (featureProcessedCacheDirectory, scenarioID) => { + return path.join(featureProcessedCacheDirectory, scenarioID) + '.osrm'; + }; + + // test/cache/{feature_path}/{feature_hash}/{osrm_hash}/{scenario}.osm + this.getInputCacheFile = (featureProcessedCacheDirectory, scenarioID) => { + return path.join(featureProcessedCacheDirectory, scenarioID) + '.osm'; + }; + + + return this; }; diff --git a/features/support/data.js b/features/support/data.js index e9e1f06f46f..e124407150e 100644 --- a/features/support/data.js +++ b/features/support/data.js @@ -9,283 +9,295 @@ 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) => { - // 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.setOrigin = (origin) => { - this.origin = origin; - }; - - this.buildWaysFromTable = (table, callback) => { - // add one unconnected way for each row - var buildRow = (row, ri, cb) => { - // comments ported directly from ruby suite: - // NOTE: currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 edges - // this is related to the fact that a oneway dead-end street doesn't make a lot of sense - - // if we stack ways on different x coordinates, routability tests get messed up, because osrm might pick a neighboring way if the one test can't be used. - // instead we place all lines as a string on the same y coordinate. this prevents using neighboring ways. - - // add some nodes - - var makeFakeNode = (namePrefix, offset) => { - 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)}); - }; - - var nodes = ['a','b','c','d','e'].map((l, i) => makeFakeNode(l, i)); - - nodes.forEach(node => { this.OSMDB.addNode(node); }); - - // ...with a way between them - var way = new OSM.Way(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID); - - nodes.forEach(node => { way.addNode(node); }); - - // remove tags that describe expected test result, reject empty tags - var tags = {}; - for (var rkey in row) { - if (!rkey.match(/^forw\b/) && + 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 = 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) => { + // add one unconnected way for each row + var buildRow = (row, ri, cb) => { + // comments ported directly from ruby suite: + // NOTE: currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 edges + // this is related to the fact that a oneway dead-end street doesn't make a lot of sense + + // if we stack ways on different x coordinates, routability tests get messed up, because osrm might pick a neighboring way if the one test can't be used. + // instead we place all lines as a string on the same y coordinate. this prevents using neighboring ways. + + // 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, coord[0], + coord[1], {name: util.format('%s%d', namePrefix, ri)}); + }; + + var nodes = ['a','b','c','d','e'].map((l, i) => makeFakeNode(l, i)); + + nodes.forEach(node => { this.OSMDB.addNode(node); }); + + // ...with a way between them + var way = new OSM.Way(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID); + + nodes.forEach(node => { way.addNode(node); }); + + // remove tags that describe expected test result, reject empty tags + var tags = {}; + for (var rkey in row) { + if (!rkey.match(/^forw\b/) && !rkey.match(/^backw\b/) && !rkey.match(/^bothw\b/) && row[rkey].length) - tags[rkey] = row[rkey]; - } - - var wayTags = { highway: 'primary' }, - nodeTags = {}; - - for (var key in tags) { - var nodeMatch = key.match(/node\/(.*)/); - if (nodeMatch) { - if (tags[key] === '(nil)') { - delete nodeTags[key]; - } else { - nodeTags[nodeMatch[1]] = tags[key]; - } - } else { - if (tags[key] === '(nil)') { - delete wayTags[key]; - } else { - wayTags[key] = tags[key]; - } - } - } - - wayTags.name = util.format('w%d', ri); - way.setTags(wayTags); - this.OSMDB.addWay(way); - - for (var k in nodeTags) { - nodes[2].addTag(k, nodeTags[k]); - } - cb(); - }; - - var q = d3.queue(); - table.hashes().forEach((row, ri) => { - q.defer(buildRow, row, ri); - }); - - q.awaitAll(callback); - }; - - this.tableCoordToLonLat = (ci, ri) => { - return [this.origin[0] + ci * this.zoom, this.origin[1] - ri * this.zoom].map(ensureDecimal); - }; - - this.addOSMNode = (name, lon, lat, id) => { - id = id || this.makeOSMId(); - var node = new OSM.Node(id, this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID, lon, lat, {name: name}); - this.OSMDB.addNode(node); - this.nameNodeHash[name] = node; - }; - - this.addLocation = (name, lon, lat) => { - this.locationHash[name] = new classes.Location(lon, lat); - }; - - this.findNodeByName = (s) => { - if (s.length !== 1) throw new Error(util.format('*** invalid node name "%s", must be single characters', s)); - if (!s.match(/[a-z0-9]/)) throw new Error(util.format('*** invalid node name "%s", must be alphanumeric', s)); - - var fromNode; - if (s.match(/[a-z]/)) { - fromNode = this.nameNodeHash[s.toString()]; + tags[rkey] = row[rkey]; + } + + var wayTags = { highway: 'primary' }, + nodeTags = {}; + + for (var key in tags) { + var nodeMatch = key.match(/node\/(.*)/); + if (nodeMatch) { + if (tags[key] === '(nil)') { + delete nodeTags[key]; + } else { + nodeTags[nodeMatch[1]] = tags[key]; + } } else { - fromNode = this.locationHash[s.toString()]; - } - - return fromNode; - }; - - // find a node based on an array containing lon/lat - this.findNodeByLocation = (node_location) => { - var searched_coordinate = new classes.Location(node_location[0],node_location[1]); - for (var node in this.nameNodeHash) - { - var node_coordinate = new classes.Location(this.nameNodeHash[node].lon,this.nameNodeHash[node].lat); - if (this.FuzzyMatch.matchCoordinate(searched_coordinate, node_coordinate, this.zoom)) - { - return node; - } + if (tags[key] === '(nil)') { + delete wayTags[key]; + } else { + wayTags[key] = tags[key]; + } } - return '_'; - }; - - this.findWayByName = (s) => { - 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; - }; - - this.resetOSM = () => { - this.OSMDB.clear(); - this.nameNodeHash = {}; - this.locationHash = {}; - this.shortcutsHash = {}; - this.nameWayHash = {}; - this.nameRelationHash = {}; - this.osmID = 0; - }; + } - this.writeOSM = (callback) => { - fs.exists(this.scenarioCacheFile, (exists) => { - if (exists) callback(); - else { - this.OSMDB.toXML((xml) => { - fs.writeFile(this.scenarioCacheFile, xml, callback); - }); - } - }); - }; + wayTags.name = util.format('w%d', ri); + way.setTags(wayTags); + this.OSMDB.addWay(way); - this.linkOSM = (callback) => { - fs.exists(this.inputCacheFile, (exists) => { - if (exists) callback(); - else { - fs.link(this.scenarioCacheFile, this.inputCacheFile, callback); - } - }); - }; - - this.extractData = (p, callback) => { - let stamp = p.processedCacheFile + '.stamp_extract'; - fs.exists(stamp, (exists) => { - if (exists) return callback(); - - this.runBin('osrm-extract', util.format('%s --profile %s %s', p.extractArgs, p.profileFile, p.inputCacheFile), p.environment, (err) => { - if (err) { - return callback(new Error(util.format('osrm-extract %s: %s', errorReason(err), err.cmd))); - } - fs.writeFile(stamp, 'ok', callback); - }); - }); + for (var k in nodeTags) { + nodes[2].addTag(k, nodeTags[k]); + } + cb(); }; - this.contractData = (p, callback) => { - let stamp = p.processedCacheFile + '.stamp_contract'; - fs.exists(stamp, (exists) => { - if (exists) return callback(); - - this.runBin('osrm-contract', util.format('%s %s', p.contractArgs, p.processedCacheFile), p.environment, (err) => { - if (err) { - return callback(new Error(util.format('osrm-contract %s: %s', errorReason(err), err))); - } - fs.writeFile(stamp, 'ok', callback); - }); + var q = d3.queue(); + table.hashes().forEach((row, ri) => { + q.defer(buildRow, row, ri); + }); + + q.awaitAll(callback); + }; + + this.tableCoordToLonLat = (ci, ri) => { + return this.offsetOriginBy(ci, -ri).map(ensureDecimal); + }; + + this.addOSMNode = (name, lon, lat, id) => { + id = id || this.makeOSMId(); + var node = new OSM.Node(id, this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID, lon, lat, {name: name}); + this.OSMDB.addNode(node); + this.nameNodeHash[name] = node; + }; + + this.addLocation = (name, lon, lat) => { + this.locationHash[name] = new classes.Location(lon, lat); + }; + + this.findNodeByName = (s) => { + if (s.length !== 1) throw new Error(util.format('*** invalid node name "%s", must be single characters', s)); + if (!s.match(/[a-z0-9]/)) throw new Error(util.format('*** invalid node name "%s", must be alphanumeric', s)); + + var fromNode; + if (s.match(/[a-z]/)) { + fromNode = this.nameNodeHash[s.toString()]; + } else { + fromNode = this.locationHash[s.toString()]; + } + + return fromNode; + }; + + // find a node based on an array containing lon/lat + this.findNodeByLocation = (node_location) => { + var searched_coordinate = new classes.Location(node_location[0],node_location[1]); + for (var node in this.nameNodeHash) + { + var node_coordinate = new classes.Location(this.nameNodeHash[node].lon,this.nameNodeHash[node].lat); + if (this.FuzzyMatch.matchCoordinate(searched_coordinate, node_coordinate, this.zoom)) + { + return node; + } + } + return '_'; + }; + + this.findWayByName = (s) => { + 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; + }; + + this.resetOSM = () => { + this.OSMDB.clear(); + this.nameNodeHash = {}; + this.locationHash = {}; + this.shortcutsHash = {}; + this.nameWayHash = {}; + this.nameRelationHash = {}; + this.osmID = 0; + }; + + this.writeOSM = (callback) => { + fs.exists(this.scenarioCacheFile, (exists) => { + if (exists) callback(); + else { + this.OSMDB.toXML((xml) => { + fs.writeFile(this.scenarioCacheFile, xml, callback); }); - }; - - this.partitionData = (p, callback) => { - let stamp = p.processedCacheFile + '.stamp_partition'; - fs.exists(stamp, (exists) => { - if (exists) return callback(); - - this.runBin('osrm-partition', util.format('%s %s', p.partitionArgs, p.processedCacheFile), p.environment, (err) => { - if (err) { - return callback(new Error(util.format('osrm-partition %s: %s', errorReason(err), err.cmd))); - } - fs.writeFile(stamp, 'ok', callback); - }); - }); - }; - - this.customizeData = (p, callback) => { - let stamp = p.processedCacheFile + '.stamp_customize'; - fs.exists(stamp, (exists) => { - if (exists) return callback(); - - this.runBin('osrm-customize', util.format('%s %s', p.customizeArgs, p.processedCacheFile), p.environment, (err) => { - if (err) { - return callback(new Error(util.format('osrm-customize %s: %s', errorReason(err), err))); - } - fs.writeFile(stamp, 'ok', callback); - }); - }); - }; - - this.extractContractPartitionAndCustomize = (callback) => { - // a shallow copy of scenario parameters to avoid data inconsistency - // if a cucumber timeout occurs during deferred jobs - let p = {extractArgs: this.extractArgs, contractArgs: this.contractArgs, - partitionArgs: this.partitionArgs, customizeArgs: this.customizeArgs, - profileFile: this.profileFile, inputCacheFile: this.inputCacheFile, - processedCacheFile: this.processedCacheFile, environment: this.environment}; - let queue = d3.queue(1); - queue.defer(this.extractData.bind(this), p); - queue.defer(this.partitionData.bind(this), p); - queue.defer(this.contractData.bind(this), p); - queue.defer(this.customizeData.bind(this), p); - queue.awaitAll(callback); - }; - - this.writeAndLinkOSM = (callback) => { - let queue = d3.queue(1); - queue.defer(this.writeOSM.bind(this)); - queue.defer(this.linkOSM.bind(this)); - queue.awaitAll(callback); - }; - - this.reprocess = (callback) => { - let queue = d3.queue(1); - queue.defer(this.writeAndLinkOSM.bind(this)); - queue.defer(this.extractContractPartitionAndCustomize.bind(this)); - queue.awaitAll(callback); - }; - - this.reprocessAndLoadData = (callback) => { - let queue = d3.queue(1); - queue.defer(this.writeAndLinkOSM.bind(this)); - queue.defer(this.extractContractPartitionAndCustomize.bind(this)); - queue.defer(this.osrmLoader.load.bind(this.osrmLoader), this.processedCacheFile); - queue.awaitAll(callback); - }; - - this.processRowsAndDiff = (table, fn, callback) => { - var q = d3.queue(1); - - table.hashes().forEach((row, i) => { q.defer(fn, row, i); }); - - q.awaitAll((err, actual) => { - if (err) return callback(err); - let diff = tableDiff(table, actual); - if (diff) callback(diff); - else callback(); - }); - }; + } + }); + }; + + this.linkOSM = (callback) => { + fs.exists(this.inputCacheFile, (exists) => { + if (exists) callback(); + else { + fs.link(this.scenarioCacheFile, this.inputCacheFile, callback); + } + }); + }; + + this.extractData = (p, callback) => { + let stamp = p.processedCacheFile + '.stamp_extract'; + fs.exists(stamp, (exists) => { + if (exists) return callback(); + + this.runBin('osrm-extract', util.format('%s --profile %s %s', p.extractArgs, p.profileFile, p.inputCacheFile), p.environment, (err) => { + if (err) { + return callback(new Error(util.format('osrm-extract %s: %s', errorReason(err), err.cmd))); + } + fs.writeFile(stamp, 'ok', callback); + }); + }); + }; + + this.contractData = (p, callback) => { + let stamp = p.processedCacheFile + '.stamp_contract'; + fs.exists(stamp, (exists) => { + if (exists) return callback(); + + this.runBin('osrm-contract', util.format('%s %s', p.contractArgs, p.processedCacheFile), p.environment, (err) => { + if (err) { + return callback(new Error(util.format('osrm-contract %s: %s', errorReason(err), err))); + } + fs.writeFile(stamp, 'ok', callback); + }); + }); + }; + + this.partitionData = (p, callback) => { + let stamp = p.processedCacheFile + '.stamp_partition'; + fs.exists(stamp, (exists) => { + if (exists) return callback(); + + this.runBin('osrm-partition', util.format('%s %s', p.partitionArgs, p.processedCacheFile), p.environment, (err) => { + if (err) { + return callback(new Error(util.format('osrm-partition %s: %s', errorReason(err), err.cmd))); + } + fs.writeFile(stamp, 'ok', callback); + }); + }); + }; + + this.customizeData = (p, callback) => { + let stamp = p.processedCacheFile + '.stamp_customize'; + fs.exists(stamp, (exists) => { + if (exists) return callback(); + + this.runBin('osrm-customize', util.format('%s %s', p.customizeArgs, p.processedCacheFile), p.environment, (err) => { + if (err) { + return callback(new Error(util.format('osrm-customize %s: %s', errorReason(err), err))); + } + fs.writeFile(stamp, 'ok', callback); + }); + }); + }; + + this.extractContractPartitionAndCustomize = (callback) => { + // a shallow copy of scenario parameters to avoid data inconsistency + // if a cucumber timeout occurs during deferred jobs + let p = {extractArgs: this.extractArgs, contractArgs: this.contractArgs, + partitionArgs: this.partitionArgs, customizeArgs: this.customizeArgs, + profileFile: this.profileFile, inputCacheFile: this.inputCacheFile, + processedCacheFile: this.processedCacheFile, environment: this.environment}; + let queue = d3.queue(1); + queue.defer(this.extractData.bind(this), p); + queue.defer(this.partitionData.bind(this), p); + queue.defer(this.contractData.bind(this), p); + queue.defer(this.customizeData.bind(this), p); + queue.awaitAll(callback); + }; + + this.writeAndLinkOSM = (callback) => { + let queue = d3.queue(1); + queue.defer(this.writeOSM.bind(this)); + queue.defer(this.linkOSM.bind(this)); + queue.awaitAll(callback); + }; + + this.reprocess = (callback) => { + let queue = d3.queue(1); + queue.defer(this.writeAndLinkOSM.bind(this)); + queue.defer(this.extractContractPartitionAndCustomize.bind(this)); + queue.awaitAll(callback); + }; + + this.reprocessAndLoadData = (callback) => { + let p = {loaderArgs: this.loaderArgs, inputFile: this.processedCacheFile}; + let queue = d3.queue(1); + queue.defer(this.writeAndLinkOSM.bind(this)); + queue.defer(this.extractContractPartitionAndCustomize.bind(this)); + queue.defer(this.osrmLoader.load.bind(this.osrmLoader), p); + queue.awaitAll(callback); + }; + + this.processRowsAndDiff = (table, fn, callback) => { + var q = d3.queue(1); + + table.hashes().forEach((row, i) => { q.defer(fn, row, i); }); + + q.awaitAll((err, actual) => { + if (err) return callback(err); + let diff = tableDiff(table, actual); + if (diff) callback(diff); + else callback(); + }); + }; }; diff --git a/features/support/data_classes.js b/features/support/data_classes.js index 53003bb9f3c..24e7d0f0017 100644 --- a/features/support/data_classes.js +++ b/features/support/data_classes.js @@ -3,130 +3,130 @@ const util = require('util'); module.exports = { - Location: class { - constructor (lon, lat) { - this.lon = lon; - this.lat = lat; - } - }, + Location: class { + constructor (lon, lat) { + this.lon = lon; + this.lat = lat; + } + }, - 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; + 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+\+-(.+)$/), - 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+\+-(.+)$/), - matchRangeNumbers = want.match(/\d+\+-\d+/); + var matchPercent = 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+\+-(.+)$/), + matchRangeNumbers = want.match(/\d+\+-\d+/); - function inRange(margin, got, want) { - var fromR = parseFloat(want) - margin, - toR = parseFloat(want) + margin; - return parseFloat(got) >= fromR && parseFloat(got) <= toR; - } - function parseIntersectionString(str) { - return str.split(';') - .map((turn_intersections) => turn_intersections - .split(',') - .map((intersection) => intersection - .split(' ') - .map((entry_bearing_pair) => entry_bearing_pair - .split(':')))); - } + function inRange(margin, got, want) { + var fromR = parseFloat(want) - margin, + toR = parseFloat(want) + margin; + return parseFloat(got) >= fromR && parseFloat(got) <= toR; + } + function parseIntersectionString(str) { + return str.split(';') + .map((turn_intersections) => turn_intersections + .split(',') + .map((intersection) => intersection + .split(' ') + .map((entry_bearing_pair) => entry_bearing_pair + .split(':')))); + } - if (got === want) { - return true; - } else if (matchBearingListAbs) { - let want_and_margin = want.split('+-'), - margin = parseFloat(want_and_margin[1].trim()), - want_pairs = want_and_margin[0].trim().split(',').map((pair) => pair.split('->')), - got_pairs = got.split(',').map((pair) => pair.split('->')); - if (want_pairs.length != got_pairs.length) - { - return false; - } - for (var i = 0; i < want_pairs.length; ++i) - { - if (!inRange(margin, got_pairs[i][0], want_pairs[i][0]) || + if (got === want) { + return true; + } else if (matchBearingListAbs) { + let want_and_margin = want.split('+-'), + margin = parseFloat(want_and_margin[1].trim()), + want_pairs = want_and_margin[0].trim().split(',').map((pair) => pair.split('->')), + got_pairs = got.split(',').map((pair) => pair.split('->')); + if (want_pairs.length != got_pairs.length) + { + return false; + } + for (var i = 0; i < want_pairs.length; ++i) + { + if (!inRange(margin, got_pairs[i][0], want_pairs[i][0]) || !inRange(margin, got_pairs[i][1], want_pairs[i][1])) - { - return false; - } - } - return true; - } else if (matchIntersectionListAbs) { - let margin = parseFloat(want.split('+-')[1]), - want_intersections = parseIntersectionString(want.split('+-')[0].trim()), - got_intersections = parseIntersectionString(got); - if (want_intersections.length != got_intersections.length) - { - return false; - } - for (let step_idx = 0; step_idx < want_intersections.length; ++step_idx) - { - if (want_intersections[step_idx].length != got_intersections[step_idx].length) - { - return false; - } - for (let intersection_idx = 0; intersection_idx < want_intersections[step_idx].length; ++intersection_idx) - { - if (want_intersections[step_idx][intersection_idx].length != got_intersections[step_idx][intersection_idx].length) - { - return false; - } - for (let pair_idx = 0; pair_idx < want_intersections[step_idx][intersection_idx].length; ++pair_idx) - { - let want_pair = want_intersections[step_idx][intersection_idx][pair_idx], - got_pair = got_intersections[step_idx][intersection_idx][pair_idx]; - if (got_pair[0] != want_pair[0] || + { + return false; + } + } + return true; + } else if (matchIntersectionListAbs) { + let margin = parseFloat(want.split('+-')[1]), + want_intersections = parseIntersectionString(want.split('+-')[0].trim()), + got_intersections = parseIntersectionString(got); + if (want_intersections.length != got_intersections.length) + { + return false; + } + for (let step_idx = 0; step_idx < want_intersections.length; ++step_idx) + { + if (want_intersections[step_idx].length != got_intersections[step_idx].length) + { + return false; + } + for (let intersection_idx = 0; intersection_idx < want_intersections[step_idx].length; ++intersection_idx) + { + if (want_intersections[step_idx][intersection_idx].length != got_intersections[step_idx][intersection_idx].length) + { + return false; + } + for (let pair_idx = 0; pair_idx < want_intersections[step_idx][intersection_idx].length; ++pair_idx) + { + let want_pair = want_intersections[step_idx][intersection_idx][pair_idx], + got_pair = got_intersections[step_idx][intersection_idx][pair_idx]; + if (got_pair[0] != want_pair[0] || !inRange(margin, got_pair[1], want_pair[1])) - { - return false; - } - } - } - } - return true; - } else if (matchPercent) { // percentage range: 100 ~ 5% - var target = parseFloat(matchPercent[1]), - percentage = parseFloat(matchPercent[2]); - if (target === 0) { - return true; - } else { - let ratio = Math.abs(1 - parseFloat(got) / target); - return 100 * ratio < percentage; - } - } else if (matchAbs) { // absolute range: 100 +-5 - let margin = parseFloat(matchAbs[2]); - 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; + } } + } } + return true; + } else if (matchPercent) { // percentage range: 100 ~ 5% + var target = parseFloat(matchPercent[1]), + percentage = parseFloat(matchPercent[2]); + if (target === 0) { + return true; + } else { + let ratio = Math.abs(1 - parseFloat(got) / target); + return 100 * ratio < percentage; + } + } else if (matchAbs) { // absolute range: 100 +-5 + let margin = parseFloat(matchAbs[2]); + 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; + } + } - matchLocation (got, want) { - if (got == null || want == null) return false; - return this.match(got[0], util.format('%d ~0.0025%', want.lon)) && + matchLocation (got, want) { + if (got == null || want == null) return false; + return this.match(got[0], util.format('%d ~0.0025%', want.lon)) && this.match(got[1], util.format('%d ~0.0025%', want.lat)); - } + } - matchCoordinate (got, want, zoom) { - if (got == null || want == null) return false; - return this.match(got.lon, util.format('%d +- %d', want.lon, 0.25*zoom)) && + matchCoordinate (got, want, zoom) { + if (got == null || want == null) return false; + return this.match(got.lon, util.format('%d +- %d', want.lon, 0.25*zoom)) && this.match(got.lat, util.format('%d +- %d', want.lat, 0.25*zoom)); - } - } + + } }; diff --git a/features/support/env.js b/features/support/env.js index a76938c16f1..64967ca9718 100644 --- a/features/support/env.js +++ b/features/support/env.js @@ -9,123 +9,125 @@ const tryConnect = require('../lib/try_connect'); // Sets up all constants that are valid for all features module.exports = function () { - this.initializeEnv = (callback) => { - this.TIMEOUT = process.env.CUCUMBER_TIMEOUT && parseInt(process.env.CUCUMBER_TIMEOUT) || 5000; - // set cucumber default timeout - this.setDefaultTimeout(this.TIMEOUT); - this.ROOT_PATH = process.cwd(); - - this.TEST_PATH = path.resolve(this.ROOT_PATH, 'test'); - this.CACHE_PATH = path.resolve(this.TEST_PATH, 'cache'); - this.LOGS_PATH = path.resolve(this.TEST_PATH, 'logs'); - - 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_PROFILE = 'bicycle'; - this.DEFAULT_INPUT_FORMAT = 'osm'; - 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; - this.OSM_TIMESTAMP = '2000-01-01T00:00:00Z'; - this.WAY_SPACING = 100; - this.DEFAULT_GRID_SIZE = 100; // meters - // get algorithm name from the command line profile argument - this.ROUTING_ALGORITHM = process.argv[process.argv.indexOf('-p') + 1].match('mld') ? 'MLD' : 'CH'; - this.TIMEZONE_NAMES = this.PLATFORM_WINDOWS ? 'win' : 'iana'; - - this.OSRM_PORT = process.env.OSRM_PORT && parseInt(process.env.OSRM_PORT) || 5000; - this.OSRM_IP = process.env.OSRM_IP || '127.0.0.1'; - this.HOST = `http://${this.OSRM_IP}:${this.OSRM_PORT}`; - - this.OSRM_PROFILE = process.env.OSRM_PROFILE; - - if (this.PLATFORM_WINDOWS) { - this.TERMSIGNAL = 9; - this.EXE = '.exe'; - } else { - this.TERMSIGNAL = 'SIGTERM'; - this.EXE = ''; - } - - // heuristically detect .so/.a/.dll/.lib suffix - this.LIB = ['lib%s.a', 'lib%s.so', '%s.dll', '%s.lib'].find((format) => { - try { - const lib = this.BIN_PATH + '/' + util.format(format, 'osrm'); - fs.accessSync(lib, fs.F_OK); - } catch(e) { return false; } - return true; - }); + this.initializeEnv = (callback) => { + this.TIMEOUT = process.env.CUCUMBER_TIMEOUT && parseInt(process.env.CUCUMBER_TIMEOUT) || 5000; + // set cucumber default timeout + this.setDefaultTimeout(this.TIMEOUT); + this.ROOT_PATH = process.cwd(); + + this.TEST_PATH = path.resolve(this.ROOT_PATH, 'test'); + this.CACHE_PATH = path.resolve(this.TEST_PATH, 'cache'); + this.LOGS_PATH = path.resolve(this.TEST_PATH, 'logs'); + + 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'); + this.DATASET_NAME = 'cucumber'; + this.PLATFORM_WINDOWS = process.platform.match(/^win.*/); + this.DEFAULT_ENVIRONMENT = process.env; + this.DEFAULT_PROFILE = 'bicycle'; + this.DEFAULT_INPUT_FORMAT = 'osm'; + let loadMethod = process.argv[process.argv.indexOf('-m') +1]; + this.DEFAULT_LOAD_METHOD = loadMethod.match('mmap') ? 'mmap' : loadMethod.match('directly') ? 'directly' : 'datastore'; + this.DEFAULT_ORIGIN = [1,1]; + this.OSM_USER = 'osrm'; + this.OSM_UID = 1; + this.OSM_TIMESTAMP = '2000-01-01T00:00:00Z'; + this.WAY_SPACING = 100; + this.DEFAULT_GRID_SIZE = 100; // meters + // get algorithm name from the command line profile argument + this.ROUTING_ALGORITHM = process.argv[process.argv.indexOf('-p') + 1].match('mld') ? 'MLD' : 'CH'; + this.TIMEZONE_NAMES = this.PLATFORM_WINDOWS ? 'win' : 'iana'; + + this.OSRM_PORT = process.env.OSRM_PORT && parseInt(process.env.OSRM_PORT) || 5000; + 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.1; + + this.HOST = `http://${this.OSRM_IP}:${this.OSRM_PORT}`; + + this.OSRM_PROFILE = process.env.OSRM_PROFILE; + + if (this.PLATFORM_WINDOWS) { + this.TERMSIGNAL = 9; + this.EXE = '.exe'; + } else { + this.TERMSIGNAL = 'SIGTERM'; + this.EXE = ''; + } + + // heuristically detect .so/.a/.dll/.lib suffix + this.LIB = ['lib%s.a', 'lib%s.so', '%s.dll', '%s.lib'].find((format) => { + try { + const lib = this.BIN_PATH + '/' + util.format(format, 'osrm'); + fs.accessSync(lib, fs.F_OK); + } catch(e) { return false; } + return true; + }); - if (this.LIB === undefined) { - throw new Error('*** Unable to detect dynamic or static libosrm libraries'); - } - - 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_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_GUIDANCE_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_guidance'), - this.LIB_OSRM_CONTRACT_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_contract'), - 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'); - - fs.exists(this.TEST_PATH, (exists) => { - if (exists) - return callback(); - else - return callback(new Error('*** Test folder doesn\'t exist.')); - }); - }; + if (this.LIB === undefined) { + throw new Error('*** Unable to detect dynamic or static libosrm libraries'); + } + + 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'); + + fs.exists(this.TEST_PATH, (exists) => { + if (exists) + return callback(); + else + return callback(new Error('*** Test folder doesn\'t exist.')); + }); + }; - this.getProfilePath = (profile) => { - return path.resolve(this.PROFILES_PATH, profile + '.lua'); - }; + this.getProfilePath = (profile) => { + return path.resolve(this.PROFILES_PATH, profile + '.lua'); + }; - this.verifyOSRMIsNotRunning = (callback) => { - tryConnect(this.OSRM_IP, this.OSRM_PORT, (err) => { - if (!err) return callback(new Error('*** osrm-routed is already running.')); - else callback(); + this.verifyOSRMIsNotRunning = (callback) => { + tryConnect(this.OSRM_IP, this.OSRM_PORT, (err) => { + if (!err) return callback(new Error('*** osrm-routed is already running.')); + else callback(); + }); + }; + + this.verifyExistenceOfBinaries = (callback) => { + var verify = (binPath, cb) => { + fs.exists(binPath, (exists) => { + if (!exists) return cb(new Error(util.format('%s is missing. Build failed?', binPath))); + var helpPath = util.format('%s --help', binPath); + child_process.exec(helpPath, (err) => { + if (err) { + return cb(new Error(util.format('*** %s exited with code %d', helpPath, err.code))); + } + cb(); }); + }); }; - this.verifyExistenceOfBinaries = (callback) => { - var verify = (binPath, cb) => { - fs.exists(binPath, (exists) => { - if (!exists) return cb(new Error(util.format('%s is missing. Build failed?', binPath))); - var helpPath = util.format('%s --help', binPath); - child_process.exec(helpPath, (err) => { - if (err) { - return cb(new Error(util.format('*** %s exited with code %d', helpPath, err.code))); - } - cb(); - }); - }); - }; - - var q = d3.queue(); - [this.OSRM_EXTRACT_PATH, this.OSRM_CONTRACT_PATH, this.OSRM_ROUTED_PATH].forEach(bin => { q.defer(verify, bin); }); - q.awaitAll(callback); - }; + var q = d3.queue(); + [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); + }; - process.on('exit', () => { - this.osrmLoader.shutdown(() => {}); - }); + process.on('exit', () => { + this.osrmLoader.shutdown(() => {}); + }); - process.on('SIGINT', () => { - process.exit(2); - // TODO need to handle for windows?? - }); + process.on('SIGINT', () => { + process.exit(2); + // TODO need to handle for windows?? + }); }; diff --git a/features/support/fbresult_generated.js b/features/support/fbresult_generated.js new file mode 100644 index 00000000000..262f2068316 --- /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 00000000000..748ae5751f9 --- /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/fuzzy.js b/features/support/fuzzy.js index 6eebe0a6159..fa8378cb381 100644 --- a/features/support/fuzzy.js +++ b/features/support/fuzzy.js @@ -1,5 +1,5 @@ var classes = require('./data_classes'); module.exports = function() { - this.FuzzyMatch = new classes.FuzzyMatch(); + this.FuzzyMatch = new classes.FuzzyMatch(); }; diff --git a/features/support/hooks.js b/features/support/hooks.js index 01c2e6e8921..ee9ce8aa5b1 100644 --- a/features/support/hooks.js +++ b/features/support/hooks.js @@ -2,64 +2,65 @@ var d3 = require('d3-queue'); var path = require('path'); -var mkdirp = require('mkdirp'); -var rimraf = require('rimraf'); +var fs = require('fs'); var OSM = require('../lib/osm'); var OSRMLoader = require('../lib/osrm_loader'); +const { createDir } = require('../lib/utils'); module.exports = function () { - this.registerHandler('BeforeFeatures', {timeout: 30000}, (features, callback) => { - this.osrmLoader = new OSRMLoader(this); - this.OSMDB = new OSM.DB(); + this.registerHandler('BeforeFeatures', { timeout: 30000 }, (features, callback) => { + this.osrmLoader = new OSRMLoader(this); + this.OSMDB = new OSM.DB(); - let queue = d3.queue(1); - queue.defer(this.initializeEnv.bind(this)); - queue.defer(this.verifyOSRMIsNotRunning.bind(this)); - queue.defer(this.verifyExistenceOfBinaries.bind(this)); - queue.defer(this.initializeCache.bind(this)); - queue.defer(this.setupFeatures.bind(this, features)); - queue.awaitAll(callback); - }); + let queue = d3.queue(1); + queue.defer(this.initializeEnv.bind(this)); + queue.defer(this.verifyOSRMIsNotRunning.bind(this)); + queue.defer(this.verifyExistenceOfBinaries.bind(this)); + queue.defer(this.initializeCache.bind(this)); + queue.defer(this.setupFeatures.bind(this, features)); + queue.awaitAll(callback); + }); - this.BeforeFeature((feature, callback) => { - this.profile = this.OSRM_PROFILE || this.DEFAULT_PROFILE; - this.profileFile = path.join(this.PROFILES_PATH, this.profile + '.lua'); - this.setupFeatureCache(feature); - callback(); - }); + this.BeforeFeature((feature, callback) => { + this.profile = this.OSRM_PROFILE || this.DEFAULT_PROFILE; + this.profileFile = path.join(this.PROFILES_PATH, this.profile + '.lua'); + this.setupFeatureCache(feature); + callback(); + }); - this.Before((scenario, callback) => { - this.osrmLoader.setLoadMethod(this.DEFAULT_LOAD_METHOD); - this.setGridSize(this.DEFAULT_GRID_SIZE); - this.setOrigin(this.DEFAULT_ORIGIN); - this.queryParams = {}; - this.extractArgs = ''; - this.contractArgs = ''; - this.partitionArgs = ''; - this.customizeArgs = ''; - this.environment = Object.assign(this.DEFAULT_ENVIRONMENT); - this.resetOSM(); + this.Before((scenario, callback) => { + this.osrmLoader.setLoadMethod(this.DEFAULT_LOAD_METHOD); + this.setGridSize(this.DEFAULT_GRID_SIZE); + this.setOrigin(this.DEFAULT_ORIGIN); + this.queryParams = {}; + this.extractArgs = ''; + this.contractArgs = ''; + this.partitionArgs = ''; + this.customizeArgs = ''; + this.loaderArgs = ''; + this.environment = Object.assign(this.DEFAULT_ENVIRONMENT); + this.resetOSM(); - this.scenarioID = this.getScenarioID(scenario); - this.setupScenarioCache(this.scenarioID); + this.scenarioID = this.getScenarioID(scenario); + this.setupScenarioCache(this.scenarioID); - // setup output logging - let logDir = path.join(this.LOGS_PATH, this.featureID); - this.scenarioLogFile = path.join(logDir, this.scenarioID) + '.log'; - d3.queue(1) - .defer(mkdirp, logDir) - .defer(rimraf, this.scenarioLogFile) - .awaitAll(callback); - // uncomment to get path to logfile - // console.log(' Writing logging output to ' + this.scenarioLogFile); - }); + // setup output logging + let logDir = path.join(this.LOGS_PATH, this.featureID); + this.scenarioLogFile = path.join(logDir, this.scenarioID) + '.log'; + d3.queue(1) + .defer(createDir, logDir) + .defer((callback) => fs.rm(this.scenarioLogFile, { force: true }, callback)) + .awaitAll(callback); + // uncomment to get path to logfile + // console.log(' Writing logging output to ' + this.scenarioLogFile); + }); - this.After((scenario, callback) => { - this.resetOptionsOutput(); - callback(); - }); + this.After((scenario, callback) => { + this.resetOptionsOutput(); + callback(); + }); - this.AfterFeatures((features, callback) => { - callback(); - }); + this.AfterFeatures((features, callback) => { + callback(); + }); }; diff --git a/features/support/http.js b/features/support/http.js index 71f61761a45..fa10f94a20e 100644 --- a/features/support/http.js +++ b/features/support/http.js @@ -1,53 +1,74 @@ -var Timeout = require('node-timeout'); -var request = require('request'); +const { Timeout } = require('../lib/utils'); +const http = require('http'); +const https = require('https'); +function httpRequest(url, callback) { + const client = url.startsWith('https') ? https : http; + const req = client.get(url, (res) => { + let data = ''; + + // Collect data chunks + res.on('data', (chunk) => { + data += chunk; + }); + + // Handle end of response + res.on('end', () => { + callback(null, res, data); + }); + }); + + // Handle errors + req.on('error', (err) => { + callback(err); + }); + + req.end(); +} module.exports = function () { - this.paramsToString = (params) => { - var paramString = ''; - if (params.coordinates !== undefined) { - // FIXME this disables passing the output if its a default - // Remove after #2173 is fixed. - var outputString = (params.output && params.output !== 'json') ? ('.' + params.output) : ''; - paramString = params.coordinates.join(';') + outputString; - delete params.coordinates; - delete params.output; - } - if (Object.keys(params).length) { - paramString += '?' + Object.keys(params).map(k => k + '=' + params[k]).join('&'); - } + this.paramsToString = (params) => { + var paramString = ''; + if (params.coordinates !== undefined) { + // FIXME this disables passing the output if its a default + // Remove after #2173 is fixed. + var outputString = (params.output && params.output !== 'json') ? ('.' + params.output) : ''; + paramString = params.coordinates.join(';') + outputString; + delete params.coordinates; + delete params.output; + } + if (Object.keys(params).length) { + paramString += '?' + Object.keys(params).map(k => k + '=' + params[k]).join('&'); + } - return paramString; - }; + return paramString; + }; + + // FIXME this needs to be simplified! + this.sendRequest = (baseUri, parameters, callback) => { + + var limit = Timeout(this.TIMEOUT, { err: { statusCode: 408 } }); + var runRequest = (cb) => { + var params = this.paramsToString(parameters); + this.query = baseUri + (params.length ? '/' + params : ''); - // FIXME this needs to be simplified! - // - remove usage of node-timeout - // - replace with node's native timout mechanism - this.sendRequest = (baseUri, parameters, callback) => { - var limit = Timeout(this.TIMEOUT, { err: { statusCode: 408 } }); - - var runRequest = (cb) => { - var params = this.paramsToString(parameters); - this.query = baseUri + (params.length ? '/' + params : ''); - - request(this.query, (err, res, body) => { - if (err && err.code === 'ECONNREFUSED') { - return cb(new Error('*** osrm-routed is not running.')); - } else if (err && err.statusCode === 408) { - return cb(new Error()); - } - - return cb(err, res, body); - }); - }; - - runRequest(limit((err, res, body) => { - if (err) { - if (err.statusCode === 408) - return callback(new Error('*** osrm-routed did not respond')); - else if (err.code === 'ECONNREFUSED') - return callback(new Error('*** osrm-routed is not running')); - } - return callback(err, res, body); - })); + httpRequest(this.query, (err, res, body) => { + if (err && err.code === 'ECONNREFUSED') { + return cb(new Error('*** osrm-routed is not running.')); + } else if (err && err.statusCode === 408) { + return cb(new Error()); + } + return cb(err, res, body); + }); }; + + runRequest(limit((err, res, body) => { + if (err) { + if (err.statusCode === 408) + return callback(new Error('*** osrm-routed did not respond')); + else if (err.code === 'ECONNREFUSED') + return callback(new Error('*** osrm-routed is not running')); + } + return callback(err, res, body); + })); + }; }; diff --git a/features/support/route.js b/features/support/route.js index cd713372df9..d5e14ecec87 100644 --- a/features/support/route.js +++ b/features/support/route.js @@ -1,305 +1,291 @@ 'use strict'; -const Timeout = require('node-timeout'); -const request = require('request'); const ensureDecimal = require('../lib/utils').ensureDecimal; module.exports = function () { - this.requestPath = (service, params, callback) => { - var uri; - if (service == 'timestamp') { - uri = [this.HOST, service].join('/'); - } else { - uri = [this.HOST, service, 'v1', this.profile].join('/'); - } - - return this.sendRequest(uri, params, callback); - }; - - this.requestUrl = (path, callback) => { - var uri = this.query = [this.HOST, path].join('/'), - limit = Timeout(this.TIMEOUT, { err: { statusCode: 408 } }); - - function runRequest (cb) { - request(uri, cb); - } - - runRequest(limit((err, res, body) => { - if (err) { - if (err.statusCode === 408) return callback(this.RoutedError('*** osrm-routed did not respond')); - else if (err.code === 'ECONNREFUSED') - return callback(this.RoutedError('*** osrm-routed is not running')); - } else - return callback(err, res, body); - })); - }; - - // Overwrites the default values in defaults - // e.g. [[a, 1], [b, 2]], [[a, 5], [d, 10]] => [[a, 5], [b, 2], [d, 10]] - this.overwriteParams = (defaults, other) => { - var otherMap = {}; - for (var key in other) otherMap[key] = other[key]; - return Object.assign({}, defaults, otherMap); - }; - - var encodeWaypoints = (waypoints) => { - return waypoints.map(w => [w.lon, w.lat].map(ensureDecimal).join(',')); - }; - - this.requestRoute = (waypoints, bearings, approaches, userParams, callback) => { - if (bearings.length && bearings.length !== waypoints.length) throw new Error('*** number of bearings does not equal the number of waypoints'); - if (approaches.length && approaches.length !== waypoints.length) throw new Error('*** number of approaches does not equal the number of waypoints'); - - var defaults = { - output: 'json', - steps: 'true', - alternatives: 'false' - }, - params = this.overwriteParams(defaults, userParams), - encodedWaypoints = encodeWaypoints(waypoints); - - params.coordinates = encodedWaypoints; - - if (bearings.length) { - params.bearings = bearings.map(b => { - var bs = b.split(','); - if (bs.length === 2) return b; - else return b += ',10'; - }).join(';'); - } - - if (approaches.length) { - params.approaches = approaches.join(';'); - } - return this.requestPath('route', params, callback); - }; - - this.requestNearest = (node, userParams, callback) => { - var defaults = { - output: 'json' - }, - params = this.overwriteParams(defaults, userParams); - params.coordinates = [[node.lon, node.lat].join(',')]; - - return this.requestPath('nearest', params, callback); - }; - - this.requestTable = (waypoints, userParams, callback) => { - var defaults = { - output: 'json' - }, - params = this.overwriteParams(defaults, userParams); - - params.coordinates = waypoints.map(w => [w.coord.lon, w.coord.lat].join(',')); - var srcs = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'src').map(w => w[1]), - dsts = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'dst').map(w => w[1]); - if (srcs.length) params.sources = srcs.join(';'); - if (dsts.length) params.destinations = dsts.join(';'); - - return this.requestPath('table', params, callback); - }; - - this.requestTrip = (waypoints, userParams, callback) => { - var defaults = { - output: 'json' - }, - params = this.overwriteParams(defaults, userParams); - - params.coordinates = encodeWaypoints(waypoints); - - return this.requestPath('trip', params, callback); - }; - - this.requestMatching = (waypoints, timestamps, userParams, callback) => { - var defaults = { - output: 'json' - }, - params = this.overwriteParams(defaults, userParams); - - params.coordinates = encodeWaypoints(waypoints); - - if (timestamps.length) { - params.timestamps = timestamps.join(';'); - } - - return this.requestPath('match', params, callback); - }; - - this.extractInstructionList = (instructions, keyFinder) => { - if (instructions) { - return instructions.legs.reduce((m, v) => m.concat(v.steps), []) - .map(keyFinder) - .join(','); - } - }; - - this.summary = (instructions) => { - if (instructions) { - return instructions.legs.map(l => l.summary).join(';'); - } - }; - - this.wayList = (instructions) => { - return this.extractInstructionList(instructions, s => s.name); - }; - - this.refList = (instructions) => { - return this.extractInstructionList(instructions, s => s.ref || ''); - }; - - this.pronunciationList = (instructions) => { - return this.extractInstructionList(instructions, s => s.pronunciation || ''); - }; - - this.destinationsList = (instructions) => { - return this.extractInstructionList(instructions, s => s.destinations || ''); - }; - - this.exitsList = (instructions) => { - return this.extractInstructionList(instructions, s => s.exits || ''); - }; - - this.reverseBearing = (bearing) => { - if (bearing >= 180) - return bearing - 180.; - return bearing + 180; - }; - - this.bearingList = (instructions) => { - return this.extractInstructionList(instructions, s => ('in' in s.intersections[0] ? this.reverseBearing(s.intersections[0].bearings[s.intersections[0].in]) : 0) + this.requestPath = (service, params, callback) => { + var uri; + if (service == 'timestamp') { + uri = [this.HOST, service].join('/'); + } else { + uri = [this.HOST, service, 'v1', this.profile].join('/'); + } + + return this.sendRequest(uri, params, callback); + }; + + this.requestUrl = (path, callback) => { + var uri = this.query = [this.HOST, path].join('/'); + this.sendRequest(uri, '', callback); + }; + + // Overwrites the default values in defaults + // e.g. [[a, 1], [b, 2]], [[a, 5], [d, 10]] => [[a, 5], [b, 2], [d, 10]] + this.overwriteParams = (defaults, other) => { + var otherMap = {}; + for (var key in other) otherMap[key] = other[key]; + return Object.assign({}, defaults, otherMap); + }; + + var encodeWaypoints = (waypoints) => { + return waypoints.map(w => [w.lon, w.lat].map(ensureDecimal).join(',')); + }; + + this.requestRoute = (waypoints, bearings, approaches, userParams, callback) => { + if (bearings.length && bearings.length !== waypoints.length) throw new Error('*** number of bearings does not equal the number of waypoints'); + if (approaches.length && approaches.length !== waypoints.length) throw new Error('*** number of approaches does not equal the number of waypoints'); + + var defaults = { + output: 'json', + steps: 'true', + alternatives: 'false' + }, + params = this.overwriteParams(defaults, userParams), + encodedWaypoints = encodeWaypoints(waypoints); + + params.coordinates = encodedWaypoints; + + if (bearings.length) { + params.bearings = bearings.map(b => { + var bs = b.split(','); + if (bs.length === 2) return b; + else return b += ',10'; + }).join(';'); + } + + if (approaches.length) { + params.approaches = approaches.join(';'); + } + return this.requestPath('route', params, callback); + }; + + this.requestNearest = (node, userParams, callback) => { + var defaults = { + output: 'json' + }, + params = this.overwriteParams(defaults, userParams); + params.coordinates = [[node.lon, node.lat].join(',')]; + + return this.requestPath('nearest', params, callback); + }; + + this.requestTable = (waypoints, userParams, callback) => { + var defaults = { + output: 'json' + }, + params = this.overwriteParams(defaults, userParams); + + params.coordinates = waypoints.map(w => [w.coord.lon, w.coord.lat].join(',')); + var srcs = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'src').map(w => w[1]), + dsts = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'dst').map(w => w[1]); + if (srcs.length) params.sources = srcs.join(';'); + if (dsts.length) params.destinations = dsts.join(';'); + + return this.requestPath('table', params, callback); + }; + + this.requestTrip = (waypoints, userParams, callback) => { + var defaults = { + output: 'json', + steps: 'true' + }, + params = this.overwriteParams(defaults, userParams); + + params.coordinates = encodeWaypoints(waypoints); + + return this.requestPath('trip', params, callback); + }; + + this.requestMatching = (waypoints, timestamps, userParams, callback) => { + var defaults = { + output: 'json' + }, + params = this.overwriteParams(defaults, userParams); + + params.coordinates = encodeWaypoints(waypoints); + + if (timestamps.length) { + params.timestamps = timestamps.join(';'); + } + + return this.requestPath('match', params, callback); + }; + + this.extractInstructionList = (instructions, keyFinder) => { + if (instructions) { + return instructions.legs.reduce((m, v) => m.concat(v.steps), []) + .map(keyFinder) + .join(','); + } + }; + + this.summary = (instructions) => { + if (instructions) { + return instructions.legs.map(l => l.summary).join(';'); + } + }; + + this.wayList = (instructions) => { + return this.extractInstructionList(instructions, s => s.name); + }; + + this.refList = (instructions) => { + return this.extractInstructionList(instructions, s => s.ref || ''); + }; + + this.pronunciationList = (instructions) => { + return this.extractInstructionList(instructions, s => s.pronunciation || ''); + }; + + this.destinationsList = (instructions) => { + return this.extractInstructionList(instructions, s => s.destinations || ''); + }; + + this.exitsList = (instructions) => { + return this.extractInstructionList(instructions, s => s.exits || ''); + }; + + this.reverseBearing = (bearing) => { + if (bearing >= 180) + return bearing - 180.; + return bearing + 180; + }; + + this.bearingList = (instructions) => { + return this.extractInstructionList(instructions, s => ('in' in s.intersections[0] ? this.reverseBearing(s.intersections[0].bearings[s.intersections[0].in]) : 0) + '->' + ('out' in s.intersections[0] ? s.intersections[0].bearings[s.intersections[0].out] : 0)); - }; - - this.lanesList = (instructions) => { - return this.extractInstructionList(instructions, s => { - return s.intersections.map( i => { - if(i.lanes) - { - return i.lanes.map( l => { - let indications = l.indications.join(';'); - return indications + ':' + (l.valid ? 'true' : 'false'); - }).join(' '); - } - else - { - return ''; - } - }).join(';'); - }); - }; - - this.approachList = (instructions) => { - return this.extractInstructionList(instructions, s => s.approaches || ''); - }; - - this.annotationList = (instructions) => { - if (!('annotation' in instructions.legs[0])) - return ''; - - var merged = {}; - instructions.legs.map(l => { - 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).filter(k => !k.match(/metadata/)).map(a => { - merged[a] = merged[a].join(','); + }; + + this.lanesList = (instructions) => { + return this.extractInstructionList(instructions, s => { + return s.intersections.map( i => { + if(i.lanes) + { + return i.lanes.map( l => { + let indications = l.indications.join(';'); + return indications + ':' + (l.valid ? 'true' : 'false'); + }).join(' '); + } + else + { + return ''; + } + }).join(';'); + }); + }; + + this.approachList = (instructions) => { + return this.extractInstructionList(instructions, s => s.approaches || ''); + }; + + this.annotationList = (instructions) => { + if (!('annotation' in instructions.legs[0])) + return ''; + + var merged = {}; + instructions.legs.map(l => { + 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(':')); }); - if (merged.metadata) { - Object.keys(merged.metadata).map(a => { - merged.metadata[a] = merged.metadata[a].join(','); - }); + } + }); + 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; + }; + + this.alternativesList = (instructions) => { + // alternatives_count come from tracepoints list + return instructions.tracepoints.map(t => t.alternatives_count.toString()).join(','); + }; + + this.turnList = (instructions) => { + return instructions.legs.reduce((m, v) => m.concat(v.steps), []) + .map(v => { + switch (v.maneuver.type) { + case 'depart': + case 'arrive': + return v.maneuver.type; + case 'on ramp': + case 'off ramp': + return v.maneuver.type + ' ' + v.maneuver.modifier; + case 'roundabout': + return 'roundabout-exit-' + v.maneuver.exit; + case 'rotary': + if( 'rotary_name' in v ) + return v.rotary_name + '-exit-' + v.maneuver.exit; + else + return 'rotary-exit-' + v.maneuver.exit; + case 'roundabout turn': + return v.maneuver.type + ' ' + v.maneuver.modifier + ' exit-' + v.maneuver.exit; + // FIXME this is a little bit over-simplistic for merge/fork instructions + default: + return v.maneuver.type + ' ' + v.maneuver.modifier; } - return merged; - }; - - this.alternativesList = (instructions) => { - // alternatives_count come from tracepoints list - return instructions.tracepoints.map(t => t.alternatives_count.toString()).join(','); - }; - - this.turnList = (instructions) => { - return instructions.legs.reduce((m, v) => m.concat(v.steps), []) - .map(v => { - switch (v.maneuver.type) { - case 'depart': - case 'arrive': - return v.maneuver.type; - case 'on ramp': - case 'off ramp': - return v.maneuver.type + ' ' + v.maneuver.modifier; - case 'roundabout': - return 'roundabout-exit-' + v.maneuver.exit; - case 'rotary': - if( 'rotary_name' in v ) - return v.rotary_name + '-exit-' + v.maneuver.exit; - else - return 'rotary-exit-' + v.maneuver.exit; - case 'roundabout turn': - return v.maneuver.type + ' ' + v.maneuver.modifier + ' exit-' + v.maneuver.exit; - // FIXME this is a little bit over-simplistic for merge/fork instructions - default: - return v.maneuver.type + ' ' + v.maneuver.modifier; - } - }) - .join(','); - }; - - this.locations = (instructions) => { - return instructions.legs.reduce((m, v) => m.concat(v.steps), []) - .map(v => { - return this.findNodeByLocation(v.maneuver.location); - }) - .join(','); - }; - - this.intersectionList = (instructions) => { - return instructions.legs.reduce((m, v) => m.concat(v.steps), []) - .map( v => { - return v.intersections - .map( intersection => { - var string = intersection.entry[0]+':'+intersection.bearings[0], i; - for( i = 1; i < intersection.bearings.length; ++i ) - string = string + ' ' + intersection.entry[i]+':'+intersection.bearings[i]; - return string; - }).join(','); - }).join(';'); - }; - - this.modeList = (instructions) => { - 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(',') + ']'); - }; - - this.timeList = (instructions) => { - return this.extractInstructionList(instructions, s => s.duration + 's'); - }; - - this.distanceList = (instructions) => { - return this.extractInstructionList(instructions, s => s.distance + 'm'); - }; - - this.weightName = (instructions) => { - return instructions ? instructions.weight_name : ''; - }; - - this.weightList = (instructions) => { - return this.extractInstructionList(instructions, s => s.weight); - }; + }) + .join(','); + }; + + this.locations = (instructions) => { + return instructions.legs.reduce((m, v) => m.concat(v.steps), []) + .map(v => { + return this.findNodeByLocation(v.maneuver.location); + }) + .join(','); + }; + + this.intersectionList = (instructions) => { + return instructions.legs.reduce((m, v) => m.concat(v.steps), []) + .map( v => { + return v.intersections + .map( intersection => { + var string = intersection.entry[0]+':'+intersection.bearings[0], i; + for( i = 1; i < intersection.bearings.length; ++i ) + string = string + ' ' + intersection.entry[i]+':'+intersection.bearings[i]; + return string; + }).join(','); + }).join(';'); + }; + + this.modeList = (instructions) => { + 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(',') + ']'); + }; + + this.timeList = (instructions) => { + return this.extractInstructionList(instructions, s => s.duration + 's'); + }; + + this.distanceList = (instructions) => { + return this.extractInstructionList(instructions, s => s.distance + 'm'); + }; + + this.weightName = (instructions) => { + return instructions ? instructions.weight_name : ''; + }; + + this.weightList = (instructions) => { + return this.extractInstructionList(instructions, s => s.weight); + }; }; diff --git a/features/support/run.js b/features/support/run.js index f65a17fe15b..2e55bfe8e82 100644 --- a/features/support/run.js +++ b/features/support/run.js @@ -6,53 +6,53 @@ const util = require('util'); const child_process = require('child_process'); module.exports = function () { - // replaces placeholders for in user supplied commands - this.expandOptions = (options) => { - let opts = options.slice(); - let table = { - '{osm_file}': this.inputCacheFile, - '{processed_file}': this.processedCacheFile, - '{profile_file}': this.profileFile, - '{rastersource_file}': this.rasterCacheFile, - '{speeds_file}': this.speedsCacheFile, - '{penalties_file}': this.penaltiesCacheFile, - '{timezone_names}': this.TIMEZONE_NAMES - }; + // replaces placeholders for in user supplied commands + this.expandOptions = (options) => { + let opts = options.slice(); + let table = { + '{osm_file}': this.inputCacheFile, + '{processed_file}': this.processedCacheFile, + '{profile_file}': this.profileFile, + '{rastersource_file}': this.rasterCacheFile, + '{speeds_file}': this.speedsCacheFile, + '{penalties_file}': this.penaltiesCacheFile, + '{timezone_names}': this.TIMEZONE_NAMES + }; - for (let k in table) { - opts = opts.replace(k, table[k]); - } + for (let k in table) { + opts = opts.replace(k, table[k]); + } - return opts; - }; + return opts; + }; - this.setupOutputLog = (process, log) => { - if (process.logFunc) { - process.stdout.removeListener('data', process.logFunc); - process.stderr.removeListener('data', process.logFunc); - } + this.setupOutputLog = (process, log) => { + if (process.logFunc) { + process.stdout.removeListener('data', process.logFunc); + process.stderr.removeListener('data', process.logFunc); + } - process.logFunc = (message) => { log.write(message); }; - process.stdout.on('data', process.logFunc); - process.stderr.on('data', process.logFunc); - }; + process.logFunc = (message) => { log.write(message); }; + process.stdout.on('data', process.logFunc); + process.stderr.on('data', process.logFunc); + }; - this.runBin = (bin, options, env, callback) => { - let cmd = path.resolve(util.format('%s/%s%s', this.BIN_PATH, bin, this.EXE)); - let opts = options.split(' ').filter((x) => { return x && x.length > 0; }); - let log = fs.createWriteStream(this.scenarioLogFile, {'flags': 'a'}); - log.write(util.format('*** running %s %s\n', cmd, options)); - // we need to set a large maxbuffer here because we have long running processes like osrm-routed - // with lots of log output - let child = child_process.execFile(cmd, opts, {maxBuffer: 1024 * 1024 * 1000, env: env}, callback); - child.on('exit', function(code) { - log.write(util.format('*** %s exited with code %d\n', bin, code)); - // remove listeners and close log file -> some tail messages can be lost - child.stdout.removeListener('data', child.logFunc); - child.stderr.removeListener('data', child.logFunc); - log.end(); - }.bind(this)); - this.setupOutputLog(child, log); - return child; - }; + this.runBin = (bin, options, env, callback) => { + let cmd = path.resolve(util.format('%s/%s%s', this.BIN_PATH, bin, this.EXE)); + let opts = options.split(' ').filter((x) => { return x && x.length > 0; }); + let log = fs.createWriteStream(this.scenarioLogFile, {'flags': 'a'}); + log.write(util.format('*** running %s %s\n', cmd, options)); + // we need to set a large maxbuffer here because we have long running processes like osrm-routed + // with lots of log output + let child = child_process.execFile(cmd, opts, {maxBuffer: 1024 * 1024 * 1000, env: env}, callback); + child.on('exit', function(code) { + log.write(util.format('*** %s exited with code %d\n', bin, code)); + // remove listeners and close log file -> some tail messages can be lost + child.stdout.removeListener('data', child.logFunc); + child.stderr.removeListener('data', child.logFunc); + log.end(); + }.bind(this)); + this.setupOutputLog(child, log); + return child; + }; }; diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js index 20fc0cf71a2..54f74a3df7f 100644 --- a/features/support/shared_steps.js +++ b/features/support/shared_steps.js @@ -4,279 +4,285 @@ var util = require('util'); var assert = require('assert'); module.exports = function () { - this.ShouldGetAResponse = () => { - assert.equal(this.response.statusCode, 200); - assert.ok(this.response.body); - assert.ok(this.response.body.length); - }; - - this.ShouldBeValidJSON = (callback) => { - try { - this.json = JSON.parse(this.response.body); - callback(); - } catch (e) { - callback(e); - } - }; - - this.ShouldBeWellFormed = () => { - assert.equal(typeof this.json.status, 'number'); - }; - - this.WhenIRouteIShouldGet = (table, callback) => { - this.reprocessAndLoadData((e) => { - if (e) return callback(e); - var headers = new Set(table.raw()[0]); - - var requestRow = (row, ri, cb) => { - var got; - - var afterRequest = (err, res, body) => { - if (err) return cb(err); - 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, - driving_sides; - - let json = JSON.parse(body); - - got.code = json.code; - - let hasRoute = json.code === 'Ok'; - - if (hasRoute) { - instructions = this.wayList(json.routes[0]); - pronunciations = this.pronunciationList(json.routes[0]); - refs = this.refList(json.routes[0]); - destinations = this.destinationsList(json.routes[0]); - exits = this.exitsList(json.routes[0]); - bearings = this.bearingList(json.routes[0]); - 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]); - lanes = this.lanesList(json.routes[0]); - summary = this.summary(json.routes[0]); - locations = this.locations(json.routes[0]); - annotation = this.annotationList(json.routes[0]); - weight_name = this.weightName(json.routes[0]); - weights = this.weightList(json.routes[0]); - approaches = this.approachList(json.routes[0]); - } - - if (headers.has('status')) { - got.status = res.statusCode.toString(); - } - - if (headers.has('message')) { - got.message = json.message || ''; - } - - if (headers.has('data_version')) { - got.data_version = json.data_version || ''; - } - - if (headers.has('#')) { - // comment column - got['#'] = row['#']; - } - - if (headers.has('geometry')) { - got.geometry = json.routes[0].geometry; - } - - if (headers.has('route')) { - got.route = (instructions || '').trim(); - } - - if (headers.has('summary')) { - got.summary = (summary || '').trim(); - } - - if (headers.has('alternative')) { - // TODO examine more than first alternative? - got.alternative =''; - if (json.routes && json.routes.length > 1) - got.alternative = this.wayList(json.routes[1]); - } - - var distance = hasRoute && json.routes[0].distance, - time = hasRoute && json.routes[0].duration, - weight = hasRoute && json.routes[0].weight; - - if (headers.has('distance')) { - if (row.distance.length) { - if (!row.distance.match(/\d+m/)) - return cb(new Error('*** Distance must be specified in meters. (ex: 250m)')); - got.distance = instructions ? util.format('%dm', distance) : ''; - } else { - got.distance = ''; - } - } - - if (headers.has('weight')) { - if (row.weight.length) { - 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 { - got.weight = ''; - } - } - - if (headers.has('time')) { - if (!row.time.match(/\d+s/)) - return cb(new Error('*** Time must be specied in seconds. (ex: 60s)')); - got.time = instructions ? util.format('%ds', time) : ''; - } - - if (headers.has('lanes')) { - got.lanes = (lanes || '').trim(); - } - - if (headers.has('speed')) { - if (row.speed !== '' && instructions) { - if (!row.speed.match(/\d+ km\/h/)) - cb(new Error('*** Speed must be specied in km/h. (ex: 50 km/h)')); - var speed = time > 0 ? Math.round(3.6*distance/time) : null; - got.speed = util.format('%d km/h', speed); - } else { - got.speed = ''; - } - } - - if (headers.has('intersections')) { - got.intersections = (intersections || '').trim(); - } - - if (headers.has('locations')){ - got.locations = (locations || '').trim(); - } - /* + this.ShouldGetAResponse = () => { + assert.equal(this.response.statusCode, 200); + assert.ok(this.response.body); + assert.ok(this.response.body.length); + }; + + this.ShouldBeValidJSON = (callback) => { + try { + this.json = JSON.parse(this.response.body); + callback(); + } catch (e) { + callback(e); + } + }; + + this.ShouldBeWellFormed = () => { + assert.equal(typeof this.json.status, 'number'); + }; + + this.WhenIRouteIShouldGet = (table, callback) => { + this.reprocessAndLoadData((e) => { + if (e) return callback(e); + var headers = new Set(table.raw()[0]); + + var requestRow = (row, ri, cb) => { + var got; + + var afterRequest = (err, res, body) => { + if (err) return cb(err); + 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, + driving_sides; + + let json = JSON.parse(body); + + got.code = json.code; + + let hasRoute = json.code === 'Ok'; + + if (hasRoute) { + instructions = this.wayList(json.routes[0]); + pronunciations = this.pronunciationList(json.routes[0]); + refs = this.refList(json.routes[0]); + destinations = this.destinationsList(json.routes[0]); + exits = this.exitsList(json.routes[0]); + bearings = this.bearingList(json.routes[0]); + 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]); + lanes = this.lanesList(json.routes[0]); + summary = this.summary(json.routes[0]); + locations = this.locations(json.routes[0]); + annotation = this.annotationList(json.routes[0]); + weight_name = this.weightName(json.routes[0]); + weights = this.weightList(json.routes[0]); + approaches = this.approachList(json.routes[0]); + } + + if (headers.has('status')) { + got.status = res.statusCode.toString(); + } + + if (headers.has('message')) { + got.message = json.message || ''; + } + + if (headers.has('data_version')) { + got.data_version = json.data_version || ''; + } + + if (headers.has('#')) { + // comment column + got['#'] = row['#']; + } + + if (headers.has('geometry')) { + got.geometry = json.routes[0].geometry; + } + + if (headers.has('route')) { + got.route = (instructions || '').trim(); + } + + if (headers.has('summary')) { + got.summary = (summary || '').trim(); + } + + if (headers.has('alternative')) { + // TODO examine more than first alternative? + got.alternative =''; + if (json.routes && json.routes.length > 1) + got.alternative = this.wayList(json.routes[1]); + } + + var distance = hasRoute && json.routes[0].distance, + time = hasRoute && json.routes[0].duration, + weight = hasRoute && json.routes[0].weight; + + if (headers.has('distance')) { + if (row.distance.length) { + if (!row.distance.match(/\d+m/)) + return cb(new Error('*** Distance must be specified in meters. (ex: 250m)')); + got.distance = instructions ? util.format('%dm', distance) : ''; + } else { + got.distance = ''; + } + } + + if (headers.has('weight')) { + if (row.weight.length) { + 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 { + got.weight = ''; + } + } + + if (headers.has('time')) { + if (!row.time.match(/\d+s/)) + return cb(new Error('*** Time must be specied in seconds. (ex: 60s)')); + got.time = instructions ? util.format('%ds', time) : ''; + } + + if (headers.has('lanes')) { + got.lanes = (lanes || '').trim(); + } + + if (headers.has('speed')) { + if (row.speed !== '' && instructions) { + if (!row.speed.match(/\d+ km\/h/)) + cb(new Error('*** Speed must be specied in km/h. (ex: 50 km/h)')); + var speed = time > 0 ? Math.round(3.6*distance/time) : null; + got.speed = util.format('%d km/h', speed); + } else { + got.speed = ''; + } + } + + if (headers.has('intersections')) { + got.intersections = (intersections || '').trim(); + } + + 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 metadata_whitelist = [ 'datasource_names' ]; - if (k.match(/^a:/)) { - let a_type = k.slice(2); - if (whitelist.indexOf(a_type) == -1) - return cb(new Error('Unrecognized annotation field', a_type)); - 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]) || ''; - } - }); - - var putValue = (key, value) => { - if (headers.has(key)) got[key] = instructions ? value : ''; - }; - - putValue('ref', refs); - putValue('bearing', bearings); - putValue('turns', turns); - putValue('modes', modes); - putValue('classes', classes); - putValue('times', times); - putValue('distances', distances); - putValue('pronunciations', pronunciations); - putValue('destinations', destinations); - putValue('exits', exits); - putValue('weight_name', weight_name); - putValue('weights', weights); - putValue('weight', weight); - putValue('approach', approaches); - - 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]; - } - } - - cb(null, got); - } else { - cb(new Error('request failed to return valid body')); - } - }; - - if (headers.has('request')) { - got = { request: row.request }; - this.requestUrl(row.request, afterRequest); - } else { - var defaultParams = this.queryParams; - var userParams = []; - got = {}; - for (var k in row) { - var match = k.match(/param:(.*)/); - if (match) { - if (row[k] === '(nil)') { - userParams.push([match[1], null]); - } else if (row[k]) { - userParams.push([match[1], row[k]]); - } - got[k] = row[k]; - } - } - - var params = this.overwriteParams(defaultParams, userParams), - waypoints = [], - bearings = [], - approaches = []; - - if (row.bearings) { - got.bearings = row.bearings; - bearings = row.bearings.split(' ').filter(b => !!b); - } - - if (row.approaches) { - got.approaches = row.approaches; - approaches = row.approaches.split(' ').filter(b => !!b); - } - - if (row.from && row.to) { - var fromNode = this.findNodeByName(row.from); - if (!fromNode) return cb(new Error(util.format('*** unknown from-node "%s"', row.from))); - waypoints.push(fromNode); - - var toNode = this.findNodeByName(row.to); - if (!toNode) return cb(new Error(util.format('*** unknown to-node "%s"', row.to))); - waypoints.push(toNode); - - got.from = row.from; - got.to = row.to; - this.requestRoute(waypoints, bearings, approaches, params, afterRequest); - } else if (row.waypoints) { - row.waypoints.split(',').forEach((n) => { - var node = this.findNodeByName(n.trim()); - if (!node) return cb(new Error(util.format('*** unknown waypoint node "%s"', n.trim()))); - waypoints.push(node); - }); - got.waypoints = row.waypoints; - this.requestRoute(waypoints, bearings, approaches, params, afterRequest); - } else { - return cb(new Error('*** no waypoints')); - } - } + // 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 metadata_whitelist = [ 'datasource_names' ]; + if (k.match(/^a:/)) { + let a_type = k.slice(2); + if (whitelist.indexOf(a_type) == -1) + return cb(new Error('Unrecognized annotation field', a_type)); + 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]) || ''; + } + }); + + var putValue = (key, value) => { + if (headers.has(key)) got[key] = instructions ? value : ''; }; - this.processRowsAndDiff(table, requestRow, callback); - }); - }; + putValue('ref', refs); + putValue('bearing', bearings); + putValue('turns', turns); + putValue('modes', modes); + putValue('classes', classes); + putValue('times', times); + putValue('distances', distances); + putValue('pronunciations', pronunciations); + putValue('destinations', destinations); + putValue('exits', exits); + putValue('weight_name', weight_name); + putValue('weights', weights); + putValue('weight', weight); + putValue('approach', approaches); + + 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]; + } + } + cb(null, got); + } else { + cb(new Error('request failed to return valid body')); + } + }; + + if (headers.has('request')) { + got = { request: row.request }; + this.requestUrl(row.request, afterRequest); + } else { + var defaultParams = this.queryParams; + var userParams = []; + got = {}; + for (var k in row) { + var match = k.match(/param:(.*)/); + if (match) { + if (row[k] === '(nil)') { + userParams.push([match[1], null]); + } else if (row[k]) { + userParams.push([match[1], row[k]]); + } + got[k] = row[k]; + } + } + + var params = this.overwriteParams(defaultParams, userParams), + waypoints = [], + bearings = [], + approaches = []; + + if (row.bearings) { + got.bearings = row.bearings; + bearings = row.bearings.split(' ').filter(b => !!b); + } + + if (row.approaches) { + got.approaches = row.approaches; + approaches = row.approaches.split(' ').filter(b => !!b); + } + + if (row.from && row.to) { + var fromNode = this.findNodeByName(row.from); + if (!fromNode) return cb(new Error(util.format('*** unknown from-node "%s"', row.from))); + waypoints.push(fromNode); + + var toNode = this.findNodeByName(row.to); + if (!toNode) return cb(new Error(util.format('*** unknown to-node "%s"', row.to))); + waypoints.push(toNode); + + got.from = row.from; + got.to = row.to; + this.requestRoute(waypoints, bearings, approaches, params, afterRequest); + } else if (row.waypoints) { + row.waypoints.split(',').forEach((n) => { + var node = this.findNodeByName(n.trim()); + if (!node) return cb(new Error(util.format('*** unknown waypoint node "%s"', n.trim()))); + waypoints.push(node); + }); + got.waypoints = row.waypoints; + this.requestRoute(waypoints, bearings, approaches, params, afterRequest); + } else { + return cb(new Error('*** no waypoints')); + } + } + }; + + this.processRowsAndDiff(table, requestRow, callback); + }); + }; }; diff --git a/features/testbot/alternative_loop.feature b/features/testbot/alternative_loop.feature index 1821379694d..1e2925f1889 100644 --- a/features/testbot/alternative_loop.feature +++ b/features/testbot/alternative_loop.feature @@ -40,7 +40,7 @@ Feature: Alternative route | 7 | 8 | ca,ab,bd,dc,ca,ca | | - @mld-only + @mld 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 diff --git a/features/testbot/annotations.feature b/features/testbot/annotations.feature index 706eb95041d..cff8461b244 100644 --- a/features/testbot/annotations.feature +++ b/features/testbot/annotations.feature @@ -115,4 +115,4 @@ Feature: Annotations When I route I should get | from | to | route | a:speed | a:distance | a:duration | a:nodes | - | a | c | abc,abc | 10:10 | 249.998641:299.931643 | 25:30 | 1:2:3 | + | a | c | abc,abc | 10:10 | 249.9876189:299.962882 | 25:30 | 1:2:3 | diff --git a/features/testbot/approaches.feature b/features/testbot/approaches.feature index d3e0c463006..fb3f008616d 100644 --- a/features/testbot/approaches.feature +++ b/features/testbot/approaches.feature @@ -38,7 +38,41 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc,bc | - Scenario: Start End opposite approach, option unrestricted for Start and End + Scenario: Start End same approach, option unrestricted for Start and opposite for End + Given the profile "testbot" + 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 opposite | ab,bc | + + Scenario: Start End same approach, option opposite for Start and curb for End + Given the profile "testbot" + 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 | opposite curb | ab,bc,bc | + + Scenario: Start End different approach, option unrestricted for Start and End Given the profile "testbot" And the node map """ @@ -56,7 +90,7 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted unrestricted | ab,bc | - Scenario: Start End opposite approach, option unrestricted for Start and curb for End + Scenario: Start End different approach, option unrestricted for Start and curb for End Given the profile "testbot" And the node map """ @@ -74,6 +108,43 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | + Scenario: Start End different approach, option unrestricted for Start and opposite for End + Given the profile "testbot" + 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 opposite | ab,bc,bc | + + Scenario: Start End different approach, option curb for Start and opposite for End + Given the profile "testbot" + And the node map + """ + e + a------b------c-----------d + s + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + + When I route I should get + | from | to | approaches | route | + | s | e | curb opposite | cd,cd,ab,ab | + ############### # Oneway Test # @@ -111,10 +182,44 @@ Feature: Approach parameter | bc | yes | When I route I should get - | from | to | approaches | route | + | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | - Scenario: Test on oneway segment, Start End opposite approach, option unrestricted for Start and End + Scenario: Test on oneway segment, Start End same approach, option unrestricted for Start and opposite for End + Given the profile "testbot" + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc | + + Scenario: Test on oneway segment, Start End same approach, option opposite for Start and curb for End + Given the profile "testbot" + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + + When I route I should get + | from | to | approaches | route | + | s | e | opposite curb | ab,bc | + + Scenario: Test on oneway segment, Start End different approach, option unrestricted for Start and End Given the profile "testbot" And the node map """ @@ -132,7 +237,7 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted unrestricted | ab,bc | - Scenario: Test on oneway segment, Start End opposite approach, option unrestricted for Start and curb for End + Scenario: Test on oneway segment, Start End different approach, option unrestricted for Start and curb for End Given the profile "testbot" And the node map """ @@ -150,6 +255,42 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | + Scenario: Test on oneway segment, Start End different approach, option unrestricted for Start and opposite for End + Given the profile "testbot" + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc | + + Scenario: Test on oneway segment, Start End different approach, option curb for Start and opposite for End + Given the profile "testbot" + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + + When I route I should get + | from | to | approaches | route | + | s | e | curb opposite | ab,bc | + ############## # UTurn Test # ############## @@ -175,6 +316,27 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | | + Scenario: UTurn test, router can find a route because uturn authorized to reach opposite side + Given the profile "testbot" + And the node map + """ + e s + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | bc | bc | c | no_u_turn | + + When I route I should get + | from | to | approaches | route | + | s | e | curb opposite | bc,ab,ab | + Scenario: UTurn test, router can find a route because he can use the roundabout Given the profile "testbot" @@ -198,8 +360,9 @@ Feature: Approach parameter | restriction | bc | bc | c | no_u_turn | When I route I should get - | from | to | approaches | route | - | s | e | unrestricted curb | ab,bc,bc | + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc,bc | + | s | e | opposite curb | ab,bc,bc | Scenario: Start End same approach, option unrestricted for Start and curb for End, left-hand driving @@ -228,6 +391,32 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | + Scenario: Start End same approach, option unrestricted for Start and opposite 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 opposite | ab,bc,bc | + ####################### # Left-side countries # @@ -260,9 +449,8 @@ Feature: Approach parameter """ And the node map """ - s + s e a------b------c - e """ And the ways @@ -271,10 +459,50 @@ Feature: Approach parameter | bc | When I route I should get - | from | to | approaches | route | - | s | e | unrestricted curb | ab,bc,bc | + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc | + + Scenario: [Left-hand-side] Start End same approach, option unrestricted for Start and opposite for End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + s e + a------b------c + """ - Scenario: [Left-hand-side] Start End opposite approach, option unrestricted for Start and End + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc,bc | + + Scenario: [Left-hand-side] Start End same approach, option opposite for Start and curb for End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + e s + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | opposite curb | bc,ab,ab | + + Scenario: [Left-hand-side] Start End different approach, option unrestricted for Start and End Given the profile file "car" initialized with """ profile.properties.left_hand_driving = true @@ -295,15 +523,16 @@ Feature: Approach parameter | 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 + Scenario: [Left-hand-side] Start End different 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 + s a------b------c + e """ And the ways @@ -312,5 +541,122 @@ Feature: Approach parameter | bc | When I route I should get - | from | to | approaches | route | - | s | e | unrestricted curb | ab,bc | \ No newline at end of file + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc,bc | + + Scenario: [Left-hand-side] Start End different approach, option unrestricted for Start and opposite 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 opposite | ab,bc | + + Scenario: [Left-hand-side] Start End different approach, option curb for Start and opposite 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 | curb opposite | ab,bc | + + + + Scenario: Routes with more than two waypoints - uturns allowed + Given the profile "testbot" + And the node map + """ + 2 1 + a------b------c-----------d + | + 3 | 4 + e------f------g-----------h + | + | + i + + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + | bf | + | ef | + | fg | + | gh | + | ei | + + And the query options + | continue_straight | false | + + When I route I should get + | waypoints | approaches | locations | # | + | 1,2,3,4 | curb curb curb curb | _,_,_,a,b,f,_,_,i,h,_ | 1,2,2,a,b,f,3,3,i,h,4 (Only u-turn at end of roads) | + | 1,2,3,4 | curb unrestricted unrestricted curb | _,_,_,b,f,_,_,h,_ | 1,2,2,b,f,3,3,h,4 (Can u-turn at 2 and 3) | + | 1,2,3,4 | opposite opposite opposite opposite | _,d,a,_,_,b,f,i,_,_,_ | 1,d,a,2,2,b,f,i,3,3,4 (Only u-turn at end of roads) | + | 1,2,3,4 | opposite unrestricted unrestricted opposite | _,d,_,_,b,f,_,_,_ | 1,d,2,2,b,f,3,3,4 (Can u-turn at 2 and 3) | + + + Scenario: Routes with more than two waypoints - uturns forbidden + Given the profile "testbot" + And the node map + """ + 2 1 + a------b------c-----------d + | + 3 | 4 + e------f------g-----------h + | + | + i + + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + | bf | + | ef | + | fg | + | gh | + | ei | + + And the query options + | continue_straight | true | + + When I route I should get + | waypoints | approaches | locations | # | + | 1,2,3,4 | curb curb curb curb | _,_,_,a,b,f,_,_,i,h,_ | 1,2,2,a,b,f,3,3,i,h,4 (Only u-turn at end of roads) | + | 1,2,3,4 | curb opposite opposite curb | _,a,_,_,b,f,i,_,_,h,_ | 1,a,2,2,b,f,i,3,3,h,4 (switches stops with u-turns) | + | 1,2,3,4 | opposite opposite opposite opposite | _,d,a,_,_,b,f,i,_,_,_ | 1,d,a,2,2,b,f,i,3,3,4 (Only u-turn at end of roads) | + | 1,2,3,4 | opposite curb curb opposite | _,d,_,_,a,b,f,_,_,i,_ | 1,d,2,2,a,b,f,3,3,i,4 (switches stops with u-turns) | diff --git a/features/testbot/basic.feature b/features/testbot/basic.feature index 0041a133eb3..9224cd46911 100644 --- a/features/testbot/basic.feature +++ b/features/testbot/basic.feature @@ -17,9 +17,9 @@ Feature: Basic Routing | ab | When I route I should get - | from | to | route | data_version | - | 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 @@ -38,6 +38,23 @@ Feature: Basic Routing | 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 d74f4bafd8e..0ae483ca4f2 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 ec6708a706c..227324bffdf 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,ring | 0->0,0->90,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 | 0->90,90->180,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,ring | 0->180,180->270,270->0,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,ring | 0->270,270->0,0->90,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 033cc333580..da8c0cdef3b 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 1b76f45a653..50595b08797 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 | diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature index 6ac1ce21bd4..5d1ea444ac4 100644 --- a/features/testbot/distance_matrix.feature +++ b/features/testbot/distance_matrix.feature @@ -22,10 +22,10 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | e | f | - | a | 0 | 100.1 | 199.5 | 299.5 | - | b | 100.1 | 0 | 99.4 | 199.5 | - | e | 199.5 | 99.4 | 0 | 100.1 | - | f | 299.5 | 199.5 | 100.1 | 0 | + | 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 minimal network exact distances Given the node map @@ -43,11 +43,11 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | z | b | c | d | - | a | 0 | 100.1 | 199.5 | 298.9 | 398.3 | - | z | 100.1 | 0 | 99.4 | 198.8 | 298.2 | - | b | 199.5 | 99.4 | 0 | 99.4 | 198.8 | - | c | 298.9 | 198.8 | 99.4 | 0 | 99.4 | - | d | 398.3 | 298.2 | 198.8 | 99.4 | 0 | + | 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 @@ -68,10 +68,10 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | c | d | - | a | 0 | 100.1 | | | - | b | 100.1 | 0 | | | - | c | | | 0 | 100.1 | - | d | | | 100.1 | 0 | + | 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 @@ -92,7 +92,7 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | c | d | - | a | 0 | 298.9 | 99.4 | 199.5 | + | a | 0 | 299.9 | 100 | 199.9 | Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude Given the query options @@ -113,7 +113,7 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | e | - | a | 0 | 50.1 | | + | a | 0 | 50 | | Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes Given the query options @@ -134,7 +134,7 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | e | g | - | a | 0 | 100.1 | | | + | a | 0 | 100 | | | Scenario: Testbot - Travel distance matrix with different way speeds Given the node map @@ -150,21 +150,21 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | c | d | - | a | 0 | 100.1 | 200.1 | 300.2 | - | b | 100.1 | 0 | 100.1 | 200.1 | - | c | 200.1 | 100.1 | 0 | 100.1 | - | d | 300.2 | 200.1 | 100.1 | 0 | + | 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.1 | 200.1 | 300.2 | + | a | 0 | 100 | 200 | 300 | When I request a travel distance matrix I should get | | a | | a | 0 | - | b | 100.1 | - | c | 200.1 | - | d | 300.2 | + | b | 100 | + | c | 200 | + | d | 300 | Scenario: Testbot - Travel distance matrix of small grid Given the node map @@ -183,10 +183,10 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | e | f | - | a | 0 | 100.1 | 199.5 | 299.5 | - | b | 100.1 | 0 | 99.4 | 199.5 | - | e | 199.5 | 99.4 | 0 | 100.1 | - | f | 299.5 | 199.5 | 100.1 | 0 | + | 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 @@ -200,7 +200,7 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | - | a | 0 | 100.1 | + | a | 0 | 100 | | b | | 0 | Scenario: Testbot - Travel distance matrix of network with oneways @@ -218,10 +218,10 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | x | y | d | e | - | x | 0 | 300.2 | 399.6 | 299.5 | - | y | 499 | 0 | 299.5 | 199.5 | - | d | 199.5 | 299.5 | 0 | 298.9 | - | e | 299.5 | 399.6 | 100.1 | 0 | + | 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 - Rectangular travel distance matrix Given the node map @@ -240,53 +240,53 @@ Feature: Basic Distance Matrix When I route I should get | from | to | distance | - | e | a | 200m | + | e | a | 199.9m | | e | b | 100m | - | f | a | 299.9m | + | f | a | 300m | | f | b | 200m | When I request a travel distance matrix I should get | | a | b | e | f | - | a | 0 | 100.1 | 199.5 | 299.5 | + | a | 0 | 100 | 199.9 | 300 | When I request a travel distance matrix I should get | | a | | a | 0 | - | b | 100.1 | - | e | 199.5 | - | f | 299.5 | + | b | 100 | + | e | 199.9 | + | f | 300 | When I request a travel distance matrix I should get | | a | b | e | f | - | a | 0 | 100.1 | 199.5 | 299.5 | - | b | 100.1 | 0 | 99.4 | 199.5 | + | 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.1 | - | b | 100.1 | 0 | - | e | 199.5 | 99.4 | - | f | 299.5 | 199.5 | + | 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.1 | 199.5 | 299.5 | - | b | 100.1 | 0 | 99.4 | 199.5 | - | e | 199.5 | 99.4 | 0 | 100.1 | + | 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.1 | 199.5 | - | b | 100.1 | 0 | 99.4 | - | e | 199.5 | 99.4 | 0 | - | f | 299.5 | 199.5 | 100.1 | + | 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.1 | 199.5 | 299.5 | - | b | 100.1 | 0 | 99.4 | 199.5 | - | e | 199.5 | 99.4 | 0 | 100.1 | - | f | 299.5 | 199.5 | 100.1 | 0 | + | 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 @@ -306,8 +306,8 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | b | e | f | - | a | 100.1 | 199.5 | 299.5 | - | b | 0 | 99.4 | 199.5 | + | 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 @@ -328,8 +328,8 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | f | g | - | f | 0 | 298.2 | - | g | 298.2 | 0 | + | 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 @@ -362,10 +362,10 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | f | g | h | i | - | f | 0 | 298.2 | 0 | 298.2 | - | g | 298.2 | 0 | 298.2 | 0 | - | h | 0 | 298.2 | 0 | 298.2 | - | i | 298.2 | 0 | 298.2 | 0 | + | 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 @@ -383,10 +383,10 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | 1 | 2 | 3 | 4 | - | 1 | 0 | 100.1 | 399.6 | 499.7 | - | 2 | 699.1 | 0 | 299.5 | 399.6 | - | 3 | 399.6 | 499.7 | 0 | 100.1 | - | 4 | 299.5 | 399.6 | 699.1 | 0 | + | 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 distance matrix based on segment durations @@ -424,11 +424,11 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | c | d | e | - | a | 0 | 100.1 | 200.1 | 300.2 | 398.9 | - | b | 100.1 | 0 | 100.1 | 200.1 | 298.9 | - | c | 200.1 | 100.1 | 0 | 100.1 | 198.8 | - | d | 300.2 | 200.1 | 100.1 | 0 | 298.9 | - | e | 398.9 | 298.9 | 198.8 | 298.9 | 0 | + | 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 distance matrix for alternative loop paths Given the profile file @@ -468,25 +468,25 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | - | 1 | 0 | 1096.7 | 298.9 | 199.5 | 598.4 | 498.3 | 897.3 | 797.9 | - | 2 | 100.1 | 0 | 398.9 | 299.5 | 698.5 | 598.4 | 997.3 | 897.9 | - | 3 | 897.9 | 797.9 | 0 | 1097.4 | 299.5 | 199.5 | 598.4 | 499 | - | 4 | 997.3 | 897.3 | 99.4 | 0 | 398.9 | 298.9 | 697.8 | 598.4 | - | 5 | 598.4 | 498.3 | 897.3 | 797.9 | 0 | 1096.7 | 298.9 | 199.5 | - | 6 | 698.5 | 598.4 | 997.3 | 897.9 | 100.1 | 0 | 398.9 | 299.5 | - | 7 | 299.5 | 199.5 | 598.4 | 499 | 897.9 | 797.9 | 0 | 1097.4 | - | 8 | 398.9 | 298.9 | 697.8 | 598.4 | 997.3 | 897.3 | 99.4 | 0 | + | 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 | 897.9 | - | 4 | 997.3 | - | 5 | 598.4 | - | 6 | 698.5 | - | 7 | 299.5 | - | 8 | 398.9 | + | 3 | 899.9 | + | 4 | 1000 | + | 5 | 600 | + | 6 | 700 | + | 7 | 300 | + | 8 | 400 | Scenario: Testbot - Travel distance matrix with ties Given the node map @@ -511,23 +511,23 @@ Feature: Basic Distance Matrix | from | to | route | distance | | a | b | ab,ab | 450m | | a | c | ac,ac | 200m | - | a | d | ac,dc,dc | 499.9m | + | a | d | ac,dc,dc | 500m | When I request a travel distance matrix I should get | | a | b | c | d | - | a | 0 | 450.3 | 198.8 | 499 | + | a | 0 | 450 | 200 | 500 | When I request a travel distance matrix I should get | | a | | a | 0 | - | b | 450.3 | - | c | 198.8 | - | d | 499 | + | b | 450 | + | c | 200 | + | d | 500 | When I request a travel distance matrix I should get | | a | c | - | a | 0 | 198.8 | - | c | 198.8 | 0 | + | a | 0 | 200 | + | c | 200 | 0 | # Check rounding errors @@ -544,7 +544,7 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | c | d | - | a | 0 | 1000.7 | 2001.4 | 3002.1 | + | a | 0 | 1000.1 | 2000 | 3000.1 | Scenario: Testbot - OneToMany vs ManyToOne @@ -562,12 +562,12 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | - | b | 240.4 | 0 | + | b | 241.3 | 0 | When I request a travel distance matrix I should get | | a | | a | 0 | - | b | 240.4 | + | b | 241.3 | Scenario: Testbot - Varying distances between nodes Given the node map @@ -589,12 +589,13 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | c | d | e | f | - | a | 0 | 100.1 | 300.2 | 650.5 | 1930.6 | 1533 | - | b | 759 | 0 | 200.1 | 550.4 | 1830.5 | 1432.9 | - | c | 558.8 | 658.9 | 0 | 350.3 | 1630.4 | 1232.8 | - | d | 1478.9 | 1579 | 1779.1 | 0 | 1280.1 | 882.5 | - | e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 | - | f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 | + | 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 @@ -614,21 +615,21 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | f | 1 | - | a | 0 | 300.2 | 900.7 | 1501.1 | - | b | 300.2 | 0 | 600.5 | 1200.9 | - | f | 900.7 | 600.5 | 0 | 300.2 | - | 1 | 1501.1 | 1200.9 | 300.2 | 0 | + | 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.2 | 900.7 | 1501.1 | + | a | 0 | 300 | 900 | 1500 | When I request a travel distance matrix I should get | | a | | a | 0 | - | b | 300.2 | - | f | 900.7 | - | 1 | 1501.1 | + | b | 300 | + | f | 900 | + | 1 | 1500 | Scenario: Testbot - Fise input coordinate Given a grid size of 300 meters @@ -649,21 +650,21 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | f | 1 | - | a | 0 | 300.2 | 900.7 | 1501.1 | - | b | 300.2 | 0 | 600.5 | 1200.9 | - | f | 900.7 | 600.5 | 0 | 300.2 | - | 1 | 1501.1 | 1200.9 | 300.2 | 0 | + | 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.2 | 900.7 | 1501.1 | + | a | 0 | 300 | 900 | 1500 | When I request a travel distance matrix I should get | | a | | a | 0 | - | b | 300.2 | - | f | 900.7 | - | 1 | 1501.1 | + | b | 300 | + | f | 900 | + | 1 | 1500 | Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate @@ -685,28 +686,28 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | f | 1 | - | a | 0 | 300.2 | 900.7 | 1200.9 | - | b | 300.2 | 0 | 600.5 | 900.7 | - | f | 900.7 | 600.5 | 0 | 300.2 | - | 1 | 1200.9 | 900.7 | 300.2 | 0 | + | 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.2 | 900.7 | 1200.9 | + | a | 0 | 300 | 900 | 1200 | When I request a travel distance matrix I should get | | a | | a | 0 | - | b | 300.2 | - | f | 900.7 | - | 1 | 1200.9 | + | 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 + 1 2 3 """ And the ways @@ -715,11 +716,14 @@ Feature: Basic Distance Matrix | fghij | When I route I should get - | from | to | route | distance | - | 1 | 2 | abcdef,fghij,fghij | 999.9m | + | from | to | route | distance | + | 1 | 2 | abcdef,fghij,fghij | 1000.1m | + | 1 | 3 | abcdef,fghij,fghij | 1400.1m | + | 2 | 3 | fghij,fghij | 400m | + - # TODO: this is "correct", but inconsistent with viaroute When I request a travel distance matrix I should get - | | 1 | 2 | - | 1 | 0 | 1000.7 | - | 2 | 1000.7 | 0 | \ No newline at end of file + | | 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 index dce1b177c08..4c6e1510d64 100644 --- a/features/testbot/duration_matrix.feature +++ b/features/testbot/duration_matrix.feature @@ -21,6 +21,21 @@ Feature: Basic Duration Matrix | 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 @@ -431,15 +446,15 @@ Feature: Basic Duration Matrix | 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 | + | | 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 @@ -476,18 +491,18 @@ Feature: Basic Duration Matrix When I route I should get | from | to | route | distance | time | weight | - | a | c | ac,ac | 200m | 5s | 5 | + | a | c | ac,ac | 200m | 1s | 1 | When I request a travel time matrix I should get - | | a | b | c | d | - | a | 0 | 1 | 5 | 10 | + | | 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 | 15 | - | d | 10 | + | c | 1 | + | d | 6 | Scenario: Testbot - OneToMany vs ManyToOne Given the node map @@ -528,22 +543,22 @@ Feature: Basic Duration Matrix | fhigf | When I request a travel time matrix I should get - | | a | b | f | 1 | - | a | 0 | 30 | 18 | 30 | - | b | 30 | 0 | 12 | 24 | - | f | 18 | 12 | 0 | 30 | - | 1 | 30 | 24 | 30 | 0 | + | | 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 | 18 | 30 | + | | 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 | 18 | - | 1 | 30 | + | | 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 | @@ -581,22 +596,22 @@ Feature: Basic Duration Matrix | fhigf | When I request a travel time matrix I should get - | | a | b | f | 1 | - | a | 0 | 30 | 18 | 30 | - | b | 30 | 0 | 12 | 24 | - | f | 18 | 12 | 0 | 30 | - | 1 | 30 | 24 | 30 | 0 | + | | 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 | 18 | 30 | + | | 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 | 18 | - | 1 | 30 | + | | 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 | @@ -635,22 +650,22 @@ Feature: Basic Duration Matrix | fhigf | When I request a travel time matrix I should get - | | a | b | f | 1 | - | a | 0 | 30 | 18 | 24 | - | b | 30 | 0 | 12 | 18 | - | f | 18 | 12 | 0 | 30 | - | 1 | 24 | 18 | 30 | 0 | + | | 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 | 18 | 24 | + | | 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 | 18 | - | 1 | 24 | + | | 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 | @@ -704,22 +719,22 @@ Feature: Basic Duration Matrix | fhigf | When I request a travel time matrix I should get - | | a | b | f | 1 | - | a | 0 | 60 | 36 | 48 | - | b | 60 | 0 | 24 | 36 | - | f | 36 | 24 | 0 | 60 | - | 1 | 48 | 36 | 60 | 0 | + | | 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 | 36 | 48 | + | | 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 | 36 | - | 1 | 48 | + | | 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 | diff --git a/features/testbot/force_step.feature b/features/testbot/force_step.feature new file mode 100644 index 00000000000..8ad220df10d --- /dev/null +++ b/features/testbot/force_step.feature @@ -0,0 +1,101 @@ +@routing @testbot @via +Feature: Force routing steps + Background: + Given the profile "testbot" + + Scenario: Direct routes with waypoints on same edge + Given the node map + """ + 1 2 + a-------b + | | + d-------c + | | + e-------f + 3 4 + """ + + And the ways + | nodes | oneway | + | ab | no | + | ad | no | + | bc | no | + | cf | no | + | dc | no | + | de | no | + | ef | yes | + + When I route I should get + | waypoints | approaches | weight | route | + | 1,2 | | 20 | ab,ab | + | 1,2 | curb curb | 100 | ab,ad,dc,bc,ab | + | 2,1 | | 20 | ab,ab | + | 2,1 | opposite opposite | 100 | ab,bc,dc,ad,ab | + | 3,4 | | 20 | ef,ef | + | 4,3 | | 100 | ef,cf,dc,de,ef | + + Scenario: Via routes with waypoints on same edge + Given the node map + """ + 1 2 + a-------b + | | + d-5-----c + | | + e-------f + 3 4 + """ + + And the ways + | nodes | oneway | + | ab | no | + | ad | no | + | bc | no | + | cf | no | + | dc | no | + | de | no | + | ef | yes | + + When I route I should get + | waypoints | approaches | weight | route | + | 5,1,2 | | 59.8 | dc,ad,ab,ab,ab | + | 5,1,2 | unrestricted curb curb | 180.2 | dc,bc,ab,ab,ab,ad,dc,bc,ab | + | 5,2,1 | | 80.2 | dc,bc,ab,ab,ab | + | 5,2,1 | unrestricted opposite opposite | 159.8 | dc,ad,ab,ab,ab,bc,dc,ad,ab | + | 5,3,4 | | 59.8 | dc,de,ef,ef,ef | + | 5,4,3 | | 159.8 | dc,de,ef,ef,ef,cf,dc,de,ef | + + + Scenario: [U-turns allowed] Via routes with waypoints on same edge + Given the node map + """ + 1 2 + a-------b + | | + d-5-----c + | | + e-------f + 3 4 + """ + + And the ways + | nodes | oneway | + | ab | no | + | ad | no | + | bc | no | + | cf | no | + | dc | no | + | de | no | + | ef | yes | + + And the query options + | continue_straight | false | + + When I route I should get + | waypoints | approaches | weight | route | + | 5,1,2 | | 59.8 | dc,ad,ab,ab,ab | + | 5,1,2 | unrestricted curb curb | 180.2 | dc,bc,ab,ab,ab,ad,dc,bc,ab | + | 5,2,1 | | 79.8 | dc,ad,ab,ab,ab,ab | + | 5,2,1 | unrestricted opposite opposite | 159.8 | dc,ad,ab,ab,ab,bc,dc,ad,ab | + | 5,3,4 | | 59.8 | dc,de,ef,ef,ef | + | 5,4,3 | | 159.8 | dc,de,ef,ef,ef,cf,dc,de,ef | diff --git a/features/testbot/loop.feature b/features/testbot/loop.feature index 985c8ba6a0e..6c8b0804837 100644 --- a/features/testbot/loop.feature +++ b/features/testbot/loop.feature @@ -75,7 +75,7 @@ Feature: Avoid weird loops caused by rounding errors @412 @via Scenario: Avoid weird loops 3 - And the node map + Given the node map """ a b e diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature index 599afcb1dae..1cf11147292 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 @@ -117,22 +136,6 @@ Feature: Basic Map Matching | trace | matchings | | abcbd | abbd | - Scenario: Testbot - Map matching with core factor - Given the contract extra arguments "--core 0.8" - Given the node map - """ - a b c d - e - """ - - And the ways - | nodes | oneway | - | abcd | no | - - When I match I should get - | trace | timestamps | matchings | - | abcd | 0 1 2 3 | abcd | - Scenario: Testbot - Map matching with small distortion Given the node map """ @@ -279,8 +282,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 +359,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 @@ -652,7 +655,7 @@ Feature: Basic Map Matching When I match I should get | trace | geometry | code | - | defgh | 1,1,1,0.999461,1.000674,0.999461 | Ok | + | defgh | 1,1,1,0.999457,1.000674,0.999457 | Ok | @match @testbot Scenario: Regression test - waypoints trimming too much geometry @@ -682,8 +685,8 @@ Feature: Basic Map Matching | waypoints | 0;3 | | overview | full | When I match I should get - | trace | geometry | code | - | bgkj | 1.000135,1,1.000135,0.99964,1.000387,0.999137 | Ok | + | trace | geometry | code | + | bgkj | 1.000135,1,1.000135,0.999638,1.000386,0.999132 | Ok | @match @testbot @@ -712,12 +715,12 @@ Feature: Basic Map Matching | overview | full | | steps | true | When I match I should get - | trace | geometry | turns | code | - | abc | 1,0.99973,1.00027,0.99973,1.000539,0.99973 | depart,arrive | Ok | - | abd | 1,0.99973,1.00027,0.99973,1.00027,0.999461 | depart,turn right,arrive | Ok | - | abe | 1,0.99973,1.00027,0.99973,1.00027,1 | depart,turn left,arrive | Ok | - | ahd | 1,0.99973,1.00027,0.99973,1.00027,0.999461 | depart,turn right,arrive | Ok | - | ahe | 1,0.99973,1.00027,0.99973,1.00027,1 | depart,turn left,arrive | Ok | + | 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) @@ -740,9 +743,9 @@ Feature: Basic Map Matching | 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.00036,1,1.000405,1,1.00045,1 | 1:1.5:0.5:0.5 | 1:1.5:0.5:0.5 | 3.5 | - | 321 | 1.00045,1,1.000405,1,1.00036,1,1.000225,1,1.000135,1 | 0.5:0.5:1.5:1 | 0.5:0.5:1.5:1 | 3.5 | + | 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) @@ -765,9 +768,9 @@ Feature: Basic Map Matching | 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.000405,1,1.00045,1 | 1:2:0.5 | 1:2:0.5 | 3.5 | - | 4321 | 1.00045,1,1.000405,1,1.000225,1,1.000135,1 | 0.5:2:1 | 0.5:2:1 | 3.5 | + | 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) @@ -790,6 +793,7 @@ Feature: Basic Map Matching # 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.000315,1 | 15.013264 | 1.5 | 1.5 | 1.5 | - | 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 | \ No newline at end of file + | trace | geometry | a:distance | a:duration | a:weight | duration | + | 2345 | 1.00018,1,1.000314,1 | 14.91466649 | 1.4 | 1.4 | 1.4 | + | 4321 | 1.00027,1,1.000135,1 | 15.02596997 | 1.5 | 1.5 | 1.5 | + diff --git a/features/testbot/multi_level_routing.feature b/features/testbot/multi_level_routing.feature index 467ddd26ffd..5ffabec5e4a 100644 --- a/features/testbot/multi_level_routing.feature +++ b/features/testbot/multi_level_routing.feature @@ -110,33 +110,34 @@ Feature: Multi level routing When I request a travel distance matrix I should get | | a | f | l | o | - | a | 0 | 2383.7 | 1566.9 | 1366.8 | - | f | 2383.7 | 0 | 1293.3 | 1617.3 | - | l | 1566.9 | 1293.3 | 0 | 800.5 | - | o | 1366.8 | 1617.3 | 800.5 | 0 | + | 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 | 2383.7 | 1566.9 | 1366.8 | + | a | 0 | 2391.6 | 1570.8 | 1370.9 | When I request a travel distance matrix I should get | | a | | a | 0 | - | f | 2383.7 | - | l | 1566.9 | - | o | 1366.8 | + | 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 | 2383.7 | 1566.9 | 1366.8 | - | f | 2383.7 | 0 | 1293.3 | 1617.3 | + | 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 | 1366.8 | - | f | 2383.7 | 1617.3 | - | l | 1566.9 | 800.5 | - | o | 1366.8 | 0 | + | 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 af8a0b9883a..521720af7b7 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 00000000000..9d728a507a1 --- /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 c21febd07a4..fd14c86f719 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 1fff4bded9e..c70cedb3d9c 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 49a5d8df18e..c5bd6be1830 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 924e84f754c..f9a6fff81c0 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 @@ -182,4 +202,4 @@ Feature: Snap start/end point to the nearest way | x | m | xe,xe | | x | n | xf,xf | | x | o | xg,xg | - | x | p | xh,xh | \ No newline at end of file + | x | p | xh,xh | diff --git a/features/testbot/snap_intersection.feature b/features/testbot/snap_intersection.feature new file mode 100644 index 00000000000..c577c685578 --- /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 | # comment | + | 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 | # comment | + | 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.4s | 141.4 | + + 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.9s | 120.9 | diff --git a/features/testbot/status.feature b/features/testbot/status.feature index 6320924e650..0c52a46d694 100644 --- a/features/testbot/status.feature +++ b/features/testbot/status.feature @@ -58,7 +58,7 @@ Feature: Status messages | nonsense/v1/driving/1,1;1,2 | 400 | Service nonsense not found! | | | 400 | URL string malformed close to position 1: "/" | | / | 400 | URL string malformed close to position 1: "//" | - | ? | 400 | URL string malformed close to position 1: "/?" | + | ? | 400 | URL string malformed close to position 1: "/" | | route/v1/driving | 400 | URL string malformed close to position 17: "ing" | | route/v1/driving/ | 400 | URL string malformed close to position 18: "ng/" | | route/v1/driving/1 | 400 | Query string malformed close to position 19 | diff --git a/features/testbot/traffic_speeds.feature b/features/testbot/traffic_speeds.feature index f5f2198f354..db3b2372b10 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 | - | 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 | - | a | d | ad,ad | 27 km/h | 1275.7,0 | 1 | - | d | c | dc,dc | 36 km/h | 956.8,0 | 0 | - | g | b | fb,fb | 36 km/h | 164.7,0 | 0 | - | a | g | ad,df,fb,fb | 30 km/h | 1295.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 | - | 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 | - | a | d | ad,ad | 27 km/h | 1275.7,0 | 1 | - | d | c | dc,dc | 36 km/h | 956.8,0 | 0 | - | g | b | ab,ab | 1 km/h | 10010.4,0 | 1 | - | 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 | - | a | c | ab,bc,bc | 2 km/h | 20020.73,741.51,0 | 1:1 | - | b | c | bc,bc | 27 km/h | 741.51,0 | 1 | - | 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 | - | a | g | ab,ab | 1 km/h | 10010.36,0 | 1 | - | g | a | ab,ab | 1 km/h | 10010.36,0 | 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) @@ -136,13 +136,13 @@ Feature: Traffic - speeds When I route I should get | from | to | route | speed | weights | a:datasources | a:speed | a:nodes| - | a | b | fb,fb | 36 km/h | 329.4,0 | 0 | 10 | 6:2 | - | a | c | fb,bc,bc | 30 km/h | 329.4,741.5,0 | 0:1 | 10:7.5 | 6:2:3 | - | b | c | bc,bc | 27 km/h | 741.5,0 | 1 | 7.5 | 2:3 | - | a | d | fb,df,df | 36 km/h | 140,487.5,0 | 0:0 | 10:10 | 2:6:4 | - | d | c | dc,dc | 36 km/h | 956.8,0 | 0 | 10 | 4:3 | - | g | b | fb,fb | 36 km/h | 164.7,0 | 0 | 10 | 6:2 | - | a | g | fb,fb | 36 km/h | 164.7,0 | 0 | 10 | 6:2 | + | 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 9d3c454121a..86bdeded125 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 c254f8d75ad..531ccaa48e4 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,7 +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) + Scenario: Testbot - Trip: FS waypoints (less than 10) + Given the query options + | 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 @@ -93,12 +161,41 @@ Feature: Basic trip planning | 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 | + | 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: Roundtrip FE waypoints (more than 10) + Scenario: Testbot - Trip: FE waypoints (less than 10) Given the query options - | source | last | + | 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 @@ -122,8 +219,9 @@ 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 | 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 017cc54e6ec..44a2aaeebee 100644 --- a/features/testbot/via.feature +++ b/features/testbot/via.feature @@ -65,32 +65,6 @@ Feature: Via points | 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 - """ - a b c d - e f g - h i - j - """ - - And the ways - | nodes | - | abcd | - | efg | - | hi | - | be | - | cfh | - | dgij | - - When I route I should get - | waypoints | route | - | a,b,c | abcd,abcd,abcd,abcd | - | c,b,a | abcd,abcd,abcd,abcd | - | a,d,j | abcd,abcd,dgij,dgij | - | j,d,a | dgij,dgij,abcd,abcd | - Scenario: Via point at a dead end Given the node map """ diff --git a/features/testbot/weight.feature b/features/testbot/weight.feature index eae35c0ff5b..cded39b67fe 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 | 2.1 | 2.1 | 9.5 | - | t,s | abc,abc | 20m,0m | 2.1,0 | 2.1s,0s | 20.017685 | 2.1 | 2.1 | 9.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.03462663 | 2 | 2 | 10 | + | t,s | abc,abc | 20m,0m | 2,0 | 2s,0s | 20.03462663 | 2 | 2 | 10 | + | s,e | abc,abc | 40m,0m | 3.9,0 | 3.9s,0s | 29.94063646:10.01731331 | 3:0.9 | 3:0.9 | 10:11.1 | + | e,s | abc,abc | 40m,0m | 3.9,0 | 3.9s,0s | 10.01731331:29.94063646 | 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 6acb2b0c887..ae5a99c7f78 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 5f5fdc81c3f..312bb498f02 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/generated/include/engine/api/flatbuffers/fbresult_generated.h b/generated/include/engine/api/flatbuffers/fbresult_generated.h new file mode 100644 index 00000000000..0f01298198f --- /dev/null +++ b/generated/include/engine/api/flatbuffers/fbresult_generated.h @@ -0,0 +1,249 @@ +// 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" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 24 && + FLATBUFFERS_VERSION_MINOR == 3 && + FLATBUFFERS_VERSION_REVISION == 25, + "Non-compatible flatbuffers version included"); + +#include "route_generated.h" +#include "table_generated.h" + +namespace osrm { +namespace engine { +namespace api { +namespace fbresult { + +struct Error; +struct ErrorBuilder; + +struct FBResult; +struct FBResultBuilder; + +struct Error FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ErrorBuilder Builder; + 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(); + } +}; + +struct ErrorBuilder { + typedef Error Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_code(::flatbuffers::Offset<::flatbuffers::String> code) { + fbb_.AddOffset(Error::VT_CODE, code); + } + void add_message(::flatbuffers::Offset<::flatbuffers::String> message) { + fbb_.AddOffset(Error::VT_MESSAGE, message); + } + explicit ErrorBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::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<::flatbuffers::String> code = 0, + ::flatbuffers::Offset<::flatbuffers::String> 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__); +} + +struct FBResult FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef FBResultBuilder Builder; + 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<::flatbuffers::Offset> *waypoints() const { + return GetPointer> *>(VT_WAYPOINTS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *routes() const { + return GetPointer> *>(VT_ROUTES); + } + const osrm::engine::api::fbresult::TableResult *table() const { + return GetPointer(VT_TABLE); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ERROR, 1) && + 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(); + } +}; + +struct FBResultBuilder { + typedef FBResult Table; + ::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<::flatbuffers::String> data_version) { + fbb_.AddOffset(FBResult::VT_DATA_VERSION, data_version); + } + void add_waypoints(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> waypoints) { + fbb_.AddOffset(FBResult::VT_WAYPOINTS, waypoints); + } + void add_routes(::flatbuffers::Offset<::flatbuffers::Vector<::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(); + } + ::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<::flatbuffers::String> data_version = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> waypoints = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::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<::flatbuffers::Offset> *waypoints = nullptr, + const std::vector<::flatbuffers::Offset> *routes = nullptr, + ::flatbuffers::Offset table = 0) { + auto data_version__ = data_version ? _fbb.CreateString(data_version) : 0; + auto waypoints__ = waypoints ? _fbb.CreateVector<::flatbuffers::Offset>(*waypoints) : 0; + auto routes__ = routes ? _fbb.CreateVector<::flatbuffers::Offset>(*routes) : 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); +} + +} // namespace fbresult +} // namespace api +} // namespace engine +} // namespace osrm + +#endif // FLATBUFFERS_GENERATED_FBRESULT_OSRM_ENGINE_API_FBRESULT_H_ diff --git a/generated/include/engine/api/flatbuffers/position_generated.h b/generated/include/engine/api/flatbuffers/position_generated.h new file mode 100644 index 00000000000..aa3ea2d8b21 --- /dev/null +++ b/generated/include/engine/api/flatbuffers/position_generated.h @@ -0,0 +1,51 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_POSITION_OSRM_ENGINE_API_FBRESULT_H_ +#define FLATBUFFERS_GENERATED_POSITION_OSRM_ENGINE_API_FBRESULT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 24 && + FLATBUFFERS_VERSION_MINOR == 3 && + FLATBUFFERS_VERSION_REVISION == 25, + "Non-compatible flatbuffers version included"); + +namespace osrm { +namespace engine { +namespace api { +namespace fbresult { + +struct Position; + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Position FLATBUFFERS_FINAL_CLASS { + private: + float longitude_; + float latitude_; + + public: + Position() + : longitude_(0), + latitude_(0) { + } + 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); + +} // namespace fbresult +} // namespace api +} // namespace engine +} // namespace osrm + +#endif // FLATBUFFERS_GENERATED_POSITION_OSRM_ENGINE_API_FBRESULT_H_ diff --git a/generated/include/engine/api/flatbuffers/route_generated.h b/generated/include/engine/api/flatbuffers/route_generated.h new file mode 100644 index 00000000000..6ae492bd429 --- /dev/null +++ b/generated/include/engine/api/flatbuffers/route_generated.h @@ -0,0 +1,1156 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_ROUTE_OSRM_ENGINE_API_FBRESULT_H_ +#define FLATBUFFERS_GENERATED_ROUTE_OSRM_ENGINE_API_FBRESULT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 24 && + FLATBUFFERS_VERSION_MINOR == 3 && + FLATBUFFERS_VERSION_REVISION == 25, + "Non-compatible flatbuffers version included"); + +#include "waypoint_generated.h" + +namespace osrm { +namespace engine { +namespace api { +namespace fbresult { + +struct Metadata; +struct MetadataBuilder; + +struct Annotation; +struct AnnotationBuilder; + +struct StepManeuver; +struct StepManeuverBuilder; + +struct Lane; +struct LaneBuilder; + +struct Intersection; +struct IntersectionBuilder; + +struct Step; +struct StepBuilder; + +struct Leg; +struct LegBuilder; + +struct RouteObject; +struct RouteObjectBuilder; + +enum ManeuverType : int8_t { + 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 (::flatbuffers::IsOutRange(e, ManeuverType_Turn, ManeuverType_ExitRotary)) return ""; + const size_t index = static_cast(e); + return EnumNamesManeuverType()[index]; +} + +enum Turn : int8_t { + 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 (::flatbuffers::IsOutRange(e, Turn_None, Turn_SharpLeft)) return ""; + const size_t index = static_cast(e); + return EnumNamesTurn()[index]; +} + +struct Metadata FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef MetadataBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DATASOURCE_NAMES = 4 + }; + const ::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>> *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(); + } +}; + +struct MetadataBuilder { + typedef Metadata Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_datasource_names(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> datasource_names) { + fbb_.AddOffset(Metadata::VT_DATASOURCE_NAMES, datasource_names); + } + explicit MetadataBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::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<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> 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<::flatbuffers::Offset<::flatbuffers::String>> *datasource_names = nullptr) { + auto datasource_names__ = datasource_names ? _fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::String>>(*datasource_names) : 0; + return osrm::engine::api::fbresult::CreateMetadata( + _fbb, + datasource_names__); +} + +struct Annotation FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AnnotationBuilder Builder; + 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(); + } +}; + +struct AnnotationBuilder { + typedef Annotation Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_distance(::flatbuffers::Offset<::flatbuffers::Vector> distance) { + fbb_.AddOffset(Annotation::VT_DISTANCE, distance); + } + void add_duration(::flatbuffers::Offset<::flatbuffers::Vector> duration) { + fbb_.AddOffset(Annotation::VT_DURATION, duration); + } + void add_datasources(::flatbuffers::Offset<::flatbuffers::Vector> datasources) { + fbb_.AddOffset(Annotation::VT_DATASOURCES, datasources); + } + void add_nodes(::flatbuffers::Offset<::flatbuffers::Vector> nodes) { + fbb_.AddOffset(Annotation::VT_NODES, nodes); + } + void add_weight(::flatbuffers::Offset<::flatbuffers::Vector> weight) { + fbb_.AddOffset(Annotation::VT_WEIGHT, weight); + } + void add_speed(::flatbuffers::Offset<::flatbuffers::Vector> 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(); + } + ::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<::flatbuffers::Vector> distance = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> duration = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> datasources = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> nodes = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> weight = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> 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); +} + +struct StepManeuver FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef StepManeuverBuilder Builder; + 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, 4) && + VerifyField(verifier, VT_BEARING_BEFORE, 2) && + VerifyField(verifier, VT_BEARING_AFTER, 2) && + VerifyField(verifier, VT_TYPE, 1) && + VerifyField(verifier, VT_MODIFIER, 1) && + VerifyField(verifier, VT_EXIT, 1) && + verifier.EndTable(); + } +}; + +struct StepManeuverBuilder { + typedef StepManeuver Table; + ::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(); + } + ::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 = nullptr, + 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(); +} + +struct Lane FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef LaneBuilder Builder; + 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, 1) && + verifier.EndTable(); + } +}; + +struct LaneBuilder { + typedef Lane Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_indications(::flatbuffers::Offset<::flatbuffers::Vector> 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(); + } + ::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<::flatbuffers::Vector> 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); +} + +struct Intersection FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef IntersectionBuilder Builder; + 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<::flatbuffers::Offset<::flatbuffers::String>> *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<::flatbuffers::Offset> *lanes() const { + return GetPointer> *>(VT_LANES); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_LOCATION, 4) && + 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, 4) && + VerifyField(verifier, VT_OUT_BEARING, 4) && + VerifyOffset(verifier, VT_LANES) && + verifier.VerifyVector(lanes()) && + verifier.VerifyVectorOfTables(lanes()) && + verifier.EndTable(); + } +}; + +struct IntersectionBuilder { + typedef Intersection Table; + ::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<::flatbuffers::Vector> bearings) { + fbb_.AddOffset(Intersection::VT_BEARINGS, bearings); + } + void add_classes(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> classes) { + fbb_.AddOffset(Intersection::VT_CLASSES, classes); + } + void add_entry(::flatbuffers::Offset<::flatbuffers::Vector> 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<::flatbuffers::Vector<::flatbuffers::Offset>> lanes) { + fbb_.AddOffset(Intersection::VT_LANES, lanes); + } + explicit IntersectionBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::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 = nullptr, + ::flatbuffers::Offset<::flatbuffers::Vector> bearings = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> classes = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> entry = 0, + uint32_t in_bearing = 0, + uint32_t out_bearing = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::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 = nullptr, + const std::vector *bearings = nullptr, + const std::vector<::flatbuffers::Offset<::flatbuffers::String>> *classes = nullptr, + const std::vector *entry = nullptr, + uint32_t in_bearing = 0, + uint32_t out_bearing = 0, + const std::vector<::flatbuffers::Offset> *lanes = nullptr) { + auto bearings__ = bearings ? _fbb.CreateVector(*bearings) : 0; + auto classes__ = classes ? _fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::String>>(*classes) : 0; + auto entry__ = entry ? _fbb.CreateVector(*entry) : 0; + auto lanes__ = lanes ? _fbb.CreateVector<::flatbuffers::Offset>(*lanes) : 0; + return osrm::engine::api::fbresult::CreateIntersection( + _fbb, + location, + bearings__, + classes__, + entry__, + in_bearing, + out_bearing, + lanes__); +} + +struct Step FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef StepBuilder Builder; + 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<::flatbuffers::Offset> *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, 4) && + VerifyField(verifier, VT_DURATION, 4) && + VerifyOffset(verifier, VT_POLYLINE) && + verifier.VerifyString(polyline()) && + VerifyOffset(verifier, VT_COORDINATES) && + verifier.VerifyVector(coordinates()) && + VerifyField(verifier, VT_WEIGHT, 4) && + 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, 1) && + verifier.EndTable(); + } +}; + +struct StepBuilder { + typedef Step Table; + ::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<::flatbuffers::String> polyline) { + fbb_.AddOffset(Step::VT_POLYLINE, polyline); + } + void add_coordinates(::flatbuffers::Offset<::flatbuffers::Vector> 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<::flatbuffers::String> name) { + fbb_.AddOffset(Step::VT_NAME, name); + } + void add_ref(::flatbuffers::Offset<::flatbuffers::String> ref) { + fbb_.AddOffset(Step::VT_REF, ref); + } + void add_pronunciation(::flatbuffers::Offset<::flatbuffers::String> pronunciation) { + fbb_.AddOffset(Step::VT_PRONUNCIATION, pronunciation); + } + void add_destinations(::flatbuffers::Offset<::flatbuffers::String> destinations) { + fbb_.AddOffset(Step::VT_DESTINATIONS, destinations); + } + void add_exits(::flatbuffers::Offset<::flatbuffers::String> exits) { + fbb_.AddOffset(Step::VT_EXITS, exits); + } + void add_mode(::flatbuffers::Offset<::flatbuffers::String> mode) { + fbb_.AddOffset(Step::VT_MODE, mode); + } + void add_maneuver(::flatbuffers::Offset maneuver) { + fbb_.AddOffset(Step::VT_MANEUVER, maneuver); + } + void add_intersections(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> intersections) { + fbb_.AddOffset(Step::VT_INTERSECTIONS, intersections); + } + void add_rotary_name(::flatbuffers::Offset<::flatbuffers::String> rotary_name) { + fbb_.AddOffset(Step::VT_ROTARY_NAME, rotary_name); + } + void add_rotary_pronunciation(::flatbuffers::Offset<::flatbuffers::String> 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(); + } + ::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<::flatbuffers::String> polyline = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> coordinates = 0, + float weight = 0.0f, + ::flatbuffers::Offset<::flatbuffers::String> name = 0, + ::flatbuffers::Offset<::flatbuffers::String> ref = 0, + ::flatbuffers::Offset<::flatbuffers::String> pronunciation = 0, + ::flatbuffers::Offset<::flatbuffers::String> destinations = 0, + ::flatbuffers::Offset<::flatbuffers::String> exits = 0, + ::flatbuffers::Offset<::flatbuffers::String> mode = 0, + ::flatbuffers::Offset maneuver = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> intersections = 0, + ::flatbuffers::Offset<::flatbuffers::String> rotary_name = 0, + ::flatbuffers::Offset<::flatbuffers::String> 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<::flatbuffers::Offset> *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<::flatbuffers::Offset>(*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); +} + +struct Leg FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef LegBuilder Builder; + 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<::flatbuffers::Offset> *steps() const { + return GetPointer> *>(VT_STEPS); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_DISTANCE, 8) && + VerifyField(verifier, VT_DURATION, 8) && + VerifyField(verifier, VT_WEIGHT, 8) && + 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(); + } +}; + +struct LegBuilder { + typedef Leg Table; + ::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<::flatbuffers::String> summary) { + fbb_.AddOffset(Leg::VT_SUMMARY, summary); + } + void add_annotations(::flatbuffers::Offset annotations) { + fbb_.AddOffset(Leg::VT_ANNOTATIONS, annotations); + } + void add_steps(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> steps) { + fbb_.AddOffset(Leg::VT_STEPS, steps); + } + explicit LegBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::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<::flatbuffers::String> summary = 0, + ::flatbuffers::Offset annotations = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::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<::flatbuffers::Offset> *steps = nullptr) { + auto summary__ = summary ? _fbb.CreateString(summary) : 0; + auto steps__ = steps ? _fbb.CreateVector<::flatbuffers::Offset>(*steps) : 0; + return osrm::engine::api::fbresult::CreateLeg( + _fbb, + distance, + duration, + weight, + summary__, + annotations, + steps__); +} + +struct RouteObject FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef RouteObjectBuilder Builder; + 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<::flatbuffers::Offset> *legs() const { + return GetPointer> *>(VT_LEGS); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_DISTANCE, 4) && + VerifyField(verifier, VT_DURATION, 4) && + VerifyField(verifier, VT_WEIGHT, 4) && + VerifyOffset(verifier, VT_WEIGHT_NAME) && + verifier.VerifyString(weight_name()) && + VerifyField(verifier, VT_CONFIDENCE, 4) && + 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(); + } +}; + +struct RouteObjectBuilder { + typedef RouteObject Table; + ::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<::flatbuffers::String> 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<::flatbuffers::String> polyline) { + fbb_.AddOffset(RouteObject::VT_POLYLINE, polyline); + } + void add_coordinates(::flatbuffers::Offset<::flatbuffers::Vector> coordinates) { + fbb_.AddOffset(RouteObject::VT_COORDINATES, coordinates); + } + void add_legs(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> legs) { + fbb_.AddOffset(RouteObject::VT_LEGS, legs); + } + explicit RouteObjectBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::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<::flatbuffers::String> weight_name = 0, + float confidence = 0.0f, + ::flatbuffers::Offset<::flatbuffers::String> polyline = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> coordinates = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::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<::flatbuffers::Offset> *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<::flatbuffers::Offset>(*legs) : 0; + return osrm::engine::api::fbresult::CreateRouteObject( + _fbb, + distance, + duration, + weight, + weight_name__, + confidence, + polyline__, + coordinates__, + legs__); +} + +} // namespace fbresult +} // namespace api +} // namespace engine +} // namespace osrm + +#endif // FLATBUFFERS_GENERATED_ROUTE_OSRM_ENGINE_API_FBRESULT_H_ diff --git a/generated/include/engine/api/flatbuffers/table_generated.h b/generated/include/engine/api/flatbuffers/table_generated.h new file mode 100644 index 00000000000..30c6bd81ca8 --- /dev/null +++ b/generated/include/engine/api/flatbuffers/table_generated.h @@ -0,0 +1,149 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_TABLE_OSRM_ENGINE_API_FBRESULT_H_ +#define FLATBUFFERS_GENERATED_TABLE_OSRM_ENGINE_API_FBRESULT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 24 && + FLATBUFFERS_VERSION_MINOR == 3 && + FLATBUFFERS_VERSION_REVISION == 25, + "Non-compatible flatbuffers version included"); + +#include "waypoint_generated.h" + +namespace osrm { +namespace engine { +namespace api { +namespace fbresult { + +struct TableResult; +struct TableResultBuilder; + +struct TableResult FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef TableResultBuilder Builder; + 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<::flatbuffers::Offset> *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, 2) && + VerifyField(verifier, VT_COLS, 2) && + 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(); + } +}; + +struct TableResultBuilder { + typedef TableResult Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_durations(::flatbuffers::Offset<::flatbuffers::Vector> durations) { + fbb_.AddOffset(TableResult::VT_DURATIONS, durations); + } + void add_rows(uint16_t rows) { + fbb_.AddElement(TableResult::VT_ROWS, rows, 0); + } + void add_cols(uint16_t cols) { + fbb_.AddElement(TableResult::VT_COLS, cols, 0); + } + void add_distances(::flatbuffers::Offset<::flatbuffers::Vector> distances) { + fbb_.AddOffset(TableResult::VT_DISTANCES, distances); + } + void add_destinations(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> destinations) { + fbb_.AddOffset(TableResult::VT_DESTINATIONS, destinations); + } + void add_fallback_speed_cells(::flatbuffers::Offset<::flatbuffers::Vector> fallback_speed_cells) { + fbb_.AddOffset(TableResult::VT_FALLBACK_SPEED_CELLS, fallback_speed_cells); + } + explicit TableResultBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateTableResult( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset<::flatbuffers::Vector> durations = 0, + uint16_t rows = 0, + uint16_t cols = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> distances = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> destinations = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> fallback_speed_cells = 0) { + TableResultBuilder 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 CreateTableResultDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *durations = nullptr, + uint16_t rows = 0, + uint16_t cols = 0, + const std::vector *distances = nullptr, + const std::vector<::flatbuffers::Offset> *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<::flatbuffers::Offset>(*destinations) : 0; + auto fallback_speed_cells__ = fallback_speed_cells ? _fbb.CreateVector(*fallback_speed_cells) : 0; + return osrm::engine::api::fbresult::CreateTableResult( + _fbb, + durations__, + rows, + cols, + distances__, + destinations__, + fallback_speed_cells__); +} + +} // namespace fbresult +} // namespace api +} // namespace engine +} // namespace osrm + +#endif // FLATBUFFERS_GENERATED_TABLE_OSRM_ENGINE_API_FBRESULT_H_ diff --git a/generated/include/engine/api/flatbuffers/waypoint_generated.h b/generated/include/engine/api/flatbuffers/waypoint_generated.h new file mode 100644 index 00000000000..3fae94975d7 --- /dev/null +++ b/generated/include/engine/api/flatbuffers/waypoint_generated.h @@ -0,0 +1,205 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_WAYPOINT_OSRM_ENGINE_API_FBRESULT_H_ +#define FLATBUFFERS_GENERATED_WAYPOINT_OSRM_ENGINE_API_FBRESULT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 24 && + FLATBUFFERS_VERSION_MINOR == 3 && + FLATBUFFERS_VERSION_REVISION == 25, + "Non-compatible flatbuffers version included"); + +#include "position_generated.h" + +namespace osrm { +namespace engine { +namespace api { +namespace fbresult { + +struct Uint64Pair; + +struct Waypoint; +struct WaypointBuilder; + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Uint64Pair FLATBUFFERS_FINAL_CLASS { + private: + uint64_t first_; + uint64_t second_; + + public: + Uint64Pair() + : first_(0), + second_(0) { + } + 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 Waypoint FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef WaypointBuilder Builder; + 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, 4) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField(verifier, VT_LOCATION, 4) && + VerifyField(verifier, VT_NODES, 8) && + VerifyField(verifier, VT_MATCHINGS_INDEX, 4) && + VerifyField(verifier, VT_WAYPOINT_INDEX, 4) && + VerifyField(verifier, VT_ALTERNATIVES_COUNT, 4) && + VerifyField(verifier, VT_TRIPS_INDEX, 4) && + verifier.EndTable(); + } +}; + +struct WaypointBuilder { + typedef Waypoint Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_hint(::flatbuffers::Offset<::flatbuffers::String> 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<::flatbuffers::String> 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(); + } + ::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<::flatbuffers::String> hint = 0, + float distance = 0.0f, + ::flatbuffers::Offset<::flatbuffers::String> name = 0, + const osrm::engine::api::fbresult::Position *location = nullptr, + const osrm::engine::api::fbresult::Uint64Pair *nodes = nullptr, + 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 = nullptr, + const osrm::engine::api::fbresult::Uint64Pair *nodes = nullptr, + 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); +} + +} // namespace fbresult +} // namespace api +} // namespace engine +} // namespace osrm + +#endif // FLATBUFFERS_GENERATED_WAYPOINT_OSRM_ENGINE_API_FBRESULT_H_ diff --git a/include/contractor/contract_excludable_graph.hpp b/include/contractor/contract_excludable_graph.hpp index 6ae29282a26..75e3aceda0f 100644 --- a/include/contractor/contract_excludable_graph.hpp +++ b/include/contractor/contract_excludable_graph.hpp @@ -7,9 +7,7 @@ #include "contractor/graph_contractor_adaptors.hpp" #include "contractor/query_graph.hpp" -namespace osrm -{ -namespace contractor +namespace osrm::contractor { using GraphAndFilter = std::tuple>>; @@ -18,12 +16,12 @@ inline auto contractFullGraph(ContractorGraph contractor_graph, std::vector node_weights) { auto num_nodes = contractor_graph.GetNumberOfNodes(); - contractGraph(contractor_graph, node_weights); + 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, std::move(edges)}, {std::move(edge_filter)}}; + return GraphAndFilter{QueryGraph{num_nodes, edges}, {std::move(edge_filter)}}; } inline auto contractExcludableGraph(ContractorGraph contractor_graph_, @@ -56,17 +54,19 @@ 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; + 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 { auto non_core_edges = toEdges(contractor_graph); - auto new_end = - std::remove_if(non_core_edges.begin(), non_core_edges.end(), [&](const auto &edge) { - return is_shared_core[edge.source] && is_shared_core[edge.target]; - }); + auto new_end = std::remove_if(non_core_edges.begin(), + non_core_edges.end(), + [&](const auto &edge) { + return is_shared_core[edge.source] && + is_shared_core[edge.target]; + }); non_core_edges.resize(new_end - non_core_edges.begin()); edge_container.Insert(std::move(non_core_edges)); @@ -77,8 +77,8 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_, } // Extract core graph for further contraction - shared_core_graph = contractor_graph.Filter( - [&is_shared_core](const NodeID node) { return is_shared_core[node]; }); + shared_core_graph = contractor_graph.Filter([&is_shared_core](const NodeID node) + { return is_shared_core[node]; }); } for (const auto &filter : filters) @@ -91,10 +91,9 @@ inline auto contractExcludableGraph(ContractorGraph contractor_graph_, edge_container.Merge(toEdges(std::move(filtered_core_graph))); } - return GraphAndFilter{QueryGraph{num_nodes, std::move(edge_container.edges)}, + return GraphAndFilter{QueryGraph{num_nodes, edge_container.edges}, edge_container.MakeEdgeFilters()}; } -} -} +} // namespace osrm::contractor #endif diff --git a/include/contractor/contracted_edge_container.hpp b/include/contractor/contracted_edge_container.hpp index 8b37f5d4a62..c7fe48fb685 100644 --- a/include/contractor/contracted_edge_container.hpp +++ b/include/contractor/contracted_edge_container.hpp @@ -14,9 +14,7 @@ #include #include -namespace osrm -{ -namespace contractor +namespace osrm::contractor { struct ContractedEdgeContainer @@ -91,37 +89,40 @@ struct ContractedEdgeContainer // 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; - } - - // 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++; - } - - // all new edges will be sorted after the old edges - if (edge_iter == edge_end) - { - return false; - } - - 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; - }); + 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; + } + + // 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++; + } + + // all new edges will be sorted after the old edges + if (edge_iter == edge_end) + { + return false; + } + + 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; + }); // append new edges edges.insert(edges.end(), new_edges.begin(), new_end); @@ -134,10 +135,10 @@ struct ContractedEdgeContainer // 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]); - }); + 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); util::inplacePermutation(edges.begin(), edges.end(), permutation); @@ -164,7 +165,6 @@ struct ContractedEdgeContainer std::vector flags; std::vector edges; }; -} -} +} // namespace osrm::contractor #endif diff --git a/include/contractor/contracted_metric.hpp b/include/contractor/contracted_metric.hpp index f44f49e8320..b41d7f2acef 100644 --- a/include/contractor/contracted_metric.hpp +++ b/include/contractor/contracted_metric.hpp @@ -3,9 +3,7 @@ #include "contractor/query_graph.hpp" -namespace osrm -{ -namespace contractor +namespace osrm::contractor { namespace detail @@ -15,11 +13,10 @@ template struct ContractedMetric detail::QueryGraph graph; std::vector> edge_filter; }; -} +} // namespace detail using ContractedMetric = detail::ContractedMetric; using ContractedMetricView = detail::ContractedMetric; -} -} +} // namespace osrm::contractor #endif diff --git a/include/contractor/contractor.hpp b/include/contractor/contractor.hpp index ee1d2dd4233..4bd38b52bde 100644 --- a/include/contractor/contractor.hpp +++ b/include/contractor/contractor.hpp @@ -30,9 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "contractor/contractor_config.hpp" -namespace osrm -{ -namespace contractor +namespace osrm::contractor { /// Base class of osrm-contract @@ -49,7 +47,6 @@ class Contractor private: ContractorConfig config; }; -} -} +} // namespace osrm::contractor #endif // PROCESSING_CHAIN_HPP diff --git a/include/contractor/contractor_config.hpp b/include/contractor/contractor_config.hpp index 8f1455ccefa..2a30d9e8ebe 100644 --- a/include/contractor/contractor_config.hpp +++ b/include/contractor/contractor_config.hpp @@ -31,27 +31,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "storage/io_config.hpp" #include "updater/updater_config.hpp" -#include +#include -#include - -namespace osrm -{ -namespace contractor +namespace osrm::contractor { struct ContractorConfig final : storage::IOConfig { ContractorConfig() - : IOConfig({".osrm.ebg", ".osrm.ebg_nodes", ".osrm.properties"}, - {}, - {".osrm.hsgr", ".osrm.enw"}), - requested_num_threads(0) + : IOConfig( + {".osrm.ebg", ".osrm.ebg_nodes", ".osrm.properties"}, {}, {".osrm.hsgr", ".osrm.enw"}) { } // Infer the output names from the path of the .osrm file - void UseDefaultOutputNames(const boost::filesystem::path &base) + void UseDefaultOutputNames(const std::filesystem::path &base) { IOConfig::UseDefaultOutputNames(base); updater_config.UseDefaultOutputNames(base); @@ -61,19 +55,8 @@ struct ContractorConfig final : storage::IOConfig updater::UpdaterConfig updater_config; - // DEPRECATED to be removed in v6.0 - bool use_cached_priority; - - unsigned requested_num_threads; - - // 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; + unsigned requested_num_threads = 0; }; -} -} +} // namespace osrm::contractor #endif // EXTRACTOR_OPTIONS_HPP diff --git a/include/contractor/contractor_graph.hpp b/include/contractor/contractor_graph.hpp index 02cad2e0840..e88a5185c73 100644 --- a/include/contractor/contractor_graph.hpp +++ b/include/contractor/contractor_graph.hpp @@ -4,20 +4,18 @@ #include "util/dynamic_graph.hpp" #include -namespace osrm -{ -namespace contractor +namespace osrm::contractor { struct ContractorEdgeData { ContractorEdgeData() - : weight(0), duration(0), distance(0), id(0), originalEdges(0), shortcut(0), forward(0), + : weight{0}, duration{0}, distance{0}, id(0), originalEdges(0), shortcut(0), forward(0), backward(0) { } ContractorEdgeData(EdgeWeight weight, - EdgeWeight duration, + EdgeDuration duration, EdgeDistance distance, unsigned original_edges, unsigned id, @@ -30,7 +28,7 @@ struct ContractorEdgeData { } EdgeWeight weight; - EdgeWeight duration; + EdgeDuration duration; EdgeDistance distance; unsigned id; unsigned originalEdges : 29; @@ -42,7 +40,6 @@ struct ContractorEdgeData using ContractorGraph = util::DynamicGraph; using ContractorEdge = ContractorGraph::InputEdge; -} // namespace contractor -} // namespace osrm +} // namespace osrm::contractor #endif // OSRM_CONTRACTOR_CONTRACTOR_GRAPH_HPP_ diff --git a/include/contractor/contractor_heap.hpp b/include/contractor/contractor_heap.hpp index 7f505bb8aec..fc581f3b01b 100644 --- a/include/contractor/contractor_heap.hpp +++ b/include/contractor/contractor_heap.hpp @@ -5,9 +5,7 @@ #include "util/typedefs.hpp" #include "util/xor_fast_hash_storage.hpp" -namespace osrm -{ -namespace contractor +namespace osrm::contractor { struct ContractorHeapData { @@ -24,7 +22,6 @@ using ContractorHeap = util::QueryHeap>; -} // namespace contractor -} // namespace osrm +} // namespace osrm::contractor #endif // OSRM_CONTRACTOR_CONTRACTOR_HEAP_HPP_ diff --git a/include/contractor/contractor_search.hpp b/include/contractor/contractor_search.hpp index 246228980c0..6911a44bb2c 100644 --- a/include/contractor/contractor_search.hpp +++ b/include/contractor/contractor_search.hpp @@ -8,19 +8,17 @@ #include -namespace osrm -{ -namespace contractor +namespace osrm::contractor { void search(ContractorHeap &heap, const ContractorGraph &graph, + const std::vector &contractable, const unsigned number_of_targets, const int node_limit, const EdgeWeight weight_limit, const NodeID forbidden_node); -} // namespace contractor -} // namespace osrm +} // namespace osrm::contractor #endif // OSRM_CONTRACTOR_DIJKSTRA_HPP diff --git a/include/contractor/crc32_processor.hpp b/include/contractor/crc32_processor.hpp deleted file mode 100644 index 4130ed58315..00000000000 --- a/include/contractor/crc32_processor.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef ITERATOR_BASED_CRC32_H -#define ITERATOR_BASED_CRC32_H - -#if defined(__x86_64__) && !defined(__MINGW64__) -#include -#endif - -#include // for boost::crc_32_type - -#include - -namespace osrm -{ -namespace contractor -{ - -class IteratorbasedCRC32 -{ - public: - bool UsingHardware() const { return use_hardware_implementation; } - - IteratorbasedCRC32() : crc(0) { use_hardware_implementation = DetectHardwareSupport(); } - - template unsigned operator()(Iterator iter, const Iterator end) - { - unsigned crc = 0; - while (iter != end) - { - using value_type = typename std::iterator_traits::value_type; - const char *data = reinterpret_cast(&(*iter)); - - if (use_hardware_implementation) - { - crc = ComputeInHardware(data, sizeof(value_type)); - } - else - { - crc = ComputeInSoftware(data, sizeof(value_type)); - } - ++iter; - } - return crc; - } - - private: - bool DetectHardwareSupport() const - { - static const int sse42_bit = 0x00100000; - const unsigned ecx = cpuid(); - const bool sse42_found = (ecx & sse42_bit) != 0; - return sse42_found; - } - - unsigned ComputeInSoftware(const char *str, unsigned len) - { - crc_processor.process_bytes(str, len); - return crc_processor.checksum(); - } - - // adapted from http://byteworm.com/2010/10/13/crc32/ - unsigned ComputeInHardware(const char *str, unsigned len) - { -#if defined(__x86_64__) - unsigned q = len / sizeof(unsigned); - unsigned r = len % sizeof(unsigned); - unsigned *p = (unsigned *)str; - - // crc=0; - while (q--) - { - __asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;" - : "=S"(crc) - : "0"(crc), "c"(*p)); - ++p; - } - - str = reinterpret_cast(p); - while (r--) - { - __asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;" - : "=S"(crc) - : "0"(crc), "c"(*str)); - ++str; - } -#else - (void)str; - (void)len; -#endif - return crc; - } - - inline unsigned cpuid() const - { - unsigned eax = 0, ebx = 0, ecx = 0, edx = 0; - // on X64 this calls hardware cpuid(.) instr. otherwise a dummy impl. - __get_cpuid(1, &eax, &ebx, &ecx, &edx); - return ecx; - } - -#if defined(__MINGW64__) || defined(_MSC_VER) || !defined(__x86_64__) - inline void __get_cpuid(int /*param*/, - unsigned * /*eax*/, - unsigned * /*ebx*/, - unsigned *ecx, - unsigned * /*edx*/) const - { - *ecx = 0; - } -#endif - - boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> crc_processor; - unsigned crc; - bool use_hardware_implementation; -}; - -struct RangebasedCRC32 -{ - template unsigned operator()(const Iteratable &iterable) - { - return crc32(std::begin(iterable), std::end(iterable)); - } - - bool UsingHardware() const { return crc32.UsingHardware(); } - - private: - IteratorbasedCRC32 crc32; -}; -} -} - -#endif /* ITERATOR_BASED_CRC32_H */ diff --git a/include/contractor/files.hpp b/include/contractor/files.hpp index 8dcade795d2..7b77869bf0e 100644 --- a/include/contractor/files.hpp +++ b/include/contractor/files.hpp @@ -5,15 +5,11 @@ #include -namespace osrm -{ -namespace contractor -{ -namespace files +namespace osrm::contractor::files { // reads .osrm.hsgr file template -inline void readGraph(const boost::filesystem::path &path, +inline void readGraph(const std::filesystem::path &path, std::unordered_map &metrics, std::uint32_t &connectivity_checksum) { @@ -34,7 +30,7 @@ inline void readGraph(const boost::filesystem::path &path, // writes .osrm.hsgr file template -inline void writeGraph(const boost::filesystem::path &path, +inline void writeGraph(const std::filesystem::path &path, const std::unordered_map &metrics, const std::uint32_t connectivity_checksum) { @@ -52,8 +48,6 @@ inline void writeGraph(const boost::filesystem::path &path, serialization::write(writer, "/ch/metrics/" + pair.first, pair.second); } } -} -} -} +} // namespace osrm::contractor::files #endif diff --git a/include/contractor/graph_contractor.hpp b/include/contractor/graph_contractor.hpp index a6a3891c206..0cf490c61ab 100644 --- a/include/contractor/graph_contractor.hpp +++ b/include/contractor/graph_contractor.hpp @@ -5,12 +5,9 @@ #include "util/filtered_graph.hpp" -#include #include -namespace osrm -{ -namespace contractor +namespace osrm::contractor { std::vector contractGraph(ContractorGraph &graph, @@ -37,7 +34,6 @@ inline auto contractGraph(ContractorGraph &graph, graph, {}, std::move(node_is_contractable), std::move(node_weights), core_factor); } -} // namespace contractor -} // namespace osrm +} // namespace osrm::contractor #endif // OSRM_CONTRACTOR_GRAPH_CONTRACTOR_HPP diff --git a/include/contractor/graph_contractor_adaptors.hpp b/include/contractor/graph_contractor_adaptors.hpp index 94dc7e62b2a..903fa08c586 100644 --- a/include/contractor/graph_contractor_adaptors.hpp +++ b/include/contractor/graph_contractor_adaptors.hpp @@ -10,9 +10,7 @@ #include -namespace osrm -{ -namespace contractor +namespace osrm::contractor { // Make sure to move in the input edge list! @@ -29,18 +27,20 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp #ifndef NDEBUG const unsigned int constexpr DAY_IN_DECI_SECONDS = 24 * 60 * 60 * 10; - if (static_cast(std::max(input_edge.data.weight, 1)) > DAY_IN_DECI_SECONDS) + if (from_alias(std::max(input_edge.data.weight, EdgeWeight{1})) > + DAY_IN_DECI_SECONDS) { util::Log(logWARNING) << "Edge weight large -> " - << static_cast(std::max(input_edge.data.weight, 1)) + << from_alias( + std::max(input_edge.data.weight, EdgeWeight{1})) << " : " << static_cast(input_edge.source) << " -> " << static_cast(input_edge.target); } #endif edges.emplace_back(input_edge.source, input_edge.target, - std::max(input_edge.data.weight, 1), - input_edge.data.duration, + std::max(input_edge.data.weight, {1}), + to_alias(input_edge.data.duration), input_edge.data.distance, 1, input_edge.data.turn_id, @@ -50,8 +50,8 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp edges.emplace_back(input_edge.target, input_edge.source, - std::max(input_edge.data.weight, 1), - input_edge.data.duration, + std::max(input_edge.data.weight, {1}), + to_alias(input_edge.data.duration), input_edge.data.distance, 1, input_edge.data.turn_id, @@ -109,7 +109,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp // merge edges (s,t) and (t,s) into bidirectional edge if (forward_edge.data.weight == reverse_edge.data.weight) { - if ((int)forward_edge.data.weight != INVALID_EDGE_WEIGHT) + if (forward_edge.data.weight != INVALID_EDGE_WEIGHT) { forward_edge.data.backward = true; edges[edge++] = forward_edge; @@ -117,11 +117,11 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp } else { // insert seperate edges - if (((int)forward_edge.data.weight) != INVALID_EDGE_WEIGHT) + if (forward_edge.data.weight != INVALID_EDGE_WEIGHT) { edges[edge++] = forward_edge; } - if ((int)reverse_edge.data.weight != INVALID_EDGE_WEIGHT) + if (reverse_edge.data.weight != INVALID_EDGE_WEIGHT) { edges[edge++] = reverse_edge; } @@ -157,7 +157,7 @@ template inline std::vector toEdges(GraphT g 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.duration = from_alias(data.duration); new_edge.data.distance = data.distance; new_edge.data.shortcut = data.shortcut; new_edge.data.turn_id = data.id; @@ -175,7 +175,6 @@ template inline std::vector toEdges(GraphT g return edges; } -} // namespace contractor -} // namespace osrm +} // namespace osrm::contractor #endif // OSRM_CONTRACTOR_GRAPH_CONTRACTION_ADAPTORS_HPP_ diff --git a/include/contractor/query_edge.hpp b/include/contractor/query_edge.hpp index 74d38e79ecb..3776aab185a 100644 --- a/include/contractor/query_edge.hpp +++ b/include/contractor/query_edge.hpp @@ -5,9 +5,7 @@ #include -namespace osrm -{ -namespace contractor +namespace osrm::contractor { struct QueryEdge @@ -17,15 +15,15 @@ struct QueryEdge struct EdgeData { explicit EdgeData() - : turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false), - distance(0) + : turn_id(0), shortcut(false), weight{0}, duration(0), forward(false), + backward(false), distance{0} { } EdgeData(const NodeID turn_id, const bool shortcut, const EdgeWeight weight, - const EdgeWeight duration, + const EdgeDuration duration, const EdgeDistance distance, const bool forward, const bool backward) @@ -50,7 +48,7 @@ struct QueryEdge NodeID turn_id : 31; bool shortcut : 1; EdgeWeight weight; - EdgeWeight duration : 30; + EdgeDuration::value_type duration : 30; std::uint32_t forward : 1; std::uint32_t backward : 1; EdgeDistance distance; @@ -58,8 +56,8 @@ struct QueryEdge 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) { } @@ -77,7 +75,6 @@ struct QueryEdge data.distance == right.data.distance); } }; -} -} +} // namespace osrm::contractor #endif // QUERYEDGE_HPP diff --git a/include/contractor/query_graph.hpp b/include/contractor/query_graph.hpp index e5758dcfe10..44cc1409249 100644 --- a/include/contractor/query_graph.hpp +++ b/include/contractor/query_graph.hpp @@ -6,20 +6,17 @@ #include "util/static_graph.hpp" #include "util/typedefs.hpp" -namespace osrm -{ -namespace contractor +namespace osrm::contractor { namespace detail { template using QueryGraph = util::StaticGraph; -} +} // namespace detail using QueryGraph = detail::QueryGraph; using QueryGraphView = detail::QueryGraph; -} -} +} // namespace osrm::contractor #endif // QUERYEDGE_HPP diff --git a/include/contractor/serialization.hpp b/include/contractor/serialization.hpp index aa86592742d..f1c3bd969e7 100644 --- a/include/contractor/serialization.hpp +++ b/include/contractor/serialization.hpp @@ -8,11 +8,7 @@ #include "storage/serialization.hpp" #include "storage/tar.hpp" -namespace osrm -{ -namespace contractor -{ -namespace serialization +namespace osrm::contractor::serialization { template @@ -46,8 +42,6 @@ void read(storage::tar::FileReader &reader, metric.edge_filter[index]); } } -} -} -} +} // namespace osrm::contractor::serialization #endif diff --git a/include/customizer/cell_customizer.hpp b/include/customizer/cell_customizer.hpp index df549957998..69f9017e815 100644 --- a/include/customizer/cell_customizer.hpp +++ b/include/customizer/cell_customizer.hpp @@ -10,9 +10,7 @@ #include -namespace osrm -{ -namespace customizer +namespace osrm::customizer { class CellCustomizer @@ -61,7 +59,7 @@ class CellCustomizer } } heap.Clear(); - heap.Insert(source, 0, {false, 0, 0}); + heap.Insert(source, {0}, {false, {0}, {0}}); // explore search space while (!heap.Empty() && !destinations_set.empty()) @@ -102,9 +100,9 @@ class CellCustomizer distances.front() = inserted ? heap.GetData(destination).distance : INVALID_EDGE_DISTANCE; - weights.advance_begin(1); - durations.advance_begin(1); - distances.advance_begin(1); + weights.advance(1); + durations.advance(1); + distances.advance(1); } BOOST_ASSERT(weights.empty()); BOOST_ASSERT(durations.empty()); @@ -124,7 +122,8 @@ class CellCustomizer for (std::size_t level = 1; level < partition.GetNumberOfLevels(); ++level) { tbb::parallel_for(tbb::blocked_range(0, partition.GetNumberOfCells(level)), - [&](const tbb::blocked_range &range) { + [&](const tbb::blocked_range &range) + { auto &heap = heaps.local(); for (auto id = range.begin(), end = range.end(); id != end; ++id) { @@ -212,17 +211,15 @@ 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 EdgeDuration to_duration = duration + to_alias(data.duration); const EdgeDistance to_distance = distance + data.distance; if (!heap.WasInserted(to)) { - heap.Insert( - to, to_weight, {false, duration + data.duration, distance + data.distance}); + heap.Insert(to, to_weight, {false, to_duration, to_distance}); } else if (std::tie(to_weight, to_duration, to_distance) < std::tie( @@ -237,7 +234,6 @@ class CellCustomizer const partitioner::MultiLevelPartition &partition; }; -} -} +} // namespace osrm::customizer #endif // OSRM_CELLS_CUSTOMIZER_HPP diff --git a/include/customizer/cell_metric.hpp b/include/customizer/cell_metric.hpp index 7674174feda..f9ffc9b84d5 100644 --- a/include/customizer/cell_metric.hpp +++ b/include/customizer/cell_metric.hpp @@ -7,9 +7,7 @@ #include "util/typedefs.hpp" #include "util/vector_view.hpp" -namespace osrm -{ -namespace customizer +namespace osrm::customizer { namespace detail { @@ -22,11 +20,10 @@ template struct CellMetricImpl Vector durations; Vector distances; }; -} +} // namespace detail using CellMetric = detail::CellMetricImpl; using CellMetricView = detail::CellMetricImpl; -} -} +} // namespace osrm::customizer #endif diff --git a/include/customizer/customizer.hpp b/include/customizer/customizer.hpp index a7716cf1b66..e153498dcfb 100644 --- a/include/customizer/customizer.hpp +++ b/include/customizer/customizer.hpp @@ -3,9 +3,7 @@ #include "customizer/customizer_config.hpp" -namespace osrm -{ -namespace customizer +namespace osrm::customizer { class Customizer @@ -14,7 +12,6 @@ class Customizer int Run(const CustomizationConfig &config); }; -} // namespace customizer -} // namespace osrm +} // namespace osrm::customizer #endif // OSRM_CUSTOMIZE_CUSTOMIZER_HPP diff --git a/include/customizer/customizer_config.hpp b/include/customizer/customizer_config.hpp index 35ab1a35628..8068d5c47dc 100644 --- a/include/customizer/customizer_config.hpp +++ b/include/customizer/customizer_config.hpp @@ -1,17 +1,12 @@ #ifndef OSRM_CUSTOMIZE_CUSTOMIZER_CONFIG_HPP #define OSRM_CUSTOMIZE_CUSTOMIZER_CONFIG_HPP -#include - -#include -#include +#include #include "storage/io_config.hpp" #include "updater/updater_config.hpp" -namespace osrm -{ -namespace customizer +namespace osrm::customizer { struct CustomizationConfig final : storage::IOConfig @@ -29,7 +24,7 @@ struct CustomizationConfig final : storage::IOConfig { } - void UseDefaultOutputNames(const boost::filesystem::path &base) + void UseDefaultOutputNames(const std::filesystem::path &base) { IOConfig::UseDefaultOutputNames(base); updater_config.UseDefaultOutputNames(base); @@ -39,7 +34,6 @@ struct CustomizationConfig final : storage::IOConfig updater::UpdaterConfig updater_config; }; -} -} +} // namespace osrm::customizer #endif // OSRM_CUSTOMIZE_CUSTOMIZER_CONFIG_HPP diff --git a/include/customizer/edge_based_graph.hpp b/include/customizer/edge_based_graph.hpp index 840a8429984..9cf92212add 100644 --- a/include/customizer/edge_based_graph.hpp +++ b/include/customizer/edge_based_graph.hpp @@ -9,11 +9,9 @@ #include "storage/shared_memory_ownership.hpp" -#include +#include -namespace osrm -{ -namespace customizer +namespace osrm::customizer { struct EdgeBasedGraphEdgeData @@ -34,7 +32,7 @@ template void write(storage::tar::FileWriter &writer, const std::string &name, const MultiLevelGraph &graph); -} +} // namespace serialization template class MultiLevelGraph : public partitioner::MultiLevelGraph @@ -97,7 +95,7 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph; using MultiLevelEdgeBasedGraphView = MultiLevelGraph; -} -} +} // namespace osrm::customizer #endif diff --git a/include/customizer/files.hpp b/include/customizer/files.hpp index 364a2572d23..9a818d5344b 100644 --- a/include/customizer/files.hpp +++ b/include/customizer/files.hpp @@ -9,16 +9,12 @@ #include -namespace osrm -{ -namespace customizer -{ -namespace files +namespace osrm::customizer::files { // reads .osrm.cell_metrics file template -inline void readCellMetrics(const boost::filesystem::path &path, +inline void readCellMetrics(const std::filesystem::path &path, std::unordered_map> &metrics) { static_assert(std::is_same::value || @@ -48,7 +44,7 @@ inline void readCellMetrics(const boost::filesystem::path &path, // writes .osrm.cell_metrics file template inline void -writeCellMetrics(const boost::filesystem::path &path, +writeCellMetrics(const std::filesystem::path &path, const std::unordered_map> &metrics) { static_assert(std::is_same::value || @@ -76,7 +72,7 @@ writeCellMetrics(const boost::filesystem::path &path, // reads .osrm.mldgr file template -inline void readGraph(const boost::filesystem::path &path, +inline void readGraph(const std::filesystem::path &path, MultiLevelGraphT &graph, std::uint32_t &connectivity_checksum) { @@ -92,7 +88,7 @@ inline void readGraph(const boost::filesystem::path &path, // writes .osrm.mldgr file template -inline void writeGraph(const boost::filesystem::path &path, +inline void writeGraph(const std::filesystem::path &path, const MultiLevelGraphT &graph, const std::uint32_t connectivity_checksum) { @@ -106,8 +102,6 @@ inline void writeGraph(const boost::filesystem::path &path, writer.WriteFrom("/mld/connectivity_checksum", connectivity_checksum); serialization::write(writer, "/mld/multilevelgraph", graph); } -} -} -} +} // namespace osrm::customizer::files #endif diff --git a/include/customizer/serialization.hpp b/include/customizer/serialization.hpp index afe23cf9bba..afd0cc91e3d 100644 --- a/include/customizer/serialization.hpp +++ b/include/customizer/serialization.hpp @@ -9,11 +9,7 @@ #include "storage/shared_memory_ownership.hpp" #include "storage/tar.hpp" -namespace osrm -{ -namespace customizer -{ -namespace serialization +namespace osrm::customizer::serialization { template @@ -65,8 +61,6 @@ inline void write(storage::tar::FileWriter &writer, 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 osrm::customizer::serialization #endif diff --git a/include/engine/algorithm.hpp b/include/engine/algorithm.hpp index 760f78e80a5..5d86b762628 100644 --- a/include/engine/algorithm.hpp +++ b/include/engine/algorithm.hpp @@ -3,11 +3,7 @@ #include -namespace osrm -{ -namespace engine -{ -namespace routing_algorithms +namespace osrm::engine::routing_algorithms { // Contraction Hiearchy @@ -16,14 +12,14 @@ namespace ch struct Algorithm final { }; -} +} // namespace ch // Multi-Level Dijkstra namespace mld { struct Algorithm final { }; -} +} // namespace mld // Algorithm names template const char *name(); @@ -111,8 +107,6 @@ template <> struct HasGetTileTurns final : std::true_type template <> struct HasExcludeFlags final : std::true_type { }; -} -} -} +} // namespace osrm::engine::routing_algorithms #endif diff --git a/include/engine/api/base_api.hpp b/include/engine/api/base_api.hpp index e0c924348d1..4daadfc0354 100644 --- a/include/engine/api/base_api.hpp +++ b/include/engine/api/base_api.hpp @@ -2,24 +2,23 @@ #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 -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { +static const constexpr char *INTERSECTION_DELIMITER = " / "; + class BaseAPI { public: @@ -28,55 +27,156 @@ 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); - }); + std::ranges::transform(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 + protected: + util::json::Object MakeWaypoint(const PhantomNodeCandidates &candidates) const { + // TODO: check forward/reverse + const auto toName = [this](const auto &phantom) { + return std::string( + facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))); + }; + 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 = + join(candidates | std::views::transform(toName) | std::views::filter(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, - util::coordinate_calculation::fccApproximateDistance(phantom.location, - phantom.input_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, - util::coordinate_calculation::fccApproximateDistance(phantom.location, - phantom.input_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); + } + + 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 std::string( + facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))); + }; + 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 = + join(candidates | std::views::transform(toName) | std::views::filter(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; + + private: + // Helper join function using std + template std::string join(Range &&range, const std::string &delimiter) const + { + std::ostringstream result; + auto it = std::begin(range); + const auto end = std::end(range); + + if (it != end) + { + result << *it++; + while (it != end) + { + result << delimiter << *it++; + } + } + return result.str(); + } }; -} // ns api -} // ns engine -} // ns osrm +} // namespace osrm::engine::api #endif diff --git a/include/engine/api/base_parameters.hpp b/include/engine/api/base_parameters.hpp index 91ac937b4fc..1a35a030d8b 100644 --- a/include/engine/api/base_parameters.hpp +++ b/include/engine/api/base_parameters.hpp @@ -33,16 +33,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "engine/hint.hpp" #include "util/coordinate.hpp" -#include +#include #include #include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { /** @@ -51,14 +47,15 @@ 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. + * - approaches: force the phantom node to start towards the node with the road country side or + * its opposite * - * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters, + * \see OSRM, Coordinate, Hint, Bearing, RouteParameters, TableParameters, * NearestParameters, TripParameters, MatchParameters and TileParameters */ struct BaseParameters @@ -70,33 +67,43 @@ struct BaseParameters Any }; + enum class OutputFormatType + { + JSON, + FLATBUFFERS + }; + std::vector coordinates; - std::vector> hints; - std::vector> radiuses; - std::vector> bearings; - std::vector> approaches; + std::vector> hints; + std::vector> radiuses; + std::vector> bearings; + std::vector> approaches; std::vector exclude; + std::optional format = OutputFormatType::JSON; // Adds hints to response which can be included in subsequent requests, see `hints` above. bool generate_hints = true; + // Remove waypoints array from the response. + bool skip_waypoints = false; + SnappingType snapping = SnappingType::Default; - BaseParameters(const std::vector coordinates_ = {}, - const std::vector> hints_ = {}, - std::vector> radiuses_ = {}, - std::vector> bearings_ = {}, - std::vector> approaches_ = {}, + BaseParameters(std::vector coordinates_ = {}, + std::vector> hints_ = {}, + std::vector> radiuses_ = {}, + std::vector> bearings_ = {}, + std::vector> approaches_ = {}, bool generate_hints_ = true, std::vector exclude = {}, const SnappingType snapping_ = SnappingType::Default) - : coordinates(coordinates_), hints(hints_), radiuses(radiuses_), bearings(bearings_), - approaches(approaches_), exclude(std::move(exclude)), generate_hints(generate_hints_), - snapping(snapping_) + : 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()) && @@ -105,7 +112,8 @@ struct BaseParameters (approaches.empty() || approaches.size() == coordinates.size()) && std::all_of(bearings.begin(), bearings.end(), - [](const boost::optional bearing_and_range) { + [](const std::optional &bearing_and_range) + { if (bearing_and_range) { return bearing_and_range->IsValid(); @@ -114,8 +122,6 @@ struct BaseParameters }); } }; -} -} -} +} // namespace osrm::engine::api #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 00000000000..76d083d6fa1 --- /dev/null +++ b/include/engine/api/base_result.hpp @@ -0,0 +1,16 @@ +#ifndef ENGINE_API_BASE_RESULT_HPP +#define ENGINE_API_BASE_RESULT_HPP + +#include +#include + +#include + +#include "util/json_container.hpp" + +namespace osrm::engine::api +{ +using ResultT = std::variant; +} // namespace osrm::engine::api + +#endif diff --git a/include/engine/api/flatbuffers/fbresult.fbs b/include/engine/api/flatbuffers/fbresult.fbs new file mode 100644 index 00000000000..860f4624830 --- /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: TableResult; +} + +root_type FBResult; \ No newline at end of file diff --git a/include/engine/api/flatbuffers/position.fbs b/include/engine/api/flatbuffers/position.fbs new file mode 100644 index 00000000000..e78f02c672b --- /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 00000000000..902bfa1990b --- /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 00000000000..0cbd947bc4b --- /dev/null +++ b/include/engine/api/flatbuffers/table.fbs @@ -0,0 +1,11 @@ +include "waypoint.fbs"; +namespace osrm.engine.api.fbresult; + +table TableResult { + 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 00000000000..4991f72e6f5 --- /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 db30ecc9efc..001f44ff851 100644 --- a/include/engine/api/json_factory.hpp +++ b/include/engine/api/json_factory.hpp @@ -12,28 +12,36 @@ #include "util/coordinate.hpp" #include "util/json_container.hpp" -#include +#include #include #include #include #include -namespace osrm -{ -namespace engine +namespace osrm::engine { struct Hint; -namespace api -{ -namespace json +namespace api::json { namespace detail { -util::json::Array coordinateToLonLat(const util::Coordinate &coordinate); +// 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); +} + +inline bool hasValidLanes(const guidance::IntermediateIntersection &intersection) +{ + return intersection.lanes.lanes_in_turn > 0; +} + +util::json::Value coordinateToLonLat(const util::Coordinate &coordinate); /** * Ensures that a bearing value is a whole number, and clamped to the range 0-359 @@ -71,7 +79,7 @@ util::json::Object makeGeoJSONGeometry(ForwardIter begin, ForwardIter end) coordinates.values.push_back(location); coordinates.values.push_back(location); } - geojson.values["coordinates"] = std::move(coordinates); + geojson.values["coordinates"] = util::json::Value{std::move(coordinates)}; return geojson; } @@ -82,7 +90,7 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo util::json::Object makeRoute(const guidance::Route &route, util::json::Array legs, - boost::optional geometry, + std::optional geometry, const char *weight_name); // Creates a Waypoint without Hint, see the Hint overload below @@ -100,9 +108,7 @@ 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 engine -} // namespace osrm +} // namespace api::json +} // namespace osrm::engine #endif // ENGINE_GUIDANCE_API_RESPONSE_GENERATOR_HPP_ diff --git a/include/engine/api/match_api.hpp b/include/engine/api/match_api.hpp index 86a96c65b76..d7956bba499 100644 --- a/include/engine/api/match_api.hpp +++ b/include/engine/api/match_api.hpp @@ -12,11 +12,7 @@ #include "util/integer_range.hpp" -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { class MatchAPI final : public RouteAPI @@ -29,6 +25,45 @@ 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 (std::holds_alternative(response)) + { + auto &fb_result = std::get(response); + MakeResponse(sub_matchings, sub_routes, fb_result); + } + else + { + auto &json_result = std::get(response); + 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,67 +71,114 @@ 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)); + route.values.emplace("confidence", sub_matchings[index].confidence); + routes.values.emplace_back(std::move(route)); + } + if (!parameters.skip_waypoints) + { + response.values.emplace("tracepoints", MakeTracepoints(sub_matchings)); + } + response.values.emplace("matchings", std::move(routes)); + response.values.emplace("code", "Ok"); + auto data_timestamp = facade.GetTimestamp(); + if (!data_timestamp.empty()) + { + response.values.emplace("data_version", data_timestamp); } - response.values["tracepoints"] = MakeTracepoints(sub_matchings); - response.values["matchings"] = std::move(routes); - response.values["code"] = "Ok"; } 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. - util::json::Array - MakeTracepoints(const std::vector &sub_matchings) const + struct MatchingIndex { - util::json::Array waypoints; - waypoints.values.reserve(parameters.coordinates.size()); + 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(); - struct MatchingIndex + bool NotMatched() { - MatchingIndex() = default; - MatchingIndex(unsigned sub_matching_index_, unsigned point_index_) - : sub_matching_index(sub_matching_index_), point_index(point_index_) - { - } + return sub_matching_index == std::numeric_limits::max() && + point_index == std::numeric_limits::max(); + } + }; - unsigned sub_matching_index = std::numeric_limits::max(); - unsigned 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()); - bool NotMatched() - { - return sub_matching_index == std::numeric_limits::max() && - point_index == std::numeric_limits::max(); - } - }; + auto trace_idx_to_matching_idx = MakeMatchingIndices(sub_matchings); - std::vector trace_idx_to_matching_idx(parameters.coordinates.size()); - for (auto sub_matching_index : - util::irange(0u, static_cast(sub_matchings.size()))) + 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())) { - for (auto point_index : util::irange( - 0u, static_cast(sub_matchings[sub_matching_index].indices.size()))) + + if (tidy_result.can_be_removed[trace_index]) { - // 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}; + waypoints.emplace_back(fbresult::WaypointBuilder(fb_result).Finish()); + continue; + } + auto matching_index = trace_idx_to_matching_idx[trace_index]; + if (matching_index.NotMatched()) + { + waypoints.emplace_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.emplace_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()); + + 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; @@ -104,23 +186,23 @@ class MatchAPI final : public RouteAPI { if (tidy_result.can_be_removed[trace_index]) { - waypoints.values.push_back(util::json::Null()); + waypoints.values.emplace_back(util::json::Null()); continue; } auto matching_index = trace_idx_to_matching_idx[trace_index]; if (matching_index.NotMatched()) { - waypoints.values.push_back(util::json::Null()); + waypoints.values.emplace_back(util::json::Null()); continue; } const auto &phantom = sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index]; - 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]; + auto waypoint = BaseAPI::MakeWaypoint({phantom}); + waypoint.values.emplace("matchings_index", matching_index.sub_matching_index); + waypoint.values.emplace("waypoint_index", matching_index.point_index); + waypoint.values.emplace("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()) @@ -135,18 +217,39 @@ class MatchAPI final : public RouteAPI waypoint.values["waypoint_index"] = util::json::Null(); } } - waypoints.values.push_back(std::move(waypoint)); + waypoints.values.emplace_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 osrm::engine::api #endif diff --git a/include/engine/api/match_parameters.hpp b/include/engine/api/match_parameters.hpp index b54076582e0..abc93a650a2 100644 --- a/include/engine/api/match_parameters.hpp +++ b/include/engine/api/match_parameters.hpp @@ -32,11 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { /** @@ -68,8 +64,11 @@ struct MatchParameters : public RouteParameters } template - MatchParameters(std::vector timestamps_, GapsType gaps_, bool tidy_, Args... args_) - : MatchParameters(std::move(timestamps_), gaps_, tidy_, {}, std::forward(args_)...) + MatchParameters(const std::vector ×tamps_, + GapsType gaps_, + bool tidy_, + Args &&...args_) + : MatchParameters(timestamps_, gaps_, tidy_, {}, std::forward(args_)...) { } @@ -77,10 +76,11 @@ struct MatchParameters : public RouteParameters MatchParameters(std::vector timestamps_, GapsType gaps_, bool tidy_, - std::vector waypoints_, - Args... args_) - : RouteParameters{std::forward(args_)..., waypoints_}, - timestamps{std::move(timestamps_)}, gaps(gaps_), tidy(tidy_) + const std::vector &waypoints_, + Args &&...args_) + : RouteParameters{std::forward(args_)..., waypoints_}, timestamps{std::move( + timestamps_)}, + gaps(gaps_), tidy(tidy_) { } @@ -94,8 +94,6 @@ struct MatchParameters : public RouteParameters (timestamps.empty() || timestamps.size() == coordinates.size()); } }; -} -} -} +} // namespace osrm::engine::api #endif diff --git a/include/engine/api/match_parameters_tidy.hpp b/include/engine/api/match_parameters_tidy.hpp index ab4610c4f85..93a572b133e 100644 --- a/include/engine/api/match_parameters_tidy.hpp +++ b/include/engine/api/match_parameters_tidy.hpp @@ -11,13 +11,7 @@ #include #include -namespace osrm -{ -namespace engine -{ -namespace api -{ -namespace tidy +namespace osrm::engine::api::tidy { struct Thresholds @@ -122,7 +116,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; @@ -200,9 +194,6 @@ inline Result tidy(const MatchParameters ¶ms, Thresholds cfg = {15., 5}) return result; } -} // ns tidy -} // ns api -} // ns engine -} // ns osrm +} // namespace osrm::engine::api::tidy #endif diff --git a/include/engine/api/nearest_api.hpp b/include/engine/api/nearest_api.hpp index bb55b0634e5..e402e46f435 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" @@ -11,11 +12,7 @@ #include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { class NearestAPI final : public BaseAPI @@ -27,71 +24,143 @@ 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 &phantom_node = phantom_with_distance.phantom_node; - auto waypoint = MakeWaypoint(phantom_node); - - util::json::Array nodes; - - 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); - } - nodes.values.push_back(from_node); - nodes.values.push_back(to_node); - waypoint.values["nodes"] = std::move(nodes); - - return waypoint; - }); - - response.values["code"] = "Ok"; - response.values["waypoints"] = std::move(waypoints); + if (std::holds_alternative(response)) + { + auto &fb_result = std::get(response); + MakeResponse(phantom_nodes, fb_result); + } + else + { + auto &json_result = std::get(response); + MakeResponse(phantom_nodes, json_result); + } + } + + void MakeResponse(const std::vector> &phantom_nodes, + flatbuffers::FlatBufferBuilder &fb_result) const + { + auto data_timestamp = facade.GetTimestamp(); + std::optional> data_version_string = std::nullopt; + 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; + nodes.values.reserve(2); + + auto node_values = MakeNodes(phantom_node); + + nodes.values.emplace_back(node_values.first); + nodes.values.emplace_back(node_values.second); + waypoint.values.emplace("nodes", std::move(nodes)); + return waypoint; + }); + response.values.emplace("waypoints", std::move(waypoints)); + } + + response.values.emplace("code", "Ok"); + auto data_timestamp = facade.GetTimestamp(); + if (!data_timestamp.empty()) + { + response.values.emplace("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 osrm::engine::api #endif diff --git a/include/engine/api/nearest_parameters.hpp b/include/engine/api/nearest_parameters.hpp index f24251b8c53..442b7b67dbb 100644 --- a/include/engine/api/nearest_parameters.hpp +++ b/include/engine/api/nearest_parameters.hpp @@ -30,11 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "engine/api/base_parameters.hpp" -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { /** @@ -52,8 +48,6 @@ struct NearestParameters : public BaseParameters bool IsValid() const { return BaseParameters::IsValid() && number_of_results >= 1; } }; -} -} -} +} // namespace osrm::engine::api #endif // ENGINE_API_NEAREST_PARAMETERS_HPP diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index caaa92eb309..08431a2cf5d 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -3,6 +3,7 @@ #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" @@ -26,14 +27,12 @@ #include "util/integer_range.hpp" #include "util/json_util.hpp" +#include #include +#include #include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { class RouteAPI : public BaseAPI @@ -46,12 +45,57 @@ class RouteAPI : public BaseAPI void MakeResponse(const InternalManyRoutesResult &raw_routes, - const std::vector - &all_start_end_points, // all used coordinates, ignoring waypoints= parameter - util::json::Object &response) const + const std::vector + &waypoint_candidates, // all used coordinates, ignoring waypoints= parameter + osrm::engine::api::ResultT &response) const { BOOST_ASSERT(!raw_routes.routes.empty()); + if (std::holds_alternative(response)) + { + auto &fb_result = std::get(response); + MakeResponse(raw_routes, waypoint_candidates, fb_result); + } + else + { + auto &json_result = std::get(response); + 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) @@ -59,38 +103,126 @@ 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(all_start_end_points); - response.values["routes"] = std::move(jsRoutes); - response.values["code"] = "Ok"; + if (!parameters.skip_waypoints) + { + response.values.emplace("waypoints", BaseAPI::MakeWaypoints(waypoint_candidates)); + } + response.values.emplace("routes", std::move(jsRoutes)); + response.values.emplace("code", "Ok"); auto data_timestamp = facade.GetTimestamp(); if (!data_timestamp.empty()) { - response.values["data_version"] = data_timestamp; + response.values.emplace("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 + std::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)); + } + else if (parameters.geometries == RouteParameters::GeometriesType::Polyline6) + { + 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); + } + + std::optional + MakeGeometry(std::optional> &&annotations) const + { + std::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; + } - if (parameters.geometries == RouteParameters::GeometriesType::Polyline6) + 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) { - return json::makePolyline<1000000>(begin, end); + 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 @@ -107,124 +239,496 @@ class RouteAPI : public BaseAPI return annotations_store; } - util::json::Object MakeRoute(const std::vector &segment_end_coordinates, - const std::vector> &unpacked_path_segments, - const std::vector &source_traversed_in_reverse, - const std::vector &target_traversed_in_reverse) const + fbresult::ManeuverType WaypointTypeToFB(guidance::WaypointType type) 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); + switch (type) + { + case guidance::WaypointType::Arrive: + return fbresult::ManeuverType_Arrive; + case guidance::WaypointType::Depart: + return fbresult::ManeuverType_Depart; + default: + return fbresult::ManeuverType_Notification; + } + } - for (auto idx : util::irange(0UL, number_of_legs)) + 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)) { - const auto &phantoms = segment_end_coordinates[idx]; - const auto &path_data = unpacked_path_segments[idx]; + if (mask[index]) + { + result.push_back(mapping[index]); + } + } + return result; + } - const bool reversed_source = source_traversed_in_reverse[idx]; - const bool reversed_target = target_traversed_in_reverse[idx]; + 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); - 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); + // 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]; - util::Log(logDEBUG) << "Assembling steps " << std::endl; - if (parameters.steps) + // 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)) { - 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); + requested_annotations = RouteParameters::AnnotationsType::All; } - leg_geometries.push_back(std::move(leg_geometry)); - legs.push_back(std::move(leg)); + 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); + std::variant, + flatbuffers::Offset>> + geometry; + if (overview) + { + geometry = MakeGeometry(fb_result, overview->begin(), overview->end()); } - auto route = guidance::assembleRoute(legs); - boost::optional json_overview; - if (parameters.overview != RouteParameters::OverviewType::False) + 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) { - const auto use_simplification = - parameters.overview == RouteParameters::OverviewType::Simplified; - BOOST_ASSERT(use_simplification || - parameters.overview == RouteParameters::OverviewType::Full); + std::visit(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 = std::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; }); + } - auto overview = guidance::assembleOverview(leg_geometries, use_simplification); - json_overview = MakeGeometry(overview.begin(), overview.end()); + 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); + std::visit(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 + { + 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); + std::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(); - }); + 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())) @@ -235,7 +739,8 @@ class RouteAPI : public BaseAPI legs[idx].steps.begin(), legs[idx].steps.end(), std::back_inserter(step_geometries), - [this, &leg_geometry](const guidance::RouteStep &step) { + [this, &leg_geometry](const guidance::RouteStep &step) + { if (parameters.geometries == RouteParameters::GeometriesType::Polyline) { return static_cast(json::makePolyline<100000>( @@ -262,7 +767,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; @@ -276,60 +781,71 @@ 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, [&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); - } - }); + annotation.values.emplace( + "speed", + GetAnnotations(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); + } + })); } if (requested_annotations & RouteParameters::AnnotationsType::Duration) { - annotation.values["duration"] = GetAnnotations( - leg_geometry, [](const guidance::LegGeometry::Annotation &anno) { - return anno.duration; - }); + annotation.values.emplace( + "duration", + GetAnnotations(leg_geometry, + [](const guidance::LegGeometry::Annotation &anno) + { return anno.duration; })); } if (requested_annotations & RouteParameters::AnnotationsType::Distance) { - annotation.values["distance"] = GetAnnotations( - leg_geometry, [](const guidance::LegGeometry::Annotation &anno) { - return anno.distance; - }); + annotation.values.emplace( + "distance", + GetAnnotations(leg_geometry, + [](const guidance::LegGeometry::Annotation &anno) + { return anno.distance; })); } if (requested_annotations & RouteParameters::AnnotationsType::Weight) { - annotation.values["weight"] = GetAnnotations( - leg_geometry, - [](const guidance::LegGeometry::Annotation &anno) { return anno.weight; }); + annotation.values.emplace( + "weight", + GetAnnotations(leg_geometry, + [](const guidance::LegGeometry::Annotation &anno) + { return anno.weight; })); } if (requested_annotations & RouteParameters::AnnotationsType::Datasources) { - annotation.values["datasources"] = GetAnnotations( - leg_geometry, [](const guidance::LegGeometry::Annotation &anno) { - return anno.datasource; - }); + annotation.values.emplace( + "datasources", + GetAnnotations(leg_geometry, + [](const guidance::LegGeometry::Annotation &anno) + { return anno.datasource; })); } if (requested_annotations & RouteParameters::AnnotationsType::Nodes) { util::json::Array nodes; - nodes.values.reserve(leg_geometry.osm_node_ids.size()); - for (const auto node_id : leg_geometry.osm_node_ids) + nodes.values.reserve(leg_geometry.node_ids.size()); + for (const auto node_id : leg_geometry.node_ids) { - nodes.values.push_back(static_cast(node_id)); + nodes.values.push_back( + static_cast(facade.GetOSMNodeIDOfNode(node_id))); } - annotation.values["nodes"] = std::move(nodes); + annotation.values.emplace("nodes", std::move(nodes)); } // Add any supporting metadata, if needed if (requested_annotations & RouteParameters::AnnotationsType::Datasources) @@ -341,12 +857,12 @@ class RouteAPI : public BaseAPI { const auto name = facade.GetDatasourceName(i); // Length of 0 indicates the first empty name, so we can stop here - if (name.size() == 0) + if (name.empty()) break; datasource_names.values.push_back(std::string(facade.GetDatasourceName(i))); } - metadata.values["datasource_names"] = datasource_names; - annotation.values["metadata"] = metadata; + metadata.values.emplace("datasource_names", datasource_names); + annotation.values.emplace("metadata", metadata); } annotations.push_back(std::move(annotation)); @@ -364,10 +880,140 @@ 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; + } + + std::optional> + MakeOverview(const std::vector &leg_geometries) const + { + std::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 osrm::engine::api #endif diff --git a/include/engine/api/route_parameters.hpp b/include/engine/api/route_parameters.hpp index ba200050da9..a28f34b8c7c 100644 --- a/include/engine/api/route_parameters.hpp +++ b/include/engine/api/route_parameters.hpp @@ -32,11 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { /** @@ -86,20 +82,14 @@ struct RouteParameters : public BaseParameters const bool alternatives_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, - Args... args_) + const std::optional continue_straight_, + 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_}, - waypoints() + : 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,8 +100,8 @@ struct RouteParameters : public BaseParameters const bool annotations_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, - Args... args_) + const std::optional continue_straight_, + 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}, @@ -128,13 +118,13 @@ struct RouteParameters : public BaseParameters const AnnotationsType annotations_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, - Args... args_) + const std::optional continue_straight_, + Args &&...args_) : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, number_of_alternatives{alternatives_ ? 1u : 0u}, - annotations{annotations_ == AnnotationsType::None ? false : true}, - annotations_type{annotations_}, geometries{geometries_}, overview{overview_}, - continue_straight{continue_straight_}, waypoints() + annotations{annotations_ != AnnotationsType::None}, annotations_type{annotations_}, + geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_}, + waypoints() { } @@ -145,14 +135,14 @@ struct RouteParameters : public BaseParameters const bool annotations_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, + const std::optional continue_straight_, std::vector waypoints_, - const Args... args_) + 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{waypoints_} + geometries{geometries_}, overview{overview_}, + continue_straight{continue_straight_}, waypoints{std::move(waypoints_)} { } @@ -163,14 +153,14 @@ struct RouteParameters : public BaseParameters const AnnotationsType annotations_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, + const std::optional continue_straight_, std::vector waypoints_, - Args... args_) + Args &&...args_) : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, - number_of_alternatives{alternatives_ ? 1u : 0u}, - annotations{annotations_ == AnnotationsType::None ? false : true}, + number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_ != + AnnotationsType::None}, annotations_type{annotations_}, geometries{geometries_}, overview{overview_}, - continue_straight{continue_straight_}, waypoints{waypoints_} + continue_straight{continue_straight_}, waypoints{std::move(waypoints_)} { } @@ -182,7 +172,7 @@ struct RouteParameters : public BaseParameters AnnotationsType annotations_type = AnnotationsType::None; GeometriesType geometries = GeometriesType::Polyline; OverviewType overview = OverviewType::Simplified; - boost::optional continue_straight; + std::optional continue_straight; std::vector waypoints; bool IsValid() const @@ -190,9 +180,9 @@ struct RouteParameters : public BaseParameters const auto coordinates_ok = coordinates.size() >= 2; const auto base_params_ok = BaseParameters::IsValid(); const auto valid_waypoints = - std::all_of(waypoints.begin(), waypoints.end(), [this](const auto &w) { - return w < coordinates.size(); - }); + std::all_of(waypoints.begin(), + waypoints.end(), + [this](const auto &w) { return w < coordinates.size(); }); return coordinates_ok && base_params_ok && valid_waypoints; } }; @@ -212,13 +202,11 @@ inline RouteParameters::AnnotationsType operator|(RouteParameters::AnnotationsTy static_cast>(rhs)); } -inline RouteParameters::AnnotationsType operator|=(RouteParameters::AnnotationsType lhs, - RouteParameters::AnnotationsType rhs) +inline RouteParameters::AnnotationsType &operator|=(RouteParameters::AnnotationsType &lhs, + RouteParameters::AnnotationsType rhs) { return lhs = lhs | rhs; } -} // ns api -} // ns engine -} // ns osrm +} // namespace osrm::engine::api #endif diff --git a/include/engine/api/table_api.hpp b/include/engine/api/table_api.hpp index 7f94bfbe02c..2ba49d2ddf3 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" @@ -21,16 +22,14 @@ #include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::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} @@ -47,7 +46,128 @@ class TableAPI final : public BaseAPI virtual void MakeResponse(const std::pair, std::vector> &tables, - const std::vector &phantoms, + const std::vector &candidates, + const std::vector &fallback_speed_cells, + osrm::engine::api::ResultT &response) const + { + if (std::holds_alternative(response)) + { + auto &fb_result = std::get(response); + MakeResponse(tables, candidates, fallback_speed_cells, fb_result); + } + else + { + auto &json_result = std::get(response); + 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 != from_alias(INVALID_FALLBACK_SPEED) && + parameters.fallback_speed > 0; + flatbuffers::Offset> speed_cells; + if (have_speed_cells) + { + speed_cells = MakeEstimatesTable(fb_result, fallback_speed_cells); + } + + fbresult::TableResultBuilder 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 { @@ -57,73 +177,186 @@ 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.emplace("sources", MakeWaypoints(candidates)); + } + number_of_sources = candidates.size(); } else { - response.values["sources"] = MakeWaypoints(phantoms, parameters.sources); + if (!parameters.skip_waypoints) + { + response.values.emplace("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.emplace("destinations", MakeWaypoints(candidates)); + } + number_of_destinations = candidates.size(); } else { - response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations); + if (!parameters.skip_waypoints) + { + response.values.emplace("destinations", + MakeWaypoints(candidates, parameters.destinations)); + } } if (parameters.annotations & TableParameters::AnnotationsType::Duration) { - response.values["durations"] = - MakeDurationTable(tables.first, number_of_sources, number_of_destinations); + response.values.emplace( + "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); + response.values.emplace( + "distances", + MakeDistanceTable(tables.second, number_of_sources, number_of_destinations)); } - if (parameters.fallback_speed != INVALID_FALLBACK_SPEED && parameters.fallback_speed > 0) + if (parameters.fallback_speed != from_alias(INVALID_FALLBACK_SPEED) && + parameters.fallback_speed > 0) { - response.values["fallback_speed_cells"] = MakeEstimatesTable(fallback_speed_cells); + response.values.emplace("fallback_speed_cells", + MakeEstimatesTable(fallback_speed_cells)); } - response.values["code"] = "Ok"; + response.values.emplace("code", "Ok"); + auto data_timestamp = facade.GetTimestamp(); + if (!data_timestamp.empty()) + { + response.values.emplace("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 { - util::json::Array json_waypoints; - json_waypoints.values.reserve(phantoms.size()); - BOOST_ASSERT(phantoms.size() == parameters.coordinates.size()); + 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( - phantoms, - std::back_inserter(json_waypoints.values), - [this](const PhantomNode &phantom) { return BaseAPI::MakeWaypoint(phantom); }); + 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 EdgeDuration duration) + { + if (duration == MAXIMAL_EDGE_DURATION) + { + return 0.; + } + return from_alias(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(from_alias(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(candidates.size()); + BOOST_ASSERT(candidates.size() == parameters.coordinates.size()); + + 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 MakeDurationTable(const std::vector &values, + virtual util::json::Array MakeDurationTable(const std::vector &values, std::size_t number_of_rows, std::size_t number_of_columns) const { @@ -137,15 +370,18 @@ class TableAPI final : public BaseAPI std::transform(row_begin_iterator, row_end_iterator, json_row.values.begin(), - [](const EdgeWeight duration) { + [](const EdgeDuration duration) + { if (duration == MAXIMAL_EDGE_DURATION) { 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.)); + return util::json::Value( + util::json::Number(from_alias(duration) / 10.)); }); - json_table.values.push_back(std::move(json_row)); + + json_table.values.push_back(util::json::Value{json_row}); } return json_table; } @@ -164,16 +400,17 @@ class TableAPI final : public BaseAPI std::transform(row_begin_iterator, row_end_iterator, json_row.values.begin(), - [](const EdgeDistance distance) { + [](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.)); + return util::json::Value(util::json::Number( + std::round(from_alias(distance) * 10) / 10.)); }); - json_table.values.push_back(std::move(json_row)); + json_table.values.push_back(util::json::Value{json_row}); } return json_table; } @@ -183,11 +420,16 @@ class TableAPI final : public BaseAPI { util::json::Array json_table; std::for_each( - fallback_speed_cells.begin(), fallback_speed_cells.end(), [&](const auto &cell) { + 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)); + util::json::Value jCellRow{util::json::Number(static_cast(cell.row))}; + util::json::Value jCellColumn{util::json::Number(static_cast(cell.column))}; + row.values.push_back(jCellRow); + row.values.push_back(jCellColumn); + json_table.values.push_back(util::json::Value{row}); }); return json_table; } @@ -195,8 +437,6 @@ class TableAPI final : public BaseAPI const TableParameters ¶meters; }; -} // ns api -} // ns engine -} // ns osrm +} // namespace osrm::engine::api #endif diff --git a/include/engine/api/table_parameters.hpp b/include/engine/api/table_parameters.hpp index fbbf6831e9d..bbc76b6b93d 100644 --- a/include/engine/api/table_parameters.hpp +++ b/include/engine/api/table_parameters.hpp @@ -36,11 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { /** @@ -59,7 +55,7 @@ struct TableParameters : public BaseParameters { std::vector sources; std::vector destinations; - double fallback_speed = INVALID_FALLBACK_SPEED; + double fallback_speed = from_alias(INVALID_FALLBACK_SPEED); enum class FallbackCoordinateType { @@ -85,7 +81,7 @@ struct TableParameters : public BaseParameters template TableParameters(std::vector sources_, std::vector destinations_, - Args... args_) + Args &&...args_) : BaseParameters{std::forward(args_)...}, sources{std::move(sources_)}, destinations{std::move(destinations_)} { @@ -95,7 +91,7 @@ struct TableParameters : public BaseParameters TableParameters(std::vector sources_, std::vector destinations_, const AnnotationsType annotations_, - Args... args_) + Args &&...args_) : BaseParameters{std::forward(args_)...}, sources{std::move(sources_)}, destinations{std::move(destinations_)}, annotations{annotations_} { @@ -108,7 +104,7 @@ struct TableParameters : public BaseParameters double fallback_speed_, FallbackCoordinateType fallback_coordinate_type_, double scale_factor_, - Args... args_) + 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_}, @@ -122,7 +118,7 @@ struct TableParameters : public BaseParameters 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; @@ -166,8 +162,6 @@ inline TableParameters::AnnotationsType &operator|=(TableParameters::Annotations { return lhs = lhs | rhs; } -} -} -} +} // namespace osrm::engine::api #endif // ENGINE_API_TABLE_PARAMETERS_HPP diff --git a/include/engine/api/tile_parameters.hpp b/include/engine/api/tile_parameters.hpp index 137c4dac3c7..09978ac4baa 100644 --- a/include/engine/api/tile_parameters.hpp +++ b/include/engine/api/tile_parameters.hpp @@ -30,11 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { /** @@ -70,8 +66,6 @@ struct TileParameters final return valid_x && valid_y && valid_z; } }; -} -} -} +} // namespace osrm::engine::api #endif diff --git a/include/engine/api/trip_api.hpp b/include/engine/api/trip_api.hpp index b65ac1970d5..96486f026e0 100644 --- a/include/engine/api/trip_api.hpp +++ b/include/engine/api/trip_api.hpp @@ -10,11 +10,7 @@ #include "util/integer_range.hpp" -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { class TripAPI final : public RouteAPI @@ -24,85 +20,162 @@ 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 &candidates, + osrm::engine::api::ResultT &response) const + { + BOOST_ASSERT(sub_trips.size() == sub_routes.size()); + + if (std::holds_alternative(response)) + { + auto &fb_result = std::get(response); + MakeResponse(sub_trips, sub_routes, candidates, fb_result); + } + else + { + auto &json_result = std::get(response); + 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 &phantoms, + 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); - response.values["trips"] = std::move(routes); - response.values["code"] = "Ok"; + if (!parameters.skip_waypoints) + { + response.values.emplace("waypoints", MakeWaypoints(sub_trips, candidates)); + } + response.values.emplace("trips", std::move(routes)); + response.values.emplace("code", "Ok"); + auto data_timestamp = facade.GetTimestamp(); + if (!data_timestamp.empty()) + { + response.values.emplace("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. - util::json::Array MakeWaypoints(const std::vector> &sub_trips, - const std::vector &phantoms) const + + struct TripIndex { - util::json::Array waypoints; - waypoints.values.reserve(parameters.coordinates.size()); + TripIndex() = default; - struct TripIndex + TripIndex(unsigned sub_trip_index_, unsigned point_index_) + : sub_trip_index(sub_trip_index_), point_index(point_index_) { - 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(); + 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(); - } - }; + bool NotUsed() + { + return sub_trip_index == std::numeric_limits::max() && + point_index == std::numeric_limits::max(); + } + }; - std::vector input_idx_to_trip_idx(parameters.coordinates.size()); - for (auto sub_trip_index : util::irange(0u, sub_trips.size())) + 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())) { - for (auto point_index : util::irange(0u, sub_trips[sub_trip_index].size())) - { - input_idx_to_trip_idx[sub_trips[sub_trip_index][point_index]] = - TripIndex{sub_trip_index, point_index}; - } + 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 &candidates) const + { + util::json::Array waypoints; + waypoints.values.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(phantoms[input_index]); - waypoint.values["trips_index"] = trip_index.sub_trip_index; - waypoint.values["waypoint_index"] = trip_index.point_index; + auto waypoint = BaseAPI::MakeWaypoint(candidates[input_index]); + waypoint.values.emplace("trips_index", trip_index.sub_trip_index); + waypoint.values.emplace("waypoint_index", trip_index.point_index); waypoints.values.push_back(std::move(waypoint)); } 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())) + { + for (auto point_index : util::irange(0u, sub_trips[sub_trip_index].size())) + { + input_idx_to_trip_idx[sub_trips[sub_trip_index][point_index]] = + TripIndex{sub_trip_index, point_index}; + } + } + return input_idx_to_trip_idx; + } + const TripParameters ¶meters; }; -} // ns api -} // ns engine -} // ns osrm +} // namespace osrm::engine::api #endif diff --git a/include/engine/api/trip_parameters.hpp b/include/engine/api/trip_parameters.hpp index 0df38d6c952..8d28e880f12 100644 --- a/include/engine/api/trip_parameters.hpp +++ b/include/engine/api/trip_parameters.hpp @@ -30,14 +30,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "engine/api/route_parameters.hpp" -#include -#include +#include -namespace osrm -{ -namespace engine -{ -namespace api +namespace osrm::engine::api { /** @@ -64,9 +59,9 @@ struct TripParameters : public RouteParameters TripParameters(SourceType source_, DestinationType destination_, bool roundtrip_, - Args &&... args_) - : RouteParameters{std::forward(args_)...}, source{source_}, destination{destination_}, - roundtrip{roundtrip_} + Args &&...args_) + : RouteParameters{std::forward(args_)...}, source{source_}, + destination{destination_}, roundtrip{roundtrip_} { } @@ -76,8 +71,6 @@ struct TripParameters : public RouteParameters bool IsValid() const { return RouteParameters::IsValid(); } }; -} -} -} +} // namespace osrm::engine::api #endif diff --git a/include/engine/approach.hpp b/include/engine/approach.hpp index 5c6787f27b4..60fd68a463b 100644 --- a/include/engine/approach.hpp +++ b/include/engine/approach.hpp @@ -30,17 +30,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace osrm -{ -namespace engine +namespace osrm::engine { enum class Approach : std::uint8_t { CURB = 0, - UNRESTRICTED = 1 + UNRESTRICTED = 1, + OPPOSITE = 2 }; -} -} +} // namespace osrm::engine #endif diff --git a/include/engine/base64.hpp b/include/engine/base64.hpp index 024d04b297a..8af51b73973 100644 --- a/include/engine/base64.hpp +++ b/include/engine/base64.hpp @@ -3,17 +3,13 @@ #include #include -#include -#include #include #include -#include #include #include #include -#include namespace osrm { @@ -38,7 +34,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 { @@ -47,24 +43,29 @@ namespace engine // Encodes a chunk of memory to Base64. inline std::string encodeBase64(const unsigned char *first, std::size_t size) { - std::vector bytes{first, first + size}; - BOOST_ASSERT(!bytes.empty()); + BOOST_ASSERT(size > 0); - std::size_t bytes_to_pad{0}; + std::string encoded; + encoded.reserve(((size + 2) / 3) * 4); - while (bytes.size() % 3 != 0) + auto padding = (3 - size % 3) % 3; + + BOOST_ASSERT(padding == 0 || padding == 1 || padding == 2); + + for (auto itr = detail::Base64FromBinary(first); itr != detail::Base64FromBinary(first + size); + ++itr) { - bytes_to_pad += 1; - bytes.push_back(0); + encoded.push_back(*itr); } - BOOST_ASSERT(bytes_to_pad == 0 || bytes_to_pad == 1 || bytes_to_pad == 2); - BOOST_ASSERT_MSG(0 == bytes.size() % 3, "base64 input data size is not a multiple of 3"); + for (size_t index = 0; index < padding; ++index) + { + encoded.push_back('='); + } - std::string encoded{detail::Base64FromBinary{bytes.data()}, - detail::Base64FromBinary{bytes.data() + (bytes.size() - bytes_to_pad)}}; + BOOST_ASSERT(encoded.size() == (size + 2) / 3 * 4); - return encoded.append(bytes_to_pad, '='); + return encoded; } // C++11 standard 3.9.1/1: Plain char, signed char, and unsigned char are three distinct types @@ -135,7 +136,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 eaabae78156..c64e689d5f0 100644 --- a/include/engine/bearing.hpp +++ b/include/engine/bearing.hpp @@ -28,9 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef OSRM_ENGINE_BEARING_HPP #define OSRM_ENGINE_BEARING_HPP -namespace osrm -{ -namespace engine +namespace osrm::engine { struct Bearing @@ -46,7 +44,6 @@ 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 osrm::engine #endif diff --git a/include/engine/data_watchdog.hpp b/include/engine/data_watchdog.hpp index b44274545bb..a4583398a25 100644 --- a/include/engine/data_watchdog.hpp +++ b/include/engine/data_watchdog.hpp @@ -17,9 +17,7 @@ #include #include -namespace osrm -{ -namespace engine +namespace osrm::engine { namespace detail @@ -56,11 +54,14 @@ class DataWatchdogImpl( - std::make_shared( - std::vector{ - static_region.shm_key, updatable_region.shm_key})); + { + 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); @@ -75,10 +76,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); } @@ -111,16 +116,20 @@ class DataWatchdogImpl( - std::make_shared( - std::vector{ - static_region.shm_key, updatable_region.shm_key})); + { + boost::unique_lock swap_lock(factory_mutex); + facade_factory = + DataFacadeFactory( + std::make_shared( + std::vector{ + static_region.shm_key, updatable_region.shm_key})); + } } util::Log() << "DataWatchdog thread stopped"; } + mutable boost::shared_mutex factory_mutex; const std::string dataset_name; storage::SharedMonitor barrier; std::thread watcher; @@ -131,14 +140,13 @@ class DataWatchdogImpl 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 osrm::engine #endif diff --git a/include/engine/datafacade.hpp b/include/engine/datafacade.hpp index 76068a472e4..900f1166122 100644 --- a/include/engine/datafacade.hpp +++ b/include/engine/datafacade.hpp @@ -3,15 +3,12 @@ #include "engine/datafacade/contiguous_internalmem_datafacade.hpp" -namespace osrm -{ -namespace engine +namespace osrm::engine { using DataFacadeBase = datafacade::ContiguousInternalMemoryDataFacadeBase; template using DataFacade = datafacade::ContiguousInternalMemoryDataFacade; -} -} +} // namespace osrm::engine #endif diff --git a/include/engine/datafacade/algorithm_datafacade.hpp b/include/engine/datafacade/algorithm_datafacade.hpp index a83a5340c70..192d024fcee 100644 --- a/include/engine/datafacade/algorithm_datafacade.hpp +++ b/include/engine/datafacade/algorithm_datafacade.hpp @@ -12,11 +12,7 @@ #include "util/filtered_graph.hpp" #include "util/integer_range.hpp" -namespace osrm -{ -namespace engine -{ -namespace datafacade +namespace osrm::engine::datafacade { // Namespace local aliases for algorithms @@ -31,30 +27,35 @@ 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, - const std::function filter) const = 0; + virtual EdgeID FindSmallestEdge(const NodeID edge_based_node_from, + const NodeID edge_based_node_to, + const std::function &filter) const = 0; }; template <> class AlgorithmDataFacade @@ -63,6 +64,8 @@ template <> class AlgorithmDataFacade using EdgeData = customizer::EdgeBasedGraphEdgeData; using EdgeRange = util::range; + virtual ~AlgorithmDataFacade() = default; + // search graph access virtual unsigned GetNumberOfNodes() const = 0; @@ -70,23 +73,24 @@ template <> class AlgorithmDataFacade 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 EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0; + virtual EdgeRange GetAdjacentEdgeRange(const NodeID edge_based_node_id) const = 0; - virtual EdgeWeight GetNodeWeight(const NodeID node) const = 0; + virtual EdgeWeight GetNodeWeight(const NodeID edge_based_node_id) const = 0; - virtual EdgeWeight GetNodeDuration(const NodeID node) const = 0; // TODO: to be removed + virtual EdgeDuration + GetNodeDuration(const NodeID edge_based_node_id) const = 0; // TODO: to be removed - virtual EdgeDistance GetNodeDistance(const NodeID node) const = 0; + virtual EdgeDistance GetNodeDistance(const NodeID edge_based_node_id) const = 0; - virtual bool IsForwardEdge(EdgeID edge) const = 0; + virtual bool IsForwardEdge(EdgeID edge_based_edge_id) const = 0; - virtual bool IsBackwardEdge(EdgeID edge) const = 0; + virtual bool IsBackwardEdge(EdgeID edge_based_edge_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 const partitioner::MultiLevelPartitionView &GetMultiLevelPartition() const = 0; @@ -94,13 +98,13 @@ template <> class AlgorithmDataFacade 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 osrm::engine::datafacade #endif diff --git a/include/engine/datafacade/contiguous_block_allocator.hpp b/include/engine/datafacade/contiguous_block_allocator.hpp index 0af5b310b5a..ec16e303f13 100644 --- a/include/engine/datafacade/contiguous_block_allocator.hpp +++ b/include/engine/datafacade/contiguous_block_allocator.hpp @@ -3,11 +3,7 @@ #include "storage/shared_data_index.hpp" -namespace osrm -{ -namespace engine -{ -namespace datafacade +namespace osrm::engine::datafacade { class ContiguousBlockAllocator @@ -19,8 +15,6 @@ class ContiguousBlockAllocator virtual const storage::SharedDataIndex &GetIndex() = 0; }; -} // namespace datafacade -} // namespace engine -} // namespace osrm +} // namespace osrm::engine::datafacade #endif // OSRM_ENGINE_DATAFACADE_CONTIGUOUS_BLOCK_ALLOCATOR_HPP_ diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 63d4dbc3ac1..ca380ecefea 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -22,19 +22,34 @@ #include #include #include -#include #include #include #include #include -namespace osrm -{ -namespace engine -{ -namespace datafacade +namespace osrm::engine::datafacade { +static const std::string DATASET_TURN_DATA = "TurnData"; +static const std::string DATASET_TURN_LANE_DATA = "NameLaneData"; +static const std::string DATASET_NAME_DATA = "NameData"; +static const std::string DATASET_INTERSECTION_BEARINGS = "IntersectionBearings"; +static const std::string DATASET_ENTRY_CLASS = "EntryClass"; + +/** + * Macro is not ideal. But without it we either have to: + * a) Write this boiler-plate for every usage of an optional dataset. + * b) Convert to a function and add lots of polluting NOLINT(bugprone-unchecked-optional-access) + * comments. This macro keeps the API code readable. + */ +#define CHECK_DATASET_DISABLED(val, dataset) \ + { \ + if (!(val)) \ + { \ + throw osrm::util::DisabledDatasetException((dataset)); \ + } \ + } + template class ContiguousInternalMemoryAlgorithmDataFacade; template <> @@ -73,45 +88,53 @@ 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); } + NodeID GetTarget(const EdgeID edge_based_edge_id) const override final + { + return m_query_graph.GetTarget(edge_based_edge_id); + } - const EdgeData &GetEdgeData(const EdgeID e) const override final + const EdgeData &GetEdgeData(const EdgeID edge_based_edge_id) const override final { - return m_query_graph.GetEdgeData(e); + return m_query_graph.GetEdgeData(edge_based_edge_id); } - EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final + EdgeRange GetAdjacentEdgeRange(const NodeID edge_based_node_id) const override final { - return m_query_graph.GetAdjacentEdgeRange(node); + 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, - std::function filter) const override final + EdgeID + FindSmallestEdge(const NodeID edge_based_node_from, + const NodeID edge_based_node_to, + const std::function &filter) const override final { - return m_query_graph.FindSmallestEdge(from, to, filter); + return m_query_graph.FindSmallestEdge(edge_based_node_from, edge_based_node_to, filter); } }; @@ -126,50 +149,53 @@ 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; extractor::ProfileProperties *m_profile_properties; extractor::Datasources *m_datasources; std::uint32_t m_check_sum; - StringView m_data_timestamp; + std::string_view 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; + std::optional> m_lane_description_offsets; + std::optional> m_lane_description_masks; util::vector_view m_turn_weight_penalties; util::vector_view m_turn_duration_penalties; extractor::SegmentDataView segment_data; extractor::EdgeBasedNodeDataView edge_based_node_data; - guidance::TurnDataView turn_data; + std::optional 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::optional> m_lane_tuple_id_pairs; 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; + std::filesystem::path file_index_path; - extractor::IntersectionBearingsView intersection_bearings_view; + std::optional intersection_bearings_view; - extractor::NameTableView m_name_table; + std::optional 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; + std::optional> m_entry_class_table; // allocator that keeps the allocation data std::shared_ptr allocator; + bool isIndexed(const storage::SharedDataIndex &index, const std::string &name) + { + bool result = false; + index.List(name, + boost::make_function_output_iterator([&](const auto &) { result = true; })); + return result; + } + void InitializeInternalPointers(const storage::SharedDataIndex &index, const std::string &metric_name, const std::size_t exclude_index) @@ -182,7 +208,17 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade exclude_mask = m_profile_properties->excludable_classes[exclude_index]; - m_check_sum = *index.GetBlockPtr("/common/connectivity_checksum"); + // We no longer use "/common/connectivity_checksum", as osrm.edges is an optional dataset. + // Instead, we load the value from the MLD or CH graph, whichever is loaded. + if (isIndexed(index, "/mld/connectivity_checksum")) + { + m_check_sum = *index.GetBlockPtr("/mld/connectivity_checksum"); + } + else + { + BOOST_ASSERT(isIndexed(index, "/ch/connectivity_checksum")); + m_check_sum = *index.GetBlockPtr("/ch/connectivity_checksum"); + } m_data_timestamp = make_timestamp_view(index, "/common/timestamp"); @@ -195,13 +231,23 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade edge_based_node_data = make_ebn_data_view(index, "/common/ebg_node_data"); - turn_data = make_turn_data_view(index, "/common/turn_data"); + if (isIndexed(index, "/common/turn_data")) + { + turn_data = make_turn_data_view(index, "/common/turn_data"); + } + + if (isIndexed(index, "/common/names")) + { + m_name_table = make_name_table_view(index, "/common/names"); + } - m_name_table = make_name_table_view(index, "/common/names"); + if (isIndexed(index, "/common/turn_lanes")) + { + std::tie(m_lane_description_offsets, m_lane_description_masks) = + make_turn_lane_description_views(index, "/common/turn_lanes"); - 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_lane_tuple_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"); @@ -210,10 +256,12 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade 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"); + if (isIndexed(index, "/common/intersection_bearings")) + { + 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"); @@ -231,76 +279,81 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade } // 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]; } - NodeForwardRange GetUncompressedForwardGeometry(const EdgeID id) const override final + NodeForwardRange GetUncompressedForwardGeometry(const PackedGeometryID id) const override final { return segment_data.GetForwardGeometry(id); } - NodeReverseRange GetUncompressedReverseGeometry(const EdgeID id) const override final + NodeReverseRange GetUncompressedReverseGeometry(const PackedGeometryID id) const override final { return segment_data.GetReverseGeometry(id); } - DurationForwardRange GetUncompressedForwardDurations(const EdgeID id) const override final + DurationForwardRange + GetUncompressedForwardDurations(const PackedGeometryID id) const override final { return segment_data.GetForwardDurations(id); } - DurationReverseRange GetUncompressedReverseDurations(const EdgeID id) const override final + DurationReverseRange + GetUncompressedReverseDurations(const PackedGeometryID id) const override final { return segment_data.GetReverseDurations(id); } - WeightForwardRange GetUncompressedForwardWeights(const EdgeID id) const override final + WeightForwardRange GetUncompressedForwardWeights(const PackedGeometryID id) const override final { return segment_data.GetForwardWeights(id); } - WeightReverseRange GetUncompressedReverseWeights(const EdgeID id) const override final + WeightReverseRange GetUncompressedReverseWeights(const PackedGeometryID id) const override final { return segment_data.GetReverseWeights(id); } // Returns the data source ids that were used to supply the edge // weights. - DatasourceForwardRange GetUncompressedForwardDatasources(const EdgeID id) const override final + DatasourceForwardRange + GetUncompressedForwardDatasources(const PackedGeometryID id) const override final { return segment_data.GetForwardDatasources(id); } // Returns the data source ids that were used to supply the edge // weights. - DatasourceReverseRange GetUncompressedReverseDatasources(const EdgeID id) const override final + DatasourceReverseRange + GetUncompressedReverseDatasources(const PackedGeometryID id) const override final { return segment_data.GetReverseDatasources(id); } - TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID 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]; } - TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID 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]; } osrm::guidance::TurnInstruction - GetTurnInstructionForEdgeID(const EdgeID id) const override final + GetTurnInstructionForEdgeID(const EdgeID edge_based_edge_id) const override final { - return turn_data.GetTurnInstruction(id); + CHECK_DATASET_DISABLED(turn_data, DATASET_TURN_DATA); + return turn_data->GetTurnInstruction(edge_based_edge_id); } std::vector GetEdgesInBox(const util::Coordinate south_west, @@ -314,127 +367,41 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade std::vector NearestPhantomNodesInRange(const util::Coordinate input_coordinate, - const float max_distance, - 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, use_all_edges); - } - - std::vector - NearestPhantomNodesInRange(const util::Coordinate input_coordinate, - const float max_distance, - const int bearing, - const int bearing_range, + const double max_distance, + const std::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, bearing, bearing_range, approach, 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 Approach approach) const override final - { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodes( - input_coordinate, max_results, max_distance, approach); - } - - 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 - { - BOOST_ASSERT(m_geospatial_query.get()); - return m_geospatial_query->NearestPhantomNodes( - input_coordinate, max_results, bearing, bearing_range, approach); + 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 size_t max_results, + const std::optional max_distance, + const std::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, bearing, bearing_range, approach); + input_coordinate, approach, max_results, max_distance, bearing, std::nullopt); } - std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const Approach approach, - const bool use_all_edges) const override final + PhantomCandidateAlternatives + NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, + const std::optional max_distance, + const std::optional bearing, + const Approach approach, + const bool use_all_edges) const override final { BOOST_ASSERT(m_geospatial_query.get()); - return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate, approach, use_all_edges); - } - - std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const double max_distance, - const Approach approach, - const bool use_all_edges) const override final - { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate, max_distance, approach, use_all_edges); - } - - std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const double max_distance, - const int bearing, - const int bearing_range, - const Approach approach, - const bool use_all_edges) const override final - { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges); - } - - std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const int bearing, - const int bearing_range, - const Approach approach, - const bool use_all_edges) const override final - { - BOOST_ASSERT(m_geospatial_query.get()); - - return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate, bearing, bearing_range, approach, use_all_edges); + return m_geospatial_query->NearestCandidatesWithAlternativeFromBigComponent( + input_coordinate, approach, max_distance, bearing, use_all_edges); } std::uint32_t GetCheckSum() const override final { return m_check_sum; } @@ -444,73 +411,80 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade return std::string(m_data_timestamp.begin(), m_data_timestamp.end()); } - GeometryID GetGeometryIndex(const NodeID id) const override final + GeometryID GetGeometryIndex(const NodeID edge_based_node_id) const override final { - return edge_based_node_data.GetGeometryID(id); + return edge_based_node_data.GetGeometryID(edge_based_node_id); } - ComponentID GetComponentID(const NodeID id) const override final + ComponentID GetComponentID(const NodeID edge_based_node_id) const override final { - return edge_based_node_data.GetComponentID(id); + return edge_based_node_data.GetComponentID(edge_based_node_id); } - extractor::TravelMode GetTravelMode(const NodeID id) const override final + extractor::TravelMode GetTravelMode(const NodeID edge_based_node_id) const override final { - return edge_based_node_data.GetTravelMode(id); + return edge_based_node_data.GetTravelMode(edge_based_node_id); } - extractor::ClassData GetClassData(const NodeID id) const override final + extractor::ClassData GetClassData(const NodeID edge_based_node_id) const override final { - return edge_based_node_data.GetClassData(id); + return edge_based_node_data.GetClassData(edge_based_node_id); } - bool ExcludeNode(const NodeID id) const override final + bool ExcludeNode(const NodeID edge_based_node_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 { auto indexes = extractor::getClassIndexes(class_data); std::vector classes(indexes.size()); - std::transform(indexes.begin(), indexes.end(), classes.begin(), [this](const auto index) { - return m_profile_properties->GetClassName(index); - }); + std::transform(indexes.begin(), + indexes.end(), + classes.begin(), + [this](const auto index) + { return m_profile_properties->GetClassName(index); }); 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 + std::string_view GetNameForID(const NameID id) const override final { - return m_name_table.GetNameForID(id); + CHECK_DATASET_DISABLED(m_name_table, DATASET_NAME_DATA); + return m_name_table->GetNameForID(id); } - StringView GetRefForID(const NameID id) const override final + std::string_view GetRefForID(const NameID id) const override final { - return m_name_table.GetRefForID(id); + CHECK_DATASET_DISABLED(m_name_table, DATASET_NAME_DATA); + return m_name_table->GetRefForID(id); } - StringView GetPronunciationForID(const NameID id) const override final + std::string_view GetPronunciationForID(const NameID id) const override final { - return m_name_table.GetPronunciationForID(id); + CHECK_DATASET_DISABLED(m_name_table, DATASET_NAME_DATA); + return m_name_table->GetPronunciationForID(id); } - StringView GetDestinationsForID(const NameID id) const override final + std::string_view GetDestinationsForID(const NameID id) const override final { - return m_name_table.GetDestinationsForID(id); + CHECK_DATASET_DISABLED(m_name_table, DATASET_NAME_DATA); + return m_name_table->GetDestinationsForID(id); } - StringView GetExitsForID(const NameID id) const override final + std::string_view GetExitsForID(const NameID id) const override final { - return m_name_table.GetExitsForID(id); + CHECK_DATASET_DISABLED(m_name_table, DATASET_NAME_DATA); + return m_name_table->GetExitsForID(id); } - StringView GetDatasourceName(const DatasourceID id) const override final + std::string_view GetDatasourceName(const DatasourceID id) const override final { return m_datasources->GetSourceName(id); } @@ -537,55 +511,74 @@ 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); + CHECK_DATASET_DISABLED(intersection_bearings_view, DATASET_INTERSECTION_BEARINGS); + return intersection_bearings_view->GetBearingClass(node_based_node_id); } - 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); + CHECK_DATASET_DISABLED(turn_data, DATASET_TURN_DATA); + return turn_data->GetPreTurnBearing(edge_based_edge_id); } - 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); + CHECK_DATASET_DISABLED(turn_data, DATASET_TURN_DATA); + 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); - return m_entry_class_table.at(entry_class_id); + CHECK_DATASET_DISABLED(m_entry_class_table, DATASET_ENTRY_CLASS); + CHECK_DATASET_DISABLED(turn_data, DATASET_TURN_DATA); + + 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); } + bool HasLaneData(const EdgeID edge_based_edge_id) const override final + { + CHECK_DATASET_DISABLED(turn_data, DATASET_TURN_DATA); + return turn_data->HasLaneData(edge_based_edge_id); + } - util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const override final + util::guidance::LaneTupleIdPair + GetLaneData(const EdgeID edge_based_edge_id) const override final { - BOOST_ASSERT(HasLaneData(id)); - return m_lane_tupel_id_pairs.at(turn_data.GetLaneDataID(id)); + CHECK_DATASET_DISABLED(turn_data, DATASET_TURN_DATA); + CHECK_DATASET_DISABLED(m_lane_tuple_id_pairs, DATASET_TURN_LANE_DATA); + + BOOST_ASSERT(HasLaneData(edge_based_edge_id)); + return m_lane_tuple_id_pairs->at(turn_data->GetLaneDataID(edge_based_edge_id)); } extractor::TurnLaneDescription GetTurnDescription(const LaneDescriptionID lane_description_id) const override final { + CHECK_DATASET_DISABLED(m_lane_description_offsets, DATASET_TURN_LANE_DATA); + CHECK_DATASET_DISABLED(m_lane_description_masks, DATASET_TURN_LANE_DATA); + if (lane_description_id == INVALID_LANE_DESCRIPTIONID) return {}; else 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]); + m_lane_description_masks->begin() + + m_lane_description_offsets->at(lane_description_id), + m_lane_description_masks->begin() + + m_lane_description_offsets->at(lane_description_id + 1)); } - bool IsLeftHandDriving(const NodeID id) const override final + bool IsLeftHandDriving(const NodeID edge_based_node_id) const override final { // TODO: can be moved to a data block indexed by GeometryID - return edge_based_node_data.IsLeftHandDriving(id); + return edge_based_node_data.IsLeftHandDriving(edge_based_node_id); } - bool IsSegregated(const NodeID id) const override final + bool IsSegregated(const NodeID edge_based_node_id) const override final { - return edge_based_node_data.IsSegregated(id); + return edge_based_node_data.IsSegregated(edge_based_node_id); } std::vector @@ -609,15 +602,21 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade 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}); - }); + results.reserve(std::distance(found_range.first, found_range.second)); + + 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; } }; @@ -630,7 +629,7 @@ 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, metric_name, exclude_index), @@ -691,57 +690,62 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade : public Algo 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); } - EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final + EdgeRange GetAdjacentEdgeRange(const NodeID edge_based_node_id) const override final { - return query_graph.GetAdjacentEdgeRange(node); + return query_graph.GetAdjacentEdgeRange(edge_based_node_id); } - EdgeWeight GetNodeWeight(const NodeID node) const override final + EdgeWeight GetNodeWeight(const NodeID edge_based_node_id) const override final { - return query_graph.GetNodeWeight(node); + return query_graph.GetNodeWeight(edge_based_node_id); } - EdgeDuration GetNodeDuration(const NodeID node) const override final + EdgeDuration GetNodeDuration(const NodeID edge_based_node_id) const override final { - return query_graph.GetNodeDuration(node); + return query_graph.GetNodeDuration(edge_based_node_id); } - EdgeDistance GetNodeDistance(const NodeID node) const override final + EdgeDistance GetNodeDistance(const NodeID edge_based_node_id) const override final { - return query_graph.GetNodeDistance(node); + return query_graph.GetNodeDistance(edge_based_node_id); } - bool IsForwardEdge(const NodeID node) const override final + bool IsForwardEdge(const NodeID edge_based_node_id) const override final { - return query_graph.IsForwardEdge(node); + return query_graph.IsForwardEdge(edge_based_node_id); } - bool IsBackwardEdge(const NodeID node) const override final + bool IsBackwardEdge(const NodeID edge_based_node_id) const override final { - return query_graph.IsBackwardEdge(node); + return query_graph.IsBackwardEdge(edge_based_node_id); } - NodeID GetTarget(const EdgeID e) const override final { return query_graph.GetTarget(e); } + NodeID GetTarget(const EdgeID edge_based_edge_id) const override final + { + return query_graph.GetTarget(edge_based_edge_id); + } - const EdgeData &GetEdgeData(const EdgeID e) const override final + const EdgeData &GetEdgeData(const EdgeID edge_based_edge_id) const override final { - return query_graph.GetEdgeData(e); + return query_graph.GetEdgeData(edge_based_edge_id); } - EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const override final + EdgeRange GetBorderEdgeRange(const LevelID level, + const NodeID edge_based_node_id) const override final { - return query_graph.GetBorderEdgeRange(level, node); + 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); } }; @@ -752,7 +756,7 @@ 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, metric_name, exclude_index), @@ -760,8 +764,6 @@ class ContiguousInternalMemoryDataFacade final { } }; -} -} -} +} // namespace osrm::engine::datafacade #endif // CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 77dab643fa4..b42584b3b4f 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -26,48 +26,42 @@ #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 -#include +#include #include -namespace osrm -{ -namespace engine -{ -namespace datafacade +namespace osrm::engine::datafacade { -using StringView = util::StringView; - class BaseDataFacade { public: using RTreeLeaf = extractor::EdgeBasedNodeSegment; using NodeForwardRange = - boost::iterator_range; - using NodeReverseRange = boost::reversed_range; + std::ranges::subrange; + using NodeReverseRange = std::ranges::reverse_view; using WeightForwardRange = - boost::iterator_range; - using WeightReverseRange = boost::reversed_range; + std::ranges::subrange; + + using WeightReverseRange = std::ranges::reverse_view; using DurationForwardRange = - boost::iterator_range; - using DurationReverseRange = boost::reversed_range; + std::ranges::subrange; + using DurationReverseRange = std::ranges::reverse_view; using DatasourceForwardRange = - boost::iterator_range; - using DatasourceReverseRange = boost::reversed_range; + std::ranges::subrange; + using DatasourceReverseRange = std::ranges::reverse_view; BaseDataFacade() {} virtual ~BaseDataFacade() {} @@ -77,46 +71,51 @@ class BaseDataFacade 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 NodeForwardRange GetUncompressedForwardGeometry(const EdgeID id) const = 0; - virtual NodeReverseRange GetUncompressedReverseGeometry(const EdgeID id) const = 0; + virtual NodeForwardRange GetUncompressedForwardGeometry(const PackedGeometryID id) const = 0; + virtual NodeReverseRange GetUncompressedReverseGeometry(const PackedGeometryID id) const = 0; - virtual TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID id) const = 0; + virtual TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID edge_based_edge_id) const = 0; - virtual TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID 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 WeightForwardRange GetUncompressedForwardWeights(const EdgeID id) const = 0; - virtual WeightReverseRange 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 DurationForwardRange GetUncompressedForwardDurations(const EdgeID id) const = 0; - virtual DurationReverseRange 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 DatasourceForwardRange GetUncompressedForwardDatasources(const EdgeID id) const = 0; - virtual DatasourceReverseRange 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 std::string_view GetDatasourceName(const DatasourceID id) const = 0; - virtual osrm::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; @@ -125,79 +124,41 @@ 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 bool use_all_edges) const = 0; - virtual std::vector - NearestPhantomNodesInRange(const util::Coordinate input_coordinate, - const float max_distance, + const double max_distance, + const std::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 std::optional max_distance, + const std::optional bearing, const Approach approach) const = 0; - virtual std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const Approach approach, - const bool use_all_edges) const = 0; - virtual std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const double max_distance, - const Approach approach, - const bool use_all_edges) 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 bool use_all_edges) const = 0; - virtual std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const int bearing, - const int bearing_range, - const Approach approach, - const bool use_all_edges = false) const = 0; - - virtual bool HasLaneData(const EdgeID id) const = 0; - virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0; + virtual PhantomCandidateAlternatives + NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, + const std::optional max_distance, + const std::optional bearing, + const Approach approach, + const bool use_all_edges) const = 0; + + 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; + virtual std::string_view GetNameForID(const NameID id) const = 0; - virtual StringView GetRefForID(const NameID id) const = 0; + virtual std::string_view GetRefForID(const NameID id) const = 0; - virtual StringView GetPronunciationForID(const NameID id) const = 0; + virtual std::string_view GetPronunciationForID(const NameID id) const = 0; - virtual StringView GetDestinationsForID(const NameID id) const = 0; + virtual std::string_view GetDestinationsForID(const NameID id) const = 0; - virtual StringView GetExitsForID(const NameID id) const = 0; + virtual std::string_view GetExitsForID(const NameID id) const = 0; virtual bool GetContinueStraightDefault() const = 0; @@ -209,22 +170,20 @@ class BaseDataFacade virtual double GetWeightMultiplier() const = 0; - virtual osrm::guidance::TurnBearing PreTurnBearing(const EdgeID eid) const = 0; - virtual osrm::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 NodeID id) const = 0; + virtual bool IsLeftHandDriving(const NodeID edge_based_node_id) const = 0; - virtual bool IsSegregated(const NodeID) 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 osrm::engine::datafacade #endif // DATAFACADE_BASE_HPP diff --git a/include/engine/datafacade/mmap_memory_allocator.hpp b/include/engine/datafacade/mmap_memory_allocator.hpp index 60df71e90b5..6d7a99a16ae 100644 --- a/include/engine/datafacade/mmap_memory_allocator.hpp +++ b/include/engine/datafacade/mmap_memory_allocator.hpp @@ -9,20 +9,15 @@ #include -#include #include -namespace osrm -{ -namespace engine -{ -namespace datafacade +namespace osrm::engine::datafacade { /** * This allocator uses file backed mmap memory block as the data location. */ -class MMapMemoryAllocator : public ContiguousBlockAllocator +class MMapMemoryAllocator final : public ContiguousBlockAllocator { public: explicit MMapMemoryAllocator(const storage::StorageConfig &config); @@ -33,12 +28,10 @@ class MMapMemoryAllocator : public ContiguousBlockAllocator private: storage::SharedDataIndex index; - std::vector mapped_memory_files; + std::vector mapped_memory_files; std::string rtree_filename; }; -} // namespace datafacade -} // namespace engine -} // namespace osrm +} // namespace osrm::engine::datafacade #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 0dd555e2696..8cf5db0bf43 100644 --- a/include/engine/datafacade/process_memory_allocator.hpp +++ b/include/engine/datafacade/process_memory_allocator.hpp @@ -6,11 +6,7 @@ #include -namespace osrm -{ -namespace engine -{ -namespace datafacade +namespace osrm::engine::datafacade { /** @@ -20,7 +16,7 @@ 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); @@ -34,8 +30,6 @@ class ProcessMemoryAllocator : public ContiguousBlockAllocator std::unique_ptr internal_memory; }; -} // namespace datafacade -} // namespace engine -} // namespace osrm +} // namespace osrm::engine::datafacade #endif // OSRM_ENGINE_DATAFACADE_PROCESS_MEMORY_ALLOCATOR_HPP_ diff --git a/include/engine/datafacade/shared_memory_allocator.hpp b/include/engine/datafacade/shared_memory_allocator.hpp index 00b37ac7fd5..71170316c6d 100644 --- a/include/engine/datafacade/shared_memory_allocator.hpp +++ b/include/engine/datafacade/shared_memory_allocator.hpp @@ -8,11 +8,7 @@ #include -namespace osrm -{ -namespace engine -{ -namespace datafacade +namespace osrm::engine::datafacade { /** @@ -20,7 +16,7 @@ namespace datafacade * Many SharedMemoryDataFacade objects can be created that point to the same shared * memory block. */ -class SharedMemoryAllocator : public ContiguousBlockAllocator +class SharedMemoryAllocator final : public ContiguousBlockAllocator { public: explicit SharedMemoryAllocator( @@ -35,8 +31,6 @@ class SharedMemoryAllocator : public ContiguousBlockAllocator std::vector> memory_regions; }; -} // namespace datafacade -} // namespace engine -} // namespace osrm +} // namespace osrm::engine::datafacade #endif // OSRM_ENGINE_DATAFACADE_SHARED_MEMORY_ALLOCATOR_HPP_ diff --git a/include/engine/datafacade_factory.hpp b/include/engine/datafacade_factory.hpp index a4ff57f38dc..10a7e35cc47 100644 --- a/include/engine/datafacade_factory.hpp +++ b/include/engine/datafacade_factory.hpp @@ -12,13 +12,10 @@ #include "storage/shared_datatype.hpp" -#include #include #include -namespace osrm -{ -namespace engine +namespace osrm::engine { // This class selects the right facade for template