Compare commits

..

62 Commits

Author SHA1 Message Date
Daniel Patterson aed7df6173 New build with fixed tests. 2019-02-10 01:07:33 -08:00
Daniel Patterson e3b09875c6 Fix nodejs tests. 2019-02-10 01:06:54 -08:00
Daniel Patterson 52ceea429b Bump version. 2019-02-10 00:54:35 -08:00
Kevin Kreiser 3d4d51d6b7 Consider acceleration profile of vehicle travelling - particularly affects very short routes. 2019-02-10 00:53:40 -08:00
Daniel Patterson 23c69f4c3d Revert "Add stoppage penalty - consider acceleration and braking time, which can dominate short route ETAs."
This reverts commit 05647adcc6.
2019-02-10 00:42:47 -08:00
Daniel Patterson 9d044bf388 Revert "Fix swapped variables, new version."
This reverts commit 67e99c9809.
2019-02-10 00:42:46 -08:00
Daniel Patterson 823d7e45e7 Revert "change phantom node to store an appx speed regardless of direction. use this speed to estimate an accel/decel penalty and scale the penalty based on the distance traveled up to a cutoff. only used in the table plugin at the moment. TODO still lives in the guidance assemble_leg area"
This reverts commit ca55521c87.
2019-02-10 00:42:10 -08:00
Daniel Patterson 6b961dccfc Revert "Add a bunch of tests at different scales. Switch to using linear acceleration estimates to add penalties to start/end of trips."
This reverts commit 6b9006f6e7.
2019-02-10 00:42:08 -08:00
Daniel Patterson 44d4903985 Bump another test release. 2019-02-09 02:55:39 -08:00
Daniel Patterson 55e05b70ac Revert accidental change. 2019-02-09 02:55:18 -08:00
Daniel Patterson 210908dbe6 Bump new test release. 2019-02-09 02:42:38 -08:00
Daniel Patterson 6b9006f6e7 Add a bunch of tests at different scales. Switch to using linear acceleration estimates to add penalties to start/end of trips. 2019-02-09 02:31:36 -08:00
Kevin Kreiser ca55521c87 change phantom node to store an appx speed regardless of direction. use this speed to estimate an accel/decel penalty and scale the penalty based on the distance traveled up to a cutoff. only used in the table plugin at the moment. TODO still lives in the guidance assemble_leg area 2019-02-09 02:31:26 -08:00
Daniel Patterson 67e99c9809 Fix swapped variables, new version. 2019-02-08 15:50:33 -08:00
Kevin Kreiser 05647adcc6 Add stoppage penalty - consider acceleration and braking time, which can dominate short route ETAs. 2019-02-08 15:32:26 -08:00
Daniel Patterson 6c37b71046 Actually expose snapping in node bindings. 2019-02-03 12:09:24 -08:00
Daniel Patterson cb2a46b8d9 Merge changes from c1eda57c13 - add snapping=any|default parameter. 2019-02-03 10:40:26 -08:00
Daniel Patterson b1451a7421 Release 5.21.0 2018-12-18 16:17:34 -07:00
Daniel Patterson da1c251144 Prep 5.21.0-rc.1 2018-12-15 21:43:10 -07:00
Daniel Patterson 1eab7b41d1 Update CHANGELOG. 2018-12-15 21:07:06 -07:00
Daniel Patterson 1dca8ae76a Correct invalid tests - these captured the incorrect behaviour, the matrices should've been symmetrical (a->o == o->a for these cases) 2018-12-15 21:07:06 -07:00
Daniel Patterson 002e86863d Add test to ensure forward/reverse snapping distances are correct, and fix some tests that were incorrect due to the bug. 2018-12-15 21:07:06 -07:00
Daniel Patterson 1d82b01816 Count reverse offset from the back of the geometry, not the front. 2018-12-15 21:07:06 -07:00
Frédéric Rodrigo 714719c377 Lua maxspeed parsing refactoring (#5144)
* Lua maxspeed parsing refactoring
2018-12-14 21:58:07 -07:00
Huyen Chau Nguyen 77b4fbb69c Fix maxspeed to consider source:maxspeed tags (#5217)
* In Belgium the maximum speed in rural areas is 70 in the region Flanders
* parse maxspeed using source:maxspeed and maxspeed:type tags
* add changelog
* make maxspeed:advisory more important than maxspeed
* add test for source:maxspeed
2018-12-14 21:42:44 -07:00
Matt Riggott 11fde865f7 Document switch to Debian base images (#5281)
* Document switch to Debian base images
2018-12-14 21:36:09 -07:00
Salim KAYABASI 717406043a Remove unused Node binary publishing, and upgrade build environment.
Upgrades the build environment to Node 10, which let's us pull down some security fixes in package dependencies that were unfixed in Node 4.

Also removes Node 4 and 6 binary publishing which were almost never used (20 downloads out of 50,000).

Fixes https://github.com/Project-OSRM/osrm-backend/issues/5312
2018-12-14 21:34:48 -07:00
Daniel Patterson 1ef85c57cc Upgrade CI environment to Node 10, remove builds for < Node 8
Remove yarn, npm is fast now, and comes with node.
Synchronize package-lock.json and package.json
2018-12-14 14:56:21 -07:00
Daniel Patterson d0180517a8 Merge branch 'master' of github.com:Project-OSRM/osrm-backend 2018-12-14 11:54:00 -07:00
Daniel Patterson 520b7ebbb6 Remove 5.20 build trigger from master branch - should only exist on release branches. 2018-12-14 11:53:48 -07:00
Dinesh Weerapurage 2caba96076 using libboost 1.67 in both build and run stages (#5311)
* using libboost 1.67 in both build and run stages, added execution permision for /opt
2018-12-14 11:51:05 -07:00
Daniel Patterson 81bc2f41a6 When matching, ignore 'is_startpoint' propert, snap to any edge (#5297)
Includes all edges in the rtree, but adds an `is_startpoint` flag to each.  Most plugin behaviour remains unchanged (non-startpoint edges aren't used as snapping candidates), but for map matching, we allow snapping to any edge.  This fixes map-matching across previously non-is_startpoint edges, like ferries, private service roads, and a few others.
2018-12-13 17:10:32 -07:00
Daniel Patterson 06e010b4d0 Include information on estimates in table response (#5259)
* Revert "Remove estimated_cells value in the response."

This reverts commit 364e35af06.

* Update changelog.

* fix linting

* adjust fallback_speed check

* change [].includes to [].indexOf !== -1 for compatibility with node 4

* change param name

* more cuke tests

* fix formatting
2018-12-11 12:21:57 -05:00
Kajari Ghosh 92d3ce789b Fix scale_factor bug (#5303)
* check for scale_factor != 1

* changelog
2018-12-10 17:11:08 -05:00
Kajari Ghosh 01ca32c81c Fix fallback speed validity checks (#5300)
* fix fallback_speeds check to only accept values > 0

* add invalid_fallback_speed
2018-12-10 14:53:30 -05:00
Kajari Ghosh 2e17f3010a Add a multiplier to the matrix (#5298)
* add a multiplier to the matrix

* add rounding

* remove scale_factor restrictions

* clamp for overflow error

* update check to match error message

* enforce clamping on < 0 and increase test coverage

* add an invalid scale_factor value to node tests

* increase test coverage

* changelog
2018-12-10 13:41:44 -05:00
Kajari Ghosh c4238c4ed6 Backport-v5.20.0 (#5301)
* Prepare RC.1

* Bump version.

* remove destination/sources length <= coordinates length check (#5289)

* Add node 10 builds to travis (#5246)

* Add node 10 builds to travis

* Add changelog

* bump version to rc5

* Fix fallback_speed vector access (#5291)

* add failing cuke test

* correctly access durations vector

* changelog

* one more cuke test

* bump rc version

* 5.20.0

* remove line from changelog about commit that isn't actually in here

* update CHANGELOG and osrm version in package.json for v5.20.0

* bump to restart appveyor
2018-12-10 11:27:13 -05:00
Kajari Ghosh 3d781e6f28 Fix fallback_speed vector access (#5291)
* add failing cuke test

* correctly access durations vector

* changelog

* one more cuke test
2018-12-05 00:41:06 -05:00
Daniel Paz-Soldan 4976233cff Add node 10 builds to travis (#5246)
* Add node 10 builds to travis

* Add changelog
2018-12-04 14:13:49 -05:00
Kajari Ghosh 98ea2a0b09 remove destination/sources length <= coordinates length check (#5289) 2018-12-04 13:35:26 -05:00
Dinesh Weerapurage f978900ab0 adding a debian based docker image 2018-11-08 12:03:35 +01:00
Daniel Patterson 8b6580128b Merge pull request #5255 from Project-OSRM/danpat_snapped_distance_everywhere
Return 'distance' in all waypoints for all APIs
2018-11-02 15:36:27 -07:00
Daniel Patterson 4dde9c7bbe Include distance from input to snapped for all waypoints, not just on the nearest service. 2018-11-02 15:30:52 -07:00
Daniel Patterson 973837207b Merge pull request #5257 from Project-OSRM/danpat_table_noroute_estimate
Use estimates for NoRoute in table requests
2018-11-02 01:41:50 -07:00
Daniel Patterson 364e35af06 Remove estimated_cells value in the response. 2018-11-02 01:08:59 -07:00
Daniel Patterson 985ab58f45 Add feature to fill null table entries with as-the-crow-flies estimates. 2018-11-02 01:07:24 -07:00
Daniel Patterson cb1db646f2 Merge pull request #5251 from Project-OSRM/danpat_cache_distances
Pre-calculate distance values
2018-10-30 16:14:47 -07:00
Daniel Patterson a67c4bf84d Calculating durations is unavoidable due to tie-breaking minimums, but we can avoid accumulating distances if they're not requested. 2018-10-30 15:41:06 -07:00
Daniel Patterson 498259b220 Replace dynamic distance calculation for table plugin with pre-calculated distances on shortcuts, avoiding unpacking cost.
Adds approx 10% to total data size.  Speeds up large table requests by 2 orders of magnitude.

Co-authored-by: Kajari Ghosh <ghoshkaj@gmail.com>
2018-10-30 15:41:06 -07:00
Daniel Patterson 5327f8da4e Timer script should error properly if something goes wrong, and print out what happened. 2018-10-30 15:41:06 -07:00
Daniel Patterson 802ccfb497 Merge pull request #5252 from Project-OSRM/danpat_pin_yarn
Pin Yarn to 1.11.1 so it works with Node4
2018-10-30 15:40:19 -07:00
Daniel Patterson ec369d560a Pin Yarn to 1.11.1 so it works with Node4 (https://github.com/yarnpkg/yarn/pull/6409#issuecomment-429181371) 2018-10-30 15:38:55 -07:00
Daniel Patterson 535647e439 Merge pull request #5242 from Project-OSRM/ghoshkaj_mmaperize
Support directly mmap-ing datafiles
2018-10-29 11:58:26 -07:00
Daniel Patterson 954121634f Merge branch 'master' into ghoshkaj_mmaperize 2018-10-29 09:52:50 -07:00
Daniel Patterson 594a45e7e0 Re-use msinttypes bundled with RapidJSON when compiling on Windows. (#5249) 2018-10-29 09:51:56 -07:00
Daniel Patterson 96c7b47afe Document new mmap_memory option in NodeJS API 2018-10-27 00:12:17 -07:00
Daniel Patterson b7e7d32361 Expose new --mmap switch (mmap_memory: true in NodeJS), and run test suite in this mode, as well as shared memory mode. 2018-10-26 23:54:00 -07:00
Daniel Patterson 2f9cb44368 mmap tarfiles directly when mmapping is enabled, instead of copying data into separate mmapped block
Co-authored-by: Kajari Ghosh <ghoshkaj@gmail.com>
2018-10-26 23:53:59 -07:00
Daniel Patterson d80318f8ea Match serialized bit-packing for vector<bool> to match in-memory layout for vector_view<bool> so that data can be directly mmapped. 2018-10-26 23:53:50 -07:00
Daniel Paz-Soldan b1791d1ab3 Fix anchor links in api docs (#5235) 2018-10-16 09:23:29 -07:00
Yota Toyama a53da9095a Fix table node API docs (#5204) 2018-10-01 16:45:05 +03:00
Kajari Ghosh 72e03f9af9 update changelog after 5.19 release (#5203) 2018-09-11 00:34:40 -04:00
130 changed files with 9744 additions and 11524 deletions
+4
View File
@@ -68,6 +68,10 @@ Thumbs.db
/*.local.bat /*.local.bat
/CMakeSettings.json /CMakeSettings.json
# Jetbrains related files #
###########################
.idea/
# stxxl related files # # stxxl related files #
####################### #######################
.stxxl .stxxl
+59 -65
View File
@@ -13,12 +13,12 @@ notifications:
branches: branches:
only: only:
- master - master
- "5.19" - 5.21
# enable building tags # enable building tags
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/ - /^v\d+\.\d+(\.\d+)?(-\S*)?$/
cache: cache:
yarn: true npm: true
ccache: true ccache: true
apt: true apt: true
directories: directories:
@@ -35,7 +35,7 @@ env:
- CMAKE_VERSION=3.7.2 - CMAKE_VERSION=3.7.2
- MASON="$(pwd)/scripts/mason.sh" - MASON="$(pwd)/scripts/mason.sh"
- ENABLE_NODE_BINDINGS=On - ENABLE_NODE_BINDINGS=On
- NODE="4" - NODE="10"
matrix: matrix:
fast_finish: true fast_finish: true
@@ -46,7 +46,7 @@ matrix:
# Debug Builds # Debug Builds
- os: linux - os: linux
compiler: "format-taginfo-docs" compiler: "format-taginfo-docs"
env: NODE=6 env: NODE=10
sudo: false sudo: false
before_install: before_install:
install: install:
@@ -54,8 +54,7 @@ matrix:
- nvm install $NODE - nvm install $NODE
- nvm use $NODE - nvm use $NODE
- npm --version - npm --version
- npm install --ignore-scripts - npm ci --ignore-scripts
- npm link --ignore-scripts
script: script:
- ./scripts/check_taginfo.py taginfo.json profiles/car.lua - ./scripts/check_taginfo.py taginfo.json profiles/car.lua
- ${MASON} install clang-format 3.8.1 - ${MASON} install clang-format 3.8.1
@@ -157,17 +156,17 @@ matrix:
- os: osx - os: osx
osx_image: xcode9.2 osx_image: xcode9.2
compiler: "mason-osx-release-node-8" compiler: "mason-osx-release-node-10"
# we use the xcode provides clang and don't install our own # we use the xcode provides clang and don't install our own
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="8" env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="10"
after_success: after_success:
- ./scripts/travis/publish.sh - ./scripts/travis/publish.sh
- os: osx - os: osx
osx_image: xcode9.2 osx_image: xcode9.2
compiler: "mason-osx-release-node-4" compiler: "mason-osx-release-node-8"
# we use the xcode provides clang and don't install our own # we use the xcode provides clang and don't install our own
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="4" env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="8"
after_success: after_success:
- ./scripts/travis/publish.sh - ./scripts/travis/publish.sh
@@ -181,54 +180,6 @@ matrix:
env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
# Node build jobs. These skip running the tests. # Node build jobs. These skip running the tests.
- os: linux
sudo: false
compiler: "node-4-mason-linux-release"
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="4"
install:
- pushd ${OSRM_BUILD_DIR}
- |
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
- npm run nodejs-tests
after_success:
- ./scripts/travis/publish.sh
- os: linux
sudo: false
compiler: "node-4-mason-linux-debug"
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="4"
install:
- pushd ${OSRM_BUILD_DIR}
- |
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
- npm run nodejs-tests
after_success:
- ./scripts/travis/publish.sh
- os: linux - os: linux
sudo: false sudo: false
compiler: "node-8-mason-linux-release" compiler: "node-8-mason-linux-release"
@@ -277,6 +228,54 @@ matrix:
after_success: after_success:
- ./scripts/travis/publish.sh - ./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
before_install: before_install:
- source $NVM_DIR/nvm.sh - source $NVM_DIR/nvm.sh
- nvm install $NODE - nvm install $NODE
@@ -295,15 +294,10 @@ before_install:
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
sudo mdutil -i off / sudo mdutil -i off /
fi fi
- |
if [[ ! -f $(which yarn) ]]; then
npm install -g yarn
fi
- export PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)") - export PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
- export PUBLISH=$([[ "${TRAVIS_TAG:-}" == "v${PACKAGE_JSON_VERSION}" ]] && echo "On" || echo "Off") - export PUBLISH=$([[ "${TRAVIS_TAG:-}" == "v${PACKAGE_JSON_VERSION}" ]] && echo "On" || echo "Off")
- echo "Using ${JOBS} jobs" - echo "Using ${JOBS} jobs"
- yarn install --ignore-scripts - npm ci --ignore-scripts
- yarn check --ignore-scripts --integrity
# Bootstrap cmake to be able to run mason # Bootstrap cmake to be able to run mason
- CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/${CMAKE_VERSION}.tar.gz" - CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/${CMAKE_VERSION}.tar.gz"
- CMAKE_DIR="mason_packages/${TRAVIS_OS_NAME}-x86_64/cmake/${CMAKE_VERSION}" - CMAKE_DIR="mason_packages/${TRAVIS_OS_NAME}-x86_64/cmake/${CMAKE_VERSION}"
@@ -382,4 +376,4 @@ script:
fi fi
- | - |
- popd - popd
- yarn test - npm test
+35
View File
@@ -1,3 +1,38 @@
# 5.21.0
- Changes from 5.20.0
- Features:
- ADDED: all waypoints in responses now contain a distance property between the original coordinate and the snapped location. [#5255](https://github.com/Project-OSRM/osrm-backend/pull/5255)
- ADDED: if `fallback_speed` is used, a new structure `fallback_speed_cells` will describe which cells contain estimated values [#5259](https://github.com/Project-OSRM/osrm-backend/pull/5259)
- REMOVED: we no longer publish Node 4 or 6 binary modules (they are still buildable from source) [#5314](https://github.com/Project-OSRM/osrm-backend/pull/5314)
- Table:
- ADDED: new parameter `scale_factor` which will scale the cell `duration` values by this factor. [#5298](https://github.com/Project-OSRM/osrm-backend/pull/5298)
- FIXED: only trigger `scale_factor` code to scan matrix when necessary. [#5303](https://github.com/Project-OSRM/osrm-backend/pull/5303)
- FIXED: fix bug in reverse offset calculation that sometimes lead to negative (and other incorrect) values in distance table results [#5315](https://github.com/Project-OSRM/osrm-backend/pull/5315)
- Docker:
- FIXED: use consistent boost version between build and runtime [#5311](https://github.com/Project-OSRM/osrm-backend/pull/5311)
- FIXED: don't override default permissions on /opt [#5311](https://github.com/Project-OSRM/osrm-backend/pull/5311)
- Matching:
- CHANGED: matching will now consider edges marked with is_startpoint=false, allowing matching over ferries and other previously non-matchable edge types. [#5297](https://github.com/Project-OSRM/osrm-backend/pull/5297)
- Profile:
- ADDED: Parse `source:maxspeed` and `maxspeed:type` tags to apply maxspeeds and add belgian flanders rural speed limit. [#5217](https://github.com/Project-OSRM/osrm-backend/pull/5217)
- CHANGED: Refactor maxspeed parsing to use common library. [#5144](https://github.com/Project-OSRM/osrm-backend/pull/5144)
# 5.20.0
- Changes from 5.19.0:
- Table:
- CHANGED: switch to pre-calculated distances for table responses for large speedup and 10% memory increase. [#5251](https://github.com/Project-OSRM/osrm-backend/pull/5251)
- ADDED: new parameter `fallback_speed` which will fill `null` cells with estimated value [#5257](https://github.com/Project-OSRM/osrm-backend/pull/5257)
- CHANGED: Remove API check for matrix sources/destination length to be less than or equal to coordinates length. [#5298](https://github.com/Project-OSRM/osrm-backend/pull/5289)
- FIXED: Fix crashing bug when using fallback_speed parameter with more sources than destinations. [#5291](https://github.com/Project-OSRM/osrm-backend/pull/5291)
- Features:
- ADDED: direct mmapping of datafiles is now supported via the `--mmap` switch. [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
- REMOVED: the previous `--memory_file` switch is now deprecated and will fallback to `--mmap` [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
- ADDED: Now publishing Node 10.x LTS binary modules [#5246](https://github.com/Project-OSRM/osrm-backend/pull/5246)
- Windows:
- FIXED: Windows builds again. [#5249](https://github.com/Project-OSRM/osrm-backend/pull/5249)
- Docker:
- CHANGED: switch from Alpine Linux to Debian Buster base images [#5281](https://github.com/Project-OSRM/osrm-backend/pull/5281)
# 5.19.0 # 5.19.0
- Changes from 5.18.0: - Changes from 5.18.0:
- Optimizations: - Optimizations:
+1 -1
View File
@@ -50,7 +50,7 @@ If you want to use the CH pipeline instead replace `osrm-partition` and `osrm-cu
### Using Docker ### Using Docker
We base our Docker images ([backend](https://hub.docker.com/r/osrm/osrm-backend/), [frontend](https://hub.docker.com/r/osrm/osrm-frontend/)) on Alpine Linux and make sure they are as lightweight as possible. We base our Docker images ([backend](https://hub.docker.com/r/osrm/osrm-backend/), [frontend](https://hub.docker.com/r/osrm/osrm-frontend/)) on Debian and make sure they are as lightweight as possible.
Download OpenStreetMap extracts for example from [Geofabrik](http://download.geofabrik.de/) Download OpenStreetMap extracts for example from [Geofabrik](http://download.geofabrik.de/)
+12 -13
View File
@@ -1,15 +1,13 @@
FROM alpine:3.6 as buildstage FROM debian:buster-slim as builder
ARG DOCKER_TAG ARG DOCKER_TAG
RUN mkdir -p /src && mkdir -p /opt RUN mkdir -p /src && mkdir -p /opt
COPY . /src COPY . /src
WORKDIR /src WORKDIR /src
RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \ apt-get update && \
apk update && \ apt-get -y --no-install-recommends install cmake make git gcc g++ libbz2-dev libstxxl-dev libstxxl1v5 libxml2-dev \
apk upgrade && \ libzip-dev libboost1.67-all-dev lua5.2 liblua5.2-dev libtbb-dev -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 && \
apk add git cmake wget make libc-dev gcc g++ bzip2-dev boost-dev zlib-dev expat-dev lua5.2-dev libtbb@testing libtbb-dev@testing && \
NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \ NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
echo "Building OSRM ${DOCKER_TAG}" && \ echo "Building OSRM ${DOCKER_TAG}" && \
git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \ git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \
@@ -26,20 +24,21 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
make -j${NPROC} install && \ make -j${NPROC} install && \
cd ../profiles && \ cd ../profiles && \
cp -r * /opt && \ cp -r * /opt && \
\
strip /usr/local/bin/* && \ strip /usr/local/bin/* && \
rm -rf /src /usr/local/lib/libosrm* rm -rf /src /usr/local/lib/libosrm*
# Multistage build to reduce image size - https://docs.docker.com/engine/userguide/eng-image/multistage-build/#use-multi-stage-builds # 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) # Only the content below ends up in the image, this helps remove /src from the image (which is large)
FROM alpine:3.6 as runstage FROM debian:buster-slim as runstage
RUN mkdir -p /src && mkdir -p /opt RUN mkdir -p /src && mkdir -p /opt
RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \ RUN apt-get update && \
apk update && \ apt-get install -y --no-install-recommends libboost-program-options1.67.0 libboost-regex1.67.0 \
apk add boost-filesystem boost-program_options boost-regex boost-iostreams boost-thread libgomp lua5.2 expat libtbb@testing libboost-date-time1.67.0 libboost-chrono1.67.0 libboost-filesystem1.67.0 \
COPY --from=buildstage /usr/local /usr/local libboost-iostreams1.67.0 libboost-thread1.67.0 expat liblua5.2-0 libtbb2 &&\
COPY --from=buildstage /opt /opt rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/local /usr/local
COPY --from=builder /opt /opt
WORKDIR /opt WORKDIR /opt
EXPOSE 5000 EXPOSE 5000
+11 -3
View File
@@ -119,7 +119,6 @@ In addition to the [general options](#general-options) the following options are
- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes. - `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
- `waypoints` array of `Waypoint` objects sorted by distance to the input coordinate. Each object has at least the following additional properties: - `waypoints` array of `Waypoint` objects sorted by distance to the input coordinate. Each object has at least the following additional properties:
- `distance`: Distance in meters to the supplied input coordinate.
- `nodes`: Array of OpenStreetMap node ids. - `nodes`: Array of OpenStreetMap node ids.
#### Example Requests #### Example Requests
@@ -236,8 +235,10 @@ In addition to the [general options](#general-options) the following options are
|------------|--------------------------------------------------|---------------------------------------------| |------------|--------------------------------------------------|---------------------------------------------|
|sources |`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as source. | |sources |`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as source. |
|destinations|`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as destination.| |destinations|`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as destination.|
|annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned. |annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. |
| |fallback_speed|`double > 0`| If no route found between a source/destination pair, calculate the as-the-crow-flies distance, then use this speed to estimate duration.|
|fallback_coordinate|`input` (default), or `snapped`| When using a `fallback_speed`, use the user-supplied coordinate (`input`), or the snapped location (`snapped`) for calculating distances.|
|scale_factor|`double > 0`| Use in conjunction with `annotations=durations`. Scales the table `duration` values by this number.|
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal** Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
to number of input locations; to number of input locations;
@@ -283,6 +284,7 @@ curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397
the i-th waypoint to the j-th waypoint. Values are given in meters. Can be `null` if no route between `i` and `j` can be found. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned. the i-th waypoint to the j-th waypoint. Values are given in meters. Can be `null` if no route between `i` and `j` can be found. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned.
- `sources` array of `Waypoint` objects describing all sources in order - `sources` array of `Waypoint` objects describing all sources in order
- `destinations` array of `Waypoint` objects describing all destinations in order - `destinations` array of `Waypoint` objects describing all destinations in order
- `fallback_speed_cells` (optional) array of arrays containing `i,j` pairs indicating which cells contain estimated values based on `fallback_speed`. Will be absent if `fallback_speed` is not used.
In case of error the following `code`s are supported in addition to the general ones: In case of error the following `code`s are supported in addition to the general ones:
@@ -383,6 +385,10 @@ All other properties might be undefined.
2361.73, 2361.73,
0 0
] ]
],
"fallback_speed_cells": [
[ 0, 1 ],
[ 1, 0 ]
] ]
} }
``` ```
@@ -551,6 +557,7 @@ Vector tiles contain two layers:
| `weight ` | `integer` | how long this segment takes to traverse, in units (may differ from `duration` when artificial biasing is applied in the Lua profiles). ACTUAL ROUTING USES THIS VALUE. | | `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 | | `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` - analagous to `speed`, but using the `weight` value rather than `duration`, rounded to the nearest integer |
| `is_startpoint` | `boolean` | whether this segment can be used as a start/endpoint for routes |
`turns` layer: `turns` layer:
@@ -905,6 +912,7 @@ Object used to describe waypoint on a route.
- `name` Name of the street the coordinate snapped to - `name` Name of the street the coordinate snapped to
- `location` Array that contains the `[longitude, latitude]` pair of the snapped coordinate - `location` Array that contains the `[longitude, latitude]` pair of the snapped coordinate
- `distance` The distance, in metres, from the input coordinate to the snapped coordinate
- `hint` Unique internal identifier of the segment (ephemeral, not constant over data updates) - `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 request to significantly speed up the query and to connect multiple services.
E.g. you can use the `hint` value obtained by the `nearest` query as `hint` values for `route` inputs. E.g. you can use the `hint` value obtained by the `nearest` query as `hint` values for `route` inputs.
+23 -19
View File
@@ -25,7 +25,9 @@ var osrm = new OSRM('network.osrm');
Make sure you prepared the dataset with the correct toolchain. 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/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Connects to the persistent shared memory datastore.
This requires you to run `osrm-datastore` prior to creating an `OSRM` object. This requires you to run `osrm-datastore` prior to creating an `OSRM` object.
- `options.memory_file` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Path to a file on disk to store the memory using mmap. - `options.memory_file` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** *DEPRECATED*
Old behaviour: Path to a file on disk to store the memory using mmap. Current behaviour: setting this value is the same as setting `mmap_memory: true`.
- `options.mmap_memory` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Map on-disk files to virtual memory addresses (mmap), rather than loading into RAM.
- `options.path` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true. - `options.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_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_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query (default: unlimited).
@@ -56,7 +58,7 @@ Returns the fastest route between two or more coordinates while visiting the way
- `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.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.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`.
`null`/`true`/`false` `null`/`true`/`false`
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** - `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples** **Examples**
@@ -88,7 +90,7 @@ Note: `coordinates` in the general options only supports a single `{longitude},{
- `options.number` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Number of nearest segments that should be returned. - `options.number` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Number of nearest segments that should be returned.
Must be an integer greater than or equal to `1`. (optional, default `1`) 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.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** - `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples** **Examples**
@@ -127,7 +129,10 @@ tables. Optionally returns distance table.
- `options.destinations` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer < - `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. #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.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** - `options.fallback_speed` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second.
- `options.fallback_coordinate` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies diestance between two points.
- `options.scale_factor` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Multiply the table duration values in the table by this number for more controlled input into a route optimization solver.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples** **Examples**
@@ -152,6 +157,7 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
Values are given in seconds. Values are given in seconds.
**`sources`**: array of [`Ẁaypoint`](#waypoint) objects describing all sources in order. **`sources`**: array of [`Ẁaypoint`](#waypoint) objects describing all sources in order.
**`destinations`**: array of [`Ẁaypoint`](#waypoint) objects describing all destinations in order. **`destinations`**: array of [`Ẁaypoint`](#waypoint) objects describing all destinations in order.
**`fallback_speed_cells`**: (optional) if `fallback_speed` is used, will be an array of arrays of `row,column` values, indicating which cells contain estimated values.
### tile ### tile
@@ -167,7 +173,7 @@ and what weights they have applied.
- `ZXY` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** an array consisting of `x`, `y`, and `z` values representing tile coordinates like - `ZXY` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** an array consisting of `x`, `y`, and `z` values representing tile coordinates like
[wiki.openstreetmap.org/wiki/Slippy_map_tilenames](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames) [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/). and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** - `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples** **Examples**
@@ -204,7 +210,7 @@ if they can not be matched successfully.
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`. - `options.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.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.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`).
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** - `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples** **Examples**
@@ -268,7 +274,7 @@ Right now, the following combinations are possible:
- `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route starts at `any` or `first` coordinate. (optional, default `any`) - `options.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.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.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** - `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples** **Examples**
@@ -322,16 +328,14 @@ osrm.route(options, { format: "json_buffer" }, function(err, response) {
## Responses ## Responses
Responses
### Route ### Route
Represents a route through (potentially multiple) waypoints. Represents a route through (potentially multiple) waypoints.
**Parameters** **Parameters**
- `exteral` **documentation** in - **documentation** in
[`osrm-backend`](../http.md#route) [`osrm-backend`](../http.md#route-object)
### RouteLeg ### RouteLeg
@@ -339,8 +343,8 @@ Represents a route between two waypoints.
**Parameters** **Parameters**
- `exteral` **documentation** in - **documentation** in
[`osrm-backend`](../http.md#routeleg) [`osrm-backend`](../http.md#routeleg-object)
### RouteStep ### RouteStep
@@ -349,15 +353,15 @@ single way to the subsequent step.
**Parameters** **Parameters**
- `exteral` **documentation** in - **documentation** in
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#routestep) [`osrm-backend`](../http.md#routestep-object)
### StepManeuver ### StepManeuver
**Parameters** **Parameters**
- `exteral` **documentation** in - **documentation** in
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#stepmaneuver) [`osrm-backend`](../http.md#stepmaneuver-object)
### Waypoint ### Waypoint
@@ -365,5 +369,5 @@ Object used to describe waypoint on a route.
**Parameters** **Parameters**
- `exteral` **documentation** in - **documentation** in
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#waypoint) [`osrm-backend`](../http.md#waypoint-object)
+9
View File
@@ -109,3 +109,12 @@ Feature: Car - Handle ferry routes
When I route I should get When I route I should get
| from | to | route | modes | time | | from | to | route | modes | time |
| c | d | bcde,bcde | ferry,ferry | 600s | | c | d | bcde,bcde | ferry,ferry | 600s |
Given the query options
| geometries | geojson |
| overview | full |
# Note that matching *should* work across unsnappable ferries
When I match I should get
| trace | geometry | duration |
| abcdef| 1,1,1.000899,1,1.000899,1,1.002697,1,1.002697,1,1.003596,1,1.003596,1,1.005394,1,1.005394,1,1.006293,1 | 610.9 |
+25
View File
@@ -137,3 +137,28 @@ OSRM will use 4/5 of the projected free-flow speed.
| primary | | | 30 | -1 | | 23 km/h | | 6.7 | | primary | | | 30 | -1 | | 23 km/h | | 6.7 |
| primary | 20 | 30 | | -1 | | 15 km/h | | 4.4 | | primary | 20 | 30 | | -1 | | 15 km/h | | 4.4 |
| primary | 20 | | 30 | -1 | | 23 km/h | | 6.7 | | primary | 20 | | 30 | -1 | | 23 km/h | | 6.7 |
Scenario: Car - Respect source:maxspeed
Given the node map
"""
a b c d e f g
"""
And the ways
| nodes | highway | source:maxspeed | maxspeed |
| ab | trunk | | |
| bc | trunk | | 60 |
| cd | trunk | FR:urban | |
| de | trunk | CH:rural | |
| ef | trunk | CH:trunk | |
| fg | trunk | CH:motorway | |
When I route I should get
| from | to | route | speed |
| a | b | ab,ab | 85 km/h |
| b | c | bc,bc | 48 km/h |
| c | d | cd,cd | 40 km/h |
| d | e | de,de | 64 km/h |
| e | f | ef,ef | 80 km/h |
| f | g | fg,fg | 96 km/h |
+25
View File
@@ -35,3 +35,28 @@ Feature: Car - Allowed start/end modes
| from | to | route | modes | | from | to | route | modes |
| 1 | 2 | ab,ab | driving,driving | | 1 | 2 | ab,ab | driving,driving |
| 2 | 1 | ab,ab | driving,driving | | 2 | 1 | ab,ab | driving,driving |
Scenario: Car - URL override of non-startpoints
Given the node map
"""
a 1 b c 2 d
"""
Given the query options
| snapping | any |
And the ways
| nodes | highway | access |
| ab | service | private |
| bc | primary | |
| cd | service | private |
When I request a travel time matrix I should get
| | 2 | c |
| 1 | 59.1 | 35.1 |
| b | 35.1 | 11.1 |
When I route I should get
| from | to | route |
| 1 | 2 | ab,bc,cd |
| 2 | 1 | cd,bc,ab |
+53 -3
View File
@@ -84,7 +84,47 @@ class OSRMDirectLoader extends OSRMBaseLoader {
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd)); throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd));
} }
}); });
callback();
this.child.readyFunc = (data) => {
if (/running and waiting for requests/.test(data)) {
this.child.stdout.removeListener('data', this.child.readyFunc);
callback();
}
};
this.child.stdout.on('data',this.child.readyFunc);
}
};
class OSRMmmapLoader extends OSRMBaseLoader {
constructor (scope) {
super(scope);
}
load (inputFile, callback) {
this.inputFile = inputFile;
this.shutdown(() => {
this.launch(callback);
});
}
osrmUp (callback) {
if (this.osrmIsRunning()) return callback(new Error("osrm-routed already running!"));
const command_arguments = util.format('%s -p %d -i %s -a %s --mmap', this.inputFile, this.scope.OSRM_PORT, this.scope.OSRM_IP, this.scope.ROUTING_ALGORITHM);
this.child = this.scope.runBin('osrm-routed', command_arguments, this.scope.environment, (err) => {
if (err && err.signal !== 'SIGINT') {
this.child = null;
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd));
}
});
this.child.readyFunc = (data) => {
if (/running and waiting for requests/.test(data)) {
this.child.stdout.removeListener('data', this.child.readyFunc);
callback();
}
};
this.child.stdout.on('data',this.child.readyFunc);
} }
}; };
@@ -135,22 +175,32 @@ class OSRMLoader {
this.scope = scope; this.scope = scope;
this.sharedLoader = new OSRMDatastoreLoader(this.scope); this.sharedLoader = new OSRMDatastoreLoader(this.scope);
this.directLoader = new OSRMDirectLoader(this.scope); this.directLoader = new OSRMDirectLoader(this.scope);
this.mmapLoader = new OSRMmmapLoader(this.scope);
this.method = scope.DEFAULT_LOAD_METHOD; this.method = scope.DEFAULT_LOAD_METHOD;
} }
load (inputFile, callback) { load (inputFile, callback) {
if (!this.loader) {
this.loader = {shutdown: (cb) => cb() };
}
if (this.method === 'datastore') { if (this.method === 'datastore') {
this.directLoader.shutdown((err) => { this.loader.shutdown((err) => {
if (err) return callback(err); if (err) return callback(err);
this.loader = this.sharedLoader; this.loader = this.sharedLoader;
this.sharedLoader.load(inputFile, callback); this.sharedLoader.load(inputFile, callback);
}); });
} else if (this.method === 'directly') { } else if (this.method === 'directly') {
this.sharedLoader.shutdown((err) => { this.loader.shutdown((err) => {
if (err) return callback(err); if (err) return callback(err);
this.loader = this.directLoader; this.loader = this.directLoader;
this.directLoader.load(inputFile, callback); this.directLoader.load(inputFile, callback);
}); });
} else if (this.method === 'mmap') {
this.loader.shutdown((err) => {
if (err) return callback(err);
this.loader = this.mmapLoader;
this.mmapLoader.load(inputFile, callback);
});
} else { } else {
callback(new Error('*** Unknown load method ' + method)); callback(new Error('*** Unknown load method ' + method));
} }
+1 -1
View File
@@ -295,7 +295,7 @@ module.exports = function () {
this.reprocess(callback); this.reprocess(callback);
}); });
this.Given(/^osrm\-routed is stopped$/, (callback) => { this.Given(/^osrm-routed is stopped$/, (callback) => {
this.OSRMLoader.shutdown(callback); this.OSRMLoader.shutdown(callback);
}); });
+25 -7
View File
@@ -3,22 +3,25 @@ var util = require('util');
module.exports = function () { module.exports = function () {
const durationsRegex = new RegExp(/^I request a travel time matrix I should get$/); 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 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 DURATIONS_NO_ROUTE = 2147483647; // MAX_INT
const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT
this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', callback);}.bind(this)); 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(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));
}; };
const durationsParse = function(v) { return isNaN(parseInt(v)); }; const durationsParse = function(v) { return isNaN(parseInt(v)); };
const distancesParse = function(v) { return isNaN(parseFloat(v)); }; const distancesParse = function(v) { return isNaN(parseFloat(v)); };
const estimatesParse = function(v) { return isNaN(parseFloat(v)); };
function tableParse(table, noRoute, annotation, callback) { function tableParse(table, noRoute, annotation, callback) {
const parse = annotation == 'distances' ? distancesParse : durationsParse; const parse = annotation == 'distances' ? distancesParse : (annotation == 'durations' ? durationsParse : estimatesParse);
const params = this.queryParams; const params = this.queryParams;
params.annotations = annotation == 'distances' ? 'distance' : 'duration'; params.annotations = ['durations','fallback_speed_cells'].indexOf(annotation) !== -1 ? 'duration' : 'distance';
var tableRows = table.raw(); var tableRows = table.raw();
@@ -61,11 +64,26 @@ function tableParse(table, noRoute, annotation, callback) {
var json = JSON.parse(response.body); var json = JSON.parse(response.body);
var result = json[annotation].map(row => { var result = {};
var hashes = {}; if (annotation === 'fallback_speed_cells') {
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; }); result = table.raw().map(row => row.map(() => ''));
return hashes; 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;
});
}
var testRow = (row, ri, cb) => { var testRow = (row, ri, cb) => {
for (var k in result[ri]) { for (var k in result[ri]) {
+6 -6
View File
@@ -21,11 +21,11 @@ module.exports = function () {
}); });
}; };
this.When(/^I run "osrm\-routed\s?(.*?)"$/, { timeout: this.TIMEOUT }, (options, callback) => { this.When(/^I run "osrm-routed\s?(.*?)"$/, { timeout: this.TIMEOUT }, (options, callback) => {
this.runAndSafeOutput('osrm-routed', options, callback); this.runAndSafeOutput('osrm-routed', options, callback);
}); });
this.When(/^I run "osrm\-(extract|contract|partition|customize)\s?(.*?)"$/, (binary, options, callback) => { this.When(/^I run "osrm-(extract|contract|partition|customize)\s?(.*?)"$/, (binary, options, callback) => {
const stamp = this.processedCacheFile + '.stamp_' + binary; const stamp = this.processedCacheFile + '.stamp_' + binary;
this.runAndSafeOutput('osrm-' + binary, options, (err) => { this.runAndSafeOutput('osrm-' + binary, options, (err) => {
if (err) return callback(err); if (err) return callback(err);
@@ -33,11 +33,11 @@ module.exports = function () {
}); });
}); });
this.When(/^I try to run "(osrm\-[a-z]+)\s?(.*?)"$/, (binary, options, callback) => { this.When(/^I try to run "(osrm-[a-z]+)\s?(.*?)"$/, (binary, options, callback) => {
this.runAndSafeOutput(binary, options, () => { callback(); }); this.runAndSafeOutput(binary, options, () => { callback(); });
}); });
this.When(/^I run "osrm\-datastore\s?(.*?)"(?: with input "([^"]*)")?$/, (options, input, callback) => { this.When(/^I run "osrm-datastore\s?(.*?)"(?: with input "([^"]*)")?$/, (options, input, callback) => {
let child = this.runAndSafeOutput('osrm-datastore', options, callback); let child = this.runAndSafeOutput('osrm-datastore', options, callback);
if (input !== undefined) if (input !== undefined)
child.stdin.write(input); child.stdin.write(input);
@@ -55,13 +55,13 @@ module.exports = function () {
this.Then(/^stdout should( not)? contain "(.*?)"$/, (not, str) => { this.Then(/^stdout should( not)? contain "(.*?)"$/, (not, str) => {
const contains = this.stdout.indexOf(str) > -1; const contains = this.stdout.indexOf(str) > -1;
assert.ok(typeof not === 'undefined' ? contains : !contains, assert.ok(typeof not === 'undefined' ? contains : !contains,
'stdout ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"'); 'stdout ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
}); });
this.Then(/^stderr should( not)? contain "(.*?)"$/, (not, str) => { this.Then(/^stderr should( not)? contain "(.*?)"$/, (not, str) => {
const contains = this.stderr.indexOf(str) > -1; const contains = this.stderr.indexOf(str) > -1;
assert.ok(typeof not === 'undefined' ? contains : !contains, assert.ok(typeof not === 'undefined' ? contains : !contains,
'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"'); 'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
}); });
this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => { this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => {
+1 -1
View File
@@ -69,7 +69,7 @@ module.exports = function () {
outputRow[direction] = result[direction].status ? outputRow[direction] = result[direction].status ?
'x' : ''; 'x' : '';
break; break;
case /^[\d\.]+ s/.test(want): case /^[\d.]+ s/.test(want):
// the result here can come back as a non-number value like // the result here can come back as a non-number value like
// `diff`, but we only want to apply the unit when it comes // `diff`, but we only want to apply the unit when it comes
// back as a number, for tableDiff's literal comparison // back as a number, for tableDiff's literal comparison
+7 -7
View File
@@ -29,7 +29,7 @@ module.exports = function() {
// setup cache for feature data // setup cache for feature data
// if OSRM_PROFILE is set to force a specific profile, then // if OSRM_PROFILE is set to force a specific profile, then
// include the profile name in the hash of the profile file // include the profile name in the hash of the profile file
hash.hashOfFile(uri, this.OSRM_PROFILE, (err, hash) => { hash.hashOfFile(uri, this.OSRM_PROFILE, (err, hash) => {
if (err) return callback(err); if (err) return callback(err);
@@ -45,10 +45,10 @@ module.exports = function() {
this.featureProcessedCacheDirectories[uri] = featureProcessedCacheDirectory; this.featureProcessedCacheDirectories[uri] = featureProcessedCacheDirectory;
d3.queue(1) d3.queue(1)
.defer(mkdirp, featureProcessedCacheDirectory) .defer(mkdirp, featureProcessedCacheDirectory)
.defer(this.cleanupFeatureCache.bind(this), featureCacheDirectory, hash) .defer(this.cleanupFeatureCache.bind(this), featureCacheDirectory, hash)
.defer(this.cleanupProcessedFeatureCache.bind(this), featureProcessedCacheDirectory, this.osrmHash) .defer(this.cleanupProcessedFeatureCache.bind(this), featureProcessedCacheDirectory, this.osrmHash)
.awaitAll(callback); .awaitAll(callback);
}); });
} }
@@ -87,7 +87,7 @@ module.exports = function() {
fs.readdir(parentPath, (err, files) => { fs.readdir(parentPath, (err, files) => {
let q = d3.queue(); let q = d3.queue();
files.filter(name => { return name !== featureHash;}) files.filter(name => { return name !== featureHash;})
.map((f) => { q.defer(rimraf, path.join(parentPath, f)); }); .map((f) => { q.defer(rimraf, path.join(parentPath, f)); });
q.awaitAll(callback); q.awaitAll(callback);
}); });
}; };
@@ -145,7 +145,7 @@ module.exports = function() {
// converts the scenario titles in file prefixes // converts the scenario titles in file prefixes
this.getScenarioID = (scenario) => { this.getScenarioID = (scenario) => {
let name = scenario.getName().toLowerCase().replace(/[\/\-'=,\(\):\*#]/g, '') let name = scenario.getName().toLowerCase().replace(/[/\-'=,():*#]/g, '')
.replace(/\s/g, '_').replace(/__/g, '_').replace(/\.\./g, '.') .replace(/\s/g, '_').replace(/__/g, '_').replace(/\.\./g, '.')
.substring(0, 64); .substring(0, 64);
return util.format('%d_%s', scenario.getLine(), name); return util.format('%d_%s', scenario.getLine(), name);
+10 -10
View File
@@ -17,12 +17,12 @@ module.exports = {
return true; return true;
var matchPercent = want.match(/(.*)\s+~(.+)%$/), var matchPercent = want.match(/(.*)\s+~(.+)%$/),
matchAbs = want.match(/(.*)\s+\+\-(.+)$/), matchAbs = want.match(/(.*)\s+\+-(.+)$/),
matchRe = want.match(/^\/(.*)\/$/), matchRe = want.match(/^\/(.*)\/$/),
// we use this for matching before/after bearing // we use this for matching before/after bearing
matchBearingListAbs = want.match(/^((\d+)->(\d+))(,(\d+)->(\d+))*\s+\+\-(.+)$/), matchBearingListAbs = want.match(/^((\d+)->(\d+))(,(\d+)->(\d+))*\s+\+-(.+)$/),
matchIntersectionListAbs = want.match(/^(((((true|false):\d+)\s{0,1})+,{0,1})+;{0,1})+\s+\+\-(.+)$/), matchIntersectionListAbs = want.match(/^(((((true|false):\d+)\s{0,1})+,{0,1})+;{0,1})+\s+\+-(.+)$/),
matchRangeNumbers = want.match(/\d+\+\-\d+/); matchRangeNumbers = want.match(/\d+\+-\d+/);
function inRange(margin, got, want) { function inRange(margin, got, want) {
var fromR = parseFloat(want) - margin, var fromR = parseFloat(want) - margin,
@@ -31,12 +31,12 @@ module.exports = {
} }
function parseIntersectionString(str) { function parseIntersectionString(str) {
return str.split(';') return str.split(';')
.map((turn_intersections) => turn_intersections .map((turn_intersections) => turn_intersections
.split(',') .split(',')
.map((intersection) => intersection .map((intersection) => intersection
.split(' ') .split(' ')
.map((entry_bearing_pair) => entry_bearing_pair .map((entry_bearing_pair) => entry_bearing_pair
.split(':')))); .split(':'))));
} }
if (got === want) { if (got === want) {
+2 -2
View File
@@ -32,7 +32,7 @@ module.exports = function () {
this.DEFAULT_ENVIRONMENT = Object.assign({STXXLCFG: stxxl_config}, process.env); this.DEFAULT_ENVIRONMENT = Object.assign({STXXLCFG: stxxl_config}, process.env);
this.DEFAULT_PROFILE = 'bicycle'; this.DEFAULT_PROFILE = 'bicycle';
this.DEFAULT_INPUT_FORMAT = 'osm'; this.DEFAULT_INPUT_FORMAT = 'osm';
this.DEFAULT_LOAD_METHOD = 'datastore'; this.DEFAULT_LOAD_METHOD = process.argv[process.argv.indexOf('-m') +1].match('mmap') ? 'mmap' : 'datastore';
this.DEFAULT_ORIGIN = [1,1]; this.DEFAULT_ORIGIN = [1,1];
this.OSM_USER = 'osrm'; this.OSM_USER = 'osrm';
this.OSM_UID = 1; this.OSM_UID = 1;
@@ -80,7 +80,7 @@ module.exports = function () {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.info(util.format('Node Version', process.version)); console.info(util.format('Node Version', process.version));
if (parseInt(process.version.match(/v(\d)/)[1]) < 4) throw new Error('*** Please upgrade to Node 4.+ to run OSRM cucumber tests'); if (parseInt(process.version.match(/v(\d+)/)[1]) < 4) throw new Error('*** Please upgrade to Node 4.+ to run OSRM cucumber tests');
fs.exists(this.TEST_PATH, (exists) => { fs.exists(this.TEST_PATH, (exists) => {
if (exists) if (exists)
+2 -2
View File
@@ -115,7 +115,7 @@ module.exports = function () {
if (headers.has('weight')) { if (headers.has('weight')) {
if (row.weight.length) { if (row.weight.length) {
if (!row.weight.match(/[\d\.]+/)) if (!row.weight.match(/[\d.]+/))
return cb(new Error('*** Weight must be specified as a numeric value. (ex: 8)')); return cb(new Error('*** Weight must be specified as a numeric value. (ex: 8)'));
got.weight = instructions ? util.format('%d', weight) : ''; got.weight = instructions ? util.format('%d', weight) : '';
} else { } else {
@@ -151,7 +151,7 @@ module.exports = function () {
if (headers.has('locations')){ if (headers.has('locations')){
got.locations = (locations || '').trim(); got.locations = (locations || '').trim();
} }
/* /*
if (headers.has('approaches')){ if (headers.has('approaches')){
got.approaches = (approaches || '').trim(); got.approaches = (approaches || '').trim();
}*/ }*/
+291 -135
View File
@@ -5,21 +5,49 @@ Feature: Basic Distance Matrix
Background: Background:
Given the profile "testbot" Given the profile "testbot"
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16" And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
Scenario: Testbot - Travel distance matrix of small grid
Scenario: Testbot - Travel distance matrix of minimal network
Given the node map Given the node map
""" """
a b a b c
d e f
""" """
And the ways And the ways
| nodes | | nodes |
| ab | | abc |
| def |
| ad |
| be |
| cf |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | | | a | b | e | f |
| a | 0 | 100+-1 | | a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100+-1 | 0 | | b | 100.1 | 0 | 99.4 | 199.5 |
| e | 199.5 | 99.4 | 0 | 100.1 |
| f | 299.5 | 199.5 | 100.1 | 0 |
Scenario: Testbot - Travel distance matrix of minimal network exact distances
Given the node map
"""
a z
b
c
d
"""
And the ways
| nodes |
| az |
| zbcd |
When I request a travel distance matrix I should get
| | a | z | b | c | d |
| a | 0 | 100.1 | 199.5 | 298.9 | 398.3 |
| z | 100.1 | 0 | 99.4 | 198.8 | 298.2 |
| b | 199.5 | 99.4 | 0 | 99.4 | 198.8 |
| c | 298.9 | 198.8 | 99.4 | 0 | 99.4 |
| d | 398.3 | 298.2 | 198.8 | 99.4 | 0 |
Scenario: Testbot - Travel distance matrix of minimal network with toll exclude Scenario: Testbot - Travel distance matrix of minimal network with toll exclude
Given the query options Given the query options
@@ -39,11 +67,11 @@ Feature: Basic Distance Matrix
| bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll | | bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | | | a | b | c | d |
| a | 0 | 100+-1 | | | | a | 0 | 100.1 | | |
| b | 100+-1 | 0 | | | | b | 100.1 | 0 | | |
| c | | | 0 | 100+-1 | | c | | | 0 | 100.1 |
| d | | | 100+-1 | 0 | | d | | | 100.1 | 0 |
Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude
Given the query options Given the query options
@@ -63,8 +91,8 @@ Feature: Basic Distance Matrix
| bd | residential | | | bd | residential | |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | | | a | b | c | d |
| a | 0 | 300+-2 | 100+-2 | 200+-2 | | a | 0 | 298.9 | 99.4 | 199.5 |
Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude
Given the query options Given the query options
@@ -84,8 +112,8 @@ Feature: Basic Distance Matrix
| efgh | residential | | | efgh | residential | |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | e | | | a | b | e |
| a | 0 | 50+-1 | | | a | 0 | 50.1 | |
Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes
Given the query options Given the query options
@@ -106,7 +134,7 @@ Feature: Basic Distance Matrix
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | e | g | | | a | b | e | g |
| a | 0 | 100+-1 | | | | a | 0 | 100.1 | | |
Scenario: Testbot - Travel distance matrix with different way speeds Scenario: Testbot - Travel distance matrix with different way speeds
Given the node map Given the node map
@@ -121,22 +149,22 @@ Feature: Basic Distance Matrix
| cd | tertiary | | cd | tertiary |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | | | a | b | c | d |
| a | 0 | 100+-1 | 200+-1 | 300+-1 | | a | 0 | 100.1 | 200.1 | 300.2 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 | | b | 100.1 | 0 | 100.1 | 200.1 |
| c | 200+-1 | 100+-1 | 0 | 100+-1 | | c | 200.1 | 100.1 | 0 | 100.1 |
| d | 300+-1 | 200+-1 | 100+-1 | 0 | | d | 300.2 | 200.1 | 100.1 | 0 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | | | a | b | c | d |
| a | 0 | 100+-1 | 200+-1 | 300+-1 | | a | 0 | 100.1 | 200.1 | 300.2 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | | | a |
| a | 0 | | a | 0 |
| b | 100+-1 | | b | 100.1 |
| c | 200+-1 | | c | 200.1 |
| d | 300+-1 | | d | 300.2 |
Scenario: Testbot - Travel distance matrix of small grid Scenario: Testbot - Travel distance matrix of small grid
Given the node map Given the node map
@@ -154,11 +182,11 @@ Feature: Basic Distance Matrix
| cf | | cf |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | e | f | | | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 | | a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 | | b | 100.1 | 0 | 99.4 | 199.5 |
| e | 200+-1 | 100+-1 | 0 | 100+-1 | | e | 199.5 | 99.4 | 0 | 100.1 |
| f | 300+-1 | 200+-1 | 100+-1 | 0 | | f | 299.5 | 199.5 | 100.1 | 0 |
Scenario: Testbot - Travel distance matrix of network with unroutable parts Scenario: Testbot - Travel distance matrix of network with unroutable parts
Given the node map Given the node map
@@ -172,7 +200,7 @@ Feature: Basic Distance Matrix
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | | | a | b |
| a | 0 | 100+-1 | | a | 0 | 100.1 |
| b | | 0 | | b | | 0 |
Scenario: Testbot - Travel distance matrix of network with oneways Scenario: Testbot - Travel distance matrix of network with oneways
@@ -189,11 +217,11 @@ Feature: Basic Distance Matrix
| by | | | by | |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | x | y | d | e | | | x | y | d | e |
| x | 0 | 300+-2 | 400+-2 | 300+-2 | | x | 0 | 300.2 | 399.6 | 299.5 |
| y | 500+-2 | 0 | 300+-2 | 200+-2 | | y | 499 | 0 | 299.5 | 199.5 |
| d | 200+-2 | 300+-2 | 0 | 300+-2 | | d | 199.5 | 299.5 | 0 | 298.9 |
| e | 300+-2 | 400+-2 | 100+-2 | 0 | | e | 299.5 | 399.6 | 100.1 | 0 |
Scenario: Testbot - Rectangular travel distance matrix Scenario: Testbot - Rectangular travel distance matrix
Given the node map Given the node map
@@ -212,53 +240,53 @@ Feature: Basic Distance Matrix
When I route I should get When I route I should get
| from | to | distance | | from | to | distance |
| e | a | 200m +- 1 | | e | a | 200m |
| e | b | 100m +- 1 | | e | b | 100m |
| f | a | 300m +- 1 | | f | a | 299.9m |
| f | b | 200m +- 1 | | f | b | 200m |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | e | f | | | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 | | a | 0 | 100.1 | 199.5 | 299.5 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | | | a |
| a | 0 | | a | 0 |
| b | 100+-1 | | b | 100.1 |
| e | 200+-1 | | e | 199.5 |
| f | 300+-1 | | f | 299.5 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | e | f | | | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 | | a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 | | b | 100.1 | 0 | 99.4 | 199.5 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | | | a | b |
| a | 0 | 100+-1 | | a | 0 | 100.1 |
| b | 100+-1 | 0 | | b | 100.1 | 0 |
| e | 200+-1 | 100+-1 | | e | 199.5 | 99.4 |
| f | 300+-1 | 200+-1 | | f | 299.5 | 199.5 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | e | f | | | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 | | a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 | | b | 100.1 | 0 | 99.4 | 199.5 |
| e | 200+-1 | 100+-1 | 0 | 100+-1 | | e | 199.5 | 99.4 | 0 | 100.1 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | e | | | a | b | e |
| a | 0 | 100+-1 | 200+-1 | | a | 0 | 100.1 | 199.5 |
| b | 100+-1 | 0 | 100+-1 | | b | 100.1 | 0 | 99.4 |
| e | 200+-1 | 100+-1 | 0 | | e | 199.5 | 99.4 | 0 |
| f | 300+-1 | 200+-1 | 100+-1 | | f | 299.5 | 199.5 | 100.1 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | e | f | | | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 | | a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 | | b | 100.1 | 0 | 99.4 | 199.5 |
| e | 200+-1 | 100+-1 | 0 | 100+-1 | | e | 199.5 | 99.4 | 0 | 100.1 |
| f | 300+-1 | 200+-1 | 100+-1 | 0 | | f | 299.5 | 199.5 | 100.1 | 0 |
Scenario: Testbot - Travel distance 3x2 matrix Scenario: Testbot - Travel distance 3x2 matrix
Given the node map Given the node map
@@ -277,9 +305,9 @@ Feature: Basic Distance Matrix
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | b | e | f | | | b | e | f |
| a | 100+-1 | 200+-1 | 300+-1 | | a | 100.1 | 199.5 | 299.5 |
| b | 0 | 100+-1 | 200+-1 | | b | 0 | 99.4 | 199.5 |
Scenario: Testbot - All coordinates are from same small component Scenario: Testbot - All coordinates are from same small component
Given a grid size of 300 meters Given a grid size of 300 meters
@@ -299,9 +327,9 @@ Feature: Basic Distance Matrix
| fg | | fg |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | f | g | | | f | g |
| f | 0 | 300+-2 | | f | 0 | 298.2 |
| g | 300+-2 | 0 | | g | 298.2 | 0 |
Scenario: Testbot - Coordinates are from different small component and snap to big CC Scenario: Testbot - Coordinates are from different small component and snap to big CC
Given a grid size of 300 meters Given a grid size of 300 meters
@@ -333,11 +361,11 @@ Feature: Basic Distance Matrix
| i | h | 300m | | i | h | 300m |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | f | g | h | i | | | f | g | h | i |
| f | 0 | 300+-2 | 0 | 300+-2 | | f | 0 | 298.2 | 0 | 298.2 |
| g | 300+-2 | 0 | 300+-2 | 0 | | g | 298.2 | 0 | 298.2 | 0 |
| h | 0 | 300+-2 | 0 | 300+-2 | | h | 0 | 298.2 | 0 | 298.2 |
| i | 300+-2 | 0 | 300+-2 | 0 | | i | 298.2 | 0 | 298.2 | 0 |
Scenario: Testbot - Travel distance matrix with loops Scenario: Testbot - Travel distance matrix with loops
Given the node map Given the node map
@@ -354,11 +382,11 @@ Feature: Basic Distance Matrix
| da | yes | | da | yes |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | 1 | 2 | 3 | 4 | | | 1 | 2 | 3 | 4 |
| 1 | 0 | 100+-1 | 400+-1 | 500+-1 | | 1 | 0 | 100.1 | 399.6 | 499.7 |
| 2 | 700+-1 | 0 | 300+-1 | 400+-1 | | 2 | 699.1 | 0 | 299.5 | 399.6 |
| 3 | 400+-1 | 500+-1 | 0 | 100+-1 | | 3 | 399.6 | 499.7 | 0 | 100.1 |
| 4 | 300+-1 | 400+-1 | 700+-1 | 0 | | 4 | 299.5 | 399.6 | 699.1 | 0 |
Scenario: Testbot - Travel distance matrix based on segment durations Scenario: Testbot - Travel distance matrix based on segment durations
@@ -395,12 +423,12 @@ Feature: Basic Distance Matrix
| ce | | ce |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | e | | | a | b | c | d | e |
| a | 0 | 100+-2 | 200+-2 | 300+-2 | 400+-2 | | a | 0 | 100.1 | 200.1 | 300.2 | 398.9 |
| b | 100+-2 | 0 | 100+-2 | 200+-2 | 300+-2 | | b | 100.1 | 0 | 100.1 | 200.1 | 298.9 |
| c | 200+-2 | 100+-2 | 0 | 100+-2 | 200+-2 | | c | 200.1 | 100.1 | 0 | 100.1 | 198.8 |
| d | 300+-2 | 200+-2 | 100+-2 | 0 | 300+-2 | | d | 300.2 | 200.1 | 100.1 | 0 | 298.9 |
| e | 400+-2 | 300+-2 | 200+-2 | 300+-2 | 0 | | e | 398.9 | 298.9 | 198.8 | 298.9 | 0 |
Scenario: Testbot - Travel distance matrix for alternative loop paths Scenario: Testbot - Travel distance matrix for alternative loop paths
Given the profile file Given the profile file
@@ -439,26 +467,26 @@ Feature: Basic Distance Matrix
| ca | yes | | ca | yes |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 1 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | | 1 | 0 | 1096.7 | 298.9 | 199.5 | 598.4 | 498.3 | 897.3 | 797.9 |
| 2 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | | 2 | 100.1 | 0 | 398.9 | 299.5 | 698.5 | 598.4 | 997.3 | 897.9 |
| 3 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | | 3 | 897.9 | 797.9 | 0 | 1097.4 | 299.5 | 199.5 | 598.4 | 499 |
| 4 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | | 4 | 997.3 | 897.3 | 99.4 | 0 | 398.9 | 298.9 | 697.8 | 598.4 |
| 5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 | | 5 | 598.4 | 498.3 | 897.3 | 797.9 | 0 | 1096.7 | 298.9 | 199.5 |
| 6 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 | | 6 | 698.5 | 598.4 | 997.3 | 897.9 | 100.1 | 0 | 398.9 | 299.5 |
| 7 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 | | 7 | 299.5 | 199.5 | 598.4 | 499 | 897.9 | 797.9 | 0 | 1097.4 |
| 8 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 | | 8 | 398.9 | 298.9 | 697.8 | 598.4 | 997.3 | 897.3 | 99.4 | 0 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | 1 | | | 1 |
| 1 | 0 | | 1 | 0 |
| 2 | 100+-5 | | 2 | 100.1 |
| 3 | 900+-5 | | 3 | 897.9 |
| 4 | 1000+-5 | | 4 | 997.3 |
| 5 | 600+-5 | | 5 | 598.4 |
| 6 | 700+-5 | | 6 | 698.5 |
| 7 | 300+-5 | | 7 | 299.5 |
| 8 | 400+-5 | | 8 | 398.9 |
Scenario: Testbot - Travel distance matrix with ties Scenario: Testbot - Travel distance matrix with ties
Given the node map Given the node map
@@ -480,26 +508,26 @@ Feature: Basic Distance Matrix
| a | c | ac,ac | 200m | 20s | 20 | | a | c | ac,ac | 200m | 20s | 20 |
When I route I should get When I route I should get
| from | to | route | distance | | from | to | route | distance |
| a | b | ab,ab | 450m | | a | b | ab,ab | 450m |
| a | c | ac,ac | 200m | | a | c | ac,ac | 200m |
| a | d | ac,dc,dc | 500m +- 1 | | a | d | ac,dc,dc | 499.9m |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | | | a | b | c | d |
| a | 0 | 450+-2 | 200+-2 | 500+-2 | | a | 0 | 450.3 | 198.8 | 499 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | | | a |
| a | 0 | | a | 0 |
| b | 450+-2 | | b | 450.3 |
| c | 200+-2 | | c | 198.8 |
| d | 500+-2 | | d | 499 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | c | | | a | c |
| a | 0 | 200+-2 | | a | 0 | 198.8 |
| c | 200+-2 | 0 | | c | 198.8 | 0 |
# Check rounding errors # Check rounding errors
@@ -515,8 +543,8 @@ Feature: Basic Distance Matrix
| abcd | | abcd |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | | | a | b | c | d |
| a | 0 | 1000+-3 | 2000+-3 | 3000+-3 | | a | 0 | 1000.7 | 2001.4 | 3002.1 |
Scenario: Testbot - OneToMany vs ManyToOne Scenario: Testbot - OneToMany vs ManyToOne
@@ -560,10 +588,138 @@ Feature: Basic Distance Matrix
| fd | | | fd | |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | b | c | d | e | f | | | a | b | c | d | e | f |
| a | 0 | 100+-1 | 300+-1 | 650+-1 | 1930+-1 | 1533+-1 | | a | 0 | 100.1 | 300.2 | 650.5 | 1930.6 | 1533 |
| b | 760+-1 | 0 | 200+-1 | 550+-1 | 1830+-1 | 1433+-1 | | b | 759 | 0 | 200.1 | 550.4 | 1830.5 | 1432.9 |
| c | 560+-2 | 660+-2 | 0 | 350+-1 | 1630+-1 | 1233+-1 | | c | 558.8 | 658.9 | 0 | 350.3 | 1630.4 | 1232.8 |
| d | 1480+-2 | 1580+-1 | 1780+-1 | 0 | 1280+-1 | 883+-1 | | d | 1478.9 | 1579 | 1779.1 | 0 | 1280.1 | 882.5 |
| e | 200+-2 | 300+-2 | 500+-1 | 710+-1 | 0 | 1593+-1 | | e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 |
| f | 597+-1 | 696+-1 | 896+-1 | 1108+-1 | 400+-3 | 0 | | f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 |
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1501.1 |
| b | 300.2 | 0 | 600.5 | 1200.9 |
| f | 900.7 | 600.5 | 0 | 300.2 |
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1501.1 |
When I request a travel distance matrix I should get
| | a |
| a | 0 |
| b | 300.2 |
| f | 900.7 |
| 1 | 1501.1 |
Scenario: Testbot - Fise input coordinate
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
| fallback_coordinate | input |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1501.1 |
| b | 300.2 | 0 | 600.5 | 1200.9 |
| f | 900.7 | 600.5 | 0 | 300.2 |
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1501.1 |
When I request a travel distance matrix I should get
| | a |
| a | 0 |
| b | 300.2 |
| f | 900.7 |
| 1 | 1501.1 |
Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
| fallback_coordinate | snapped |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1200.9 |
| b | 300.2 | 0 | 600.5 | 900.7 |
| f | 900.7 | 600.5 | 0 | 300.2 |
| 1 | 1200.9 | 900.7 | 300.2 | 0 |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1200.9 |
When I request a travel distance matrix I should get
| | a |
| a | 0 |
| b | 300.2 |
| f | 900.7 |
| 1 | 1200.9 |
Scenario: Ensure consistency with route, and make sure offsets work in both directions
Given a grid size of 100 meters
Given the node map
"""
a b c d e f g h i j
1 2
"""
And the ways
| nodes |
| abcdef |
| fghij |
When I route I should get
| from | to | route | distance |
| 1 | 2 | abcdef,fghij,fghij | 999.9m |
# TODO: this is "correct", but inconsistent with viaroute
When I request a travel distance matrix I should get
| | 1 | 2 |
| 1 | 0 | 1000.7 |
| 2 | 1000.7 | 0 |
+265
View File
@@ -510,3 +510,268 @@ Feature: Basic Duration Matrix
| | a | | | a |
| a | 0 | | a | 0 |
| b | 24.1 | | b | 24.1 |
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 30 |
| b | 30 | 0 | 12 | 24 |
| f | 18 | 12 | 0 | 30 |
| 1 | 30 | 24 | 30 | 0 |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 30 |
When I request a travel time matrix I should get
| | a |
| a | 0 |
| b | 30 |
| f | 18 |
| 1 | 30 |
When I request a travel time matrix I should get estimates for
| | a | b | f | 1 |
| a | | | Y | Y |
| b | | | Y | Y |
| f | Y | Y | | |
| 1 | Y | Y | | |
When I request a travel time matrix I should get estimates for
| | a | b | f | 1 |
| a | | | Y | Y |
When I request a travel time matrix I should get estimates for
| | a |
| a | |
| b | |
| f | Y |
| 1 | Y |
Scenario: Testbot - Filling in noroutes with estimates - use input coordinate
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
| fallback_coordinate | input |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 30 |
| b | 30 | 0 | 12 | 24 |
| f | 18 | 12 | 0 | 30 |
| 1 | 30 | 24 | 30 | 0 |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 30 |
When I request a travel time matrix I should get
| | a |
| a | 0 |
| b | 30 |
| f | 18 |
| 1 | 30 |
When I request a travel time matrix I should get estimates for
| | a | b | f | 1 |
| a | | | Y | Y |
| b | | | Y | Y |
| f | Y | Y | | |
| 1 | Y | Y | | |
When I request a travel time matrix I should get estimates for
| | a | b | f | 1 |
| a | | | Y | Y |
When I request a travel time matrix I should get estimates for
| | a |
| a | |
| b | |
| f | Y |
| 1 | Y |
Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
| fallback_coordinate | snapped |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 24 |
| b | 30 | 0 | 12 | 18 |
| f | 18 | 12 | 0 | 30 |
| 1 | 24 | 18 | 30 | 0 |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 24 |
When I request a travel time matrix I should get
| | a |
| a | 0 |
| b | 30 |
| f | 18 |
| 1 | 24 |
When I request a travel time matrix I should get estimates for
| | a | b | f | 1 |
| a | | | Y | Y |
| b | | | Y | Y |
| f | Y | Y | | |
| 1 | Y | Y | | |
When I request a travel time matrix I should get estimates for
| | a | b | f | 1 |
| a | | | Y | Y |
When I request a travel time matrix I should get estimates for
| | a |
| a | |
| b | |
| f | Y |
| 1 | Y |
Scenario: Testbot - Travel time matrix of minimal network with scale factor
Given the query options
| scale_factor | 2 |
Given the node map
"""
a b
"""
And the ways
| nodes |
| ab |
When I request a travel time matrix I should get
| | a | b |
| a | 0 | 20 |
| b | 20 | 0 |
Scenario: Testbot - Test fallback speeds and scale factor
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| scale_factor | 2 |
| fallback_speed | 5 |
| fallback_coordinate | snapped |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 60 | 36 | 48 |
| b | 60 | 0 | 24 | 36 |
| f | 36 | 24 | 0 | 60 |
| 1 | 48 | 36 | 60 | 0 |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 60 | 36 | 48 |
When I request a travel time matrix I should get
| | a |
| a | 0 |
| b | 60 |
| f | 36 |
| 1 | 48 |
When I request a travel time matrix I should get estimates for
| | a | b | f | 1 |
| a | | | Y | Y |
| b | | | Y | Y |
| f | Y | Y | | |
| 1 | Y | Y | | |
When I request a travel time matrix I should get estimates for
| | a | b | f | 1 |
| a | | | Y | Y |
When I request a travel time matrix I should get estimates for
| | a |
| a | |
| b | |
| f | Y |
| 1 | Y |
Scenario: Testbot - Travel time matrix of minimal network with overflow scale factor
Given the query options
| scale_factor | 2147483647 |
Given the node map
"""
a b
"""
And the ways
| nodes |
| ab |
When I request a travel time matrix I should get
| | a | b |
| a | 0 | 214748364.6 |
| b | 214748364.6 | 0 |
Scenario: Testbot - Travel time matrix of minimal network with fraction scale factor
Given the query options
| scale_factor | 0.5 |
Given the node map
"""
a b
"""
And the ways
| nodes |
| ab |
When I request a travel time matrix I should get
| | a | b |
| a | 0 | 5 |
| b | 5 | 0 |
+52 -54
View File
@@ -38,15 +38,15 @@ Feature: Multi level routing
Scenario: Testbot - Multi level routing Scenario: Testbot - Multi level routing
Given the node map Given the node map
""" """
ab ef ab ef
\ /
dc hg dc hg
ij mn ij mn
/ \
lkpo lkpo
""" """
And the nodes And the nodes
@@ -67,78 +67,76 @@ Feature: Multi level routing
When I route I should get When I route I should get
| from | to | route | time | | from | to | route | time |
| a | b | abcda,abcda | 20s | | a | b | abcda,abcda | 25s |
| a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 229.4s | | a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 239.2s |
| a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 144.7s | | a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 157.1s |
| a | o | abcda,cm,mnopm,mnopm,mnopm | 124.7s | | a | o | abcda,cm,mnopm,mnopm,mnopm | 137.1s |
| f | l | efghe,hj,ijkli,ijkli,ijkli | 124.7s | | f | l | efghe,hj,ijkli,ijkli | 136.7s |
| f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 144.7s | | f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 162.1s |
| l | o | ijkli,kp,mnopm,mnopm | 60s | | l | o | ijkli,kp,mnopm,mnopm | 80s |
| c | m | cm,cm | 44.7s | | c | m | cm,cm | 44.7s |
| f | a | efghe,hj,ijkli,kp,mnopm,cm,abcda,abcda | 239.2s |
| l | a | ijkli,kp,mnopm,cm,abcda,abcda | 157.1s |
When I request a travel time matrix I should get When I request a travel time matrix I should get
| | a | f | l | o | | | a | f | l | o |
| a | 0 | 229.4 | 144.7 | 124.7 | | a | 0 | 239.2 | 157.1 | 137.1 |
| f | 229.4 | 0 | 124.7 | 144.7 | | f | 239.2 | 0 | 136.7 | 162.1 |
| l | 144.7 | 124.7 | 0 | 60 | | l | 157.1 | 136.7 | 0 | 80 |
| o | 124.7 | 144.7 | 60 | 0 | | o | 137.1 | 162.1 | 80 | 0 |
When I request a travel time matrix I should get When I request a travel time matrix I should get
| | a | f | l | o | | | a | f | l | o |
| a | 0 | 229.4 | 144.7 | 124.7 | | a | 0 | 239.2 | 157.1 | 137.1 |
When I request a travel time matrix I should get When I request a travel time matrix I should get
| | a | | | a |
| a | 0 | | a | 0 |
| f | 229.4 | | f | 239.2 |
| l | 144.7 | | l | 157.1 |
| o | 124.7 | | o | 137.1 |
When I request a travel time matrix I should get When I request a travel time matrix I should get
| | a | f | l | o | | | a | f | l | o |
| a | 0 | 229.4 | 144.7 | 124.7 | | a | 0 | 239.2 | 157.1 | 137.1 |
| o | 124.7 | 144.7 | 60 | 0 | | o | 137.1 | 162.1 | 80 | 0 |
When I request a travel time matrix I should get When I request a travel time matrix I should get
| | a | o | | | a | o |
| a | 0 | 124.7 | | a | 0 | 137.1 |
| f | 229.4 | 144.7 | | f | 239.2 | 162.1 |
| l | 144.7 | 60 | | l | 157.1 | 80 |
| o | 124.7 | 0 | | o | 137.1 | 0 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | f | l | o | | | a | f | l | o |
| a | 0+-2 | 2287+-2 | 1443+-2 | 1243+-2 | | a | 0 | 2383.7 | 1566.9 | 1366.8 |
| f | 2284+-2 | 0+-2 | 1241+-2 | 1443+-2 | | f | 2383.7 | 0 | 1293.3 | 1617.3 |
| l | 1443+-2 | 1244+-2 | 0+-2 | 600+-2 | | l | 1566.9 | 1293.3 | 0 | 800.5 |
| o | 1243+-2 | 1444+-2 | 600+-2 | 0+-2 | | o | 1366.8 | 1617.3 | 800.5 | 0 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | f | l | o | | | a | f | l | o |
| a | 0 | 2287.2+-2 | 1443+-2 | 1243+-2 | | a | 0 | 2383.7 | 1566.9 | 1366.8 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | | | a |
| a | 0 | | a | 0 |
| f | 2284.5+-2 | | f | 2383.7 |
| l | 1443.1 | | l | 1566.9 |
| o | 1243 | | o | 1366.8 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | f | l | o | | | a | f | l | o |
| a | 0 | 2287+-2 | 1443+-2 | 1243+-2 | | a | 0 | 2383.7 | 1566.9 | 1366.8 |
| o | 1243 | 1444+-2 | 600+-2 | 0+-2 | | f | 2383.7 | 0 | 1293.3 | 1617.3 |
When I request a travel distance matrix I should get When I request a travel distance matrix I should get
| | a | o | | | a | o |
| a | 0+-2 | 1243+-2 | | a | 0 | 1366.8 |
| f | 2284+-2 | 1443+-2 | | f | 2383.7 | 1617.3 |
| l | 1443+-2 | 600+-2 | | l | 1566.9 | 800.5 |
| o | 1243+-2 | 0+-2 | | o | 1366.8 | 0 |
Scenario: Testbot - Multi level routing: horizontal road Scenario: Testbot - Multi level routing: horizontal road
Given the node map Given the node map
+1 -1
View File
@@ -182,4 +182,4 @@ Feature: Snap start/end point to the nearest way
| x | m | xe,xe | | x | m | xe,xe |
| x | n | xf,xf | | x | n | xf,xf |
| x | o | xg,xg | | x | o | xg,xg |
| x | p | xh,xh | | x | p | xh,xh |
+168
View File
@@ -0,0 +1,168 @@
@routing @maxspeed @testbot
Feature: Testbot - Acceleration profiles
Background: Use specific speeds
Given the profile "testbot"
Scenario: Testbot - No stoppage penalties
Given a grid size of 10 meters
Given the node map
"""
a 1 2 3 4 5 b
"""
And the ways
| nodes | highway | maxspeed:forward | maxspeed:backward |
| ab | trunk | 60 | 45 |
When I route I should get
| from | to | route | time | distance |
| a | b | ab,ab | 3.6s | 59.9m |
| a | 1 | ab,ab | 0.6s | 10m |
| a | 2 | ab,ab | 1.2s | 20m |
| a | 3 | ab,ab | 1.8s | 30m |
| a | 4 | ab,ab | 2.4s | 40m |
| a | 5 | ab,ab | 3s | 50m |
| 5 | b | ab,ab | 0.6s | 9.9m |
| 4 | b | ab,ab | 1.2s | 19.9m |
| 3 | b | ab,ab | 1.8s | 29.9m |
| 2 | b | ab,ab | 2.4s | 39.9m |
| 1 | b | ab,ab | 3s | 49.9m |
| 1 | 2 | ab,ab | 0.6s | 10m |
| 1 | 3 | ab,ab | 1.2s | 20m |
| 1 | 4 | ab,ab | 1.8s | 30m |
| 1 | 5 | ab,ab | 2.4s | 40m |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | b |
| a | 0 | 0.6 | 1.2 | 1.8 | 2.4 | 3 | 3.6 |
| 1 | 0.8 | 0 | 0.6 | 1.2 | 1.8 | 2.4 | 3 |
| 2 | 1.6 | 0.8 | 0 | 0.6 | 1.2 | 1.8 | 2.4 |
| 3 | 2.4 | 1.6 | 0.8 | 0 | 0.6 | 1.2 | 1.8 |
| 4 | 3.2 | 2.4 | 1.6 | 0.8 | 0 | 0.6 | 1.2 |
| 5 | 4 | 3.2 | 2.4 | 1.6 | 0.8 | 0 | 0.6 |
| b | 4.8 | 4 | 3.2 | 2.4 | 1.6 | 0.8 | 0 |
Scenario: Testbot - No stoppage points, tiny grid size
Given a grid size of 1 meters
Given the node map
"""
a 1 2 3 4 5 6 7 8 9 b
"""
And the ways
| nodes | highway | maxspeed:forward | maxspeed:backward |
| ab | trunk | 60 | 45 |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | b |
| a | 0 | 0 | 0.1 | 0.1 | 0.2 | 0.3 | 0.3 | 0.4 | 0.4 | 0.5 | 0.6 |
| 1 | 0 | 0 | 0.1 | 0.1 | 0.2 | 0.3 | 0.3 | 0.4 | 0.4 | 0.5 | 0.6 |
| 2 | 0.1 | 0.1 | 0 | 0 | 0.1 | 0.2 | 0.2 | 0.3 | 0.3 | 0.4 | 0.5 |
| 3 | 0.2 | 0.2 | 0.1 | 0 | 0.1 | 0.2 | 0.2 | 0.3 | 0.3 | 0.4 | 0.5 |
| 4 | 0.3 | 0.3 | 0.2 | 0.1 | 0 | 0.1 | 0.1 | 0.2 | 0.2 | 0.3 | 0.4 |
| 5 | 0.4 | 0.4 | 0.3 | 0.2 | 0.1 | 0 | 0 | 0.1 | 0.1 | 0.2 | 0.3 |
| 6 | 0.4 | 0.4 | 0.3 | 0.2 | 0.1 | 0 | 0 | 0.1 | 0.1 | 0.2 | 0.3 |
| 7 | 0.5 | 0.5 | 0.4 | 0.3 | 0.2 | 0.1 | 0.1 | 0 | 0 | 0.1 | 0.2 |
| 8 | 0.6 | 0.6 | 0.5 | 0.4 | 0.3 | 0.2 | 0.2 | 0.1 | 0 | 0.1 | 0.2 |
| 9 | 0.7 | 0.7 | 0.6 | 0.5 | 0.4 | 0.3 | 0.3 | 0.2 | 0.1 | 0 | 0.1 |
| b | 0.8 | 0.8 | 0.7 | 0.6 | 0.5 | 0.4 | 0.4 | 0.3 | 0.2 | 0.1 | 0 |
Scenario: Testbot - With stoppage points, tiny grid size
Given a grid size of 1 meters
Given the node map
"""
a 1 2 3 4 5 6 7 8 9 b
"""
And the ways
| nodes | highway | maxspeed:forward | maxspeed:backward |
| ab | trunk | 60 | 45 |
And the query options
| acceleration_profile | car |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | b |
| a | 0 | 1.1 | 1.7 | 2.1 | 2.4 | 2.6 | 2.9 | 3.1 | 3.4 | 3.5 | 3.7 |
| 1 | 1.1 | 0 | 1.1 | 1.7 | 2 | 2.3 | 2.6 | 2.8 | 3.1 | 3.3 | 3.5 |
| 2 | 1.7 | 1.1 | 0 | 1.1 | 1.7 | 2 | 2.4 | 2.6 | 2.9 | 3.1 | 3.3 |
| 3 | 2 | 1.5 | 1.1 | 0 | 1.1 | 1.5 | 2 | 2.3 | 2.6 | 2.8 | 3 |
| 4 | 2.3 | 1.9 | 1.5 | 1.1 | 0 | 1.1 | 1.7 | 2 | 2.4 | 2.6 | 2.8 |
| 5 | 2.5 | 2.2 | 1.9 | 1.5 | 1.1 | 0 | 1.1 | 1.7 | 2.1 | 2.4 | 2.6 |
| 6 | 2.8 | 2.5 | 2.3 | 2 | 1.7 | 1.1 | 0 | 1.1 | 1.7 | 2 | 2.3 |
| 7 | 3 | 2.8 | 2.5 | 2.3 | 2 | 1.7 | 1.1 | 0 | 1.1 | 1.7 | 2 |
| 8 | 3.2 | 3 | 2.8 | 2.5 | 2.3 | 2 | 1.5 | 1.1 | 0 | 1.1 | 1.5 |
| 9 | 3.4 | 3.2 | 3 | 2.8 | 2.5 | 2.3 | 1.9 | 1.5 | 1.1 | 0 | 1.1 |
| b | 3.6 | 3.4 | 3.2 | 3 | 2.8 | 2.5 | 2.2 | 1.9 | 1.5 | 1.1 | 0 |
Scenario: Testbot - Use stoppage penalty at waypoints
Given a grid size of 10 meters
Given the node map
"""
a 1 2 3 4 5 b
"""
And the ways
| nodes | highway | maxspeed:forward | maxspeed:backward |
| ab | trunk | 60 | 45 |
And the query options
| acceleration_profile | car |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | b |
| a | 0 | 3.7 | 5.3 | 6.5 | 7.5 | 8.4 | 9.1 |
| 1 | 3.6 | 0 | 3.7 | 5.3 | 6.5 | 7.5 | 8.3 |
| 2 | 5.1 | 3.6 | 0 | 3.7 | 5.3 | 6.5 | 7.5 |
| 3 | 6.3 | 5.1 | 3.6 | 0 | 3.7 | 5.3 | 6.4 |
| 4 | 7.2 | 6.3 | 5.1 | 3.6 | 0 | 3.7 | 5.2 |
| 5 | 8.1 | 7.2 | 6.3 | 5.1 | 3.6 | 0 | 3.7 |
| b | 8.9 | 8.1 | 7.2 | 6.2 | 5.1 | 3.6 | 0 |
Scenario: Long distance grid with no penalty
Given a grid size of 1000 meters
Given the node map
"""
a 1 2 3 4 5 b
"""
And the ways
| nodes | highway | maxspeed:forward | maxspeed:backward |
| ab | trunk | 60 | 45 |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | b |
| a | 0 | 59.9 | 119.9 | 179.9 | 239.9 | 299.9 | 359.9 |
| 1 | 79.9 | 0 | 60 | 120 | 180 | 240 | 300 |
| 2 | 159.9 | 80 | 0 | 60 | 120 | 180 | 240 |
| 3 | 239.9 | 160 | 80 | 0 | 60 | 120 | 180 |
| 4 | 319.9 | 240 | 160 | 80 | 0 | 60 | 120 |
| 5 | 399.9 | 320 | 240 | 160 | 80 | 0 | 60 |
| b | 479.9 | 400 | 320 | 240 | 160 | 80 | 0 |
Scenario: Long distance grid
Given a grid size of 1000 meters
Given the node map
"""
a 1 2 3 4 5 b
"""
And the ways
| nodes | highway | maxspeed:forward | maxspeed:backward |
| ab | trunk | 60 | 45 |
And the query options
| acceleration_profile | car |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | b |
| a | 0 | 65.1 | 125.1 | 185.1 | 245.1 | 305.1 | 365.1 |
| 1 | 83.7 | 0 | 65.2 | 125.2 | 185.2 | 245.2 | 305.2 |
| 2 | 163.7 | 83.8 | 0 | 65.2 | 125.2 | 185.2 | 245.2 |
| 3 | 243.7 | 163.8 | 83.8 | 0 | 65.2 | 125.2 | 185.2 |
| 4 | 323.7 | 243.8 | 163.8 | 83.8 | 0 | 65.2 | 125.2 |
| 5 | 403.7 | 323.8 | 243.8 | 163.8 | 83.8 | 0 | 65.2 |
| b | 483.7 | 403.8 | 323.8 | 243.8 | 163.8 | 83.8 | 0 |
+5 -2
View File
@@ -12,23 +12,26 @@ namespace contractor
struct ContractorEdgeData struct ContractorEdgeData
{ {
ContractorEdgeData() ContractorEdgeData()
: weight(0), duration(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0) : weight(0), duration(0), distance(0), id(0), originalEdges(0), shortcut(0), forward(0),
backward(0)
{ {
} }
ContractorEdgeData(EdgeWeight weight, ContractorEdgeData(EdgeWeight weight,
EdgeWeight duration, EdgeWeight duration,
EdgeDistance distance,
unsigned original_edges, unsigned original_edges,
unsigned id, unsigned id,
bool shortcut, bool shortcut,
bool forward, bool forward,
bool backward) bool backward)
: weight(weight), duration(duration), id(id), : weight(weight), duration(duration), distance(distance), id(id),
originalEdges(std::min((1u << 29) - 1u, original_edges)), shortcut(shortcut), originalEdges(std::min((1u << 29) - 1u, original_edges)), shortcut(shortcut),
forward(forward), backward(backward) forward(forward), backward(backward)
{ {
} }
EdgeWeight weight; EdgeWeight weight;
EdgeWeight duration; EdgeWeight duration;
EdgeDistance distance;
unsigned id; unsigned id;
unsigned originalEdges : 29; unsigned originalEdges : 29;
bool shortcut : 1; bool shortcut : 1;
@@ -41,6 +41,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
input_edge.target, input_edge.target,
std::max(input_edge.data.weight, 1), std::max(input_edge.data.weight, 1),
input_edge.data.duration, input_edge.data.duration,
input_edge.data.distance,
1, 1,
input_edge.data.turn_id, input_edge.data.turn_id,
false, false,
@@ -51,6 +52,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
input_edge.source, input_edge.source,
std::max(input_edge.data.weight, 1), std::max(input_edge.data.weight, 1),
input_edge.data.duration, input_edge.data.duration,
input_edge.data.distance,
1, 1,
input_edge.data.turn_id, input_edge.data.turn_id,
false, false,
@@ -82,6 +84,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1; forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT; forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT;
forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION; forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION;
forward_edge.data.distance = reverse_edge.data.distance = MAXIMAL_EDGE_DISTANCE;
// remove parallel edges // remove parallel edges
while (i < edges.size() && edges[i].source == source && edges[i].target == target) while (i < edges.size() && edges[i].source == source && edges[i].target == target)
{ {
@@ -90,12 +93,16 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight); forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight);
forward_edge.data.duration = forward_edge.data.duration =
std::min(edges[i].data.duration, forward_edge.data.duration); std::min(edges[i].data.duration, forward_edge.data.duration);
forward_edge.data.distance =
std::min(edges[i].data.distance, forward_edge.data.distance);
} }
if (edges[i].data.backward) if (edges[i].data.backward)
{ {
reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight); reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight);
reverse_edge.data.duration = reverse_edge.data.duration =
std::min(edges[i].data.duration, reverse_edge.data.duration); std::min(edges[i].data.duration, reverse_edge.data.duration);
reverse_edge.data.distance =
std::min(edges[i].data.distance, reverse_edge.data.distance);
} }
++i; ++i;
} }
@@ -151,6 +158,7 @@ template <class Edge, typename GraphT> inline std::vector<Edge> toEdges(GraphT g
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid"); BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
new_edge.data.weight = data.weight; new_edge.data.weight = data.weight;
new_edge.data.duration = data.duration; new_edge.data.duration = data.duration;
new_edge.data.distance = data.distance;
new_edge.data.shortcut = data.shortcut; new_edge.data.shortcut = data.shortcut;
new_edge.data.turn_id = data.id; new_edge.data.turn_id = data.id;
BOOST_ASSERT_MSG(new_edge.data.turn_id != INT_MAX, // 2^31 BOOST_ASSERT_MSG(new_edge.data.turn_id != INT_MAX, // 2^31
+8 -3
View File
@@ -17,7 +17,8 @@ struct QueryEdge
struct EdgeData struct EdgeData
{ {
explicit EdgeData() explicit EdgeData()
: turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false) : turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false),
distance(0)
{ {
} }
@@ -25,10 +26,11 @@ struct QueryEdge
const bool shortcut, const bool shortcut,
const EdgeWeight weight, const EdgeWeight weight,
const EdgeWeight duration, const EdgeWeight duration,
const EdgeDistance distance,
const bool forward, const bool forward,
const bool backward) const bool backward)
: turn_id(turn_id), shortcut(shortcut), weight(weight), duration(duration), : turn_id(turn_id), shortcut(shortcut), weight(weight), duration(duration),
forward(forward), backward(backward) forward(forward), backward(backward), distance(distance)
{ {
} }
@@ -40,6 +42,7 @@ struct QueryEdge
turn_id = other.id; turn_id = other.id;
forward = other.forward; forward = other.forward;
backward = other.backward; backward = other.backward;
distance = other.distance;
} }
// this ID is either the middle node of the shortcut, or the ID of the edge based node (node // this ID is either the middle node of the shortcut, or the ID of the edge based node (node
// based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle // based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle
@@ -50,6 +53,7 @@ struct QueryEdge
EdgeWeight duration : 30; EdgeWeight duration : 30;
std::uint32_t forward : 1; std::uint32_t forward : 1;
std::uint32_t backward : 1; std::uint32_t backward : 1;
EdgeDistance distance;
} data; } data;
QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {} QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
@@ -69,7 +73,8 @@ struct QueryEdge
return (source == right.source && target == right.target && return (source == right.source && target == right.target &&
data.weight == right.data.weight && data.duration == right.data.duration && data.weight == right.data.weight && data.duration == right.data.duration &&
data.shortcut == right.data.shortcut && data.forward == right.data.forward && data.shortcut == right.data.shortcut && data.forward == right.data.forward &&
data.backward == right.data.backward && data.turn_id == right.data.turn_id); data.backward == right.data.backward && data.turn_id == right.data.turn_id &&
data.distance == right.data.distance);
} }
}; };
} }
+37 -11
View File
@@ -22,6 +22,7 @@ class CellCustomizer
{ {
bool from_clique; bool from_clique;
EdgeDuration duration; EdgeDuration duration;
EdgeDistance distance;
}; };
public: public:
@@ -60,7 +61,7 @@ class CellCustomizer
} }
} }
heap.Clear(); heap.Clear();
heap.Insert(source, 0, {false, 0}); heap.Insert(source, 0, {false, 0, 0});
// explore search space // explore search space
while (!heap.Empty() && !destinations_set.empty()) while (!heap.Empty() && !destinations_set.empty())
@@ -68,8 +69,18 @@ class CellCustomizer
const NodeID node = heap.DeleteMin(); const NodeID node = heap.DeleteMin();
const EdgeWeight weight = heap.GetKey(node); const EdgeWeight weight = heap.GetKey(node);
const EdgeDuration duration = heap.GetData(node).duration; const EdgeDuration duration = heap.GetData(node).duration;
const EdgeDistance distance = heap.GetData(node).distance;
RelaxNode(graph, cells, allowed_nodes, metric, heap, level, node, weight, duration); RelaxNode(graph,
cells,
allowed_nodes,
metric,
heap,
level,
node,
weight,
duration,
distance);
destinations_set.erase(node); destinations_set.erase(node);
} }
@@ -77,21 +88,27 @@ class CellCustomizer
// fill a map of destination nodes to placeholder pointers // fill a map of destination nodes to placeholder pointers
auto weights = cell.GetOutWeight(source); auto weights = cell.GetOutWeight(source);
auto durations = cell.GetOutDuration(source); auto durations = cell.GetOutDuration(source);
auto distances = cell.GetOutDistance(source);
for (auto &destination : destinations) for (auto &destination : destinations)
{ {
BOOST_ASSERT(!weights.empty()); BOOST_ASSERT(!weights.empty());
BOOST_ASSERT(!durations.empty()); BOOST_ASSERT(!durations.empty());
BOOST_ASSERT(!distances.empty());
const bool inserted = heap.WasInserted(destination); const bool inserted = heap.WasInserted(destination);
weights.front() = inserted ? heap.GetKey(destination) : INVALID_EDGE_WEIGHT; weights.front() = inserted ? heap.GetKey(destination) : INVALID_EDGE_WEIGHT;
durations.front() = durations.front() =
inserted ? heap.GetData(destination).duration : MAXIMAL_EDGE_DURATION; inserted ? heap.GetData(destination).duration : MAXIMAL_EDGE_DURATION;
distances.front() =
inserted ? heap.GetData(destination).distance : INVALID_EDGE_DISTANCE;
weights.advance_begin(1); weights.advance_begin(1);
durations.advance_begin(1); durations.advance_begin(1);
distances.advance_begin(1);
} }
BOOST_ASSERT(weights.empty()); BOOST_ASSERT(weights.empty());
BOOST_ASSERT(durations.empty()); BOOST_ASSERT(durations.empty());
BOOST_ASSERT(distances.empty());
} }
} }
@@ -128,7 +145,8 @@ class CellCustomizer
LevelID level, LevelID level,
NodeID node, NodeID node,
EdgeWeight weight, EdgeWeight weight,
EdgeDuration duration) const EdgeDuration duration,
EdgeDistance distance) const
{ {
auto first_level = level == 1; auto first_level = level == 1;
BOOST_ASSERT(heap.WasInserted(node)); BOOST_ASSERT(heap.WasInserted(node));
@@ -149,6 +167,7 @@ class CellCustomizer
auto subcell = cells.GetCell(metric, level - 1, subcell_id); auto subcell = cells.GetCell(metric, level - 1, subcell_id);
auto subcell_destination = subcell.GetDestinationNodes().begin(); auto subcell_destination = subcell.GetDestinationNodes().begin();
auto subcell_duration = subcell.GetOutDuration(node).begin(); auto subcell_duration = subcell.GetOutDuration(node).begin();
auto subcell_distance = subcell.GetOutDistance(node).begin();
for (auto subcell_weight : subcell.GetOutWeight(node)) for (auto subcell_weight : subcell.GetOutWeight(node))
{ {
if (subcell_weight != INVALID_EDGE_WEIGHT) if (subcell_weight != INVALID_EDGE_WEIGHT)
@@ -161,20 +180,24 @@ class CellCustomizer
const EdgeWeight to_weight = weight + subcell_weight; const EdgeWeight to_weight = weight + subcell_weight;
const EdgeDuration to_duration = duration + *subcell_duration; const EdgeDuration to_duration = duration + *subcell_duration;
const EdgeDistance to_distance = distance + *subcell_distance;
if (!heap.WasInserted(to)) if (!heap.WasInserted(to))
{ {
heap.Insert(to, to_weight, {true, to_duration}); heap.Insert(to, to_weight, {true, to_duration, to_distance});
} }
else if (std::tie(to_weight, to_duration) < else if (std::tie(to_weight, to_duration, to_distance) <
std::tie(heap.GetKey(to), heap.GetData(to).duration)) std::tie(heap.GetKey(to),
heap.GetData(to).duration,
heap.GetData(to).distance))
{ {
heap.DecreaseKey(to, to_weight); heap.DecreaseKey(to, to_weight);
heap.GetData(to) = {true, to_duration}; heap.GetData(to) = {true, to_duration, to_distance};
} }
} }
++subcell_destination; ++subcell_destination;
++subcell_duration; ++subcell_duration;
++subcell_distance;
} }
} }
} }
@@ -195,15 +218,18 @@ class CellCustomizer
{ {
const EdgeWeight to_weight = weight + data.weight; const EdgeWeight to_weight = weight + data.weight;
const EdgeDuration to_duration = duration + data.duration; const EdgeDuration to_duration = duration + data.duration;
const EdgeDistance to_distance = distance + data.distance;
if (!heap.WasInserted(to)) if (!heap.WasInserted(to))
{ {
heap.Insert(to, to_weight, {false, duration + data.duration}); heap.Insert(
to, to_weight, {false, duration + data.duration, distance + data.distance});
} }
else if (std::tie(to_weight, to_duration) < else if (std::tie(to_weight, to_duration, to_distance) <
std::tie(heap.GetKey(to), heap.GetData(to).duration)) std::tie(
heap.GetKey(to), heap.GetData(to).duration, heap.GetData(to).distance))
{ {
heap.DecreaseKey(to, to_weight); heap.DecreaseKey(to, to_weight);
heap.GetData(to) = {false, to_duration}; heap.GetData(to) = {false, to_duration, to_distance};
} }
} }
} }
+1
View File
@@ -20,6 +20,7 @@ template <storage::Ownership Ownership> struct CellMetricImpl
Vector<EdgeWeight> weights; Vector<EdgeWeight> weights;
Vector<EdgeDuration> durations; Vector<EdgeDuration> durations;
Vector<EdgeDistance> distances;
}; };
} }
+10 -3
View File
@@ -58,8 +58,10 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
MultiLevelGraph(PartitionerGraphT &&graph, MultiLevelGraph(PartitionerGraphT &&graph,
Vector<EdgeWeight> node_weights_, Vector<EdgeWeight> node_weights_,
Vector<EdgeDuration> node_durations_) Vector<EdgeDuration> node_durations_,
: node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)) Vector<EdgeDistance> node_distances_)
: node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
node_distances(std::move(node_distances_))
{ {
util::ViewOrVector<PartitionerGraphT::EdgeArrayEntry, storage::Ownership::Container> util::ViewOrVector<PartitionerGraphT::EdgeArrayEntry, storage::Ownership::Container>
original_edge_array; original_edge_array;
@@ -83,11 +85,13 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
Vector<EdgeOffset> node_to_edge_offset_, Vector<EdgeOffset> node_to_edge_offset_,
Vector<EdgeWeight> node_weights_, Vector<EdgeWeight> node_weights_,
Vector<EdgeDuration> node_durations_, Vector<EdgeDuration> node_durations_,
Vector<EdgeDistance> node_distances_,
Vector<bool> is_forward_edge_, Vector<bool> is_forward_edge_,
Vector<bool> is_backward_edge_) Vector<bool> is_backward_edge_)
: SuperT(std::move(node_array_), std::move(edge_array_), std::move(node_to_edge_offset_)), : SuperT(std::move(node_array_), std::move(edge_array_), std::move(node_to_edge_offset_)),
node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)), node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
is_forward_edge(is_forward_edge_), is_backward_edge(is_backward_edge_) node_distances(std::move(node_distances_)), is_forward_edge(is_forward_edge_),
is_backward_edge(is_backward_edge_)
{ {
} }
@@ -95,6 +99,8 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
EdgeWeight GetNodeDuration(NodeID node) const { return node_durations[node]; } EdgeWeight GetNodeDuration(NodeID node) const { return node_durations[node]; }
EdgeDistance GetNodeDistance(NodeID node) const { return node_distances[node]; }
bool IsForwardEdge(EdgeID edge) const { return is_forward_edge[edge]; } bool IsForwardEdge(EdgeID edge) const { return is_forward_edge[edge]; }
bool IsBackwardEdge(EdgeID edge) const { return is_backward_edge[edge]; } bool IsBackwardEdge(EdgeID edge) const { return is_backward_edge[edge]; }
@@ -111,6 +117,7 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
protected: protected:
Vector<EdgeWeight> node_weights; Vector<EdgeWeight> node_weights;
Vector<EdgeDuration> node_durations; Vector<EdgeDuration> node_durations;
Vector<EdgeDistance> node_distances;
Vector<bool> is_forward_edge; Vector<bool> is_forward_edge;
Vector<bool> is_backward_edge; Vector<bool> is_backward_edge;
}; };
+4
View File
@@ -23,6 +23,7 @@ inline void read(storage::tar::FileReader &reader,
{ {
storage::serialization::read(reader, name + "/weights", metric.weights); storage::serialization::read(reader, name + "/weights", metric.weights);
storage::serialization::read(reader, name + "/durations", metric.durations); storage::serialization::read(reader, name + "/durations", metric.durations);
storage::serialization::read(reader, name + "/distances", metric.distances);
} }
template <storage::Ownership Ownership> template <storage::Ownership Ownership>
@@ -32,6 +33,7 @@ inline void write(storage::tar::FileWriter &writer,
{ {
storage::serialization::write(writer, name + "/weights", metric.weights); storage::serialization::write(writer, name + "/weights", metric.weights);
storage::serialization::write(writer, name + "/durations", metric.durations); storage::serialization::write(writer, name + "/durations", metric.durations);
storage::serialization::write(writer, name + "/distances", metric.distances);
} }
template <typename EdgeDataT, storage::Ownership Ownership> template <typename EdgeDataT, storage::Ownership Ownership>
@@ -42,6 +44,7 @@ inline void read(storage::tar::FileReader &reader,
storage::serialization::read(reader, name + "/node_array", graph.node_array); storage::serialization::read(reader, name + "/node_array", graph.node_array);
storage::serialization::read(reader, name + "/node_weights", graph.node_weights); storage::serialization::read(reader, name + "/node_weights", graph.node_weights);
storage::serialization::read(reader, name + "/node_durations", graph.node_durations); storage::serialization::read(reader, name + "/node_durations", graph.node_durations);
storage::serialization::read(reader, name + "/node_distances", graph.node_distances);
storage::serialization::read(reader, name + "/edge_array", graph.edge_array); storage::serialization::read(reader, name + "/edge_array", graph.edge_array);
storage::serialization::read(reader, name + "/is_forward_edge", graph.is_forward_edge); storage::serialization::read(reader, name + "/is_forward_edge", graph.is_forward_edge);
storage::serialization::read(reader, name + "/is_backward_edge", graph.is_backward_edge); storage::serialization::read(reader, name + "/is_backward_edge", graph.is_backward_edge);
@@ -56,6 +59,7 @@ inline void write(storage::tar::FileWriter &writer,
storage::serialization::write(writer, name + "/node_array", graph.node_array); storage::serialization::write(writer, name + "/node_array", graph.node_array);
storage::serialization::write(writer, name + "/node_weights", graph.node_weights); storage::serialization::write(writer, name + "/node_weights", graph.node_weights);
storage::serialization::write(writer, name + "/node_durations", graph.node_durations); storage::serialization::write(writer, name + "/node_durations", graph.node_durations);
storage::serialization::write(writer, name + "/node_distances", graph.node_distances);
storage::serialization::write(writer, name + "/edge_array", graph.edge_array); storage::serialization::write(writer, name + "/edge_array", graph.edge_array);
storage::serialization::write(writer, name + "/is_forward_edge", graph.is_forward_edge); storage::serialization::write(writer, name + "/is_forward_edge", graph.is_forward_edge);
storage::serialization::write(writer, name + "/is_backward_edge", graph.is_backward_edge); storage::serialization::write(writer, name + "/is_backward_edge", graph.is_backward_edge);
+5
View File
@@ -6,6 +6,7 @@
#include "engine/api/json_factory.hpp" #include "engine/api/json_factory.hpp"
#include "engine/hint.hpp" #include "engine/hint.hpp"
#include "util/coordinate_calculation.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/range/algorithm/transform.hpp> #include <boost/range/algorithm/transform.hpp>
@@ -53,6 +54,8 @@ class BaseAPI
// TODO: check forward/reverse // TODO: check forward/reverse
return json::makeWaypoint( return json::makeWaypoint(
phantom.location, phantom.location,
util::coordinate_calculation::fccApproximateDistance(phantom.location,
phantom.input_location),
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string(), facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)).to_string(),
Hint{phantom, facade.GetCheckSum()}); Hint{phantom, facade.GetCheckSum()});
} }
@@ -61,6 +64,8 @@ class BaseAPI
// TODO: check forward/reverse // TODO: check forward/reverse
return json::makeWaypoint( return json::makeWaypoint(
phantom.location, phantom.location,
util::coordinate_calculation::fccApproximateDistance(phantom.location,
phantom.input_location),
facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id)) facade.GetNameForID(facade.GetNameIndex(phantom.forward_segment_id.id))
.to_string()); .to_string());
} }
+16 -2
View File
@@ -63,6 +63,13 @@ namespace api
*/ */
struct BaseParameters struct BaseParameters
{ {
enum class SnappingType
{
Default,
Any
};
std::vector<util::Coordinate> coordinates; std::vector<util::Coordinate> coordinates;
std::vector<boost::optional<Hint>> hints; std::vector<boost::optional<Hint>> hints;
std::vector<boost::optional<double>> radiuses; std::vector<boost::optional<double>> radiuses;
@@ -73,15 +80,22 @@ struct BaseParameters
// Adds hints to response which can be included in subsequent requests, see `hints` above. // Adds hints to response which can be included in subsequent requests, see `hints` above.
bool generate_hints = true; bool generate_hints = true;
SnappingType snapping = SnappingType::Default;
// Whether or not to add acceleration/decelleration penalties at waypoints
double waypoint_acceleration_factor = 0.;
BaseParameters(const std::vector<util::Coordinate> coordinates_ = {}, BaseParameters(const std::vector<util::Coordinate> coordinates_ = {},
const std::vector<boost::optional<Hint>> hints_ = {}, const std::vector<boost::optional<Hint>> hints_ = {},
std::vector<boost::optional<double>> radiuses_ = {}, std::vector<boost::optional<double>> radiuses_ = {},
std::vector<boost::optional<Bearing>> bearings_ = {}, std::vector<boost::optional<Bearing>> bearings_ = {},
std::vector<boost::optional<Approach>> approaches_ = {}, std::vector<boost::optional<Approach>> approaches_ = {},
bool generate_hints_ = true, bool generate_hints_ = true,
std::vector<std::string> exclude = {}) std::vector<std::string> exclude = {},
const SnappingType snapping_ = SnappingType::Default,
bool waypoint_acceleration_factor_ = 0.)
: coordinates(coordinates_), hints(hints_), radiuses(radiuses_), bearings(bearings_), : coordinates(coordinates_), hints(hints_), radiuses(radiuses_), bearings(bearings_),
approaches(approaches_), exclude(std::move(exclude)), generate_hints(generate_hints_) approaches(approaches_), exclude(std::move(exclude)), generate_hints(generate_hints_),
snapping(snapping_), waypoint_acceleration_factor(waypoint_acceleration_factor_)
{ {
} }
+7 -4
View File
@@ -33,7 +33,7 @@ namespace json
namespace detail namespace detail
{ {
util::json::Array coordinateToLonLat(const util::Coordinate coordinate); util::json::Array coordinateToLonLat(const util::Coordinate &coordinate);
/** /**
* Ensures that a bearing value is a whole number, and clamped to the range 0-359 * Ensures that a bearing value is a whole number, and clamped to the range 0-359
@@ -86,11 +86,14 @@ util::json::Object makeRoute(const guidance::Route &route,
const char *weight_name); const char *weight_name);
// Creates a Waypoint without Hint, see the Hint overload below // Creates a Waypoint without Hint, see the Hint overload below
util::json::Object makeWaypoint(const util::Coordinate location, std::string name); util::json::Object
makeWaypoint(const util::Coordinate &location, const double &distance, std::string name);
// Creates a Waypoint with Hint, see the overload above when Hint is not needed // Creates a Waypoint with Hint, see the overload above when Hint is not needed
util::json::Object util::json::Object makeWaypoint(const util::Coordinate &location,
makeWaypoint(const util::Coordinate location, std::string name, const Hint &hint); const double &distance,
std::string name,
const Hint &hint);
util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps); util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps);
-1
View File
@@ -41,7 +41,6 @@ class NearestAPI final : public BaseAPI
[this](const PhantomNodeWithDistance &phantom_with_distance) { [this](const PhantomNodeWithDistance &phantom_with_distance) {
auto &phantom_node = phantom_with_distance.phantom_node; auto &phantom_node = phantom_with_distance.phantom_node;
auto waypoint = MakeWaypoint(phantom_node); auto waypoint = MakeWaypoint(phantom_node);
waypoint.values["distance"] = phantom_with_distance.distance;
util::json::Array nodes; util::json::Array nodes;
+29
View File
@@ -31,6 +31,15 @@ namespace api
class TableAPI final : public BaseAPI class TableAPI final : public BaseAPI
{ {
public: public:
struct TableCellRef
{
TableCellRef(const std::size_t &row, const std::size_t &column) : row{row}, column{column}
{
}
std::size_t row;
std::size_t column;
};
TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters &parameters_) TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters &parameters_)
: BaseAPI(facade_, parameters_), parameters(parameters_) : BaseAPI(facade_, parameters_), parameters(parameters_)
{ {
@@ -39,6 +48,7 @@ class TableAPI final : public BaseAPI
virtual void virtual void
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables, MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
const std::vector<PhantomNode> &phantoms, const std::vector<PhantomNode> &phantoms,
const std::vector<TableCellRef> &fallback_speed_cells,
util::json::Object &response) const util::json::Object &response) const
{ {
auto number_of_sources = parameters.sources.size(); auto number_of_sources = parameters.sources.size();
@@ -77,6 +87,11 @@ class TableAPI final : public BaseAPI
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations); MakeDistanceTable(tables.second, number_of_sources, number_of_destinations);
} }
if (parameters.fallback_speed != INVALID_FALLBACK_SPEED && parameters.fallback_speed > 0)
{
response.values["fallback_speed_cells"] = MakeEstimatesTable(fallback_speed_cells);
}
response.values["code"] = "Ok"; response.values["code"] = "Ok";
} }
@@ -163,6 +178,20 @@ class TableAPI final : public BaseAPI
return json_table; return json_table;
} }
virtual util::json::Array
MakeEstimatesTable(const std::vector<TableCellRef> &fallback_speed_cells) const
{
util::json::Array json_table;
std::for_each(
fallback_speed_cells.begin(), fallback_speed_cells.end(), [&](const auto &cell) {
util::json::Array row;
row.values.push_back(util::json::Number(cell.row));
row.values.push_back(util::json::Number(cell.column));
json_table.values.push_back(std::move(row));
});
return json_table;
}
const TableParameters &parameters; const TableParameters &parameters;
}; };
+34 -8
View File
@@ -59,6 +59,15 @@ struct TableParameters : public BaseParameters
{ {
std::vector<std::size_t> sources; std::vector<std::size_t> sources;
std::vector<std::size_t> destinations; std::vector<std::size_t> destinations;
double fallback_speed = INVALID_FALLBACK_SPEED;
enum class FallbackCoordinateType
{
Input = 0,
Snapped = 1
};
FallbackCoordinateType fallback_coordinate_type = FallbackCoordinateType::Input;
enum class AnnotationsType enum class AnnotationsType
{ {
@@ -70,6 +79,8 @@ struct TableParameters : public BaseParameters
AnnotationsType annotations = AnnotationsType::Duration; AnnotationsType annotations = AnnotationsType::Duration;
double scale_factor = 1;
TableParameters() = default; TableParameters() = default;
template <typename... Args> template <typename... Args>
TableParameters(std::vector<std::size_t> sources_, TableParameters(std::vector<std::size_t> sources_,
@@ -90,6 +101,22 @@ struct TableParameters : public BaseParameters
{ {
} }
template <typename... Args>
TableParameters(std::vector<std::size_t> sources_,
std::vector<std::size_t> destinations_,
const AnnotationsType annotations_,
double fallback_speed_,
FallbackCoordinateType fallback_coordinate_type_,
double scale_factor_,
Args... args_)
: BaseParameters{std::forward<Args>(args_)...}, sources{std::move(sources_)},
destinations{std::move(destinations_)}, fallback_speed{fallback_speed_},
fallback_coordinate_type{fallback_coordinate_type_}, annotations{annotations_},
scale_factor{scale_factor_}
{
}
bool IsValid() const bool IsValid() const
{ {
if (!BaseParameters::IsValid()) if (!BaseParameters::IsValid())
@@ -101,14 +128,7 @@ struct TableParameters : public BaseParameters
// 1/ The user is able to specify duplicates in srcs and dsts, in that case it's their fault // 1/ The user is able to specify duplicates in srcs and dsts, in that case it's their fault
// 2/ len(srcs) and len(dsts) smaller or equal to len(locations) // 2/ 0 <= index < len(locations)
if (sources.size() > coordinates.size())
return false;
if (destinations.size() > coordinates.size())
return false;
// 3/ 0 <= index < len(locations)
const auto not_in_range = [this](const std::size_t x) { return x >= coordinates.size(); }; const auto not_in_range = [this](const std::size_t x) { return x >= coordinates.size(); };
if (std::any_of(begin(sources), end(sources), not_in_range)) if (std::any_of(begin(sources), end(sources), not_in_range))
@@ -117,6 +137,12 @@ struct TableParameters : public BaseParameters
if (std::any_of(begin(destinations), end(destinations), not_in_range)) if (std::any_of(begin(destinations), end(destinations), not_in_range))
return false; return false;
if (fallback_speed <= 0)
return false;
if (scale_factor <= 0)
return false;
return true; return true;
} }
}; };
@@ -78,6 +78,8 @@ template <> class AlgorithmDataFacade<MLD>
virtual EdgeWeight GetNodeDuration(const NodeID node) const = 0; // TODO: to be removed virtual EdgeWeight GetNodeDuration(const NodeID node) const = 0; // TODO: to be removed
virtual EdgeDistance GetNodeDistance(const NodeID node) const = 0;
virtual bool IsForwardEdge(EdgeID edge) const = 0; virtual bool IsForwardEdge(EdgeID edge) const = 0;
virtual bool IsBackwardEdge(EdgeID edge) const = 0; virtual bool IsBackwardEdge(EdgeID edge) const = 0;
@@ -312,12 +312,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance, const float max_distance,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange( return m_geospatial_query->NearestPhantomNodesInRange(
input_coordinate, max_distance, approach); input_coordinate, max_distance, approach, use_all_edges);
} }
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
@@ -325,12 +326,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
const float max_distance, const float max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange( return m_geospatial_query->NearestPhantomNodesInRange(
input_coordinate, max_distance, bearing, bearing_range, approach); input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
} }
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
@@ -384,23 +386,25 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, approach); input_coordinate, approach, use_all_edges);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, approach); input_coordinate, max_distance, approach, use_all_edges);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
@@ -408,24 +412,26 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, bearing, bearing_range, approach); input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, bearing, bearing_range, approach); input_coordinate, bearing, bearing_range, approach, use_all_edges);
} }
std::uint32_t GetCheckSum() const override final { return m_check_sum; } std::uint32_t GetCheckSum() const override final { return m_check_sum; }
@@ -697,6 +703,11 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
return query_graph.GetNodeDuration(node); return query_graph.GetNodeDuration(node);
} }
EdgeDistance GetNodeDistance(const NodeID node) const override final
{
return query_graph.GetNodeDistance(node);
}
bool IsForwardEdge(const NodeID node) const override final bool IsForwardEdge(const NodeID node) const override final
{ {
return query_graph.IsForwardEdge(node); return query_graph.IsForwardEdge(node);
+12 -6
View File
@@ -126,11 +126,13 @@ class BaseDataFacade
const float max_distance, const float max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::vector<PhantomNodeWithDistance> virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance, const float max_distance,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::vector<PhantomNodeWithDistance> virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate, NearestPhantomNodes(const util::Coordinate input_coordinate,
@@ -157,22 +159,26 @@ class BaseDataFacade
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges = false) const = 0;
virtual bool HasLaneData(const EdgeID id) const = 0; virtual bool HasLaneData(const EdgeID id) const = 0;
virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0; virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0;
@@ -10,6 +10,7 @@
#include <boost/iostreams/device/mapped_file.hpp> #include <boost/iostreams/device/mapped_file.hpp>
#include <memory> #include <memory>
#include <string>
namespace osrm namespace osrm
{ {
@@ -24,8 +25,7 @@ namespace datafacade
class MMapMemoryAllocator : public ContiguousBlockAllocator class MMapMemoryAllocator : public ContiguousBlockAllocator
{ {
public: public:
explicit MMapMemoryAllocator(const storage::StorageConfig &config, explicit MMapMemoryAllocator(const storage::StorageConfig &config);
const boost::filesystem::path &memory_file);
~MMapMemoryAllocator() override final; ~MMapMemoryAllocator() override final;
// interface to give access to the datafacades // interface to give access to the datafacades
@@ -33,8 +33,8 @@ class MMapMemoryAllocator : public ContiguousBlockAllocator
private: private:
storage::SharedDataIndex index; storage::SharedDataIndex index;
util::vector_view<char> mapped_memory; std::vector<boost::iostreams::mapped_file> mapped_memory_files;
boost::iostreams::mapped_file mapped_memory_file; std::string rtree_filename;
}; };
} // namespace datafacade } // namespace datafacade
+2 -3
View File
@@ -32,9 +32,8 @@ class ExternalProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
public: public:
using Facade = typename DataFacadeProvider<AlgorithmT, FacadeT>::Facade; using Facade = typename DataFacadeProvider<AlgorithmT, FacadeT>::Facade;
ExternalProvider(const storage::StorageConfig &config, ExternalProvider(const storage::StorageConfig &config)
const boost::filesystem::path &memory_file) : facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config))
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config, memory_file))
{ {
} }
+9 -5
View File
@@ -63,12 +63,16 @@ template <typename Algorithm> class Engine final : public EngineInterface
<< "\" with algorithm " << routing_algorithms::name<Algorithm>(); << "\" with algorithm " << routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<WatchingProvider<Algorithm>>(config.dataset_name); facade_provider = std::make_unique<WatchingProvider<Algorithm>>(config.dataset_name);
} }
else if (!config.memory_file.empty()) else if (!config.memory_file.empty() || config.use_mmap)
{ {
util::Log(logDEBUG) << "Using memory mapped filed at " << config.memory_file if (!config.memory_file.empty())
<< " with algorithm " << routing_algorithms::name<Algorithm>(); {
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config, util::Log(logWARNING)
config.memory_file); << "The 'memory_file' option is DEPRECATED - using direct mmaping instead";
}
util::Log(logDEBUG) << "Using direct memory mapping with algorithm "
<< routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config);
} }
else else
{ {
+1
View File
@@ -89,6 +89,7 @@ struct EngineConfig final
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
bool use_shared_memory = true; bool use_shared_memory = true;
boost::filesystem::path memory_file; boost::filesystem::path memory_file;
bool use_mmap = true;
Algorithm algorithm = Algorithm::CH; Algorithm algorithm = Algorithm::CH;
std::string verbosity; std::string verbosity;
std::string dataset_name; std::string dataset_name;
+48 -24
View File
@@ -53,13 +53,15 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
std::vector<PhantomNodeWithDistance> std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate, NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate](const CandidateSegment &segment) { [this, approach, &input_coordinate, use_all_edges](const CandidateSegment &segment) {
return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)), return boolPairAnd(
CheckApproach(input_coordinate, segment, approach)); boolPairAnd(HasValidEdge(segment, use_all_edges), CheckSegmentExclude(segment)),
CheckApproach(input_coordinate, segment, approach));
}, },
[this, max_distance, input_coordinate](const std::size_t, [this, max_distance, input_coordinate](const std::size_t,
const CandidateSegment &segment) { const CandidateSegment &segment) {
@@ -76,15 +78,17 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate, bearing, bearing_range]( [this, approach, &input_coordinate, bearing, bearing_range, use_all_edges](
const CandidateSegment &segment) { const CandidateSegment &segment) {
auto use_direction = auto use_direction =
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range), boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment))); boolPairAnd(HasValidEdge(segment, use_all_edges),
CheckSegmentExclude(segment)));
use_direction = use_direction =
boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach)); boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach));
return use_direction; return use_direction;
@@ -201,18 +205,23 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate, &has_big_component, &has_small_component]( [this,
const CandidateSegment &segment) { approach,
&input_coordinate,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment = auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); (!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment); auto use_directions = std::make_pair(use_segment, use_segment);
const auto valid_edges = HasValidEdge(segment); const auto valid_edges = HasValidEdge(segment, use_all_edges);
const auto admissible_segments = CheckSegmentExclude(segment); const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, admissible_segments); use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(use_directions, valid_edges); use_directions = boolPairAnd(use_directions, valid_edges);
@@ -247,19 +256,24 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
// a second phantom node is return that is the nearest coordinate in a big component. // a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate, &has_big_component, &has_small_component]( [this,
const CandidateSegment &segment) { approach,
&input_coordinate,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment = auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); (!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment); auto use_directions = std::make_pair(use_segment, use_segment);
const auto valid_edges = HasValidEdge(segment); const auto valid_edges = HasValidEdge(segment, use_all_edges);
const auto admissible_segments = CheckSegmentExclude(segment); const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, admissible_segments); use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(use_directions, valid_edges); use_directions = boolPairAnd(use_directions, valid_edges);
@@ -294,7 +308,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
@@ -306,12 +321,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
bearing, bearing,
bearing_range, bearing_range,
&has_big_component, &has_big_component,
&has_small_component](const CandidateSegment &segment) { &has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment = auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); (!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment); auto use_directions = std::make_pair(use_segment, use_segment);
const auto admissible_segments = CheckSegmentExclude(segment); const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, HasValidEdge(segment)); use_directions = boolPairAnd(use_directions, HasValidEdge(segment, use_all_edges));
if (use_segment) if (use_segment)
{ {
@@ -352,7 +368,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
@@ -364,12 +381,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
bearing, bearing,
bearing_range, bearing_range,
&has_big_component, &has_big_component,
&has_small_component](const CandidateSegment &segment) { &has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment = auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); (!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment); auto use_directions = std::make_pair(use_segment, use_segment);
const auto admissible_segments = CheckSegmentExclude(segment); const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, HasValidEdge(segment)); use_directions = boolPairAnd(use_directions, HasValidEdge(segment, use_all_edges));
if (use_segment) if (use_segment)
{ {
@@ -461,6 +479,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
EdgeDuration{0}); EdgeDuration{0});
EdgeDistance forward_distance_offset = 0; EdgeDistance forward_distance_offset = 0;
// Sum up the distance from the start to the fwd_segment_position
for (auto current = forward_geometry.begin(); for (auto current = forward_geometry.begin();
current < forward_geometry.begin() + data.fwd_segment_position; current < forward_geometry.begin() + data.fwd_segment_position;
++current) ++current)
@@ -490,8 +509,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
EdgeDuration{0}); EdgeDuration{0});
EdgeDistance reverse_distance_offset = 0; EdgeDistance reverse_distance_offset = 0;
for (auto current = forward_geometry.begin(); // Sum up the distance from just after the fwd_segment_position to the end
current < forward_geometry.end() - data.fwd_segment_position - 2; for (auto current = forward_geometry.begin() + data.fwd_segment_position + 1;
current != std::prev(forward_geometry.end());
++current) ++current)
{ {
reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance( reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance(
@@ -628,7 +648,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
* which means that this edge is not currently traversible. If this is the case, * which means that this edge is not currently traversible. If this is the case,
* then we shouldn't snap to this edge. * then we shouldn't snap to this edge.
*/ */
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment) const std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment,
const bool use_all_edges = false) const
{ {
bool forward_edge_valid = false; bool forward_edge_valid = false;
@@ -652,6 +673,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
reverse_edge_valid = data.reverse_segment_id.enabled; reverse_edge_valid = data.reverse_segment_id.enabled;
} }
forward_edge_valid = forward_edge_valid && (data.is_startpoint || use_all_edges);
reverse_edge_valid = reverse_edge_valid && (data.is_startpoint || use_all_edges);
return std::make_pair(forward_edge_valid, reverse_edge_valid); return std::make_pair(forward_edge_valid, reverse_edge_valid);
} }
+15 -7
View File
@@ -138,7 +138,8 @@ class BasePlugin
std::vector<std::vector<PhantomNodeWithDistance>> std::vector<std::vector<PhantomNodeWithDistance>>
GetPhantomNodesInRange(const datafacade::BaseDataFacade &facade, GetPhantomNodesInRange(const datafacade::BaseDataFacade &facade,
const api::BaseParameters &parameters, const api::BaseParameters &parameters,
const std::vector<double> radiuses) const const std::vector<double> radiuses,
bool use_all_edges = false) const
{ {
std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes( std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
parameters.coordinates.size()); parameters.coordinates.size());
@@ -171,12 +172,13 @@ class BasePlugin
radiuses[i], radiuses[i],
parameters.bearings[i]->bearing, parameters.bearings[i]->bearing,
parameters.bearings[i]->range, parameters.bearings[i]->range,
approach); approach,
use_all_edges);
} }
else else
{ {
phantom_nodes[i] = facade.NearestPhantomNodesInRange( phantom_nodes[i] = facade.NearestPhantomNodesInRange(
parameters.coordinates[i], radiuses[i], approach); parameters.coordinates[i], radiuses[i], approach, use_all_edges);
} }
} }
@@ -268,6 +270,7 @@ class BasePlugin
const bool use_bearings = !parameters.bearings.empty(); const bool use_bearings = !parameters.bearings.empty();
const bool use_radiuses = !parameters.radiuses.empty(); const bool use_radiuses = !parameters.radiuses.empty();
const bool use_approaches = !parameters.approaches.empty(); const bool use_approaches = !parameters.approaches.empty();
const bool use_all_edges = parameters.snapping == api::BaseParameters::SnappingType::Any;
BOOST_ASSERT(parameters.IsValid()); BOOST_ASSERT(parameters.IsValid());
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size())) for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
@@ -294,7 +297,8 @@ class BasePlugin
*parameters.radiuses[i], *parameters.radiuses[i],
parameters.bearings[i]->bearing, parameters.bearings[i]->bearing,
parameters.bearings[i]->range, parameters.bearings[i]->range,
approach); approach,
use_all_edges);
} }
else else
{ {
@@ -303,7 +307,8 @@ class BasePlugin
parameters.coordinates[i], parameters.coordinates[i],
parameters.bearings[i]->bearing, parameters.bearings[i]->bearing,
parameters.bearings[i]->range, parameters.bearings[i]->range,
approach); approach,
use_all_edges);
} }
} }
else else
@@ -312,13 +317,16 @@ class BasePlugin
{ {
phantom_node_pairs[i] = phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent( facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], *parameters.radiuses[i], approach); parameters.coordinates[i],
*parameters.radiuses[i],
approach,
use_all_edges);
} }
else else
{ {
phantom_node_pairs[i] = phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent( facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], approach); parameters.coordinates[i], approach, use_all_edges);
} }
} }
+4 -8
View File
@@ -34,8 +34,7 @@ class RoutingAlgorithmsInterface
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes, ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance, const bool calculate_distance) const = 0;
const bool calculate_duration) const = 0;
virtual routing_algorithms::SubMatchingList virtual routing_algorithms::SubMatchingList
MapMatching(const routing_algorithms::CandidateLists &candidates_list, MapMatching(const routing_algorithms::CandidateLists &candidates_list,
@@ -88,8 +87,7 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes, ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance, const bool calculate_distance) const final override;
const bool calculate_duration) const final override;
routing_algorithms::SubMatchingList routing_algorithms::SubMatchingList
MapMatching(const routing_algorithms::CandidateLists &candidates_list, MapMatching(const routing_algorithms::CandidateLists &candidates_list,
@@ -198,8 +196,7 @@ std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes, RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &_source_indices, const std::vector<std::size_t> &_source_indices,
const std::vector<std::size_t> &_target_indices, const std::vector<std::size_t> &_target_indices,
const bool calculate_distance, const bool calculate_distance) const
const bool calculate_duration) const
{ {
BOOST_ASSERT(!phantom_nodes.empty()); BOOST_ASSERT(!phantom_nodes.empty());
@@ -222,8 +219,7 @@ RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &p
phantom_nodes, phantom_nodes,
std::move(source_indices), std::move(source_indices),
std::move(target_indices), std::move(target_indices),
calculate_distance, calculate_distance);
calculate_duration);
} }
template <typename Algorithm> template <typename Algorithm>
@@ -25,15 +25,17 @@ struct NodeBucket
unsigned from_clique_arc : 1; unsigned from_clique_arc : 1;
EdgeWeight weight; EdgeWeight weight;
EdgeDuration duration; EdgeDuration duration;
EdgeDistance distance;
NodeBucket(NodeID middle_node, NodeBucket(NodeID middle_node,
NodeID parent_node, NodeID parent_node,
bool from_clique_arc, bool from_clique_arc,
unsigned column_index, unsigned column_index,
EdgeWeight weight, EdgeWeight weight,
EdgeDuration duration) EdgeDuration duration,
EdgeDistance distance)
: middle_node(middle_node), parent_node(parent_node), column_index(column_index), : middle_node(middle_node), parent_node(parent_node), column_index(column_index),
from_clique_arc(from_clique_arc), weight(weight), duration(duration) from_clique_arc(from_clique_arc), weight(weight), duration(duration), distance(distance)
{ {
} }
@@ -41,9 +43,10 @@ struct NodeBucket
NodeID parent_node, NodeID parent_node,
unsigned column_index, unsigned column_index,
EdgeWeight weight, EdgeWeight weight,
EdgeDuration duration) EdgeDuration duration,
EdgeDistance distance)
: middle_node(middle_node), parent_node(parent_node), column_index(column_index), : middle_node(middle_node), parent_node(parent_node), column_index(column_index),
from_clique_arc(false), weight(weight), duration(duration) from_clique_arc(false), weight(weight), duration(duration), distance(distance)
{ {
} }
@@ -94,8 +97,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance, const bool calculate_distance);
const bool calculate_duration);
} // namespace routing_algorithms } // namespace routing_algorithms
} // namespace engine } // namespace engine
@@ -85,13 +85,17 @@ void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
{ {
heap.Insert(phantom_node.forward_segment_id.id, heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(), -phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); {phantom_node.forward_segment_id.id,
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance()});
} }
if (phantom_node.IsValidReverseSource()) if (phantom_node.IsValidReverseSource())
{ {
heap.Insert(phantom_node.reverse_segment_id.id, heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(), -phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()}); {phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance()});
} }
} }
@@ -102,13 +106,17 @@ void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
{ {
heap.Insert(phantom_node.forward_segment_id.id, heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(), phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()}); {phantom_node.forward_segment_id.id,
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance()});
} }
if (phantom_node.IsValidReverseTarget()) if (phantom_node.IsValidReverseTarget())
{ {
heap.Insert(phantom_node.reverse_segment_id.id, heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(), phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()}); {phantom_node.reverse_segment_id.id,
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance()});
} }
} }
@@ -186,9 +186,10 @@ void routingStep(const DataFacade<Algorithm> &facade,
} }
template <bool UseDuration> template <bool UseDuration>
EdgeWeight getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node) std::tuple<EdgeWeight, EdgeDistance> getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
{ {
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT; EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT;
EdgeDistance loop_distance = MAXIMAL_EDGE_DISTANCE;
for (auto edge : facade.GetAdjacentEdgeRange(node)) for (auto edge : facade.GetAdjacentEdgeRange(node))
{ {
const auto &data = facade.GetEdgeData(edge); const auto &data = facade.GetEdgeData(edge);
@@ -198,11 +199,15 @@ EdgeWeight getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
if (to == node) if (to == node)
{ {
const auto value = UseDuration ? data.duration : data.weight; const auto value = UseDuration ? data.duration : data.weight;
loop_weight = std::min(loop_weight, value); if (value < loop_weight)
{
loop_weight = value;
loop_distance = data.distance;
}
} }
} }
} }
return loop_weight; return std::make_tuple(loop_weight, loop_distance);
} }
/** /**
@@ -509,90 +509,6 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges)); return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
} }
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
// This gives us a packed path (node ids) from the base graph around s and t,
// and overlay node ids otherwise. We then have to unpack the overlay clique
// edges by recursively descending unpacking the path down to the base graph.
using UnpackedNodes = std::vector<NodeID>;
using UnpackedEdges = std::vector<EdgeID>;
using UnpackedPath = std::tuple<EdgeWeight, UnpackedNodes, UnpackedEdges>;
template <typename Algorithm, typename... Args>
UnpackedPath
unpackPathAndCalculateDistance(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool force_loop_forward,
const bool force_loop_reverse,
EdgeWeight weight_upper_bound,
PackedPath packed_path,
NodeID middle,
Args... args)
{
EdgeWeight weight = weight_upper_bound;
const auto &partition = facade.GetMultiLevelPartition();
const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle;
// Unpack path
std::vector<NodeID> unpacked_nodes;
std::vector<EdgeID> unpacked_edges;
unpacked_nodes.reserve(packed_path.size());
unpacked_edges.reserve(packed_path.size());
unpacked_nodes.push_back(source_node);
for (auto const &packed_edge : packed_path)
{
NodeID source, target;
bool overlay_edge;
std::tie(source, target, overlay_edge) = packed_edge;
if (!overlay_edge)
{ // a base graph edge
unpacked_nodes.push_back(target);
unpacked_edges.push_back(facade.FindEdge(source, target));
}
else
{ // an overlay graph edge
LevelID level = getNodeQueryLevel(partition, source, args...);
CellID parent_cell_id = partition.GetCell(level, source);
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
LevelID sublevel = level - 1;
// Here heaps can be reused, let's go deeper!
forward_heap.Clear();
reverse_heap.Clear();
forward_heap.Insert(source, 0, {source});
reverse_heap.Insert(target, 0, {target});
// TODO: when structured bindings will be allowed change to
// auto [subpath_weight, subpath_source, subpath_target, subpath] = ...
EdgeWeight subpath_weight;
std::vector<NodeID> subpath_nodes;
std::vector<EdgeID> subpath_edges;
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data,
facade,
forward_heap,
reverse_heap,
force_loop_forward,
force_loop_reverse,
weight_upper_bound,
sublevel,
parent_cell_id);
BOOST_ASSERT(!subpath_edges.empty());
BOOST_ASSERT(subpath_nodes.size() > 1);
BOOST_ASSERT(subpath_nodes.front() == source);
BOOST_ASSERT(subpath_nodes.back() == target);
unpacked_nodes.insert(
unpacked_nodes.end(), std::next(subpath_nodes.begin()), subpath_nodes.end());
unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end());
}
}
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
}
// Alias to be compatible with the CH-based search // Alias to be compatible with the CH-based search
template <typename Algorithm> template <typename Algorithm>
inline void search(SearchEngineData<Algorithm> &engine_working_data, inline void search(SearchEngineData<Algorithm> &engine_working_data,
+13 -5
View File
@@ -30,7 +30,11 @@ struct HeapData
struct ManyToManyHeapData : HeapData struct ManyToManyHeapData : HeapData
{ {
EdgeWeight duration; EdgeWeight duration;
ManyToManyHeapData(NodeID p, EdgeWeight duration) : HeapData(p), duration(duration) {} EdgeDistance distance;
ManyToManyHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance)
: HeapData(p), duration(duration), distance(distance)
{
}
}; };
template <> struct SearchEngineData<routing_algorithms::ch::Algorithm> template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
@@ -75,12 +79,16 @@ struct MultiLayerDijkstraHeapData
struct ManyToManyMultiLayerDijkstraHeapData : MultiLayerDijkstraHeapData struct ManyToManyMultiLayerDijkstraHeapData : MultiLayerDijkstraHeapData
{ {
EdgeWeight duration; EdgeWeight duration;
ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration) EdgeDistance distance;
: MultiLayerDijkstraHeapData(p), duration(duration) ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance)
: MultiLayerDijkstraHeapData(p), duration(duration), distance(distance)
{ {
} }
ManyToManyMultiLayerDijkstraHeapData(NodeID p, bool from, EdgeWeight duration) ManyToManyMultiLayerDijkstraHeapData(NodeID p,
: MultiLayerDijkstraHeapData(p, from), duration(duration) bool from,
EdgeWeight duration,
EdgeDistance distance)
: MultiLayerDijkstraHeapData(p, from), duration(duration), distance(distance)
{ {
} }
}; };
+12 -5
View File
@@ -15,20 +15,25 @@ struct EdgeBasedEdge
public: public:
struct EdgeData struct EdgeData
{ {
EdgeData() : turn_id(0), weight(0), duration(0), forward(false), backward(false) {} EdgeData()
: turn_id(0), weight(0), distance(0), duration(0), forward(false), backward(false)
{
}
EdgeData(const NodeID turn_id, EdgeData(const NodeID turn_id,
const EdgeWeight weight, const EdgeWeight weight,
const EdgeDistance distance,
const EdgeWeight duration, const EdgeWeight duration,
const bool forward, const bool forward,
const bool backward) const bool backward)
: turn_id(turn_id), weight(weight), duration(duration), forward(forward), : turn_id(turn_id), weight(weight), distance(distance), duration(duration),
backward(backward) forward(forward), backward(backward)
{ {
} }
NodeID turn_id; // ID of the edge based node (node based edge) NodeID turn_id; // ID of the edge based node (node based edge)
EdgeWeight weight; EdgeWeight weight;
EdgeDistance distance;
EdgeWeight duration : 30; EdgeWeight duration : 30;
std::uint32_t forward : 1; std::uint32_t forward : 1;
std::uint32_t backward : 1; std::uint32_t backward : 1;
@@ -43,6 +48,7 @@ struct EdgeBasedEdge
const NodeID edge_id, const NodeID edge_id,
const EdgeWeight weight, const EdgeWeight weight,
const EdgeWeight duration, const EdgeWeight duration,
const EdgeDistance distance,
const bool forward, const bool forward,
const bool backward); const bool backward);
EdgeBasedEdge(const NodeID source, const NodeID target, const EdgeBasedEdge::EdgeData &data); EdgeBasedEdge(const NodeID source, const NodeID target, const EdgeBasedEdge::EdgeData &data);
@@ -53,7 +59,7 @@ struct EdgeBasedEdge
NodeID target; NodeID target;
EdgeData data; EdgeData data;
}; };
static_assert(sizeof(extractor::EdgeBasedEdge) == 20, static_assert(sizeof(extractor::EdgeBasedEdge) == 24,
"Size of extractor::EdgeBasedEdge type is " "Size of extractor::EdgeBasedEdge type is "
"bigger than expected. This will influence " "bigger than expected. This will influence "
"memory consumption."); "memory consumption.");
@@ -67,9 +73,10 @@ inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
const NodeID turn_id, const NodeID turn_id,
const EdgeWeight weight, const EdgeWeight weight,
const EdgeWeight duration, const EdgeWeight duration,
const EdgeDistance distance,
const bool forward, const bool forward,
const bool backward) const bool backward)
: source(source), target(target), data{turn_id, weight, duration, forward, backward} : source(source), target(target), data{turn_id, weight, distance, duration, forward, backward}
{ {
} }
@@ -89,9 +89,9 @@ class EdgeBasedGraphFactory
// The following get access functions destroy the content in the factory // The following get access functions destroy the content in the factory
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges); void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes); void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes);
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights); void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations); void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations);
void GetEdgeBasedNodeDistances(std::vector<EdgeDistance> &output_node_distances);
std::uint32_t GetConnectivityChecksum() const; std::uint32_t GetConnectivityChecksum() const;
std::uint64_t GetNumberOfEdgeBasedNodes() const; std::uint64_t GetNumberOfEdgeBasedNodes() const;
@@ -111,14 +111,11 @@ class EdgeBasedGraphFactory
std::vector<ConditionalTurnPenalty> std::vector<ConditionalTurnPenalty>
IndexConditionals(std::vector<Conditional> &&conditionals) const; IndexConditionals(std::vector<Conditional> &&conditionals) const;
//! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
//! graph
std::vector<bool> m_edge_based_node_is_startpoint;
//! node weights that indicate the length of the segment (node based) represented by the //! node weights that indicate the length of the segment (node based) represented by the
//! edge-based node //! edge-based node
std::vector<EdgeWeight> m_edge_based_node_weights; std::vector<EdgeWeight> m_edge_based_node_weights;
std::vector<EdgeDuration> m_edge_based_node_durations; std::vector<EdgeDuration> m_edge_based_node_durations;
std::vector<EdgeDistance> m_edge_based_node_distances;
//! list of edge based nodes (compressed segments) //! list of edge based nodes (compressed segments)
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments; std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
@@ -22,7 +22,9 @@ struct EdgeBasedNodeSegment
EdgeBasedNodeSegment() EdgeBasedNodeSegment()
: forward_segment_id{SPECIAL_SEGMENTID, false}, : forward_segment_id{SPECIAL_SEGMENTID, false},
reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID), v(SPECIAL_NODEID), reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID), v(SPECIAL_NODEID),
fwd_segment_position(std::numeric_limits<unsigned short>::max()) fwd_segment_position(std::numeric_limits<unsigned short>::max() >>
1), // >> 1 because we've only got 15 bits
is_startpoint(false)
{ {
} }
@@ -30,9 +32,10 @@ struct EdgeBasedNodeSegment
const SegmentID reverse_segment_id_, const SegmentID reverse_segment_id_,
NodeID u, NodeID u,
NodeID v, NodeID v,
unsigned short fwd_segment_position) unsigned short fwd_segment_position,
bool is_startpoint_)
: forward_segment_id(forward_segment_id_), reverse_segment_id(reverse_segment_id_), u(u), : forward_segment_id(forward_segment_id_), reverse_segment_id(reverse_segment_id_), u(u),
v(v), fwd_segment_position(fwd_segment_position) v(v), fwd_segment_position(fwd_segment_position), is_startpoint(is_startpoint_)
{ {
BOOST_ASSERT(forward_segment_id.enabled || reverse_segment_id.enabled); BOOST_ASSERT(forward_segment_id.enabled || reverse_segment_id.enabled);
} }
@@ -41,7 +44,8 @@ struct EdgeBasedNodeSegment
SegmentID reverse_segment_id; // edge-based graph node ID in reverse direction (v->u if exists) SegmentID reverse_segment_id; // edge-based graph node ID in reverse direction (v->u if exists)
NodeID u; // node-based graph node ID of the start node NodeID u; // node-based graph node ID of the start node
NodeID v; // node-based graph node ID of the target node NodeID v; // node-based graph node ID of the target node
unsigned short fwd_segment_position; // segment id in a compressed geometry unsigned short fwd_segment_position : 15; // segment id in a compressed geometry
bool is_startpoint : 1;
}; };
} }
} }
+1 -2
View File
@@ -85,9 +85,9 @@ class Extractor
// output data // output data
EdgeBasedNodeDataContainer &edge_based_nodes_container, EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments, std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights, std::vector<EdgeWeight> &edge_based_node_weights,
std::vector<EdgeDuration> &edge_based_node_durations, std::vector<EdgeDuration> &edge_based_node_durations,
std::vector<EdgeDistance> &edge_based_node_distances,
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list, util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
std::uint32_t &connectivity_checksum); std::uint32_t &connectivity_checksum);
@@ -96,7 +96,6 @@ class Extractor
const std::vector<EdgeBasedNodeSegment> &input_node_segments, const std::vector<EdgeBasedNodeSegment> &input_node_segments,
EdgeBasedNodeDataContainer &nodes_container) const; EdgeBasedNodeDataContainer &nodes_container) const;
void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments, void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments,
std::vector<bool> node_is_startpoint,
const std::vector<util::Coordinate> &coordinates); const std::vector<util::Coordinate> &coordinates);
std::shared_ptr<RestrictionMap> LoadRestrictionMap(); std::shared_ptr<RestrictionMap> LoadRestrictionMap();
+30 -6
View File
@@ -453,8 +453,8 @@ void writeNames(const boost::filesystem::path &path, const NameTableT &table)
serialization::write(writer, "/common/names", table); serialization::write(writer, "/common/names", table);
} }
template <typename NodeWeigtsVectorT> template <typename NodeWeightsVectorT>
void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVectorT &weights) void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeightsVectorT &weights)
{ {
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint; const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
storage::tar::FileReader reader{path, fingerprint}; storage::tar::FileReader reader{path, fingerprint};
@@ -462,9 +462,33 @@ void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVec
storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights); storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights);
} }
template <typename NodeWeigtsVectorT, typename NodeDurationsVectorT> template <typename NodeDistancesVectorT>
void readEdgeBasedNodeDistances(const boost::filesystem::path &path,
NodeDistancesVectorT &distances)
{
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
storage::tar::FileReader reader{path, fingerprint};
storage::serialization::read(reader, "/extractor/edge_based_node_distances", distances);
}
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT, typename NodeDistancesVectorT>
void writeEdgeBasedNodeWeightsDurationsDistances(const boost::filesystem::path &path,
const NodeWeightsVectorT &weights,
const NodeDurationsVectorT &durations,
const NodeDistancesVectorT &distances)
{
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
storage::tar::FileWriter writer{path, fingerprint};
storage::serialization::write(writer, "/extractor/edge_based_node_weights", weights);
storage::serialization::write(writer, "/extractor/edge_based_node_durations", durations);
storage::serialization::write(writer, "/extractor/edge_based_node_distances", distances);
}
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT>
void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path, void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
NodeWeigtsVectorT &weights, NodeWeightsVectorT &weights,
NodeDurationsVectorT &durations) NodeDurationsVectorT &durations)
{ {
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint; const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
@@ -474,9 +498,9 @@ void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
storage::serialization::read(reader, "/extractor/edge_based_node_durations", durations); storage::serialization::read(reader, "/extractor/edge_based_node_durations", durations);
} }
template <typename NodeWeigtsVectorT, typename NodeDurationsVectorT> template <typename NodeWeightsVectorT, typename NodeDurationsVectorT>
void writeEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path, void writeEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
const NodeWeigtsVectorT &weights, const NodeWeightsVectorT &weights,
const NodeDurationsVectorT &durations) const NodeDurationsVectorT &durations)
{ {
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint; const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
@@ -63,7 +63,7 @@ struct InternalExtractorEdge
WeightData weight_data, WeightData weight_data,
DurationData duration_data, DurationData duration_data,
util::Coordinate source_coordinate) util::Coordinate source_coordinate)
: result(source, target, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)), : result(source, target, 0, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)),
duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate)) duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate))
{ {
} }
+18 -6
View File
@@ -97,6 +97,7 @@ struct NodeBasedEdge
NodeID target, NodeID target,
EdgeWeight weight, EdgeWeight weight,
EdgeDuration duration, EdgeDuration duration,
EdgeDistance distance,
GeometryID geometry_id, GeometryID geometry_id,
AnnotationID annotation_data, AnnotationID annotation_data,
NodeBasedEdgeClassification flags); NodeBasedEdgeClassification flags);
@@ -107,6 +108,7 @@ struct NodeBasedEdge
NodeID target; // 32 4 NodeID target; // 32 4
EdgeWeight weight; // 32 4 EdgeWeight weight; // 32 4
EdgeDuration duration; // 32 4 EdgeDuration duration; // 32 4
EdgeDistance distance; // 32 4
GeometryID geometry_id; // 32 4 GeometryID geometry_id; // 32 4
AnnotationID annotation_data; // 32 4 AnnotationID annotation_data; // 32 4
NodeBasedEdgeClassification flags; // 32 4 NodeBasedEdgeClassification flags; // 32 4
@@ -120,6 +122,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
OSMNodeID target, OSMNodeID target,
EdgeWeight weight, EdgeWeight weight,
EdgeDuration duration, EdgeDuration duration,
EdgeDistance distance,
GeometryID geometry_id, GeometryID geometry_id,
AnnotationID annotation_data, AnnotationID annotation_data,
NodeBasedEdgeClassification flags); NodeBasedEdgeClassification flags);
@@ -137,7 +140,8 @@ inline NodeBasedEdgeClassification::NodeBasedEdgeClassification()
} }
inline NodeBasedEdge::NodeBasedEdge() inline NodeBasedEdge::NodeBasedEdge()
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), annotation_data(-1) : source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), distance(0),
annotation_data(-1)
{ {
} }
@@ -145,11 +149,12 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
NodeID target, NodeID target,
EdgeWeight weight, EdgeWeight weight,
EdgeDuration duration, EdgeDuration duration,
EdgeDistance distance,
GeometryID geometry_id, GeometryID geometry_id,
AnnotationID annotation_data, AnnotationID annotation_data,
NodeBasedEdgeClassification flags) NodeBasedEdgeClassification flags)
: source(source), target(target), weight(weight), duration(duration), geometry_id(geometry_id), : source(source), target(target), weight(weight), duration(duration), distance(distance),
annotation_data(annotation_data), flags(flags) geometry_id(geometry_id), annotation_data(annotation_data), flags(flags)
{ {
} }
@@ -175,11 +180,18 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
OSMNodeID target, OSMNodeID target,
EdgeWeight weight, EdgeWeight weight,
EdgeDuration duration, EdgeDuration duration,
EdgeDistance distance,
GeometryID geometry_id, GeometryID geometry_id,
AnnotationID annotation_data, AnnotationID annotation_data,
NodeBasedEdgeClassification flags) NodeBasedEdgeClassification flags)
: NodeBasedEdge( : NodeBasedEdge(SPECIAL_NODEID,
SPECIAL_NODEID, SPECIAL_NODEID, weight, duration, geometry_id, annotation_data, flags), SPECIAL_NODEID,
weight,
duration,
distance,
geometry_id,
annotation_data,
flags),
osm_source_id(std::move(source)), osm_target_id(std::move(target)) osm_source_id(std::move(source)), osm_target_id(std::move(target))
{ {
} }
@@ -189,7 +201,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM()
{ {
} }
static_assert(sizeof(extractor::NodeBasedEdge) == 28, static_assert(sizeof(extractor::NodeBasedEdge) == 32,
"Size of extractor::NodeBasedEdge type is " "Size of extractor::NodeBasedEdge type is "
"bigger than expected. This will influence " "bigger than expected. This will influence "
"memory consumption."); "memory consumption.");
+151
View File
@@ -142,6 +142,10 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
if (shared_memory.IsEmpty()) if (shared_memory.IsEmpty())
return engine_config_ptr(); return engine_config_ptr();
auto mmap_memory = params->Get(Nan::New("mmap_memory").ToLocalChecked());
if (mmap_memory.IsEmpty())
return engine_config_ptr();
if (!memory_file->IsUndefined()) if (!memory_file->IsUndefined())
{ {
if (path->IsUndefined()) if (path->IsUndefined())
@@ -190,6 +194,18 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
return engine_config_ptr(); return engine_config_ptr();
} }
} }
if (!mmap_memory->IsUndefined())
{
if (mmap_memory->IsBoolean())
{
engine_config->use_mmap = Nan::To<bool>(mmap_memory).FromJust();
}
else
{
Nan::ThrowError("mmap_memory option must be a boolean");
return engine_config_ptr();
}
}
if (path->IsUndefined() && !engine_config->use_shared_memory) if (path->IsUndefined() && !engine_config->use_shared_memory)
{ {
@@ -676,6 +692,77 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo<v8::Value> &arg
} }
} }
if (obj->Has(Nan::New("snapping").ToLocalChecked()))
{
v8::Local<v8::Value> snapping = obj->Get(Nan::New("snapping").ToLocalChecked());
if (snapping.IsEmpty())
return false;
if (!snapping->IsString())
{
Nan::ThrowError("Snapping must be a string: [default, any]");
return false;
}
const Nan::Utf8String snapping_utf8str(snapping);
std::string snapping_str{*snapping_utf8str, *snapping_utf8str + snapping_utf8str.length()};
if (snapping_str == "default")
{
params->snapping = osrm::RouteParameters::SnappingType::Default;
}
else if (snapping_str == "any")
{
params->snapping = osrm::RouteParameters::SnappingType::Any;
}
else
{
Nan::ThrowError("'snapping' param must be one of [default, any]");
return false;
}
}
if (obj->Has(Nan::New("acceleration_profile").ToLocalChecked()))
{
v8::Local<v8::Value> acceleration_profile =
obj->Get(Nan::New("acceleration_profile").ToLocalChecked());
if (acceleration_profile.IsEmpty())
return false;
if (!acceleration_profile->IsNumber() || !acceleration_profile->IsString())
{
Nan::ThrowError("acceleration_profile must be a decimal number or one of 'car', 'fast_car', 'slow_car', 'truck', or 'tractor_trailer'");
return false;
}
if (acceleration_profile->IsString()) {
std::string ssaf = *v8::String::Utf8Value(acceleration_profile);
// If they say 'yes', they get the default
if (ssaf == "car") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_CAR;
} else if (ssaf == "fast_car") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_FAST_CAR;
} else if (ssaf == "slow_car") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_SLOW_CAR;
} else if (ssaf == "truck") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_TRUCK;
} else if (ssaf == "tractor_trailer") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_TRACTOR_TRAILER;
} else {
Nan::ThrowError("acceleration_profile must be a decimal number or one of 'car', 'fast_car', 'slow_car', 'truck', or 'tractor_trailer'");
return false;
}
return true;
}
const auto value = acceleration_profile->NumberValue();
if (value < 0) {
Nan::ThrowError("acceleration_profile cannot be negative");
return false;
}
params->waypoint_acceleration_factor = value;
}
return true; return true;
} }
@@ -1167,6 +1254,70 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
} }
} }
if (obj->Has(Nan::New("fallback_speed").ToLocalChecked()))
{
auto fallback_speed = obj->Get(Nan::New("fallback_speed").ToLocalChecked());
if (!fallback_speed->IsNumber())
{
Nan::ThrowError("fallback_speed must be a number");
return table_parameters_ptr();
}
else if (fallback_speed->NumberValue() <= 0)
{
Nan::ThrowError("fallback_speed must be > 0");
return table_parameters_ptr();
}
params->fallback_speed = static_cast<double>(fallback_speed->NumberValue());
}
if (obj->Has(Nan::New("fallback_coordinate").ToLocalChecked()))
{
auto fallback_coordinate = obj->Get(Nan::New("fallback_coordinate").ToLocalChecked());
if (!fallback_coordinate->IsString())
{
Nan::ThrowError("fallback_coordinate must be a string: [input, snapped]");
return table_parameters_ptr();
}
std::string fallback_coordinate_str = *v8::String::Utf8Value(fallback_coordinate);
if (fallback_coordinate_str == "snapped")
{
params->fallback_coordinate_type =
osrm::TableParameters::FallbackCoordinateType::Snapped;
}
else if (fallback_coordinate_str == "input")
{
params->fallback_coordinate_type = osrm::TableParameters::FallbackCoordinateType::Input;
}
else
{
Nan::ThrowError("'fallback_coordinate' param must be one of [input, snapped]");
return table_parameters_ptr();
}
}
if (obj->Has(Nan::New("scale_factor").ToLocalChecked()))
{
auto scale_factor = obj->Get(Nan::New("scale_factor").ToLocalChecked());
if (!scale_factor->IsNumber())
{
Nan::ThrowError("scale_factor must be a number");
return table_parameters_ptr();
}
else if (scale_factor->NumberValue() <= 0)
{
Nan::ThrowError("scale_factor must be > 0");
return table_parameters_ptr();
}
params->scale_factor = static_cast<double>(scale_factor->NumberValue());
}
return params; return params;
} }
+33 -14
View File
@@ -75,28 +75,35 @@ template <storage::Ownership Ownership> class CellStorageImpl
// Implementation of the cell view. We need a template parameter here // Implementation of the cell view. We need a template parameter here
// because we need to derive a read-only and read-write view from this. // because we need to derive a read-only and read-write view from this.
template <typename WeightValueT, typename DurationValueT> class CellImpl template <typename WeightValueT, typename DurationValueT, typename DistanceValueT>
class CellImpl
{ {
private: private:
using WeightPtrT = WeightValueT *; using WeightPtrT = WeightValueT *;
using DurationPtrT = DurationValueT *; using DurationPtrT = DurationValueT *;
using DistancePtrT = DistanceValueT *;
BoundarySize num_source_nodes; BoundarySize num_source_nodes;
BoundarySize num_destination_nodes; BoundarySize num_destination_nodes;
WeightPtrT const weights; WeightPtrT const weights;
DurationPtrT const durations; DurationPtrT const durations;
DistancePtrT const distances;
const NodeID *const source_boundary; const NodeID *const source_boundary;
const NodeID *const destination_boundary; const NodeID *const destination_boundary;
using RowIterator = WeightPtrT; using RowIterator = WeightPtrT;
// Possibly replace with // Possibly replace with
// http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/reference/adaptors/reference/strided.html // http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/reference/adaptors/reference/strided.html
class ColumnIterator : public boost::iterator_facade<ColumnIterator,
WeightValueT, template <typename ValuePtrT>
class ColumnIterator : public boost::iterator_facade<ColumnIterator<ValuePtrT>,
decltype(*std::declval<ValuePtrT>()),
boost::random_access_traversal_tag> boost::random_access_traversal_tag>
{ {
typedef boost::iterator_facade<ColumnIterator,
WeightValueT, using ValueT = decltype(*std::declval<ValuePtrT>());
typedef boost::iterator_facade<ColumnIterator<ValueT>,
ValueT,
boost::random_access_traversal_tag> boost::random_access_traversal_tag>
base_t; base_t;
@@ -108,7 +115,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
explicit ColumnIterator() : current(nullptr), stride(1) {} explicit ColumnIterator() : current(nullptr), stride(1) {}
explicit ColumnIterator(WeightPtrT begin, std::size_t row_length) explicit ColumnIterator(ValuePtrT begin, std::size_t row_length)
: current(begin), stride(row_length) : current(begin), stride(row_length)
{ {
BOOST_ASSERT(begin != nullptr); BOOST_ASSERT(begin != nullptr);
@@ -126,7 +133,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
} }
friend class ::boost::iterator_core_access; friend class ::boost::iterator_core_access;
WeightPtrT current; ValuePtrT current;
const std::size_t stride; const std::size_t stride;
}; };
@@ -147,12 +154,13 @@ template <storage::Ownership Ownership> class CellStorageImpl
auto iter = auto iter =
std::find(destination_boundary, destination_boundary + num_destination_nodes, node); std::find(destination_boundary, destination_boundary + num_destination_nodes, node);
if (iter == destination_boundary + num_destination_nodes) if (iter == destination_boundary + num_destination_nodes)
return boost::make_iterator_range(ColumnIterator{}, ColumnIterator{}); return boost::make_iterator_range(ColumnIterator<ValuePtr>{},
ColumnIterator<ValuePtr>{});
auto column = std::distance(destination_boundary, iter); auto column = std::distance(destination_boundary, iter);
auto begin = ColumnIterator{ptr + column, num_destination_nodes}; auto begin = ColumnIterator<ValuePtr>{ptr + column, num_destination_nodes};
auto end = ColumnIterator{ptr + column + num_source_nodes * num_destination_nodes, auto end = ColumnIterator<ValuePtr>{
num_destination_nodes}; ptr + column + num_source_nodes * num_destination_nodes, num_destination_nodes};
return boost::make_iterator_range(begin, end); return boost::make_iterator_range(begin, end);
} }
@@ -165,6 +173,10 @@ template <storage::Ownership Ownership> class CellStorageImpl
auto GetInDuration(NodeID node) const { return GetInRange(durations, node); } auto GetInDuration(NodeID node) const { return GetInRange(durations, node); }
auto GetInDistance(NodeID node) const { return GetInRange(distances, node); }
auto GetOutDistance(NodeID node) const { return GetOutRange(distances, node); }
auto GetSourceNodes() const auto GetSourceNodes() const
{ {
return boost::make_iterator_range(source_boundary, source_boundary + num_source_nodes); return boost::make_iterator_range(source_boundary, source_boundary + num_source_nodes);
@@ -179,17 +191,20 @@ template <storage::Ownership Ownership> class CellStorageImpl
CellImpl(const CellData &data, CellImpl(const CellData &data,
WeightPtrT const all_weights, WeightPtrT const all_weights,
DurationPtrT const all_durations, DurationPtrT const all_durations,
DistancePtrT const all_distances,
const NodeID *const all_sources, const NodeID *const all_sources,
const NodeID *const all_destinations) const NodeID *const all_destinations)
: num_source_nodes{data.num_source_nodes}, : num_source_nodes{data.num_source_nodes},
num_destination_nodes{data.num_destination_nodes}, num_destination_nodes{data.num_destination_nodes},
weights{all_weights + data.value_offset}, weights{all_weights + data.value_offset},
durations{all_durations + data.value_offset}, durations{all_durations + data.value_offset},
distances{all_distances + data.value_offset},
source_boundary{all_sources + data.source_boundary_offset}, source_boundary{all_sources + data.source_boundary_offset},
destination_boundary{all_destinations + data.destination_boundary_offset} destination_boundary{all_destinations + data.destination_boundary_offset}
{ {
BOOST_ASSERT(all_weights != nullptr); BOOST_ASSERT(all_weights != nullptr);
BOOST_ASSERT(all_durations != nullptr); BOOST_ASSERT(all_durations != nullptr);
BOOST_ASSERT(all_distances != nullptr);
BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr); BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr);
BOOST_ASSERT(num_destination_nodes == 0 || all_destinations != nullptr); BOOST_ASSERT(num_destination_nodes == 0 || all_destinations != nullptr);
} }
@@ -201,7 +216,8 @@ template <storage::Ownership Ownership> class CellStorageImpl
const NodeID *const all_destinations) const NodeID *const all_destinations)
: num_source_nodes{data.num_source_nodes}, : num_source_nodes{data.num_source_nodes},
num_destination_nodes{data.num_destination_nodes}, weights{nullptr}, num_destination_nodes{data.num_destination_nodes}, weights{nullptr},
durations{nullptr}, source_boundary{all_sources + data.source_boundary_offset}, durations{nullptr}, distances{nullptr},
source_boundary{all_sources + data.source_boundary_offset},
destination_boundary{all_destinations + data.destination_boundary_offset} destination_boundary{all_destinations + data.destination_boundary_offset}
{ {
BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr); BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr);
@@ -212,8 +228,8 @@ template <storage::Ownership Ownership> class CellStorageImpl
std::size_t LevelIDToIndex(LevelID level) const { return level - 1; } std::size_t LevelIDToIndex(LevelID level) const { return level - 1; }
public: public:
using Cell = CellImpl<EdgeWeight, EdgeDuration>; using Cell = CellImpl<EdgeWeight, EdgeDuration, EdgeDistance>;
using ConstCell = CellImpl<const EdgeWeight, const EdgeDuration>; using ConstCell = CellImpl<const EdgeWeight, const EdgeDuration, const EdgeDistance>;
CellStorageImpl() {} CellStorageImpl() {}
@@ -361,6 +377,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
metric.weights.resize(total_size + 1, INVALID_EDGE_WEIGHT); metric.weights.resize(total_size + 1, INVALID_EDGE_WEIGHT);
metric.durations.resize(total_size + 1, MAXIMAL_EDGE_DURATION); metric.durations.resize(total_size + 1, MAXIMAL_EDGE_DURATION);
metric.distances.resize(total_size + 1, INVALID_EDGE_DISTANCE);
return metric; return metric;
} }
@@ -388,6 +405,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
return ConstCell{cells[cell_index], return ConstCell{cells[cell_index],
metric.weights.data(), metric.weights.data(),
metric.durations.data(), metric.durations.data(),
metric.distances.data(),
source_boundary.empty() ? nullptr : source_boundary.data(), source_boundary.empty() ? nullptr : source_boundary.data(),
destination_boundary.empty() ? nullptr : destination_boundary.data()}; destination_boundary.empty() ? nullptr : destination_boundary.data()};
} }
@@ -415,6 +433,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
return Cell{cells[cell_index], return Cell{cells[cell_index],
metric.weights.data(), metric.weights.data(),
metric.durations.data(), metric.durations.data(),
metric.distances.data(),
source_boundary.data(), source_boundary.data(),
destination_boundary.data()}; destination_boundary.data()};
} }
@@ -43,6 +43,7 @@ splitBidirectionalEdges(const std::vector<extractor::EdgeBasedEdge> &edges)
edge.data.turn_id, edge.data.turn_id,
std::max(edge.data.weight, 1), std::max(edge.data.weight, 1),
edge.data.duration, edge.data.duration,
edge.data.distance,
edge.data.forward, edge.data.forward,
edge.data.backward); edge.data.backward);
@@ -51,6 +52,7 @@ splitBidirectionalEdges(const std::vector<extractor::EdgeBasedEdge> &edges)
edge.data.turn_id, edge.data.turn_id,
std::max(edge.data.weight, 1), std::max(edge.data.weight, 1),
edge.data.duration, edge.data.duration,
edge.data.distance,
edge.data.backward, edge.data.backward,
edge.data.forward); edge.data.forward);
} }
+30 -2
View File
@@ -135,6 +135,19 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
}, },
qi::_1)]; qi::_1)];
acceleration_alpha_defaults_rule =
qi::lit("car")[qi::_val = ACCELERATION_ALPHA_CAR] |
qi::lit("fast_car")[qi::_val = ACCELERATION_ALPHA_FAST_CAR] |
qi::lit("slow_car")[qi::_val = ACCELERATION_ALPHA_SLOW_CAR] |
qi::lit("truck")[qi::_val = ACCELERATION_ALPHA_TRUCK] |
qi::lit("tractor_trailer")[qi::_val = ACCELERATION_ALPHA_TRACTOR_TRAILER];
acceleration_profile_rule =
qi::lit("acceleration_profile=") >
(qi::double_ | acceleration_alpha_defaults_rule)
[ph::bind(&engine::api::BaseParameters::waypoint_acceleration_factor, qi::_r1) =
qi::_1];
query_rule = query_rule =
((location_rule % ';') | polyline_rule | ((location_rule % ';') | polyline_rule |
polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1]; polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1];
@@ -162,6 +175,13 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
(-approach_type % (-approach_type %
';')[ph::bind(&engine::api::BaseParameters::approaches, qi::_r1) = qi::_1]; ';')[ph::bind(&engine::api::BaseParameters::approaches, qi::_r1) = qi::_1];
snapping_type.add("default", engine::api::BaseParameters::SnappingType::Default)(
"any", engine::api::BaseParameters::SnappingType::Any);
snapping_rule =
qi::lit("snapping=") >
snapping_type[ph::bind(&engine::api::BaseParameters::snapping, qi::_r1) = qi::_1];
exclude_rule = qi::lit("exclude=") > exclude_rule = qi::lit("exclude=") >
(qi::as_string[+qi::char_("a-zA-Z0-9")] % (qi::as_string[+qi::char_("a-zA-Z0-9")] %
',')[ph::bind(&engine::api::BaseParameters::exclude, qi::_r1) = qi::_1]; ',')[ph::bind(&engine::api::BaseParameters::exclude, qi::_r1) = qi::_1];
@@ -171,13 +191,17 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
| bearings_rule(qi::_r1) // | bearings_rule(qi::_r1) //
| generate_hints_rule(qi::_r1) // | generate_hints_rule(qi::_r1) //
| approach_rule(qi::_r1) // | approach_rule(qi::_r1) //
| exclude_rule(qi::_r1); | exclude_rule(qi::_r1) //
| snapping_rule(qi::_r1) //
| acceleration_profile_rule(qi::_r1);//
} }
protected: protected:
qi::rule<Iterator, Signature> base_rule; qi::rule<Iterator, Signature> base_rule;
qi::rule<Iterator, Signature> query_rule; qi::rule<Iterator, Signature> query_rule;
qi::real_parser<double, json_policy> double_;
private: private:
qi::rule<Iterator, Signature> bearings_rule; qi::rule<Iterator, Signature> bearings_rule;
qi::rule<Iterator, Signature> radiuses_rule; qi::rule<Iterator, Signature> radiuses_rule;
@@ -186,6 +210,7 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::rule<Iterator, Signature> generate_hints_rule; qi::rule<Iterator, Signature> generate_hints_rule;
qi::rule<Iterator, Signature> approach_rule; qi::rule<Iterator, Signature> approach_rule;
qi::rule<Iterator, Signature> exclude_rule; qi::rule<Iterator, Signature> exclude_rule;
qi::rule<Iterator, Signature> acceleration_profile_rule;
qi::rule<Iterator, osrm::engine::Bearing()> bearing_rule; qi::rule<Iterator, osrm::engine::Bearing()> bearing_rule;
qi::rule<Iterator, osrm::util::Coordinate()> location_rule; qi::rule<Iterator, osrm::util::Coordinate()> location_rule;
@@ -195,9 +220,12 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::rule<Iterator, unsigned char()> base64_char; qi::rule<Iterator, unsigned char()> base64_char;
qi::rule<Iterator, std::string()> polyline_chars; qi::rule<Iterator, std::string()> polyline_chars;
qi::rule<Iterator, double()> unlimited_rule; qi::rule<Iterator, double()> unlimited_rule;
qi::real_parser<double, json_policy> double_; qi::rule<Iterator, Signature> snapping_rule;
qi::rule<Iterator, double()> acceleration_alpha_defaults_rule;
qi::symbols<char, engine::Approach> approach_type; qi::symbols<char, engine::Approach> approach_type;
qi::symbols<char, engine::api::BaseParameters::SnappingType> snapping_type;
}; };
} }
} }
+26 -1
View File
@@ -48,10 +48,28 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
(qi::lit("all") | (qi::lit("all") |
(size_t_ % ';')[ph::bind(&engine::api::TableParameters::sources, qi::_r1) = qi::_1]); (size_t_ % ';')[ph::bind(&engine::api::TableParameters::sources, qi::_r1) = qi::_1]);
fallback_speed_rule =
qi::lit("fallback_speed=") >
(double_)[ph::bind(&engine::api::TableParameters::fallback_speed, qi::_r1) = qi::_1];
fallback_coordinate_type.add("input",
engine::api::TableParameters::FallbackCoordinateType::Input)(
"snapped", engine::api::TableParameters::FallbackCoordinateType::Snapped);
scale_factor_rule =
qi::lit("scale_factor=") >
(double_)[ph::bind(&engine::api::TableParameters::scale_factor, qi::_r1) = qi::_1];
table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1); table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1);
root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") > root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
-('?' > (table_rule(qi::_r1) | base_rule(qi::_r1)) % '&'); -('?' > (table_rule(qi::_r1) | base_rule(qi::_r1) | scale_factor_rule(qi::_r1) |
fallback_speed_rule(qi::_r1) |
(qi::lit("fallback_coordinate=") >
fallback_coordinate_type
[ph::bind(&engine::api::TableParameters::fallback_coordinate_type,
qi::_r1) = qi::_1])) %
'&');
} }
TableParametersGrammar(qi::rule<Iterator, Signature> &root_rule_) : BaseGrammar(root_rule_) TableParametersGrammar(qi::rule<Iterator, Signature> &root_rule_) : BaseGrammar(root_rule_)
@@ -73,13 +91,20 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
qi::rule<Iterator, Signature> base_rule; qi::rule<Iterator, Signature> base_rule;
private: private:
using json_policy = no_trailing_dot_policy<double, 'j', 's', 'o', 'n'>;
qi::rule<Iterator, Signature> root_rule; qi::rule<Iterator, Signature> root_rule;
qi::rule<Iterator, Signature> table_rule; qi::rule<Iterator, Signature> table_rule;
qi::rule<Iterator, Signature> sources_rule; qi::rule<Iterator, Signature> sources_rule;
qi::rule<Iterator, Signature> destinations_rule; qi::rule<Iterator, Signature> destinations_rule;
qi::rule<Iterator, Signature> fallback_speed_rule;
qi::rule<Iterator, Signature> scale_factor_rule;
qi::rule<Iterator, std::size_t()> size_t_; qi::rule<Iterator, std::size_t()> size_t_;
qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations; qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations;
qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list; qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list;
qi::symbols<char, engine::api::TableParameters::FallbackCoordinateType>
fallback_coordinate_type;
qi::real_parser<double, json_policy> double_;
}; };
} }
} }
+8 -3
View File
@@ -16,10 +16,15 @@ struct Block
{ {
std::uint64_t num_entries; std::uint64_t num_entries;
std::uint64_t byte_size; std::uint64_t byte_size;
std::uint64_t offset;
Block() : num_entries(0), byte_size(0) {} Block() : num_entries(0), byte_size(0), offset(0) {}
Block(std::uint64_t num_entries, std::uint64_t byte_size, std::uint64_t offset)
: num_entries(num_entries), byte_size(byte_size), offset(offset)
{
}
Block(std::uint64_t num_entries, std::uint64_t byte_size) Block(std::uint64_t num_entries, std::uint64_t byte_size)
: num_entries(num_entries), byte_size(byte_size) : num_entries(num_entries), byte_size(byte_size), offset(0)
{ {
} }
}; };
@@ -29,7 +34,7 @@ using NamedBlock = std::tuple<std::string, Block>;
template <typename T> Block make_block(uint64_t num_entries) template <typename T> Block make_block(uint64_t num_entries)
{ {
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer"); static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
return Block{num_entries, sizeof(T) * num_entries}; return Block{num_entries, sizeof(T) * num_entries, 0};
} }
} }
} }
+40 -22
View File
@@ -9,6 +9,7 @@
#include "storage/shared_datatype.hpp" #include "storage/shared_datatype.hpp"
#include "storage/tar.hpp" #include "storage/tar.hpp"
#include <boost/assert.hpp>
#include <boost/function_output_iterator.hpp> #include <boost/function_output_iterator.hpp>
#include <boost/iterator/function_input_iterator.hpp> #include <boost/iterator/function_input_iterator.hpp>
@@ -30,22 +31,37 @@ namespace serialization
namespace detail namespace detail
{ {
template <typename T, typename BlockT = unsigned char> template <typename T, typename BlockT = unsigned char>
inline BlockT packBits(const T &data, std::size_t index, std::size_t count) inline BlockT packBits(const T &data, std::size_t base_index, const std::size_t count)
{ {
static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool"); static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool");
static_assert(std::is_unsigned<BlockT>::value, "BlockT must be unsigned type");
static_assert(std::is_integral<BlockT>::value, "BlockT must be an integral type");
static_assert(CHAR_BIT == 8, "Non-8-bit bytes not supported, sorry!");
BOOST_ASSERT(sizeof(BlockT) * CHAR_BIT >= count);
// Note: if this packing is changed, be sure to update vector_view<bool>
// as well, so that on-disk and in-memory layouts match.
BlockT value = 0; BlockT value = 0;
for (std::size_t bit = 0; bit < count; ++bit, ++index) for (std::size_t bit = 0; bit < count; ++bit)
value = (value << 1) | data[index]; {
value |= (data[base_index + bit] ? BlockT{1} : BlockT{0}) << bit;
}
return value; return value;
} }
template <typename T, typename BlockT = unsigned char> template <typename T, typename BlockT = unsigned char>
inline void unpackBits(T &data, std::size_t index, std::size_t count, BlockT value) inline void
unpackBits(T &data, const std::size_t base_index, const std::size_t count, const BlockT value)
{ {
static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool"); static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool");
const BlockT mask = BlockT{1} << (count - 1); static_assert(std::is_unsigned<BlockT>::value, "BlockT must be unsigned type");
for (std::size_t bit = 0; bit < count; value <<= 1, ++bit, ++index) static_assert(std::is_integral<BlockT>::value, "BlockT must be an integral type");
data[index] = value & mask; static_assert(CHAR_BIT == 8, "Non-8-bit bytes not supported, sorry!");
BOOST_ASSERT(sizeof(BlockT) * CHAR_BIT >= count);
for (std::size_t bit = 0; bit < count; ++bit)
{
data[base_index + bit] = value & (BlockT{1} << bit);
}
} }
template <typename VectorT> template <typename VectorT>
@@ -55,15 +71,16 @@ void readBoolVector(tar::FileReader &reader, const std::string &name, VectorT &d
data.resize(count); data.resize(count);
std::uint64_t index = 0; std::uint64_t index = 0;
constexpr std::uint64_t WORD_BITS = CHAR_BIT * sizeof(std::uint64_t); using BlockType = std::uint64_t;
constexpr std::uint64_t BLOCK_BITS = CHAR_BIT * sizeof(BlockType);
const auto decode = [&](const std::uint64_t block) { const auto decode = [&](const BlockType block) {
auto read_size = std::min<std::size_t>(count - index, WORD_BITS); auto read_size = std::min<std::size_t>(count - index, BLOCK_BITS);
unpackBits<VectorT, std::uint64_t>(data, index, read_size, block); unpackBits<VectorT, BlockType>(data, index, read_size, block);
index += WORD_BITS; index += BLOCK_BITS;
}; };
reader.ReadStreaming<std::uint64_t>(name, boost::make_function_output_iterator(decode)); reader.ReadStreaming<BlockType>(name, boost::make_function_output_iterator(decode));
} }
template <typename VectorT> template <typename VectorT>
@@ -73,19 +90,20 @@ void writeBoolVector(tar::FileWriter &writer, const std::string &name, const Vec
writer.WriteElementCount64(name, count); writer.WriteElementCount64(name, count);
std::uint64_t index = 0; std::uint64_t index = 0;
constexpr std::uint64_t WORD_BITS = CHAR_BIT * sizeof(std::uint64_t); using BlockType = std::uint64_t;
constexpr std::uint64_t BLOCK_BITS = CHAR_BIT * sizeof(BlockType);
// FIXME on old boost version the function_input_iterator does not work with lambdas // FIXME on old boost version the function_input_iterator does not work with lambdas
// so we need to wrap it in a function here. // so we need to wrap it in a function here.
const std::function<std::uint64_t()> encode_function = [&]() -> std::uint64_t { const std::function<BlockType()> encode_function = [&]() -> BlockType {
auto write_size = std::min<std::size_t>(count - index, WORD_BITS); auto write_size = std::min<std::size_t>(count - index, BLOCK_BITS);
auto packed = packBits<VectorT, std::uint64_t>(data, index, write_size); auto packed = packBits<VectorT, BlockType>(data, index, write_size);
index += WORD_BITS; index += BLOCK_BITS;
return packed; return packed;
}; };
std::uint64_t number_of_blocks = (count + WORD_BITS - 1) / WORD_BITS; std::uint64_t number_of_blocks = (count + BLOCK_BITS - 1) / BLOCK_BITS;
writer.WriteStreaming<std::uint64_t>( writer.WriteStreaming<BlockType>(
name, name,
boost::make_function_input_iterator(encode_function, boost::infinite()), boost::make_function_input_iterator(encode_function, boost::infinite()),
number_of_blocks); number_of_blocks);
@@ -266,9 +284,9 @@ template <typename K, typename V> void write(io::BufferWriter &writer, const std
} }
} }
inline void read(io::BufferReader &reader, DataLayout &layout) { read(reader, layout.blocks); } inline void read(io::BufferReader &reader, BaseDataLayout &layout) { read(reader, layout.blocks); }
inline void write(io::BufferWriter &writer, const DataLayout &layout) inline void write(io::BufferWriter &writer, const BaseDataLayout &layout)
{ {
write(writer, layout.blocks); write(writer, layout.blocks);
} }
+24 -11
View File
@@ -5,6 +5,7 @@
#include <boost/function_output_iterator.hpp> #include <boost/function_output_iterator.hpp>
#include <type_traits>
#include <unordered_map> #include <unordered_map>
namespace osrm namespace osrm
@@ -19,8 +20,8 @@ class SharedDataIndex
public: public:
struct AllocatedRegion struct AllocatedRegion
{ {
char *memory_ptr; void *memory_ptr;
DataLayout layout; std::unique_ptr<BaseDataLayout> layout;
}; };
SharedDataIndex() = default; SharedDataIndex() = default;
@@ -29,10 +30,10 @@ class SharedDataIndex
// Build mapping from block name to region // Build mapping from block name to region
for (auto index : util::irange<std::uint32_t>(0, regions.size())) for (auto index : util::irange<std::uint32_t>(0, regions.size()))
{ {
regions[index].layout.List("", regions[index].layout->List("",
boost::make_function_output_iterator([&](const auto &name) { boost::make_function_output_iterator([&](const auto &name) {
block_to_region[name] = index; block_to_region[name] = index;
})); }));
} }
} }
@@ -40,32 +41,44 @@ class SharedDataIndex
{ {
for (const auto &region : regions) for (const auto &region : regions)
{ {
region.layout.List(name_prefix, out); region.layout->List(name_prefix, out);
} }
} }
template <typename T> auto GetBlockPtr(const std::string &name) const template <typename T> auto GetBlockPtr(const std::string &name) const
{ {
#if !defined(__GNUC__) || (__GNUC__ > 4)
// is_tivially_copyable only exists in GCC >=5
static_assert(std::is_trivially_copyable<T>::value,
"Block-based data must be a trivially copyable type");
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
#endif
const auto &region = GetBlockRegion(name); const auto &region = GetBlockRegion(name);
return region.layout.GetBlockPtr<T>(region.memory_ptr, name); return reinterpret_cast<T *>(region.layout->GetBlockPtr(region.memory_ptr, name));
} }
template <typename T> auto GetBlockPtr(const std::string &name) template <typename T> auto GetBlockPtr(const std::string &name)
{ {
#if !defined(__GNUC__) || (__GNUC__ > 4)
// is_tivially_copyable only exists in GCC >=5
static_assert(std::is_trivially_copyable<T>::value,
"Block-based data must be a trivially copyable type");
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
#endif
const auto &region = GetBlockRegion(name); const auto &region = GetBlockRegion(name);
return region.layout.GetBlockPtr<T>(region.memory_ptr, name); return reinterpret_cast<T *>(region.layout->GetBlockPtr(region.memory_ptr, name));
} }
std::size_t GetBlockEntries(const std::string &name) const std::size_t GetBlockEntries(const std::string &name) const
{ {
const auto &region = GetBlockRegion(name); const auto &region = GetBlockRegion(name);
return region.layout.GetBlockEntries(name); return region.layout->GetBlockEntries(name);
} }
std::size_t GetBlockSize(const std::string &name) const std::size_t GetBlockSize(const std::string &name) const
{ {
const auto &region = GetBlockRegion(name); const auto &region = GetBlockRegion(name);
return region.layout.GetBlockSize(name); return region.layout->GetBlockSize(name);
} }
private: private:
+67 -31
View File
@@ -20,12 +20,12 @@ namespace osrm
namespace storage namespace storage
{ {
class DataLayout; class BaseDataLayout;
namespace serialization namespace serialization
{ {
inline void read(io::BufferReader &reader, DataLayout &layout); inline void read(io::BufferReader &reader, BaseDataLayout &layout);
inline void write(io::BufferWriter &writer, const DataLayout &layout); inline void write(io::BufferWriter &writer, const BaseDataLayout &layout);
} // namespace serialization } // namespace serialization
namespace detail namespace detail
@@ -54,44 +54,28 @@ inline std::string trimName(const std::string &name_prefix, const std::string &n
} }
} // namespace detail } // namespace detail
class DataLayout class BaseDataLayout
{ {
public: public:
DataLayout() : blocks{} {} virtual ~BaseDataLayout() = default;
inline void SetBlock(const std::string &name, Block block) { blocks[name] = std::move(block); } inline void SetBlock(const std::string &name, Block block) { blocks[name] = std::move(block); }
inline uint64_t GetBlockEntries(const std::string &name) const inline std::uint64_t GetBlockEntries(const std::string &name) const
{ {
return GetBlock(name).num_entries; return GetBlock(name).num_entries;
} }
inline uint64_t GetBlockSize(const std::string &name) const { return GetBlock(name).byte_size; } inline std::uint64_t GetBlockSize(const std::string &name) const
{
return GetBlock(name).byte_size;
}
inline bool HasBlock(const std::string &name) const inline bool HasBlock(const std::string &name) const
{ {
return blocks.find(name) != blocks.end(); return blocks.find(name) != blocks.end();
} }
inline uint64_t GetSizeOfLayout() const
{
uint64_t result = 0;
for (const auto &name_and_block : blocks)
{
result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT;
}
return result;
}
template <typename T> inline T *GetBlockPtr(char *shared_memory, const std::string &name) const
{
static_assert(BLOCK_ALIGNMENT % std::alignment_of<T>::value == 0,
"Datatype does not fit alignment constraints.");
char *ptr = (char *)GetAlignedBlockPtr(shared_memory, name);
return (T *)ptr;
}
// Depending on the name prefix this function either lists all blocks with the same prefix // Depending on the name prefix this function either lists all blocks with the same prefix
// or all entries in the sub-directory. // or all entries in the sub-directory.
// '/ch/edge' -> '/ch/edge_filter/0/blocks', '/ch/edge_filter/1/blocks' // '/ch/edge' -> '/ch/edge_filter/0/blocks', '/ch/edge_filter/1/blocks'
@@ -115,10 +99,10 @@ class DataLayout
} }
} }
private: virtual inline void *GetBlockPtr(void *base_ptr, const std::string &name) const = 0;
friend void serialization::read(io::BufferReader &reader, DataLayout &layout); virtual inline std::uint64_t GetSizeOfLayout() const = 0;
friend void serialization::write(io::BufferWriter &writer, const DataLayout &layout);
protected:
const Block &GetBlock(const std::string &name) const const Block &GetBlock(const std::string &name) const
{ {
auto iter = blocks.find(name); auto iter = blocks.find(name);
@@ -130,10 +114,42 @@ class DataLayout
return iter->second; return iter->second;
} }
friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout);
friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout);
std::map<std::string, Block> blocks;
};
class ContiguousDataLayout final : public BaseDataLayout
{
public:
inline std::uint64_t GetSizeOfLayout() const override final
{
std::uint64_t result = 0;
for (const auto &name_and_block : blocks)
{
result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT;
}
return result;
}
inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final
{
// TODO: re-enable this alignment checking somehow
// static_assert(BLOCK_ALIGNMENT % std::alignment_of<T>::value == 0,
// "Datatype does not fit alignment constraints.");
return GetAlignedBlockPtr(base_ptr, name);
}
private:
friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout);
friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout);
// Fit aligned storage in buffer to 64 bytes to conform with AVX 512 types // Fit aligned storage in buffer to 64 bytes to conform with AVX 512 types
inline void *align(void *&ptr) const noexcept inline void *align(void *&ptr) const noexcept
{ {
const auto intptr = reinterpret_cast<uintptr_t>(ptr); const auto intptr = reinterpret_cast<std::uintptr_t>(ptr);
const auto aligned = (intptr - 1u + BLOCK_ALIGNMENT) & -BLOCK_ALIGNMENT; const auto aligned = (intptr - 1u + BLOCK_ALIGNMENT) & -BLOCK_ALIGNMENT;
return ptr = reinterpret_cast<void *>(aligned); return ptr = reinterpret_cast<void *>(aligned);
} }
@@ -157,7 +173,27 @@ class DataLayout
} }
static constexpr std::size_t BLOCK_ALIGNMENT = 64; static constexpr std::size_t BLOCK_ALIGNMENT = 64;
std::map<std::string, Block> blocks; };
class TarDataLayout final : public BaseDataLayout
{
public:
inline std::uint64_t GetSizeOfLayout() const override final
{
std::uint64_t result = 0;
for (const auto &name_and_block : blocks)
{
result += GetBlockSize(name_and_block.first);
}
return result;
}
inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final
{
auto offset = GetBlock(name).offset;
const auto offset_address = reinterpret_cast<std::uintptr_t>(base_ptr) + offset;
return reinterpret_cast<void *>(offset_address);
}
}; };
struct SharedRegion struct SharedRegion
+9 -3
View File
@@ -35,22 +35,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <string> #include <string>
#include <vector>
namespace osrm namespace osrm
{ {
namespace storage namespace storage
{ {
void populateLayoutFromFile(const boost::filesystem::path &path, storage::BaseDataLayout &layout);
class Storage class Storage
{ {
public: public:
Storage(StorageConfig config); Storage(StorageConfig config);
int Run(int max_wait, const std::string &name, bool only_metric); int Run(int max_wait, const std::string &name, bool only_metric);
void PopulateStaticLayout(DataLayout &layout);
void PopulateUpdatableLayout(DataLayout &layout);
void PopulateStaticData(const SharedDataIndex &index); void PopulateStaticData(const SharedDataIndex &index);
void PopulateUpdatableData(const SharedDataIndex &index); void PopulateUpdatableData(const SharedDataIndex &index);
void PopulateLayout(storage::BaseDataLayout &layout,
const std::vector<std::pair<bool, boost::filesystem::path>> &files);
std::string PopulateLayoutWithRTree(storage::BaseDataLayout &layout);
std::vector<std::pair<bool, boost::filesystem::path>> GetUpdatableFiles();
std::vector<std::pair<bool, boost::filesystem::path>> GetStaticFiles();
private: private:
StorageConfig config; StorageConfig config;
+10 -3
View File
@@ -294,11 +294,14 @@ inline auto make_filtered_cell_metric_view(const SharedDataIndex &index,
auto prefix = name + "/exclude/" + std::to_string(exclude_index); auto prefix = name + "/exclude/" + std::to_string(exclude_index);
auto weights_block_id = prefix + "/weights"; auto weights_block_id = prefix + "/weights";
auto durations_block_id = prefix + "/durations"; auto durations_block_id = prefix + "/durations";
auto distances_block_id = prefix + "/distances";
auto weights = make_vector_view<EdgeWeight>(index, weights_block_id); auto weights = make_vector_view<EdgeWeight>(index, weights_block_id);
auto durations = make_vector_view<EdgeDuration>(index, durations_block_id); auto durations = make_vector_view<EdgeDuration>(index, durations_block_id);
auto distances = make_vector_view<EdgeDistance>(index, distances_block_id);
return customizer::CellMetricView{std::move(weights), std::move(durations)}; return customizer::CellMetricView{
std::move(weights), std::move(durations), std::move(distances)};
} }
inline auto make_cell_metric_view(const SharedDataIndex &index, const std::string &name) inline auto make_cell_metric_view(const SharedDataIndex &index, const std::string &name)
@@ -311,12 +314,14 @@ inline auto make_cell_metric_view(const SharedDataIndex &index, const std::strin
{ {
auto weights_block_id = prefix + "/weights"; auto weights_block_id = prefix + "/weights";
auto durations_block_id = prefix + "/durations"; auto durations_block_id = prefix + "/durations";
auto distances_block_id = prefix + "/distances";
auto weights = make_vector_view<EdgeWeight>(index, weights_block_id); auto weights = make_vector_view<EdgeWeight>(index, weights_block_id);
auto durations = make_vector_view<EdgeDuration>(index, durations_block_id); auto durations = make_vector_view<EdgeDuration>(index, durations_block_id);
auto distances = make_vector_view<EdgeDistance>(index, distances_block_id);
cell_metric_excludes.push_back( cell_metric_excludes.push_back(customizer::CellMetricView{
customizer::CellMetricView{std::move(weights), std::move(durations)}); std::move(weights), std::move(durations), std::move(distances)});
} }
return cell_metric_excludes; return cell_metric_excludes;
@@ -332,6 +337,7 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std:
index, name + "/node_to_edge_offset"); index, name + "/node_to_edge_offset");
auto node_weights = make_vector_view<EdgeWeight>(index, name + "/node_weights"); auto node_weights = make_vector_view<EdgeWeight>(index, name + "/node_weights");
auto node_durations = make_vector_view<EdgeDuration>(index, name + "/node_durations"); auto node_durations = make_vector_view<EdgeDuration>(index, name + "/node_durations");
auto node_distances = make_vector_view<EdgeDistance>(index, name + "/node_distances");
auto is_forward_edge = make_vector_view<bool>(index, name + "/is_forward_edge"); auto is_forward_edge = make_vector_view<bool>(index, name + "/is_forward_edge");
auto is_backward_edge = make_vector_view<bool>(index, name + "/is_backward_edge"); auto is_backward_edge = make_vector_view<bool>(index, name + "/is_backward_edge");
@@ -340,6 +346,7 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std:
std::move(node_to_offset), std::move(node_to_offset),
std::move(node_weights), std::move(node_weights),
std::move(node_durations), std::move(node_durations),
std::move(node_distances),
std::move(is_forward_edge), std::move(is_forward_edge),
std::move(is_backward_edge)); std::move(is_backward_edge));
} }
+11 -5
View File
@@ -22,11 +22,17 @@ class Updater
std::vector<EdgeWeight> &node_weights, std::vector<EdgeWeight> &node_weights,
std::uint32_t &connectivity_checksum) const; std::uint32_t &connectivity_checksum) const;
EdgeID EdgeID LoadAndUpdateEdgeExpandedGraph(
LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list, std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights, std::vector<EdgeWeight> &node_weights,
std::vector<EdgeDuration> &node_durations, // TODO: to be deleted std::vector<EdgeDuration> &node_durations, // TODO: remove when optional
std::uint32_t &connectivity_checksum) const; std::uint32_t &connectivity_checksum) const;
EdgeID LoadAndUpdateEdgeExpandedGraph(
std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
std::vector<EdgeDuration> &node_durations, // TODO: remove when optional
std::vector<EdgeDistance> &node_distances, // TODO: remove when optional
std::uint32_t &connectivity_checksum) const;
private: private:
UpdaterConfig config; UpdaterConfig config;
+19
View File
@@ -1,9 +1,11 @@
#ifndef OSRM_UTIL_DEBUG_HPP_ #ifndef OSRM_UTIL_DEBUG_HPP_
#define OSRM_UTIL_DEBUG_HPP_ #define OSRM_UTIL_DEBUG_HPP_
#include "extractor/edge_based_edge.hpp"
#include "extractor/node_data_container.hpp" #include "extractor/node_data_container.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "guidance/intersection.hpp" #include "guidance/intersection.hpp"
#include "guidance/turn_instruction.hpp"
#include "guidance/turn_lane_data.hpp" #include "guidance/turn_lane_data.hpp"
#include "engine/guidance/route_step.hpp" #include "engine/guidance/route_step.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
@@ -186,6 +188,23 @@ inline std::ostream &operator<<(std::ostream &out, const LaneDataVector &turn_la
} }
} }
} }
namespace extractor
{
inline std::ostream &operator<<(std::ostream &out, const EdgeBasedEdge &edge)
{
out << " EdgeBasedEdge {";
out << " source " << edge.source << ", target: " << edge.target;
out << " EdgeBasedEdgeData data {";
out << " turn_id: " << edge.data.turn_id << ", weight: " << edge.data.weight;
out << " distance: " << edge.data.distance << ", duration: " << edge.data.duration;
out << " forward: " << (edge.data.forward == 0 ? "false" : "true")
<< ", backward: " << (edge.data.backward == 0 ? "false" : "true");
out << " }";
out << "}";
return out;
}
}
} }
#endif /*OSRM_ENGINE_GUIDANCE_DEBUG_HPP_*/ #endif /*OSRM_ENGINE_GUIDANCE_DEBUG_HPP_*/
+3 -3
View File
@@ -29,7 +29,7 @@ THE SOFTWARE.
#include <math.h> #include <math.h>
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include "msinttypes/stdint.h" #include "rapidjson/msinttypes/stdint.h"
#include <intrin.h> #include <intrin.h>
#else #else
#include <stdint.h> #include <stdint.h>
@@ -488,8 +488,8 @@ inline void Prettify(char *buffer, int length, int k)
inline void dtoa_milo(double value, char *buffer) inline void dtoa_milo(double value, char *buffer)
{ {
// Not handling NaN and inf // Not handling NaN and inf
assert(!isnan(value)); assert(!std::isnan(value));
assert(!isinf(value)); assert(!std::isinf(value));
if (value == 0) if (value == 0)
{ {
+17 -16
View File
@@ -15,14 +15,14 @@ namespace util
namespace detail namespace detail
{ {
template <typename T, typename RegionT> template <typename T, typename MmapContainerT>
util::vector_view<T> mmapFile(const boost::filesystem::path &file, RegionT &region) util::vector_view<T> mmapFile(const boost::filesystem::path &file, MmapContainerT &mmap_container)
{ {
try try
{ {
region.open(file); mmap_container.open(file);
std::size_t num_objects = region.size() / sizeof(T); std::size_t num_objects = mmap_container.size() / sizeof(T);
auto data_ptr = region.data(); auto data_ptr = mmap_container.data();
BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0); BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0);
return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects); return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects);
} }
@@ -34,9 +34,10 @@ util::vector_view<T> mmapFile(const boost::filesystem::path &file, RegionT &regi
} }
} }
template <typename T, typename RegionT> template <typename T, typename MmapContainerT>
util::vector_view<T> util::vector_view<T> mmapFile(const boost::filesystem::path &file,
mmapFile(const boost::filesystem::path &file, RegionT &region, const std::size_t size) MmapContainerT &mmap_container,
const std::size_t size)
{ {
try try
{ {
@@ -45,10 +46,10 @@ mmapFile(const boost::filesystem::path &file, RegionT &region, const std::size_t
params.path = file.string(); params.path = file.string();
params.flags = boost::iostreams::mapped_file::readwrite; params.flags = boost::iostreams::mapped_file::readwrite;
params.new_file_size = size; params.new_file_size = size;
region.open(params); mmap_container.open(params);
std::size_t num_objects = size / sizeof(T); std::size_t num_objects = size / sizeof(T);
auto data_ptr = region.data(); auto data_ptr = mmap_container.data();
BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0); BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0);
return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects); return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects);
} }
@@ -63,24 +64,24 @@ mmapFile(const boost::filesystem::path &file, RegionT &region, const std::size_t
template <typename T> template <typename T>
util::vector_view<const T> mmapFile(const boost::filesystem::path &file, util::vector_view<const T> mmapFile(const boost::filesystem::path &file,
boost::iostreams::mapped_file_source &region) boost::iostreams::mapped_file_source &mmap_container)
{ {
return detail::mmapFile<const T>(file, region); return detail::mmapFile<const T>(file, mmap_container);
} }
template <typename T> template <typename T>
util::vector_view<T> mmapFile(const boost::filesystem::path &file, util::vector_view<T> mmapFile(const boost::filesystem::path &file,
boost::iostreams::mapped_file &region) boost::iostreams::mapped_file &mmap_container)
{ {
return detail::mmapFile<T>(file, region); return detail::mmapFile<T>(file, mmap_container);
} }
template <typename T> template <typename T>
util::vector_view<T> mmapFile(const boost::filesystem::path &file, util::vector_view<T> mmapFile(const boost::filesystem::path &file,
boost::iostreams::mapped_file &region, boost::iostreams::mapped_file &mmap_container,
std::size_t size) std::size_t size)
{ {
return detail::mmapFile<T>(file, region, size); return detail::mmapFile<T>(file, mmap_container, size);
} }
} }
} }
+10 -4
View File
@@ -9,6 +9,7 @@
#include <tbb/parallel_sort.h> #include <tbb/parallel_sort.h>
#include <iostream>
#include <memory> #include <memory>
#include <utility> #include <utility>
@@ -20,24 +21,27 @@ namespace util
struct NodeBasedEdgeData struct NodeBasedEdgeData
{ {
NodeBasedEdgeData() NodeBasedEdgeData()
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), geometry_id({0, false}), : weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT),
reversed(false), annotation_data(-1) distance(INVALID_EDGE_DISTANCE), geometry_id({0, false}), reversed(false),
annotation_data(-1)
{ {
} }
NodeBasedEdgeData(EdgeWeight weight, NodeBasedEdgeData(EdgeWeight weight,
EdgeWeight duration, EdgeWeight duration,
EdgeDistance distance,
GeometryID geometry_id, GeometryID geometry_id,
bool reversed, bool reversed,
extractor::NodeBasedEdgeClassification flags, extractor::NodeBasedEdgeClassification flags,
AnnotationID annotation_data) AnnotationID annotation_data)
: weight(weight), duration(duration), geometry_id(geometry_id), reversed(reversed), : weight(weight), duration(duration), distance(distance), geometry_id(geometry_id),
flags(flags), annotation_data(annotation_data) reversed(reversed), flags(flags), annotation_data(annotation_data)
{ {
} }
EdgeWeight weight; EdgeWeight weight;
EdgeWeight duration; EdgeWeight duration;
EdgeDistance distance;
GeometryID geometry_id; GeometryID geometry_id;
bool reversed : 1; bool reversed : 1;
extractor::NodeBasedEdgeClassification flags; extractor::NodeBasedEdgeClassification flags;
@@ -80,11 +84,13 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
const extractor::NodeBasedEdge &input_edge) { const extractor::NodeBasedEdge &input_edge) {
output_edge.data.weight = input_edge.weight; output_edge.data.weight = input_edge.weight;
output_edge.data.duration = input_edge.duration; output_edge.data.duration = input_edge.duration;
output_edge.data.distance = input_edge.distance;
output_edge.data.flags = input_edge.flags; output_edge.data.flags = input_edge.flags;
output_edge.data.annotation_data = input_edge.annotation_data; output_edge.data.annotation_data = input_edge.annotation_data;
BOOST_ASSERT(output_edge.data.weight > 0); BOOST_ASSERT(output_edge.data.weight > 0);
BOOST_ASSERT(output_edge.data.duration > 0); BOOST_ASSERT(output_edge.data.duration > 0);
BOOST_ASSERT(output_edge.data.distance >= 0);
}); });
tbb::parallel_sort(edges_list.begin(), edges_list.end()); tbb::parallel_sort(edges_list.begin(), edges_list.end());
+10
View File
@@ -113,8 +113,18 @@ static const SegmentWeight MAX_SEGMENT_WEIGHT = INVALID_SEGMENT_WEIGHT - 1;
static const SegmentDuration MAX_SEGMENT_DURATION = INVALID_SEGMENT_DURATION - 1; static const SegmentDuration MAX_SEGMENT_DURATION = INVALID_SEGMENT_DURATION - 1;
static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<EdgeWeight>::max(); static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<EdgeWeight>::max();
static const EdgeDuration MAXIMAL_EDGE_DURATION = std::numeric_limits<EdgeDuration>::max(); static const EdgeDuration MAXIMAL_EDGE_DURATION = std::numeric_limits<EdgeDuration>::max();
static const EdgeDistance MAXIMAL_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max();
static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits<TurnPenalty>::max(); static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits<TurnPenalty>::max();
static const EdgeDistance INVALID_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max(); static const EdgeDistance INVALID_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max();
static const EdgeDistance INVALID_FALLBACK_SPEED = std::numeric_limits<double>::max();
// Recommended value for passenger vehicles from
// https://fdotwww.blob.core.windows.net/sitefinity/docs/default-source/content/rail/publications/studies/safety/accelerationresearch.pdf?sfvrsn=716a4bb1_0
static const double ACCELERATION_ALPHA_CAR = 6.0;
static const double ACCELERATION_ALPHA_FAST_CAR = 18;
static const double ACCELERATION_ALPHA_SLOW_CAR = 2;
static const double ACCELERATION_ALPHA_TRUCK = 1.5;
static const double ACCELERATION_ALPHA_TRACTOR_TRAILER = 0.5;
// FIXME the bitfields we use require a reduced maximal duration, this should be kept consistent // FIXME the bitfields we use require a reduced maximal duration, this should be kept consistent
// within the code base. For now we have to ensure that we don't case 30 bit to -1 and break any // within the code base. For now we have to ensure that we don't case 30 bit to -1 and break any
+15
View File
@@ -195,7 +195,10 @@ template <> class vector_view<bool>
{ {
BOOST_ASSERT_MSG(index < m_size, "invalid size"); BOOST_ASSERT_MSG(index < m_size, "invalid size");
const std::size_t bucket = index / WORD_BITS; const std::size_t bucket = index / WORD_BITS;
// Note: ordering of bits here should match packBits in storage/serialization.hpp
// so that directly mmap-ing data is possible
const auto offset = index % WORD_BITS; const auto offset = index % WORD_BITS;
BOOST_ASSERT(WORD_BITS > offset);
return m_ptr[bucket] & (static_cast<Word>(1) << offset); return m_ptr[bucket] & (static_cast<Word>(1) << offset);
} }
@@ -224,11 +227,23 @@ template <> class vector_view<bool>
{ {
BOOST_ASSERT(index < m_size); BOOST_ASSERT(index < m_size);
const auto bucket = index / WORD_BITS; const auto bucket = index / WORD_BITS;
// Note: ordering of bits here should match packBits in storage/serialization.hpp
// so that directly mmap-ing data is possible
const auto offset = index % WORD_BITS; const auto offset = index % WORD_BITS;
BOOST_ASSERT(WORD_BITS > offset);
return reference{m_ptr + bucket, static_cast<Word>(1) << offset}; return reference{m_ptr + bucket, static_cast<Word>(1) << offset};
} }
template <typename T> friend void swap(vector_view<T> &, vector_view<T> &) noexcept; template <typename T> friend void swap(vector_view<T> &, vector_view<T> &) noexcept;
friend std::ostream &operator<<(std::ostream &os, const vector_view<bool> &rhs)
{
for (std::size_t i = 0; i < rhs.size(); ++i)
{
os << (i > 0 ? " " : "") << rhs.at(i);
}
return os;
}
}; };
// Both vector_view<T> and the vector_view<bool> specializations share this impl. // Both vector_view<T> and the vector_view<bool> specializations share this impl.
+6732 -2897
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -1,13 +1,13 @@
{ {
"name": "osrm", "name": "osrm",
"version": "5.19.0", "version": "5.21.0-customsnapping.8",
"private": false, "private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": { "dependencies": {
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"nan": "^2.6.2", "nan": "^2.11.1",
"node-cmake": "^2.3.2", "node-cmake": "^2.3.2",
"node-pre-gyp": "^0.6.36", "node-pre-gyp": "^0.12.0",
"rimraf": "^2.5.4" "rimraf": "^2.5.4"
}, },
"browserify": { "browserify": {
@@ -18,7 +18,7 @@
}, },
"scripts": { "scripts": {
"lint": "node ./node_modules/eslint/bin/eslint.js -c ./.eslintrc features/step_definitions/ features/support/", "lint": "node ./node_modules/eslint/bin/eslint.js -c ./.eslintrc features/step_definitions/ features/support/",
"test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld", "test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify -m mmap && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld -m mmap",
"clean": "rm -rf test/cache", "clean": "rm -rf test/cache",
"docs": "./scripts/build_api_docs.sh", "docs": "./scripts/build_api_docs.sh",
"install": "node-pre-gyp install --fallback-to-build=false || ./scripts/node_install.sh", "install": "node-pre-gyp install --fallback-to-build=false || ./scripts/node_install.sh",
@@ -47,14 +47,14 @@
"csv-stringify": "^3.0.0", "csv-stringify": "^3.0.0",
"cucumber": "^1.2.1", "cucumber": "^1.2.1",
"d3-queue": "^2.0.3", "d3-queue": "^2.0.3",
"docbox": "^1.0.6", "docbox": "^1.0.11",
"documentation": "^4.0.0-rc.1", "documentation": "^4.0.0-rc.1",
"eslint": "^2.4.0", "eslint": "^5.10.0",
"faucet": "^0.0.1", "faucet": "^0.0.1",
"jsonpath": "^1.0.0", "jsonpath": "^1.0.0",
"node-timeout": "0.0.4", "node-timeout": "0.0.4",
"polyline": "^0.2.0", "polyline": "^0.2.0",
"request": "^2.69.0", "request": "^2.88.0",
"tape": "^4.7.0", "tape": "^4.7.0",
"turf": "^3.0.14", "turf": "^3.0.14",
"xmlbuilder": "^4.2.1" "xmlbuilder": "^4.2.1"
+4 -17
View File
@@ -7,6 +7,7 @@ Sequence = require('lib/sequence')
Handlers = require("lib/way_handlers") Handlers = require("lib/way_handlers")
find_access_tag = require("lib/access").find_access_tag find_access_tag = require("lib/access").find_access_tag
limit = require("lib/maxspeed").limit limit = require("lib/maxspeed").limit
Measure = require("lib/measure")
function setup() function setup()
local default_speed = 15 local default_speed = 15
@@ -206,20 +207,6 @@ function setup()
} }
end end
local function parse_maxspeed(source)
if not source then
return 0
end
local n = tonumber(source:match("%d*"))
if not n then
n = 0
end
if string.match(source, "mph") or string.match(source, "mp/h") then
n = (n*1609)/1000
end
return n
end
function process_node(profile, node, result) function process_node(profile, node, result)
-- parse access and barrier tags -- parse access and barrier tags
local highway = node:get_value_by_key("highway") local highway = node:get_value_by_key("highway")
@@ -276,9 +263,9 @@ function handle_bicycle_tags(profile,way,result,data)
-- other tags -- other tags
data.junction = way:get_value_by_key("junction") data.junction = way:get_value_by_key("junction")
data.maxspeed = parse_maxspeed(way:get_value_by_key ( "maxspeed") ) data.maxspeed = Measure.get_max_speed(way:get_value_by_key ("maxspeed")) or 0
data.maxspeed_forward = parse_maxspeed(way:get_value_by_key( "maxspeed:forward")) data.maxspeed_forward = Measure.get_max_speed(way:get_value_by_key("maxspeed:forward")) or 0
data.maxspeed_backward = parse_maxspeed(way:get_value_by_key( "maxspeed:backward")) data.maxspeed_backward = Measure.get_max_speed(way:get_value_by_key("maxspeed:backward")) or 0
data.barrier = way:get_value_by_key("barrier") data.barrier = way:get_value_by_key("barrier")
data.oneway = way:get_value_by_key("oneway") data.oneway = way:get_value_by_key("oneway")
data.oneway_bicycle = way:get_value_by_key("oneway:bicycle") data.oneway_bicycle = way:get_value_by_key("oneway:bicycle")
+1
View File
@@ -269,6 +269,7 @@ function setup()
["at:rural"] = 100, ["at:rural"] = 100,
["at:trunk"] = 100, ["at:trunk"] = 100,
["be:motorway"] = 120, ["be:motorway"] = 120,
["be-vlg:rural"] = 70,
["by:urban"] = 60, ["by:urban"] = 60,
["by:motorway"] = 110, ["by:motorway"] = 110,
["ch:rural"] = 80, ["ch:rural"] = 80,
+19
View File
@@ -6,6 +6,18 @@ Measure = {}
local inch_to_meters = 0.0254 local inch_to_meters = 0.0254
local feet_to_inches = 12 local feet_to_inches = 12
local pound_to_kilograms = 0.45359237 local pound_to_kilograms = 0.45359237
local miles_to_kilometers = 1.609
-- Parse speed value as kilometers by hours.
function Measure.parse_value_speed(source)
local n = tonumber(source:match("%d*"))
if n then
if string.match(source, "mph") or string.match(source, "mp/h") then
n = n * miles_to_kilometers
end
return n
end
end
--- Parse string as a height in meters. --- Parse string as a height in meters.
--- according to http://wiki.openstreetmap.org/wiki/Key:maxheight --- according to http://wiki.openstreetmap.org/wiki/Key:maxheight
@@ -42,6 +54,13 @@ function Measure.parse_value_kilograms(value)
end end
end end
--- Get maxspeed of specified way in kilometers by hours.
function Measure.get_max_speed(raw_value)
if raw_value then
return Measure.parse_value_speed(raw_value)
end
end
-- default maxheight value defined in https://wiki.openstreetmap.org/wiki/Key:maxheight#Non-numerical_values -- default maxheight value defined in https://wiki.openstreetmap.org/wiki/Key:maxheight#Non-numerical_values
local default_maxheight = 4.5 local default_maxheight = 4.5
-- Available Non numerical values equal to 4.5; below_default and no_indications are not considered -- Available Non numerical values equal to 4.5; below_default and no_indications are not considered
+4 -7
View File
@@ -432,7 +432,7 @@ end
-- maxspeed and advisory maxspeed -- maxspeed and advisory maxspeed
function WayHandlers.maxspeed(profile,way,result,data) function WayHandlers.maxspeed(profile,way,result,data)
local keys = Sequence { 'maxspeed:advisory', 'maxspeed' } local keys = Sequence { 'maxspeed:advisory', 'maxspeed', 'source:maxspeed', 'maxspeed:type' }
local forward, backward = Tags.get_forward_backward_by_set(way,data,keys) local forward, backward = Tags.get_forward_backward_by_set(way,data,keys)
forward = WayHandlers.parse_maxspeed(forward,profile) forward = WayHandlers.parse_maxspeed(forward,profile)
backward = WayHandlers.parse_maxspeed(backward,profile) backward = WayHandlers.parse_maxspeed(backward,profile)
@@ -450,12 +450,9 @@ function WayHandlers.parse_maxspeed(source,profile)
if not source then if not source then
return 0 return 0
end end
local n = tonumber(source:match("%d*"))
if n then local n = Measure.get_max_speed(source)
if string.match(source, "mph") or string.match(source, "mp/h") then if not n then
n = (n*1609)/1000
end
else
-- parse maxspeed like FR:urban -- parse maxspeed like FR:urban
source = string.lower(source) source = string.lower(source)
n = profile.maxspeed_table[source] n = profile.maxspeed_table[source]
+6 -2
View File
@@ -6,8 +6,12 @@ var fs = require('fs');
var name = process.argv[2]; var name = process.argv[2];
var cmd = process.argv.slice(3).join(' '); var cmd = process.argv.slice(3).join(' ');
var start = Date.now(); var start = Date.now();
exec(cmd, (err) => { exec(cmd, (err, stdout, stderr) => {
if (err) return console.log(err); if (err) {
console.log(stdout);
console.log(stderr);
return process.exit(err.code);
}
var stop = +new Date(); var stop = +new Date();
var time = (stop - start) / 1000.; var time = (stop - start) / 1000.;
fs.appendFileSync('/tmp/osrm.timings', `${name}\t${time}`, 'utf-8'); fs.appendFileSync('/tmp/osrm.timings', `${name}\t${time}`, 'utf-8');
+4
View File
@@ -215,6 +215,7 @@ void ContractNode(ContractorThreadData *data,
target, target,
path_weight, path_weight,
in_data.duration + out_data.duration, in_data.duration + out_data.duration,
in_data.distance + out_data.distance,
out_data.originalEdges + in_data.originalEdges, out_data.originalEdges + in_data.originalEdges,
node, node,
SHORTCUT_ARC, SHORTCUT_ARC,
@@ -225,6 +226,7 @@ void ContractNode(ContractorThreadData *data,
source, source,
path_weight, path_weight,
in_data.duration + out_data.duration, in_data.duration + out_data.duration,
in_data.distance + out_data.distance,
out_data.originalEdges + in_data.originalEdges, out_data.originalEdges + in_data.originalEdges,
node, node,
SHORTCUT_ARC, SHORTCUT_ARC,
@@ -280,6 +282,7 @@ void ContractNode(ContractorThreadData *data,
target, target,
path_weight, path_weight,
in_data.duration + out_data.duration, in_data.duration + out_data.duration,
in_data.distance + out_data.distance,
out_data.originalEdges + in_data.originalEdges, out_data.originalEdges + in_data.originalEdges,
node, node,
SHORTCUT_ARC, SHORTCUT_ARC,
@@ -290,6 +293,7 @@ void ContractNode(ContractorThreadData *data,
source, source,
path_weight, path_weight,
in_data.duration + out_data.duration, in_data.duration + out_data.duration,
in_data.distance + out_data.distance,
out_data.originalEdges + in_data.originalEdges, out_data.originalEdges + in_data.originalEdges,
node, node,
SHORTCUT_ARC, SHORTCUT_ARC,
+10 -4
View File
@@ -76,6 +76,7 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
const partitioner::MultiLevelPartition &mlp, const partitioner::MultiLevelPartition &mlp,
std::vector<EdgeWeight> &node_weights, std::vector<EdgeWeight> &node_weights,
std::vector<EdgeDuration> &node_durations, std::vector<EdgeDuration> &node_durations,
std::vector<EdgeDistance> &node_distances,
std::uint32_t &connectivity_checksum) std::uint32_t &connectivity_checksum)
{ {
updater::Updater updater(config.updater_config); updater::Updater updater(config.updater_config);
@@ -84,6 +85,8 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
EdgeID num_nodes = updater.LoadAndUpdateEdgeExpandedGraph( EdgeID num_nodes = updater.LoadAndUpdateEdgeExpandedGraph(
edge_based_edge_list, node_weights, node_durations, connectivity_checksum); edge_based_edge_list, node_weights, node_durations, connectivity_checksum);
extractor::files::readEdgeBasedNodeDistances(config.GetPath(".osrm.enw"), node_distances);
auto directed = partitioner::splitBidirectionalEdges(edge_based_edge_list); auto directed = partitioner::splitBidirectionalEdges(edge_based_edge_list);
auto tidied = partitioner::prepareEdgesForUsageInGraph< auto tidied = partitioner::prepareEdgesForUsageInGraph<
@@ -124,10 +127,11 @@ int Customizer::Run(const CustomizationConfig &config)
partitioner::files::readPartition(config.GetPath(".osrm.partition"), mlp); partitioner::files::readPartition(config.GetPath(".osrm.partition"), mlp);
std::vector<EdgeWeight> node_weights; std::vector<EdgeWeight> node_weights;
std::vector<EdgeDuration> node_durations; // TODO: to be removed later std::vector<EdgeDuration> node_durations; // TODO: remove when durations are optional
std::vector<EdgeDistance> node_distances; // TODO: remove when distances are optional
std::uint32_t connectivity_checksum = 0; std::uint32_t connectivity_checksum = 0;
auto graph = LoadAndUpdateEdgeExpandedGraph( auto graph = LoadAndUpdateEdgeExpandedGraph(
config, mlp, node_weights, node_durations, connectivity_checksum); config, mlp, node_weights, node_durations, node_distances, connectivity_checksum);
BOOST_ASSERT(graph.GetNumberOfNodes() == node_weights.size()); BOOST_ASSERT(graph.GetNumberOfNodes() == node_weights.size());
std::for_each(node_weights.begin(), node_weights.end(), [](auto &w) { w &= 0x7fffffff; }); std::for_each(node_weights.begin(), node_weights.end(), [](auto &w) { w &= 0x7fffffff; });
util::Log() << "Loaded edge based graph: " << graph.GetNumberOfEdges() << " edges, " util::Log() << "Loaded edge based graph: " << graph.GetNumberOfEdges() << " edges, "
@@ -166,8 +170,10 @@ int Customizer::Run(const CustomizationConfig &config)
util::Log() << "MLD customization writing took " << TIMER_SEC(writing_mld_data) << " seconds"; util::Log() << "MLD customization writing took " << TIMER_SEC(writing_mld_data) << " seconds";
TIMER_START(writing_graph); TIMER_START(writing_graph);
MultiLevelEdgeBasedGraph shaved_graph{ MultiLevelEdgeBasedGraph shaved_graph{std::move(graph),
std::move(graph), std::move(node_weights), std::move(node_durations)}; std::move(node_weights),
std::move(node_durations),
std::move(node_distances)};
customizer::files::writeGraph( customizer::files::writeGraph(
config.GetPath(".osrm.mldgr"), shaved_graph, connectivity_checksum); config.GetPath(".osrm.mldgr"), shaved_graph, connectivity_checksum);
TIMER_STOP(writing_graph); TIMER_STOP(writing_graph);
+9 -4
View File
@@ -94,7 +94,7 @@ std::string waypointTypeToString(const guidance::WaypointType waypoint_type)
return waypoint_type_names[static_cast<std::size_t>(waypoint_type)]; return waypoint_type_names[static_cast<std::size_t>(waypoint_type)];
} }
util::json::Array coordinateToLonLat(const util::Coordinate coordinate) util::json::Array coordinateToLonLat(const util::Coordinate &coordinate)
{ {
util::json::Array array; util::json::Array array;
array.values.push_back(static_cast<double>(util::toFloating(coordinate.lon))); array.values.push_back(static_cast<double>(util::toFloating(coordinate.lon)));
@@ -240,17 +240,22 @@ util::json::Object makeRoute(const guidance::Route &route,
return json_route; return json_route;
} }
util::json::Object makeWaypoint(const util::Coordinate location, std::string name) util::json::Object
makeWaypoint(const util::Coordinate &location, const double &distance, std::string name)
{ {
util::json::Object waypoint; util::json::Object waypoint;
waypoint.values["location"] = detail::coordinateToLonLat(location); waypoint.values["location"] = detail::coordinateToLonLat(location);
waypoint.values["name"] = std::move(name); waypoint.values["name"] = std::move(name);
waypoint.values["distance"] = distance;
return waypoint; return waypoint;
} }
util::json::Object makeWaypoint(const util::Coordinate location, std::string name, const Hint &hint) util::json::Object makeWaypoint(const util::Coordinate &location,
const double &distance,
std::string name,
const Hint &hint)
{ {
auto waypoint = makeWaypoint(location, name); auto waypoint = makeWaypoint(location, distance, name);
waypoint.values["hint"] = hint.ToBase64(); waypoint.values["hint"] = hint.ToBase64();
return waypoint; return waypoint;
} }
+37 -32
View File
@@ -1,5 +1,6 @@
#include "engine/datafacade/mmap_memory_allocator.hpp" #include "engine/datafacade/mmap_memory_allocator.hpp"
#include "storage/block.hpp"
#include "storage/io.hpp" #include "storage/io.hpp"
#include "storage/serialization.hpp" #include "storage/serialization.hpp"
#include "storage/storage.hpp" #include "storage/storage.hpp"
@@ -7,7 +8,7 @@
#include "util/log.hpp" #include "util/log.hpp"
#include "util/mmap_file.hpp" #include "util/mmap_file.hpp"
#include "boost/assert.hpp" #include <boost/assert.hpp>
namespace osrm namespace osrm
{ {
@@ -16,46 +17,50 @@ namespace engine
namespace datafacade namespace datafacade
{ {
MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config, MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config)
const boost::filesystem::path &memory_file)
{ {
storage::Storage storage(config); storage::Storage storage(config);
std::vector<storage::SharedDataIndex::AllocatedRegion> allocated_regions;
if (!boost::filesystem::exists(memory_file))
{ {
storage::DataLayout initial_layout; std::unique_ptr<storage::BaseDataLayout> fake_layout =
storage.PopulateStaticLayout(initial_layout); std::make_unique<storage::TarDataLayout>();
storage.PopulateUpdatableLayout(initial_layout);
auto data_size = initial_layout.GetSizeOfLayout(); // Convert the boost::filesystem::path object into a plain string
// that's stored as a member of this allocator object
rtree_filename = storage.PopulateLayoutWithRTree(*fake_layout);
storage::io::BufferWriter writer; // Now, we add one more AllocatedRegion, with it's start address as the start
storage::serialization::write(writer, initial_layout); // of the rtree_filename string we've saved. In the fake_layout, we've
auto encoded_layout = writer.GetBuffer(); // stated that the data is at offset 0, which is where the string starts
// at it's own memory address.
auto total_size = data_size + encoded_layout.size(); // The syntax &(rtree_filename[0]) gets the memory address of the first char.
// We can't use the convenient `.data()` or `.c_str()` methods, because
mapped_memory = util::mmapFile<char>(memory_file, mapped_memory_file, total_size); // prior to C++17 (which we're not using), those return a `const char *`,
// which isn't compatible with the `char *` that AllocatedRegion expects
std::copy(encoded_layout.begin(), encoded_layout.end(), mapped_memory.data()); // for it's memory_ptr
allocated_regions.push_back({&(rtree_filename[0]), std::move(fake_layout)});
index = storage::SharedDataIndex(
{{mapped_memory.data() + encoded_layout.size(), std::move(initial_layout)}});
storage.PopulateStaticData(index);
storage.PopulateUpdatableData(index);
} }
else
auto files = storage.GetStaticFiles();
auto updatable_files = storage.GetUpdatableFiles();
files.insert(files.end(), updatable_files.begin(), updatable_files.end());
for (const auto &file : files)
{ {
mapped_memory = util::mmapFile<char>(memory_file, mapped_memory_file); if (boost::filesystem::exists(file.second))
{
storage::DataLayout layout; std::unique_ptr<storage::BaseDataLayout> layout =
storage::io::BufferReader reader(mapped_memory.data(), mapped_memory.size()); std::make_unique<storage::TarDataLayout>();
storage::serialization::read(reader, layout); boost::iostreams::mapped_file mapped_memory_file;
auto layout_size = reader.GetPosition(); util::mmapFile<char>(file.second, mapped_memory_file);
mapped_memory_files.push_back(std::move(mapped_memory_file));
index = storage::SharedDataIndex({{mapped_memory.data() + layout_size, std::move(layout)}}); storage::populateLayoutFromFile(file.second, *layout);
allocated_regions.push_back({mapped_memory_file.data(), std::move(layout)});
}
} }
index = storage::SharedDataIndex{std::move(allocated_regions)};
} }
MMapMemoryAllocator::~MMapMemoryAllocator() {} MMapMemoryAllocator::~MMapMemoryAllocator() {}
@@ -15,14 +15,20 @@ ProcessMemoryAllocator::ProcessMemoryAllocator(const storage::StorageConfig &con
storage::Storage storage(config); storage::Storage storage(config);
// Calculate the layout/size of the memory block // Calculate the layout/size of the memory block
storage::DataLayout layout; auto static_files = storage.GetStaticFiles();
storage.PopulateStaticLayout(layout); auto updatable_files = storage.GetUpdatableFiles();
storage.PopulateUpdatableLayout(layout); std::unique_ptr<storage::BaseDataLayout> layout =
std::make_unique<storage::ContiguousDataLayout>();
storage.PopulateLayoutWithRTree(*layout);
storage.PopulateLayout(*layout, static_files);
storage.PopulateLayout(*layout, updatable_files);
// Allocate the memory block, then load data from files into it // Allocate the memory block, then load data from files into it
internal_memory = std::make_unique<char[]>(layout.GetSizeOfLayout()); internal_memory = std::make_unique<char[]>(layout->GetSizeOfLayout());
index = storage::SharedDataIndex({{internal_memory.get(), std::move(layout)}}); std::vector<storage::SharedDataIndex::AllocatedRegion> regions;
regions.push_back({internal_memory.get(), std::move(layout)});
index = {std::move(regions)};
storage.PopulateStaticData(index); storage.PopulateStaticData(index);
storage.PopulateUpdatableData(index); storage.PopulateUpdatableData(index);
@@ -25,8 +25,9 @@ SharedMemoryAllocator::SharedMemoryAllocator(
auto mem = storage::makeSharedMemory(shm_key); auto mem = storage::makeSharedMemory(shm_key);
storage::io::BufferReader reader(reinterpret_cast<char *>(mem->Ptr()), mem->Size()); storage::io::BufferReader reader(reinterpret_cast<char *>(mem->Ptr()), mem->Size());
storage::DataLayout layout; std::unique_ptr<storage::BaseDataLayout> layout =
storage::serialization::read(reader, layout); std::make_unique<storage::ContiguousDataLayout>();
storage::serialization::read(reader, *layout);
auto layout_size = reader.GetPosition(); auto layout_size = reader.GetPosition();
regions.push_back({reinterpret_cast<char *>(mem->Ptr()) + layout_size, std::move(layout)}); regions.push_back({reinterpret_cast<char *>(mem->Ptr()) + layout_size, std::move(layout)});
+3 -1
View File
@@ -23,7 +23,9 @@ bool EngineConfig::IsValid() const
unlimited_or_more_than(max_results_nearest, 0) && unlimited_or_more_than(max_results_nearest, 0) &&
max_alternatives >= 0; max_alternatives >= 0;
return ((use_shared_memory && all_path_are_empty) || storage_config.IsValid()) && limits_valid; return ((use_shared_memory && all_path_are_empty) || (use_mmap && storage_config.IsValid()) ||
storage_config.IsValid()) &&
limits_valid;
} }
} }
} }
+2 -1
View File
@@ -213,7 +213,8 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
}); });
} }
auto candidates_lists = GetPhantomNodesInRange(facade, tidied.parameters, search_radiuses); auto candidates_lists =
GetPhantomNodesInRange(facade, tidied.parameters, search_radiuses, true);
filterCandidates(tidied.parameters.coordinates, candidates_lists); filterCandidates(tidied.parameters.coordinates, candidates_lists);
if (std::all_of(candidates_lists.begin(), if (std::all_of(candidates_lists.begin(),
+146 -2
View File
@@ -4,6 +4,7 @@
#include "engine/api/table_parameters.hpp" #include "engine/api/table_parameters.hpp"
#include "engine/routing_algorithms/many_to_many.hpp" #include "engine/routing_algorithms/many_to_many.hpp"
#include "engine/search_engine_data.hpp" #include "engine/search_engine_data.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/json_container.hpp" #include "util/json_container.hpp"
#include "util/string_util.hpp" #include "util/string_util.hpp"
@@ -85,8 +86,11 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance; bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration; bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
// Because of the Short Trip ETA adjustments below, we need distances every time
const bool distances_required = request_distance || params.waypoint_acceleration_factor > 0.;
auto result_tables_pair = algorithms.ManyToManySearch( auto result_tables_pair = algorithms.ManyToManySearch(
snapped_phantoms, params.sources, params.destinations, request_distance, request_duration); snapped_phantoms, params.sources, params.destinations, distances_required);
if ((request_duration && result_tables_pair.first.empty()) || if ((request_duration && result_tables_pair.first.empty()) ||
(request_distance && result_tables_pair.second.empty())) (request_distance && result_tables_pair.second.empty()))
@@ -94,8 +98,148 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("NoTable", "No table found", result); return Error("NoTable", "No table found", result);
} }
std::vector<api::TableAPI::TableCellRef> estimated_pairs;
// Adds some time to adjust for getting up to speed and slowing down to a stop
// Returns a new `duration`
auto adjust_for_startstop = [&](const double &acceleration_alpha,
const EdgeDuration &duration,
const EdgeDistance &distance) -> EdgeDuration {
// Very short paths can end up with 0 duration. That'll lead to a divide
// by zero, so instead, we'll assume the travel speed is 10m/s (36km/h).
// Typically, the distance is also short, so we're quibbling at tiny numbers
// here, but tiny numbers is what this adjustment lambda is all about,
// so we do try to be reasonable.
const auto average_speed =
duration == 0 ? 10 : distance /
(duration / 10.); // duration is in deciseconds, we need m/sec
// The following reference has a nice model (equations 9 through 12)
// for vehicle acceleration
// https://fdotwww.blob.core.windows.net/sitefinity/docs/default-source/content/rail/publications/studies/safety/accelerationresearch.pdf?sfvrsn=716a4bb1_0
// We solve euqation 10 for time to figure out how long it'll take
// to get up to the desired speed
// Because Equation 10 is asymptotic on v_des, we need to pick a target speed
// that's slighly less so the equation can actually get there. 1m/s less than
// target seems like a reasonable value to aim for
const auto target_speed = std::max(average_speed - 1, 0.1);
const auto initial_speed = 0.;
// Equation 9
const auto beta = acceleration_alpha / average_speed;
// Equation 10 solved for time
const auto time_to_full_speed = std::log( (average_speed - initial_speed) / (average_speed - target_speed) ) / beta;
BOOST_ASSERT(time_to_full_speed >= 0);
// Equation 11
const auto distance_to_full_speed =
average_speed * time_to_full_speed -
average_speed * (1 - std::exp(-1 * beta * time_to_full_speed)) / beta;
BOOST_ASSERT(distance_to_full_speed >= 0);
if (distance_to_full_speed > distance / 2)
{
// Because equation 12 requires velocity at halfway, and
// solving equation 11 for t requires a Lambert W function,
// we'll approximate here by assuming constant acceleration
// over distance_to_full_speed using s = ut + 1/2at^2
const auto average_acceleration =
2 * distance_to_full_speed / (time_to_full_speed * time_to_full_speed);
const auto time_to_halfway = std::sqrt(distance / average_acceleration);
BOOST_ASSERT(time_to_halfway >= 0);
return (2 * time_to_halfway) * 10; // result is in deciseconds
}
else
{
const auto cruising_distance = distance - 2 * distance_to_full_speed;
const auto cruising_time = cruising_distance / average_speed;
BOOST_ASSERT(cruising_time >= 0);
return (cruising_time + 2 * time_to_full_speed) * 10; // result is in deciseconds
}
};
// Scan table for null results - if any exist, replace with distance estimates
if (params.fallback_speed != INVALID_FALLBACK_SPEED || params.scale_factor != 1 ||
params.waypoint_acceleration_factor != 0.)
{
for (std::size_t row = 0; row < num_sources; row++)
{
for (std::size_t column = 0; column < num_destinations; column++)
{
const auto &table_index = row * num_destinations + column;
BOOST_ASSERT(table_index < result_tables_pair.first.size());
// apply an accel/deceleration penalty to the duration
if (result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION &&
row != column && params.waypoint_acceleration_factor != 0.)
{
result_tables_pair.first[table_index] =
adjust_for_startstop(params.waypoint_acceleration_factor,
result_tables_pair.first[table_index],
result_tables_pair.second[table_index]);
}
// Estimate null results based on fallback_speed (if valid) and distance
if (params.fallback_speed != INVALID_FALLBACK_SPEED && params.fallback_speed > 0 &&
result_tables_pair.first[table_index] == MAXIMAL_EDGE_DURATION)
{
const auto &source =
snapped_phantoms[params.sources.empty() ? row : params.sources[row]];
const auto &destination =
snapped_phantoms[params.destinations.empty() ? column
: params.destinations[column]];
auto distance_estimate =
params.fallback_coordinate_type ==
api::TableParameters::FallbackCoordinateType::Input
? util::coordinate_calculation::fccApproximateDistance(
source.input_location, destination.input_location)
: util::coordinate_calculation::fccApproximateDistance(
source.location, destination.location);
result_tables_pair.first[table_index] =
distance_estimate / (double)params.fallback_speed;
if (!result_tables_pair.second.empty())
{
result_tables_pair.second[table_index] = distance_estimate;
}
estimated_pairs.emplace_back(row, column);
}
// Apply a scale factor to non-null result if requested
if (params.scale_factor > 0 && params.scale_factor != 1 &&
result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION &&
result_tables_pair.first[table_index] != 0)
{
EdgeDuration diff =
MAXIMAL_EDGE_DURATION / result_tables_pair.first[table_index];
if (params.scale_factor >= diff)
{
result_tables_pair.first[table_index] = MAXIMAL_EDGE_DURATION - 1;
}
else
{
result_tables_pair.first[table_index] = std::lround(
result_tables_pair.first[table_index] * params.scale_factor);
}
}
}
}
}
// If distances weren't requested, delete them from the result so they don't
// get rendered.
if (!request_distance)
{
std::vector<EdgeDistance> empty;
result_tables_pair.second.swap(empty);
}
api::TableAPI table_api{facade, params}; api::TableAPI table_api{facade, params};
table_api.MakeResponse(result_tables_pair, snapped_phantoms, result); table_api.MakeResponse(result_tables_pair, snapped_phantoms, estimated_pairs, result);
return Status::Ok; return Status::Ok;
} }
+12 -1
View File
@@ -294,6 +294,7 @@ struct SpeedLayer : public vtzero::layer_builder
vtzero::index_value key_duration; vtzero::index_value key_duration;
vtzero::index_value key_name; vtzero::index_value key_name;
vtzero::index_value key_rate; vtzero::index_value key_rate;
vtzero::index_value key_is_startpoint;
SpeedLayer(vtzero::tile_builder &tile) SpeedLayer(vtzero::tile_builder &tile)
: layer_builder(tile, "speeds"), uint_index(*this), double_index(*this), : layer_builder(tile, "speeds"), uint_index(*this), double_index(*this),
@@ -302,7 +303,8 @@ struct SpeedLayer : public vtzero::layer_builder
key_datasource(add_key_without_dup_check("datasource")), key_datasource(add_key_without_dup_check("datasource")),
key_weight(add_key_without_dup_check("weight")), key_weight(add_key_without_dup_check("weight")),
key_duration(add_key_without_dup_check("duration")), key_duration(add_key_without_dup_check("duration")),
key_name(add_key_without_dup_check("name")), key_rate(add_key_without_dup_check("rate")) key_name(add_key_without_dup_check("name")), key_rate(add_key_without_dup_check("rate")),
key_is_startpoint(add_key_without_dup_check("is_startpoint"))
{ {
} }
@@ -349,6 +351,11 @@ class SpeedLayerFeatureBuilder : public vtzero::linestring_feature_builder
void set_rate(double value) { add_property(m_layer.key_rate, m_layer.double_index(value)); } void set_rate(double value) { add_property(m_layer.key_rate, m_layer.double_index(value)); }
void set_is_startpoint(bool value)
{
add_property(m_layer.key_is_startpoint, m_layer.bool_index(value));
}
}; // class SpeedLayerFeatureBuilder }; // class SpeedLayerFeatureBuilder
struct TurnsLayer : public vtzero::layer_builder struct TurnsLayer : public vtzero::layer_builder
@@ -485,6 +492,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
const auto reverse_datasource_idx = reverse_datasource_range( const auto reverse_datasource_idx = reverse_datasource_range(
reverse_datasource_range.size() - edge.fwd_segment_position - 1); reverse_datasource_range.size() - edge.fwd_segment_position - 1);
const auto is_startpoint = edge.is_startpoint;
const auto component_id = facade.GetComponentID(edge.forward_segment_id.id); const auto component_id = facade.GetComponentID(edge.forward_segment_id.id);
const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id); const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id);
auto name = facade.GetNameForID(name_id); auto name = facade.GetNameForID(name_id);
@@ -516,6 +525,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
fbuilder.set_duration(forward_duration / 10.0); fbuilder.set_duration(forward_duration / 10.0);
fbuilder.set_name(name); fbuilder.set_name(name);
fbuilder.set_rate(forward_rate / 10.0); fbuilder.set_rate(forward_rate / 10.0);
fbuilder.set_is_startpoint(is_startpoint);
fbuilder.commit(); fbuilder.commit();
} }
@@ -549,6 +559,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
fbuilder.set_duration(reverse_duration / 10.0); fbuilder.set_duration(reverse_duration / 10.0);
fbuilder.set_name(name); fbuilder.set_name(name);
fbuilder.set_rate(reverse_rate / 10.0); fbuilder.set_rate(reverse_rate / 10.0);
fbuilder.set_is_startpoint(is_startpoint);
fbuilder.commit(); fbuilder.commit();
} }
+1 -4
View File
@@ -217,10 +217,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
// compute the duration table of all phantom nodes // compute the duration table of all phantom nodes
auto result_duration_table = util::DistTableWrapper<EdgeWeight>( auto result_duration_table = util::DistTableWrapper<EdgeWeight>(
algorithms algorithms.ManyToManySearch(snapped_phantoms, {}, {}, /*requestDistance*/ false).first,
.ManyToManySearch(
snapped_phantoms, {}, {}, /*requestDistance*/ false, /*requestDuration*/ true)
.first,
number_of_locations); number_of_locations);
if (result_duration_table.size() == 0) if (result_duration_table.size() == 0)
@@ -90,7 +90,7 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
else else
{ {
// check whether there is a loop present at the node // check whether there is a loop present at the node
const auto loop_weight = getLoopWeight<false>(facade, node); const auto loop_weight = std::get<0>(getLoopWeight<false>(facade, node));
const EdgeWeight new_weight_with_loop = new_weight + loop_weight; const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
if (loop_weight != INVALID_EDGE_WEIGHT && if (loop_weight != INVALID_EDGE_WEIGHT &&
new_weight_with_loop <= *upper_bound_to_shortest_path_weight) new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
+35 -186
View File
@@ -21,18 +21,21 @@ namespace ch
inline bool addLoopWeight(const DataFacade<ch::Algorithm> &facade, inline bool addLoopWeight(const DataFacade<ch::Algorithm> &facade,
const NodeID node, const NodeID node,
EdgeWeight &weight, EdgeWeight &weight,
EdgeDuration &duration) EdgeDuration &duration,
EdgeDistance &distance)
{ // Special case for CH when contractor creates a loop edge node->node { // Special case for CH when contractor creates a loop edge node->node
BOOST_ASSERT(weight < 0); BOOST_ASSERT(weight < 0);
const auto loop_weight = ch::getLoopWeight<false>(facade, node); const auto loop_weight = ch::getLoopWeight<false>(facade, node);
if (loop_weight != INVALID_EDGE_WEIGHT) if (std::get<0>(loop_weight) != INVALID_EDGE_WEIGHT)
{ {
const auto new_weight_with_loop = weight + loop_weight; const auto new_weight_with_loop = weight + std::get<0>(loop_weight);
if (new_weight_with_loop >= 0) if (new_weight_with_loop >= 0)
{ {
weight = new_weight_with_loop; weight = new_weight_with_loop;
duration += ch::getLoopWeight<true>(facade, node); auto result = ch::getLoopWeight<true>(facade, node);
duration += std::get<0>(result);
distance += std::get<1>(result);
return true; return true;
} }
} }
@@ -46,6 +49,7 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
const NodeID node, const NodeID node,
const EdgeWeight weight, const EdgeWeight weight,
const EdgeDuration duration, const EdgeDuration duration,
const EdgeDistance distance,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap, typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
const PhantomNode &) const PhantomNode &)
{ {
@@ -63,21 +67,23 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
const auto edge_weight = data.weight; const auto edge_weight = data.weight;
const auto edge_duration = data.duration; const auto edge_duration = data.duration;
const auto edge_distance = data.distance;
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid"); BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
const auto to_weight = weight + edge_weight; const auto to_weight = weight + edge_weight;
const auto to_duration = duration + edge_duration; const auto to_duration = duration + edge_duration;
const auto to_distance = distance + edge_distance;
// New Node discovered -> Add to Heap + Node Info Storage // New Node discovered -> Add to Heap + Node Info Storage
if (!query_heap.WasInserted(to)) if (!query_heap.WasInserted(to))
{ {
query_heap.Insert(to, to_weight, {node, to_duration}); query_heap.Insert(to, to_weight, {node, to_duration, to_distance});
} }
// Found a shorter Path -> Update weight and set new parent // Found a shorter Path -> Update weight and set new parent
else if (std::tie(to_weight, to_duration) < else if (std::tie(to_weight, to_duration) <
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration)) std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
{ {
query_heap.GetData(to) = {node, to_duration}; query_heap.GetData(to) = {node, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight); query_heap.DecreaseKey(to, to_weight);
} }
} }
@@ -91,12 +97,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
const std::vector<NodeBucket> &search_space_with_buckets, const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<EdgeWeight> &weights_table, std::vector<EdgeWeight> &weights_table,
std::vector<EdgeDuration> &durations_table, std::vector<EdgeDuration> &durations_table,
std::vector<EdgeDistance> &distances_table,
std::vector<NodeID> &middle_nodes_table, std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node) const PhantomNode &phantom_node)
{ {
const auto node = query_heap.DeleteMin(); const auto node = query_heap.DeleteMin();
const auto source_weight = query_heap.GetKey(node); const auto source_weight = query_heap.GetKey(node);
const auto source_duration = query_heap.GetData(node).duration; const auto source_duration = query_heap.GetData(node).duration;
const auto source_distance = query_heap.GetData(node).distance;
// Check if each encountered node has an entry // Check if each encountered node has an entry
const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(), const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(),
@@ -109,33 +117,44 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto column_index = current_bucket.column_index; const auto column_index = current_bucket.column_index;
const auto target_weight = current_bucket.weight; const auto target_weight = current_bucket.weight;
const auto target_duration = current_bucket.duration; const auto target_duration = current_bucket.duration;
const auto target_distance = current_bucket.distance;
auto &current_weight = weights_table[row_index * number_of_targets + column_index]; auto &current_weight = weights_table[row_index * number_of_targets + column_index];
EdgeDistance nulldistance = 0;
auto &current_duration = durations_table[row_index * number_of_targets + column_index]; auto &current_duration = durations_table[row_index * number_of_targets + column_index];
auto &current_distance =
distances_table.empty() ? nulldistance
: distances_table[row_index * number_of_targets + column_index];
// Check if new weight is better // Check if new weight is better
auto new_weight = source_weight + target_weight; auto new_weight = source_weight + target_weight;
auto new_duration = source_duration + target_duration; auto new_duration = source_duration + target_duration;
auto new_distance = source_distance + target_distance;
if (new_weight < 0) if (new_weight < 0)
{ {
if (addLoopWeight(facade, node, new_weight, new_duration)) if (addLoopWeight(facade, node, new_weight, new_duration, new_distance))
{ {
current_weight = std::min(current_weight, new_weight); current_weight = std::min(current_weight, new_weight);
current_duration = std::min(current_duration, new_duration); current_duration = std::min(current_duration, new_duration);
current_distance = std::min(current_distance, new_distance);
middle_nodes_table[row_index * number_of_targets + column_index] = node; middle_nodes_table[row_index * number_of_targets + column_index] = node;
} }
} }
else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration)) else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration) &&
new_distance >= 0)
{ {
current_weight = new_weight; current_weight = new_weight;
current_duration = new_duration; current_duration = new_duration;
current_distance = new_distance;
middle_nodes_table[row_index * number_of_targets + column_index] = node; middle_nodes_table[row_index * number_of_targets + column_index] = node;
} }
} }
relaxOutgoingEdges<FORWARD_DIRECTION>( relaxOutgoingEdges<FORWARD_DIRECTION>(
facade, node, source_weight, source_duration, query_heap, phantom_node); facade, node, source_weight, source_duration, source_distance, query_heap, phantom_node);
} }
void backwardRoutingStep(const DataFacade<Algorithm> &facade, void backwardRoutingStep(const DataFacade<Algorithm> &facade,
@@ -147,172 +166,19 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto node = query_heap.DeleteMin(); const auto node = query_heap.DeleteMin();
const auto target_weight = query_heap.GetKey(node); const auto target_weight = query_heap.GetKey(node);
const auto target_duration = query_heap.GetData(node).duration; const auto target_duration = query_heap.GetData(node).duration;
const auto target_distance = query_heap.GetData(node).distance;
const auto parent = query_heap.GetData(node).parent; const auto parent = query_heap.GetData(node).parent;
// Store settled nodes in search space bucket // Store settled nodes in search space bucket
search_space_with_buckets.emplace_back( search_space_with_buckets.emplace_back(
node, parent, column_index, target_weight, target_duration); node, parent, column_index, target_weight, target_duration, target_distance);
relaxOutgoingEdges<REVERSE_DIRECTION>( relaxOutgoingEdges<REVERSE_DIRECTION>(
facade, node, target_weight, target_duration, query_heap, phantom_node); facade, node, target_weight, target_duration, target_distance, query_heap, phantom_node);
} }
} // namespace ch } // namespace ch
void retrievePackedPathFromSearchSpace(const NodeID middle_node_id,
const unsigned column_index,
const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<NodeID> &packed_leg)
{
auto bucket_list = std::equal_range(search_space_with_buckets.begin(),
search_space_with_buckets.end(),
middle_node_id,
NodeBucket::ColumnCompare(column_index));
NodeID current_node_id = middle_node_id;
BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1,
"The pointers are not pointing to the same element.");
while (bucket_list.first->parent_node != current_node_id &&
bucket_list.first != search_space_with_buckets.end())
{
current_node_id = bucket_list.first->parent_node;
packed_leg.emplace_back(current_node_id);
bucket_list = std::equal_range(search_space_with_buckets.begin(),
search_space_with_buckets.end(),
current_node_id,
NodeBucket::ColumnCompare(column_index));
}
}
void calculateDistances(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &query_heap,
const DataFacade<ch::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &target_indices,
const std::size_t row_index,
const std::size_t source_index,
const PhantomNode &source_phantom,
const std::size_t number_of_targets,
const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<EdgeDistance> &distances_table,
const std::vector<NodeID> &middle_nodes_table)
{
std::vector<NodeID> packed_leg;
for (auto column_index : util::irange<std::size_t>(0, number_of_targets))
{
const auto target_index = target_indices[column_index];
const auto &target_phantom = phantom_nodes[target_index];
if (source_index == target_index)
{
distances_table[row_index * number_of_targets + column_index] = 0.0;
continue;
}
NodeID middle_node_id = middle_nodes_table[row_index * number_of_targets + column_index];
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
{
distances_table[row_index * number_of_targets + column_index] = INVALID_EDGE_DISTANCE;
continue;
}
// Step 1: Find path from source to middle node
ch::retrievePackedPathFromSingleManyToManyHeap(query_heap, middle_node_id, packed_leg);
std::reverse(packed_leg.begin(), packed_leg.end());
packed_leg.push_back(middle_node_id);
// Step 2: Find path from middle to target node
retrievePackedPathFromSearchSpace(
middle_node_id, column_index, search_space_with_buckets, packed_leg);
if (packed_leg.size() == 1 && (needsLoopForward(source_phantom, target_phantom) ||
needsLoopBackwards(source_phantom, target_phantom)))
{
auto weight = ch::getLoopWeight<false>(facade, packed_leg.front());
if (weight != INVALID_EDGE_WEIGHT)
packed_leg.push_back(packed_leg.front());
}
if (!packed_leg.empty())
{
auto annotation =
ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end());
distances_table[row_index * number_of_targets + column_index] = annotation;
// check the direction of travel to figure out how to calculate the offset to/from
// the source/target
if (source_phantom.forward_segment_id.id == packed_leg.front())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// -->s <-- subtract offset to start at source
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset = source_phantom.GetForwardDistance();
distances_table[row_index * number_of_targets + column_index] -= offset;
}
else if (source_phantom.reverse_segment_id.id == packed_leg.front())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// s<------- <-- subtract offset to start at source
// ... <-- want this distance
// entry 0---1---2---3 <-- 3 is exit node
EdgeDistance offset = source_phantom.GetReverseDistance();
distances_table[row_index * number_of_targets + column_index] -= offset;
}
if (target_phantom.forward_segment_id.id == packed_leg.back())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// ++>t <-- add offset to get to target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset = target_phantom.GetForwardDistance();
distances_table[row_index * number_of_targets + column_index] += offset;
}
else if (target_phantom.reverse_segment_id.id == packed_leg.back())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// <++t <-- add offset to get from target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset = target_phantom.GetReverseDistance();
distances_table[row_index * number_of_targets + column_index] += offset;
}
}
else
{
// there is no shortcut to unpack. source and target are on the same EBG Node.
// if the offset of the target is greater than the offset of the source, subtract it
if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance())
{
// --------->t <-- offsets
// ->s <-- subtract source offset from target offset
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset =
target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance();
distances_table[row_index * number_of_targets + column_index] = offset;
}
else
{
// s<--- <-- offsets
// t<--------- <-- subtract source offset from target offset
// ...... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
EdgeDistance offset =
target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance();
distances_table[row_index * number_of_targets + column_index] = offset;
}
}
packed_leg.clear();
}
}
template <> template <>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data, manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
@@ -320,18 +186,16 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance, const bool calculate_distance)
const bool calculate_duration)
{ {
(void)calculate_duration; // TODO: stub to use when computing durations become optional
const auto number_of_sources = source_indices.size(); const auto number_of_sources = source_indices.size();
const auto number_of_targets = target_indices.size(); const auto number_of_targets = target_indices.size();
const auto number_of_entries = number_of_sources * number_of_targets; const auto number_of_entries = number_of_sources * number_of_targets;
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT); std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION); std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table; std::vector<EdgeDistance> distances_table(calculate_distance ? number_of_entries : 0,
MAXIMAL_EDGE_DISTANCE);
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID); std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
std::vector<NodeBucket> search_space_with_buckets; std::vector<NodeBucket> search_space_with_buckets;
@@ -380,25 +244,10 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
search_space_with_buckets, search_space_with_buckets,
weights_table, weights_table,
durations_table, durations_table,
distances_table,
middle_nodes_table, middle_nodes_table,
source_phantom); source_phantom);
} }
if (calculate_distance)
{
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
calculateDistances(query_heap,
facade,
phantom_nodes,
target_indices,
row_index,
source_index,
source_phantom,
number_of_targets,
search_space_with_buckets,
distances_table,
middle_nodes_table);
}
} }
return std::make_pair(durations_table, distances_table); return std::make_pair(durations_table, distances_table);
+114 -374
View File
@@ -41,6 +41,7 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
const NodeID node, const NodeID node,
const EdgeWeight weight, const EdgeWeight weight,
const EdgeDuration duration, const EdgeDuration duration,
const EdgeDistance distance,
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap, typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
Args... args) Args... args)
{ {
@@ -65,65 +66,77 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
{ // Shortcuts in forward direction { // Shortcuts in forward direction
auto destination = cell.GetDestinationNodes().begin(); auto destination = cell.GetDestinationNodes().begin();
auto shortcut_durations = cell.GetOutDuration(node); auto shortcut_durations = cell.GetOutDuration(node);
auto shortcut_distances = cell.GetOutDistance(node);
for (auto shortcut_weight : cell.GetOutWeight(node)) for (auto shortcut_weight : cell.GetOutWeight(node))
{ {
BOOST_ASSERT(destination != cell.GetDestinationNodes().end()); BOOST_ASSERT(destination != cell.GetDestinationNodes().end());
BOOST_ASSERT(!shortcut_durations.empty()); BOOST_ASSERT(!shortcut_durations.empty());
BOOST_ASSERT(!shortcut_distances.empty());
const NodeID to = *destination; const NodeID to = *destination;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to) if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
{ {
const auto to_weight = weight + shortcut_weight; const auto to_weight = weight + shortcut_weight;
const auto to_duration = duration + shortcut_durations.front(); const auto to_duration = duration + shortcut_durations.front();
const auto to_distance = distance + shortcut_distances.front();
if (!query_heap.WasInserted(to)) if (!query_heap.WasInserted(to))
{ {
query_heap.Insert(to, to_weight, {node, true, to_duration}); query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance});
} }
else if (std::tie(to_weight, to_duration, node) < else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to), std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration, query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent)) query_heap.GetData(to).parent))
{ {
query_heap.GetData(to) = {node, true, to_duration}; query_heap.GetData(to) = {node, true, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight); query_heap.DecreaseKey(to, to_weight);
} }
} }
++destination; ++destination;
shortcut_durations.advance_begin(1); shortcut_durations.advance_begin(1);
shortcut_distances.advance_begin(1);
} }
BOOST_ASSERT(shortcut_durations.empty()); BOOST_ASSERT(shortcut_durations.empty());
BOOST_ASSERT(shortcut_distances.empty());
} }
else else
{ // Shortcuts in backward direction { // Shortcuts in backward direction
auto source = cell.GetSourceNodes().begin(); auto source = cell.GetSourceNodes().begin();
auto shortcut_durations = cell.GetInDuration(node); auto shortcut_durations = cell.GetInDuration(node);
auto shortcut_distances = cell.GetInDistance(node);
for (auto shortcut_weight : cell.GetInWeight(node)) for (auto shortcut_weight : cell.GetInWeight(node))
{ {
BOOST_ASSERT(source != cell.GetSourceNodes().end()); BOOST_ASSERT(source != cell.GetSourceNodes().end());
BOOST_ASSERT(!shortcut_durations.empty()); BOOST_ASSERT(!shortcut_durations.empty());
BOOST_ASSERT(!shortcut_distances.empty());
const NodeID to = *source; const NodeID to = *source;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to) if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
{ {
const auto to_weight = weight + shortcut_weight; const auto to_weight = weight + shortcut_weight;
const auto to_duration = duration + shortcut_durations.front(); const auto to_duration = duration + shortcut_durations.front();
const auto to_distance = distance + shortcut_distances.front();
if (!query_heap.WasInserted(to)) if (!query_heap.WasInserted(to))
{ {
query_heap.Insert(to, to_weight, {node, true, to_duration}); query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance});
} }
else if (std::tie(to_weight, to_duration, node) < else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to), std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration, query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent)) query_heap.GetData(to).parent))
{ {
query_heap.GetData(to) = {node, true, to_duration}; query_heap.GetData(to) = {node, true, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight); query_heap.DecreaseKey(to, to_weight);
} }
} }
++source; ++source;
shortcut_durations.advance_begin(1); shortcut_durations.advance_begin(1);
shortcut_distances.advance_begin(1);
} }
BOOST_ASSERT(shortcut_durations.empty()); BOOST_ASSERT(shortcut_durations.empty());
BOOST_ASSERT(shortcut_distances.empty());
} }
} }
@@ -143,25 +156,28 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge); const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge);
const auto node_weight = facade.GetNodeWeight(node_id); const auto node_weight = facade.GetNodeWeight(node_id);
const auto node_duration = facade.GetNodeDuration(node_id); const auto node_duration = facade.GetNodeDuration(node_id);
const auto node_distance = facade.GetNodeDistance(node_id);
const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id); const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id);
const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id); const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id);
BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid"); BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid");
const auto to_weight = weight + turn_weight; const auto to_weight = weight + turn_weight;
const auto to_duration = duration + turn_duration; const auto to_duration = duration + turn_duration;
const auto to_distance = distance + node_distance;
// New Node discovered -> Add to Heap + Node Info Storage // New Node discovered -> Add to Heap + Node Info Storage
if (!query_heap.WasInserted(to)) if (!query_heap.WasInserted(to))
{ {
query_heap.Insert(to, to_weight, {node, false, to_duration}); query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance});
} }
// Found a shorter Path -> Update weight and set new parent // Found a shorter Path -> Update weight and set new parent
else if (std::tie(to_weight, to_duration, node) < else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to), std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration, query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent)) query_heap.GetData(to).parent))
{ {
query_heap.GetData(to) = {node, false, to_duration}; query_heap.GetData(to) = {node, false, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight); query_heap.DecreaseKey(to, to_weight);
} }
} }
@@ -182,11 +198,12 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{ {
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT); std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION); std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table; std::vector<EdgeDistance> distances_table(calculate_distance ? phantom_indices.size() : 0,
MAXIMAL_EDGE_DISTANCE);
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID); std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID);
// Collect destination (source) nodes into a map // Collect destination (source) nodes into a map
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration>> std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>>
target_nodes_index; target_nodes_index;
target_nodes_index.reserve(phantom_indices.size()); target_nodes_index.reserve(phantom_indices.size());
for (std::size_t index = 0; index < phantom_indices.size(); ++index) for (std::size_t index = 0; index < phantom_indices.size(); ++index)
@@ -201,13 +218,15 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{phantom_node.forward_segment_id.id, {phantom_node.forward_segment_id.id,
std::make_tuple(index, std::make_tuple(index,
phantom_node.GetForwardWeightPlusOffset(), phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration())}); phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseTarget()) if (phantom_node.IsValidReverseTarget())
target_nodes_index.insert( target_nodes_index.insert(
{phantom_node.reverse_segment_id.id, {phantom_node.reverse_segment_id.id,
std::make_tuple(index, std::make_tuple(index,
phantom_node.GetReverseWeightPlusOffset(), phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration())}); phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance())});
} }
else if (DIRECTION == REVERSE_DIRECTION) else if (DIRECTION == REVERSE_DIRECTION)
{ {
@@ -216,13 +235,15 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{phantom_node.forward_segment_id.id, {phantom_node.forward_segment_id.id,
std::make_tuple(index, std::make_tuple(index,
-phantom_node.GetForwardWeightPlusOffset(), -phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration())}); -phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseSource()) if (phantom_node.IsValidReverseSource())
target_nodes_index.insert( target_nodes_index.insert(
{phantom_node.reverse_segment_id.id, {phantom_node.reverse_segment_id.id,
std::make_tuple(index, std::make_tuple(index,
-phantom_node.GetReverseWeightPlusOffset(), -phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration())}); -phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance())});
} }
} }
@@ -232,44 +253,55 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
auto &query_heap = *(engine_working_data.many_to_many_heap); auto &query_heap = *(engine_working_data.many_to_many_heap);
// Check if node is in the destinations list and update weights/durations // Check if node is in the destinations list and update weights/durations
auto update_values = [&](NodeID node, EdgeWeight weight, EdgeDuration duration) { auto update_values =
auto candidates = target_nodes_index.equal_range(node); [&](NodeID node, EdgeWeight weight, EdgeDuration duration, EdgeDistance distance) {
for (auto it = candidates.first; it != candidates.second;) auto candidates = target_nodes_index.equal_range(node);
{ for (auto it = candidates.first; it != candidates.second;)
std::size_t index;
EdgeWeight target_weight;
EdgeDuration target_duration;
std::tie(index, target_weight, target_duration) = it->second;
const auto path_weight = weight + target_weight;
if (path_weight >= 0)
{ {
const auto path_duration = duration + target_duration; std::size_t index;
EdgeWeight target_weight;
EdgeDuration target_duration;
EdgeDistance target_distance;
std::tie(index, target_weight, target_duration, target_distance) = it->second;
if (std::tie(path_weight, path_duration) < const auto path_weight = weight + target_weight;
std::tie(weights[index], durations[index])) if (path_weight >= 0)
{ {
weights[index] = path_weight; const auto path_duration = duration + target_duration;
durations[index] = path_duration; const auto path_distance = distance + target_distance;
middle_nodes_table[index] = node;
EdgeDistance nulldistance = 0;
auto &current_distance =
distances_table.empty() ? nulldistance : distances_table[index];
if (std::tie(path_weight, path_duration, path_distance) <
std::tie(weights[index], durations[index], current_distance))
{
weights[index] = path_weight;
durations[index] = path_duration;
current_distance = path_distance;
middle_nodes_table[index] = node;
}
// Remove node from destinations list
it = target_nodes_index.erase(it);
}
else
{
++it;
} }
// Remove node from destinations list
it = target_nodes_index.erase(it);
} }
else };
{
++it;
}
}
};
auto insert_node = [&](NodeID node, EdgeWeight initial_weight, EdgeDuration initial_duration) { auto insert_node = [&](NodeID node,
EdgeWeight initial_weight,
EdgeDuration initial_duration,
EdgeDistance initial_distance) {
// Update single node paths // Update single node paths
update_values(node, initial_weight, initial_duration); update_values(node, initial_weight, initial_duration, initial_distance);
query_heap.Insert(node, initial_weight, {node, initial_duration}); query_heap.Insert(node, initial_weight, {node, initial_duration, initial_distance});
// Place adjacent nodes into heap // Place adjacent nodes into heap
for (auto edge : facade.GetAdjacentEdgeRange(node)) for (auto edge : facade.GetAdjacentEdgeRange(node))
@@ -292,8 +324,9 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
facade.GetWeightPenaltyForEdgeID(turn_id); facade.GetWeightPenaltyForEdgeID(turn_id);
const auto edge_duration = initial_duration + facade.GetNodeDuration(node_id) + const auto edge_duration = initial_duration + facade.GetNodeDuration(node_id) +
facade.GetDurationPenaltyForEdgeID(turn_id); facade.GetDurationPenaltyForEdgeID(turn_id);
const auto edge_distance = initial_distance + facade.GetNodeDistance(node_id);
query_heap.Insert(to, edge_weight, {node, edge_duration}); query_heap.Insert(to, edge_weight, {node, edge_duration, edge_distance});
} }
} }
}; };
@@ -307,14 +340,16 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{ {
insert_node(phantom_node.forward_segment_id.id, insert_node(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(), -phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration()); -phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance());
} }
if (phantom_node.IsValidReverseSource()) if (phantom_node.IsValidReverseSource())
{ {
insert_node(phantom_node.reverse_segment_id.id, insert_node(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(), -phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration()); -phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance());
} }
} }
else if (DIRECTION == REVERSE_DIRECTION) else if (DIRECTION == REVERSE_DIRECTION)
@@ -323,14 +358,16 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{ {
insert_node(phantom_node.forward_segment_id.id, insert_node(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(), phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration()); phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance());
} }
if (phantom_node.IsValidReverseTarget()) if (phantom_node.IsValidReverseTarget())
{ {
insert_node(phantom_node.reverse_segment_id.id, insert_node(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(), phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration()); phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance());
} }
} }
} }
@@ -341,141 +378,23 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const auto node = query_heap.DeleteMin(); const auto node = query_heap.DeleteMin();
const auto weight = query_heap.GetKey(node); const auto weight = query_heap.GetKey(node);
const auto duration = query_heap.GetData(node).duration; const auto duration = query_heap.GetData(node).duration;
const auto distance = query_heap.GetData(node).distance;
// Update values // Update values
update_values(node, weight, duration); update_values(node, weight, duration, distance);
// Relax outgoing edges // Relax outgoing edges
relaxOutgoingEdges<DIRECTION>(facade, relaxOutgoingEdges<DIRECTION>(facade,
node, node,
weight, weight,
duration, duration,
distance,
query_heap, query_heap,
phantom_nodes, phantom_nodes,
phantom_index, phantom_index,
phantom_indices); phantom_indices);
} }
if (calculate_distance)
{
// Initialize unpacking heaps
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
distances_table.resize(phantom_indices.size(), INVALID_EDGE_DISTANCE);
for (unsigned location = 0; location < phantom_indices.size(); ++location)
{
// Get the "middle" node that is the last node of a path
const NodeID middle_node_id = middle_nodes_table[location];
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
{
continue;
}
// Retrieve the packed path from the heap
PackedPath packed_path = mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(
query_heap, middle_node_id);
// ... and reverse it to have packed edges in the correct order,
if (DIRECTION == FORWARD_DIRECTION)
{
std::reverse(packed_path.begin(), packed_path.end());
}
// ... unpack path
auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1;
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> unpacked_nodes;
std::vector<EdgeID> unpacked_edges;
std::tie(weight, unpacked_nodes, unpacked_edges) =
unpackPathAndCalculateDistance(engine_working_data,
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
INVALID_EDGE_WEIGHT,
packed_path,
middle_node_id,
phantom_nodes,
phantom_index,
phantom_indices);
// Accumulate the path length without the last node
auto annotation = 0.0;
BOOST_ASSERT(!unpacked_nodes.empty());
for (auto node = unpacked_nodes.begin(), last_node = std::prev(unpacked_nodes.end());
node != last_node;
++node)
{
annotation += computeEdgeDistance(facade, *node);
}
// ... and add negative source and positive target offsets
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
// Get source and target phantom nodes
// * 1-to-N: source is a single index, target is the corresponding from the indices list
// * N-to-1: source is the corresponding from the indices list, target is a single index
auto source_phantom_index = phantom_index;
auto target_phantom_index = phantom_indices[location];
if (DIRECTION == REVERSE_DIRECTION)
{
std::swap(source_phantom_index, target_phantom_index);
}
const auto &source_phantom = phantom_nodes[source_phantom_index];
const auto &target_phantom = phantom_nodes[target_phantom_index];
const NodeID source_node = unpacked_nodes.front();
const NodeID target_node = unpacked_nodes.back();
EdgeDistance source_offset = 0., target_offset = 0.;
if (source_phantom.IsValidForwardSource() &&
source_phantom.forward_segment_id.id == source_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// -->s <-- subtract offset to start at source
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
source_offset = source_phantom.GetForwardDistance();
}
else if (source_phantom.IsValidReverseSource() &&
source_phantom.reverse_segment_id.id == source_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// s<------- <-- subtract offset to start at source
// ... <-- want this distance
// entry 0---1---2---3 <-- 3 is exit node
source_offset = source_phantom.GetReverseDistance();
}
if (target_phantom.IsValidForwardTarget() &&
target_phantom.forward_segment_id.id == target_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// ++>t <-- add offset to get to target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
target_offset = target_phantom.GetForwardDistance();
}
else if (target_phantom.IsValidReverseTarget() &&
target_phantom.reverse_segment_id.id == target_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// <++t <-- add offset to get from target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
target_offset = target_phantom.GetReverseDistance();
}
distances_table[location] = -source_offset + annotation + target_offset;
}
}
return std::make_pair(durations, distances_table); return std::make_pair(durations, distances_table);
} }
@@ -491,12 +410,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
const std::vector<NodeBucket> &search_space_with_buckets, const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<EdgeWeight> &weights_table, std::vector<EdgeWeight> &weights_table,
std::vector<EdgeDuration> &durations_table, std::vector<EdgeDuration> &durations_table,
std::vector<EdgeDistance> &distances_table,
std::vector<NodeID> &middle_nodes_table, std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node) const PhantomNode &phantom_node)
{ {
const auto node = query_heap.DeleteMin(); const auto node = query_heap.DeleteMin();
const auto source_weight = query_heap.GetKey(node); const auto source_weight = query_heap.GetKey(node);
const auto source_duration = query_heap.GetData(node).duration; const auto source_duration = query_heap.GetData(node).duration;
const auto source_distance = query_heap.GetData(node).distance;
// Check if each encountered node has an entry // Check if each encountered node has an entry
const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(), const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(),
@@ -509,6 +430,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto column_idx = current_bucket.column_index; const auto column_idx = current_bucket.column_index;
const auto target_weight = current_bucket.weight; const auto target_weight = current_bucket.weight;
const auto target_duration = current_bucket.duration; const auto target_duration = current_bucket.duration;
const auto target_distance = current_bucket.distance;
// Get the value location in the results tables: // Get the value location in the results tables:
// * row-major direct (row_idx, column_idx) index for forward direction // * row-major direct (row_idx, column_idx) index for forward direction
@@ -519,21 +441,27 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
auto &current_weight = weights_table[location]; auto &current_weight = weights_table[location];
auto &current_duration = durations_table[location]; auto &current_duration = durations_table[location];
EdgeDistance nulldistance = 0;
auto &current_distance = distances_table.empty() ? nulldistance : distances_table[location];
// Check if new weight is better // Check if new weight is better
auto new_weight = source_weight + target_weight; auto new_weight = source_weight + target_weight;
auto new_duration = source_duration + target_duration; auto new_duration = source_duration + target_duration;
auto new_distance = source_distance + target_distance;
if (new_weight >= 0 && if (new_weight >= 0 &&
std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration)) std::tie(new_weight, new_duration, new_distance) <
std::tie(current_weight, current_duration, current_distance))
{ {
current_weight = new_weight; current_weight = new_weight;
current_duration = new_duration; current_duration = new_duration;
current_distance = new_distance;
middle_nodes_table[location] = node; middle_nodes_table[location] = node;
} }
} }
relaxOutgoingEdges<DIRECTION>( relaxOutgoingEdges<DIRECTION>(
facade, node, source_weight, source_duration, query_heap, phantom_node); facade, node, source_weight, source_duration, source_distance, query_heap, phantom_node);
} }
template <bool DIRECTION> template <bool DIRECTION>
@@ -546,18 +474,25 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto node = query_heap.DeleteMin(); const auto node = query_heap.DeleteMin();
const auto target_weight = query_heap.GetKey(node); const auto target_weight = query_heap.GetKey(node);
const auto target_duration = query_heap.GetData(node).duration; const auto target_duration = query_heap.GetData(node).duration;
const auto target_distance = query_heap.GetData(node).distance;
const auto parent = query_heap.GetData(node).parent; const auto parent = query_heap.GetData(node).parent;
const auto from_clique_arc = query_heap.GetData(node).from_clique_arc; const auto from_clique_arc = query_heap.GetData(node).from_clique_arc;
// Store settled nodes in search space bucket // Store settled nodes in search space bucket
search_space_with_buckets.emplace_back( search_space_with_buckets.emplace_back(
node, parent, from_clique_arc, column_idx, target_weight, target_duration); node, parent, from_clique_arc, column_idx, target_weight, target_duration, target_distance);
const auto &partition = facade.GetMultiLevelPartition(); const auto &partition = facade.GetMultiLevelPartition();
const auto maximal_level = partition.GetNumberOfLevels() - 1; const auto maximal_level = partition.GetNumberOfLevels() - 1;
relaxOutgoingEdges<!DIRECTION>( relaxOutgoingEdges<!DIRECTION>(facade,
facade, node, target_weight, target_duration, query_heap, phantom_node, maximal_level); node,
target_weight,
target_duration,
target_distance,
query_heap,
phantom_node,
maximal_level);
} }
template <bool DIRECTION> template <bool DIRECTION>
@@ -596,182 +531,6 @@ void retrievePackedPathFromSearchSpace(NodeID middle_node_id,
} }
} }
template <bool DIRECTION>
void calculateDistances(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
const DataFacade<mld::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &target_indices,
const unsigned row_idx,
const std::size_t source_index,
const unsigned number_of_sources,
const unsigned number_of_targets,
const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<EdgeDistance> &distances_table,
const std::vector<NodeID> &middle_nodes_table,
SearchEngineData<mld::Algorithm> &engine_working_data)
{
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
facade.GetMaxBorderNodeID() + 1);
for (unsigned column_idx = 0; column_idx < number_of_targets; ++column_idx)
{
// Step 1: Get source and target phantom nodes that were used in the bucketed search
auto source_phantom_index = source_index;
auto target_phantom_index = target_indices[column_idx];
const auto &source_phantom = phantom_nodes[source_phantom_index];
const auto &target_phantom = phantom_nodes[target_phantom_index];
const auto location = DIRECTION == FORWARD_DIRECTION
? row_idx * number_of_targets + column_idx
: row_idx + column_idx * number_of_sources;
if (source_phantom_index == target_phantom_index)
{
distances_table[location] = 0.0;
continue;
}
NodeID middle_node_id = middle_nodes_table[location];
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
{
distances_table[location] = INVALID_EDGE_DISTANCE;
continue;
}
// Step 2: Find path from source to middle node
PackedPath packed_path =
mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(query_heap, middle_node_id);
if (DIRECTION == FORWARD_DIRECTION)
{
std::reverse(packed_path.begin(), packed_path.end());
}
auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1;
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> unpacked_nodes_from_source;
std::vector<EdgeID> unpacked_edges;
std::tie(weight, unpacked_nodes_from_source, unpacked_edges) =
unpackPathAndCalculateDistance(engine_working_data,
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
INVALID_EDGE_WEIGHT,
packed_path,
middle_node_id,
source_phantom);
// Step 3: Find path from middle to target node
packed_path.clear();
retrievePackedPathFromSearchSpace<DIRECTION>(
middle_node_id, column_idx, search_space_with_buckets, packed_path);
if (DIRECTION == REVERSE_DIRECTION)
{
std::reverse(packed_path.begin(), packed_path.end());
}
std::vector<NodeID> unpacked_nodes_to_target;
std::tie(weight, unpacked_nodes_to_target, unpacked_edges) =
unpackPathAndCalculateDistance(engine_working_data,
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
INVALID_EDGE_WEIGHT,
packed_path,
middle_node_id,
target_phantom);
if (DIRECTION == REVERSE_DIRECTION)
{
std::swap(unpacked_nodes_to_target, unpacked_nodes_from_source);
}
// Step 4: Compute annotation value along the path nodes without the target node
auto annotation = 0.0;
for (auto node = unpacked_nodes_from_source.begin(),
last_node = std::prev(unpacked_nodes_from_source.end());
node != last_node;
++node)
{
annotation += computeEdgeDistance(facade, *node);
}
for (auto node = unpacked_nodes_to_target.begin(),
last_node = std::prev(unpacked_nodes_to_target.end());
node != last_node;
++node)
{
annotation += computeEdgeDistance(facade, *node);
}
// Step 5: Get phantom node offsets and compute the annotation value
EdgeDistance source_offset = 0., target_offset = 0.;
{
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
if (DIRECTION == REVERSE_DIRECTION)
{
std::swap(source_phantom_index, target_phantom_index);
}
const auto &source_phantom = phantom_nodes[source_phantom_index];
const auto &target_phantom = phantom_nodes[target_phantom_index];
NodeID source_node = unpacked_nodes_from_source.front();
NodeID target_node = unpacked_nodes_to_target.back();
if (source_phantom.IsValidForwardSource() &&
source_phantom.forward_segment_id.id == source_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// -->s <-- subtract offset to start at source
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
source_offset = source_phantom.GetForwardDistance();
}
else if (source_phantom.IsValidReverseSource() &&
source_phantom.reverse_segment_id.id == source_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// s<------- <-- subtract offset to start at source
// ... <-- want this distance
// entry 0---1---2---3 <-- 3 is exit node
source_offset = source_phantom.GetReverseDistance();
}
if (target_phantom.IsValidForwardTarget() &&
target_phantom.forward_segment_id.id == target_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// ++>t <-- add offset to get to target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
target_offset = target_phantom.GetForwardDistance();
}
else if (target_phantom.IsValidReverseTarget() &&
target_phantom.reverse_segment_id.id == target_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// <++t <-- add offset to get from target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
target_offset = target_phantom.GetReverseDistance();
}
}
distances_table[location] = -source_offset + annotation + target_offset;
}
}
template <bool DIRECTION> template <bool DIRECTION>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data, manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
@@ -787,7 +546,8 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT); std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION); std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table; std::vector<EdgeDistance> distances_table(calculate_distance ? number_of_entries : 0,
INVALID_EDGE_DISTANCE);
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID); std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
std::vector<NodeBucket> search_space_with_buckets; std::vector<NodeBucket> search_space_with_buckets;
@@ -846,25 +606,9 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
search_space_with_buckets, search_space_with_buckets,
weights_table, weights_table,
durations_table, durations_table,
middle_nodes_table,
source_phantom);
}
if (calculate_distance)
{
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
calculateDistances<DIRECTION>(query_heap,
facade,
phantom_nodes,
target_indices, // source_indices
row_idx,
source_index,
number_of_sources,
number_of_targets,
search_space_with_buckets,
distances_table, distances_table,
middle_nodes_table, middle_nodes_table,
engine_working_data); source_phantom);
} }
} }
@@ -892,12 +636,8 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const std::vector<PhantomNode> &phantom_nodes, const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices, const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices, const std::vector<std::size_t> &target_indices,
const bool calculate_distance, const bool calculate_distance)
const bool calculate_duration)
{ {
(void)calculate_duration; // flag stub to use for calculating distances in matrix in mld in the
// future
if (source_indices.size() == 1) if (source_indices.size() == 1)
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search { // TODO: check if target_indices.size() == 1 and do a bi-directional search
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data, return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
+29 -21
View File
@@ -95,12 +95,6 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSe
swap(nodes, m_edge_based_node_segments); swap(nodes, m_edge_based_node_segments);
} }
void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_startpoint)
{
using std::swap; // Koenig swap
swap(m_edge_based_node_is_startpoint, node_is_startpoint);
}
void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights) void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights)
{ {
using std::swap; // Koenig swap using std::swap; // Koenig swap
@@ -114,6 +108,13 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeDurations(
swap(m_edge_based_node_durations, output_node_durations); swap(m_edge_based_node_durations, output_node_durations);
} }
void EdgeBasedGraphFactory::GetEdgeBasedNodeDistances(
std::vector<EdgeDistance> &output_node_distances)
{
using std::swap; // Koenig swap
swap(m_edge_based_node_distances, output_node_distances);
}
std::uint32_t EdgeBasedGraphFactory::GetConnectivityChecksum() const std::uint32_t EdgeBasedGraphFactory::GetConnectivityChecksum() const
{ {
return m_connectivity_checksum; return m_connectivity_checksum;
@@ -222,10 +223,9 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_2]), edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_2]),
current_edge_source_coordinate_id, current_edge_source_coordinate_id,
current_edge_target_coordinate_id, current_edge_target_coordinate_id,
i); i,
forward_data.flags.startpoint || reverse_data.flags.startpoint);
m_edge_based_node_is_startpoint.push_back(forward_data.flags.startpoint ||
reverse_data.flags.startpoint);
current_edge_source_coordinate_id = current_edge_target_coordinate_id; current_edge_source_coordinate_id = current_edge_target_coordinate_id;
} }
@@ -291,8 +291,12 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
{ {
// heuristic: node-based graph node is a simple intersection with four edges // heuristic: node-based graph node is a simple intersection with four edges
// (edge-based nodes) // (edge-based nodes)
m_edge_based_node_weights.reserve(4 * m_node_based_graph.GetNumberOfNodes()); constexpr std::size_t ESTIMATED_EDGE_COUNT = 4;
m_edge_based_node_durations.reserve(4 * m_node_based_graph.GetNumberOfNodes()); m_edge_based_node_weights.reserve(ESTIMATED_EDGE_COUNT * m_node_based_graph.GetNumberOfNodes());
m_edge_based_node_durations.reserve(ESTIMATED_EDGE_COUNT *
m_node_based_graph.GetNumberOfNodes());
m_edge_based_node_distances.reserve(ESTIMATED_EDGE_COUNT *
m_node_based_graph.GetNumberOfNodes());
nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID); nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID);
// renumber edge based node of outgoing edges // renumber edge based node of outgoing edges
@@ -310,6 +314,7 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
m_edge_based_node_weights.push_back(edge_data.weight); m_edge_based_node_weights.push_back(edge_data.weight);
m_edge_based_node_durations.push_back(edge_data.duration); m_edge_based_node_durations.push_back(edge_data.duration);
m_edge_based_node_distances.push_back(edge_data.distance);
BOOST_ASSERT(numbered_edges_count < m_node_based_graph.GetNumberOfEdges()); BOOST_ASSERT(numbered_edges_count < m_node_based_graph.GetNumberOfEdges());
nbe_to_ebn_mapping[current_edge] = numbered_edges_count; nbe_to_ebn_mapping[current_edge] = numbered_edges_count;
@@ -407,15 +412,17 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
m_edge_based_node_weights.push_back(ebn_weight); m_edge_based_node_weights.push_back(ebn_weight);
m_edge_based_node_durations.push_back( m_edge_based_node_durations.push_back(
m_edge_based_node_durations[nbe_to_ebn_mapping[eid]]); m_edge_based_node_durations[nbe_to_ebn_mapping[eid]]);
m_edge_based_node_distances.push_back(
m_edge_based_node_distances[nbe_to_ebn_mapping[eid]]);
edge_based_node_id++; edge_based_node_id++;
progress.PrintStatus(progress_counter++); progress.PrintStatus(progress_counter++);
} }
} }
BOOST_ASSERT(m_edge_based_node_segments.size() == m_edge_based_node_is_startpoint.size());
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_weights.size()); BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_weights.size());
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_durations.size()); BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_durations.size());
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_distances.size());
util::Log() << "Generated " << m_number_of_edge_based_nodes << " nodes (" util::Log() << "Generated " << m_number_of_edge_based_nodes << " nodes ("
<< way_restriction_map.NumberOfDuplicatedNodes() << way_restriction_map.NumberOfDuplicatedNodes()
@@ -652,16 +659,17 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// auto turn_id = m_edge_based_edge_list.size(); // auto turn_id = m_edge_based_edge_list.size();
auto weight = boost::numeric_cast<EdgeWeight>(edge_data1.weight + weight_penalty); auto weight = boost::numeric_cast<EdgeWeight>(edge_data1.weight + weight_penalty);
auto duration = boost::numeric_cast<EdgeWeight>(edge_data1.duration + duration_penalty); auto duration = boost::numeric_cast<EdgeWeight>(edge_data1.duration + duration_penalty);
auto distance = boost::numeric_cast<EdgeDistance>(edge_data1.distance);
EdgeBasedEdge edge_based_edge = { EdgeBasedEdge edge_based_edge = {edge_based_node_from,
edge_based_node_from, edge_based_node_to,
edge_based_node_to, SPECIAL_NODEID, // This will be updated once the main
SPECIAL_NODEID, // This will be updated once the main loop // loop completes!
// completes! weight,
weight, duration,
duration, distance,
true, true,
false}; false};
// We write out the mapping between the edge-expanded edges and the original nodes. // We write out the mapping between the edge-expanded edges and the original nodes.
// Since each edge represents a possible maneuver, external programs can use this to // Since each edge represents a possible maneuver, external programs can use this to
+4
View File
@@ -387,12 +387,16 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
const auto weight = edge_iterator->weight_data(distance); const auto weight = edge_iterator->weight_data(distance);
const auto duration = edge_iterator->duration_data(distance); const auto duration = edge_iterator->duration_data(distance);
const auto accurate_distance =
util::coordinate_calculation::fccApproximateDistance(source_coord, target_coord);
ExtractionSegment segment(source_coord, target_coord, distance, weight, duration); ExtractionSegment segment(source_coord, target_coord, distance, weight, duration);
scripting_environment.ProcessSegment(segment); scripting_environment.ProcessSegment(segment);
auto &edge = edge_iterator->result; auto &edge = edge_iterator->result;
edge.weight = std::max<EdgeWeight>(1, std::round(segment.weight * weight_multiplier)); edge.weight = std::max<EdgeWeight>(1, std::round(segment.weight * weight_multiplier));
edge.duration = std::max<EdgeWeight>(1, std::round(segment.duration * 10.)); edge.duration = std::max<EdgeWeight>(1, std::round(segment.duration * 10.));
edge.distance = accurate_distance;
// assign new node id // assign new node id
const auto node_id = mapExternalToInternalNodeID( const auto node_id = mapExternalToInternalNodeID(

Some files were not shown because too many files have changed in this diff Show More