Compare commits

...

23 Commits

Author SHA1 Message Date
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
65 changed files with 4986 additions and 11018 deletions
+4
View File
@@ -68,6 +68,10 @@ Thumbs.db
/*.local.bat
/CMakeSettings.json
# Jetbrains related files #
###########################
.idea/
# stxxl related files #
#######################
.stxxl
+7 -68
View File
@@ -13,11 +13,12 @@ notifications:
branches:
only:
- master
- 5.21
# enable building tags
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
cache:
yarn: true
npm: true
ccache: true
apt: true
directories:
@@ -34,7 +35,7 @@ env:
- CMAKE_VERSION=3.7.2
- MASON="$(pwd)/scripts/mason.sh"
- ENABLE_NODE_BINDINGS=On
- NODE="4"
- NODE="10"
matrix:
fast_finish: true
@@ -45,7 +46,7 @@ matrix:
# Debug Builds
- os: linux
compiler: "format-taginfo-docs"
env: NODE=6
env: NODE=10
sudo: false
before_install:
install:
@@ -53,8 +54,7 @@ matrix:
- nvm install $NODE
- nvm use $NODE
- npm --version
- npm install --ignore-scripts
- npm link --ignore-scripts
- npm ci --ignore-scripts
script:
- ./scripts/check_taginfo.py taginfo.json profiles/car.lua
- ${MASON} install clang-format 3.8.1
@@ -170,14 +170,6 @@ matrix:
after_success:
- ./scripts/travis/publish.sh
- os: osx
osx_image: xcode9.2
compiler: "mason-osx-release-node-4"
# we use the xcode provides clang and don't install our own
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="4"
after_success:
- ./scripts/travis/publish.sh
# Shared Library
- os: linux
compiler: "gcc-7-release-shared"
@@ -188,54 +180,6 @@ matrix:
env: CCOMPILER='gcc-7' CXXCOMPILER='g++-7' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
# Node build jobs. These skip running the tests.
- os: linux
sudo: false
compiler: "node-4-mason-linux-release"
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="4"
install:
- pushd ${OSRM_BUILD_DIR}
- |
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
- npm run nodejs-tests
after_success:
- ./scripts/travis/publish.sh
- os: linux
sudo: false
compiler: "node-4-mason-linux-debug"
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="4"
install:
- pushd ${OSRM_BUILD_DIR}
- |
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
- npm run nodejs-tests
after_success:
- ./scripts/travis/publish.sh
- os: linux
sudo: false
compiler: "node-8-mason-linux-release"
@@ -350,15 +294,10 @@ before_install:
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
sudo mdutil -i off /
fi
- |
if [[ ! -f $(which yarn) ]]; then
npm install -g yarn@1.11.1
fi
- export PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
- export PUBLISH=$([[ "${TRAVIS_TAG:-}" == "v${PACKAGE_JSON_VERSION}" ]] && echo "On" || echo "Off")
- echo "Using ${JOBS} jobs"
- yarn install --ignore-scripts
- yarn check --ignore-scripts --integrity
- npm ci --ignore-scripts
# Bootstrap cmake to be able to run mason
- CMAKE_URL="https://mason-binaries.s3.amazonaws.com/${TRAVIS_OS_NAME}-x86_64/cmake/${CMAKE_VERSION}.tar.gz"
- CMAKE_DIR="mason_packages/${TRAVIS_OS_NAME}-x86_64/cmake/${CMAKE_VERSION}"
@@ -437,4 +376,4 @@ script:
fi
- |
- popd
- yarn test
- npm test
+22 -2
View File
@@ -1,4 +1,23 @@
# UNRELEASED
# 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)
@@ -8,10 +27,11 @@
- 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: 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: Now publishing Node 10.x LTS binary modules [#5246](https://github.com/Project-OSRM/osrm-backend/pull/5246)
- Windows:
- FIXED: Windows builds again. [#5249](https://github.com/Project-OSRM/osrm-backend/pull/5249)
- Docker:
- CHANGED: switch from Alpine Linux to Debian Buster base images [#5281](https://github.com/Project-OSRM/osrm-backend/pull/5281)
# 5.19.0
- Changes from 5.18.0:
+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
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/)
+4 -6
View File
@@ -7,7 +7,7 @@ WORKDIR /src
RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
apt-get update && \
apt-get -y --no-install-recommends install cmake make git gcc g++ libbz2-dev libstxxl-dev libstxxl1v5 libxml2-dev \
libzip-dev libboost-all-dev lua5.2 liblua5.2-dev libtbb-dev -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 && \
libzip-dev libboost1.67-all-dev lua5.2 liblua5.2-dev libtbb-dev -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 && \
NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
echo "Building OSRM ${DOCKER_TAG}" && \
git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \
@@ -24,7 +24,6 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
make -j${NPROC} install && \
cd ../profiles && \
cp -r * /opt && \
\
strip /usr/local/bin/* && \
rm -rf /src /usr/local/lib/libosrm*
@@ -34,13 +33,12 @@ RUN NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
FROM debian:buster-slim as runstage
RUN mkdir -p /src && mkdir -p /opt
RUN apt-get update && \
apt-get install -y --no-install-recommends libboost-program-options1.62.0 libboost-regex1.62.0 \
libboost-date-time1.62.0 libboost-chrono1.62.0 libboost-filesystem1.62.0 \
libboost-iostreams1.62.0 libboost-thread1.62.0 expat liblua5.2-0 libtbb2 &&\
apt-get install -y --no-install-recommends libboost-program-options1.67.0 libboost-regex1.67.0 \
libboost-date-time1.67.0 libboost-chrono1.67.0 libboost-filesystem1.67.0 \
libboost-iostreams1.67.0 libboost-thread1.67.0 expat liblua5.2-0 libtbb2 &&\
rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/local /usr/local
COPY --from=builder /opt /opt
RUN chmod 0644 -R /opt
WORKDIR /opt
EXPOSE 5000
+9 -2
View File
@@ -235,9 +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. |
|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. |
|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.|
|annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. |
|fallback_speed|`double > 0`| If no route found between a source/destination pair, calculate the as-the-crow-flies distance, then use this speed to estimate duration.|
|fallback_coordinate|`input` (default), or `snapped`| When using a `fallback_speed`, use the user-supplied coordinate (`input`), or the snapped location (`snapped`) for calculating distances.|
|scale_factor|`double > 0`| Use in conjunction with `annotations=durations`. Scales the table `duration` values by this number.|
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
to number of input locations;
@@ -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.
- `sources` array of `Waypoint` objects describing all sources in order
- `destinations` array of `Waypoint` objects describing all destinations in order
- `fallback_speed_cells` (optional) array of arrays containing `i,j` pairs indicating which cells contain estimated values based on `fallback_speed`. Will be absent if `fallback_speed` is not used.
In case of error the following `code`s are supported in addition to the general ones:
@@ -383,6 +385,10 @@ All other properties might be undefined.
2361.73,
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. |
| `name` | `string` | the name of the road this segment belongs to |
| `rate` | `float` | the value of `length/weight` - analagous to `speed`, but using the `weight` value rather than `duration`, rounded to the nearest integer |
| `is_startpoint` | `boolean` | whether this segment can be used as a start/endpoint for routes |
`turns` layer:
+2
View File
@@ -131,6 +131,7 @@ tables. Optionally returns distance table.
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `options.fallback_speed` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second.
- `options.fallback_coordinate` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies diestance between two points.
- `options.scale_factor` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Multiply the table duration values in the table by this number for more controlled input into a route optimization solver.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -156,6 +157,7 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
Values are given in seconds.
**`sources`**: array of [`Ẁaypoint`](#waypoint) objects describing all sources in order.
**`destinations`**: array of [`Ẁaypoint`](#waypoint) objects describing all destinations in order.
**`fallback_speed_cells`**: (optional) if `fallback_speed` is used, will be an array of arrays of `row,column` values, indicating which cells contain estimated values.
### tile
+9
View File
@@ -109,3 +109,12 @@ Feature: Car - Handle ferry routes
When I route I should get
| from | to | route | modes | time |
| c | d | bcde,bcde | ferry,ferry | 600s |
Given the query options
| geometries | geojson |
| overview | full |
# Note that matching *should* work across unsnappable ferries
When I match I should get
| trace | geometry | duration |
| abcdef| 1,1,1.000899,1,1.000899,1,1.002697,1,1.002697,1,1.003596,1,1.003596,1,1.005394,1,1.005394,1,1.006293,1 | 610.9 |
+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 | 20 | 30 | | -1 | | 15 km/h | | 4.4 |
| primary | 20 | | 30 | -1 | | 23 km/h | | 6.7 |
Scenario: Car - Respect source:maxspeed
Given the node map
"""
a b c d e f g
"""
And the ways
| nodes | highway | source:maxspeed | maxspeed |
| ab | trunk | | |
| bc | trunk | | 60 |
| cd | trunk | FR:urban | |
| de | trunk | CH:rural | |
| ef | trunk | CH:trunk | |
| fg | trunk | CH:motorway | |
When I route I should get
| from | to | route | speed |
| a | b | ab,ab | 85 km/h |
| b | c | bc,bc | 48 km/h |
| c | d | cd,cd | 40 km/h |
| d | e | de,de | 64 km/h |
| e | f | ef,ef | 80 km/h |
| f | g | fg,fg | 96 km/h |
+25
View File
@@ -35,3 +35,28 @@ Feature: Car - Allowed start/end modes
| from | to | route | modes |
| 1 | 2 | ab,ab | driving,driving |
| 2 | 1 | ab,ab | driving,driving |
Scenario: Car - URL override of non-startpoints
Given the node map
"""
a 1 b c 2 d
"""
Given the query options
| snapping | any |
And the ways
| nodes | highway | access |
| ab | service | private |
| bc | primary | |
| cd | service | private |
When I request a travel time matrix I should get
| | 2 | c |
| 1 | 59.1 | 35.1 |
| b | 35.1 | 11.1 |
When I route I should get
| from | to | route |
| 1 | 2 | ab,bc,cd |
| 2 | 1 | cd,bc,ab |
+36
View File
@@ -0,0 +1,36 @@
@routing @maxspeed @car
Feature: Car - Acceleration profiles
Background: Use specific speeds
Given the profile "car"
Given a grid size of 1000 meters
Scenario: Car - Use stoppage penalty at waypoints
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
| stoppage_penalty | 5,100 |
When I route I should get
| from | to | route | time |
| a | b | ab,ab | 481.1s |
When I route I should get
| from | to | route | time |
| b | a | ab,ab | 609.9s |
When I route I should get
| from | to | route | time |
| a | a | ab,ab | 0s |
When I request a travel time matrix I should get
| | a | b |
| a | 0 | 481.1 |
| b | 609.9 | 0 |
+1 -1
View File
@@ -295,7 +295,7 @@ module.exports = function () {
this.reprocess(callback);
});
this.Given(/^osrm\-routed is stopped$/, (callback) => {
this.Given(/^osrm-routed is stopped$/, (callback) => {
this.OSRMLoader.shutdown(callback);
});
+25 -7
View File
@@ -3,22 +3,25 @@ var util = require('util');
module.exports = function () {
const durationsRegex = new RegExp(/^I request a travel time matrix I should get$/);
const distancesRegex = new RegExp(/^I request a travel distance matrix I should get$/);
const estimatesRegex = new RegExp(/^I request a travel time matrix I should get estimates for$/);
const DURATIONS_NO_ROUTE = 2147483647; // MAX_INT
const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT
this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', callback);}.bind(this));
this.When(distancesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', callback);}.bind(this));
this.When(estimatesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'fallback_speed_cells', callback);}.bind(this));
};
const durationsParse = function(v) { return isNaN(parseInt(v)); };
const distancesParse = function(v) { return isNaN(parseFloat(v)); };
const estimatesParse = function(v) { return isNaN(parseFloat(v)); };
function tableParse(table, noRoute, annotation, callback) {
const parse = annotation == 'distances' ? distancesParse : durationsParse;
const parse = annotation == 'distances' ? distancesParse : (annotation == 'durations' ? durationsParse : estimatesParse);
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();
@@ -61,11 +64,26 @@ function tableParse(table, noRoute, annotation, callback) {
var json = JSON.parse(response.body);
var result = json[annotation].map(row => {
var hashes = {};
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; });
return hashes;
});
var result = {};
if (annotation === 'fallback_speed_cells') {
result = table.raw().map(row => row.map(() => ''));
json[annotation].forEach(pair => {
result[pair[0]+1][pair[1]+1] = 'Y';
});
result = result.slice(1).map(row => {
var hashes = {};
row.slice(1).forEach((v,i) => {
hashes[tableRows[0][i+1]] = v;
});
return hashes;
});
} else {
result = json[annotation].map(row => {
var hashes = {};
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; });
return hashes;
});
}
var testRow = (row, ri, cb) => {
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.When(/^I run "osrm\-(extract|contract|partition|customize)\s?(.*?)"$/, (binary, options, callback) => {
this.When(/^I run "osrm-(extract|contract|partition|customize)\s?(.*?)"$/, (binary, options, callback) => {
const stamp = this.processedCacheFile + '.stamp_' + binary;
this.runAndSafeOutput('osrm-' + binary, options, (err) => {
if (err) return callback(err);
@@ -33,11 +33,11 @@ module.exports = function () {
});
});
this.When(/^I try to run "(osrm\-[a-z]+)\s?(.*?)"$/, (binary, options, callback) => {
this.When(/^I try to run "(osrm-[a-z]+)\s?(.*?)"$/, (binary, options, callback) => {
this.runAndSafeOutput(binary, options, () => { callback(); });
});
this.When(/^I run "osrm\-datastore\s?(.*?)"(?: with input "([^"]*)")?$/, (options, input, callback) => {
this.When(/^I run "osrm-datastore\s?(.*?)"(?: with input "([^"]*)")?$/, (options, input, callback) => {
let child = this.runAndSafeOutput('osrm-datastore', options, callback);
if (input !== undefined)
child.stdin.write(input);
@@ -55,13 +55,13 @@ module.exports = function () {
this.Then(/^stdout should( not)? contain "(.*?)"$/, (not, str) => {
const contains = this.stdout.indexOf(str) > -1;
assert.ok(typeof not === 'undefined' ? contains : !contains,
'stdout ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
'stdout ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
});
this.Then(/^stderr should( not)? contain "(.*?)"$/, (not, str) => {
const contains = this.stderr.indexOf(str) > -1;
assert.ok(typeof not === 'undefined' ? contains : !contains,
'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
'stderr ' + (typeof not === 'undefined' ? 'does not contain' : 'contains') + ' "' + str + '"');
});
this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => {
+1 -1
View File
@@ -69,7 +69,7 @@ module.exports = function () {
outputRow[direction] = result[direction].status ?
'x' : '';
break;
case /^[\d\.]+ s/.test(want):
case /^[\d.]+ s/.test(want):
// the result here can come back as a non-number value like
// `diff`, but we only want to apply the unit when it comes
// back as a number, for tableDiff's literal comparison
+7 -7
View File
@@ -29,7 +29,7 @@ module.exports = function() {
// setup cache for feature data
// if OSRM_PROFILE is set to force a specific profile, then
// include the profile name in the hash of the profile file
// include the profile name in the hash of the profile file
hash.hashOfFile(uri, this.OSRM_PROFILE, (err, hash) => {
if (err) return callback(err);
@@ -45,10 +45,10 @@ module.exports = function() {
this.featureProcessedCacheDirectories[uri] = featureProcessedCacheDirectory;
d3.queue(1)
.defer(mkdirp, featureProcessedCacheDirectory)
.defer(this.cleanupFeatureCache.bind(this), featureCacheDirectory, hash)
.defer(this.cleanupProcessedFeatureCache.bind(this), featureProcessedCacheDirectory, this.osrmHash)
.awaitAll(callback);
.defer(mkdirp, featureProcessedCacheDirectory)
.defer(this.cleanupFeatureCache.bind(this), featureCacheDirectory, hash)
.defer(this.cleanupProcessedFeatureCache.bind(this), featureProcessedCacheDirectory, this.osrmHash)
.awaitAll(callback);
});
}
@@ -87,7 +87,7 @@ module.exports = function() {
fs.readdir(parentPath, (err, files) => {
let q = d3.queue();
files.filter(name => { return name !== featureHash;})
.map((f) => { q.defer(rimraf, path.join(parentPath, f)); });
.map((f) => { q.defer(rimraf, path.join(parentPath, f)); });
q.awaitAll(callback);
});
};
@@ -145,7 +145,7 @@ module.exports = function() {
// converts the scenario titles in file prefixes
this.getScenarioID = (scenario) => {
let name = scenario.getName().toLowerCase().replace(/[\/\-'=,\(\):\*#]/g, '')
let name = scenario.getName().toLowerCase().replace(/[/\-'=,():*#]/g, '')
.replace(/\s/g, '_').replace(/__/g, '_').replace(/\.\./g, '.')
.substring(0, 64);
return util.format('%d_%s', scenario.getLine(), name);
+10 -10
View File
@@ -17,12 +17,12 @@ module.exports = {
return true;
var matchPercent = want.match(/(.*)\s+~(.+)%$/),
matchAbs = want.match(/(.*)\s+\+\-(.+)$/),
matchAbs = want.match(/(.*)\s+\+-(.+)$/),
matchRe = want.match(/^\/(.*)\/$/),
// we use this for matching before/after bearing
matchBearingListAbs = want.match(/^((\d+)->(\d+))(,(\d+)->(\d+))*\s+\+\-(.+)$/),
matchIntersectionListAbs = want.match(/^(((((true|false):\d+)\s{0,1})+,{0,1})+;{0,1})+\s+\+\-(.+)$/),
matchRangeNumbers = want.match(/\d+\+\-\d+/);
matchBearingListAbs = want.match(/^((\d+)->(\d+))(,(\d+)->(\d+))*\s+\+-(.+)$/),
matchIntersectionListAbs = want.match(/^(((((true|false):\d+)\s{0,1})+,{0,1})+;{0,1})+\s+\+-(.+)$/),
matchRangeNumbers = want.match(/\d+\+-\d+/);
function inRange(margin, got, want) {
var fromR = parseFloat(want) - margin,
@@ -31,12 +31,12 @@ module.exports = {
}
function parseIntersectionString(str) {
return str.split(';')
.map((turn_intersections) => turn_intersections
.split(',')
.map((intersection) => intersection
.split(' ')
.map((entry_bearing_pair) => entry_bearing_pair
.split(':'))));
.map((turn_intersections) => turn_intersections
.split(',')
.map((intersection) => intersection
.split(' ')
.map((entry_bearing_pair) => entry_bearing_pair
.split(':'))));
}
if (got === want) {
+2 -2
View File
@@ -115,7 +115,7 @@ module.exports = function () {
if (headers.has('weight')) {
if (row.weight.length) {
if (!row.weight.match(/[\d\.]+/))
if (!row.weight.match(/[\d.]+/))
return cb(new Error('*** Weight must be specified as a numeric value. (ex: 8)'));
got.weight = instructions ? util.format('%d', weight) : '';
} else {
@@ -151,7 +151,7 @@ module.exports = function () {
if (headers.has('locations')){
got.locations = (locations || '').trim();
}
/*
/*
if (headers.has('approaches')){
got.approaches = (approaches || '').trim();
}*/
+44 -33
View File
@@ -596,7 +596,6 @@ Feature: Basic Distance Matrix
| e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 |
| f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 |
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
@@ -617,10 +616,21 @@ Feature: Basic Distance Matrix
| | 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 | 302.2 |
| f | 900.7 | 600.5 | 0 | 300.2 |
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
Scenario: Testbot - Filling in noroutes with estimates - use input coordinate
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
@@ -641,9 +651,21 @@ Feature: Basic Distance Matrix
| | 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 | 302.2 |
| 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"
@@ -665,25 +687,12 @@ Feature: Basic Distance Matrix
| | 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 | 302.2 |
| f | 900.7 | 600.5 | 0 | 300.2 |
| 1 | 1200.9 | 900.7 | 300.2 | 0 |
Scenario: Testbot - Asymetric fallback_speed - more sources than destinations
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 |
When I request a travel distance matrix I should get
| | a |
@@ -692,23 +701,25 @@ Feature: Basic Distance Matrix
| f | 900.7 |
| 1 | 1200.9 |
Scenario: Testbot - Asymetric fallback_speed - more destinations than sources
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 |
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 f h 1
d e g i
a b c d e f g h i j
1 2
"""
And the ways
| nodes |
| abeda |
| fhigf |
| 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
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1200.9 |
| | 1 | 2 |
| 1 | 0 | 1000.7 |
| 2 | 1000.7 | 0 |
+195 -1
View File
@@ -534,6 +534,35 @@ Feature: Basic Duration Matrix
| 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"
@@ -558,6 +587,36 @@ Feature: Basic Duration Matrix
| 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"
@@ -580,4 +639,139 @@ Feature: Basic Duration Matrix
| a | 0 | 30 | 18 | 24 |
| b | 30 | 0 | 12 | 18 |
| f | 18 | 12 | 0 | 30 |
| 1 | 24 | 18 | 30 | 0 |
| 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 |
+10 -10
View File
@@ -111,9 +111,9 @@ Feature: Multi level routing
When I request a travel distance matrix I should get
| | a | f | l | o |
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
| f | 2339.9 | 0 | 1198.1 | 1522.1 |
| l | 1618.3 | 1293.3 | 0 | 800.5 |
| o | 1418.2 | 1617.3 | 800.5 | 0 |
| f | 2383.7 | 0 | 1293.3 | 1617.3 |
| l | 1566.9 | 1293.3 | 0 | 800.5 |
| o | 1366.8 | 1617.3 | 800.5 | 0 |
When I request a travel distance matrix I should get
| | a | f | l | o |
@@ -122,21 +122,21 @@ Feature: Multi level routing
When I request a travel distance matrix I should get
| | a |
| a | 0 |
| f | 2339.9 |
| l | 1618.3 |
| o | 1418.2 |
| f | 2383.7 |
| l | 1566.9 |
| o | 1366.8 |
When I request a travel distance matrix I should get
| | a | f | l | o |
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
| f | 2339.9 | 0 | 1198.1 | 1522.1 |
| f | 2383.7 | 0 | 1293.3 | 1617.3 |
When I request a travel distance matrix I should get
| | a | o |
| a | 0 | 1366.8 |
| f | 2339.9 | 1522.1 |
| l | 1618.3 | 800.5 |
| o | 1418.2 | 0 |
| f | 2383.7 | 1617.3 |
| l | 1566.9 | 800.5 |
| o | 1366.8 | 0 |
Scenario: Testbot - Multi level routing: horizontal road
Given the node map
+1 -1
View File
@@ -182,4 +182,4 @@ Feature: Snap start/end point to the nearest way
| x | m | xe,xe |
| x | n | xf,xf |
| x | o | xg,xg |
| x | p | xh,xh |
| x | p | xh,xh |
+36
View File
@@ -0,0 +1,36 @@
@routing @maxspeed @testbot
Feature: Testbot - Acceleration profiles
Background: Use specific speeds
Given the profile "testbot"
Given a grid size of 1000 meters
Scenario: Testbot - Use stoppage penalty at waypoints
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
| stoppage_penalty | 5,100 |
When I route I should get
| from | to | route | time |
| a | b | ab,ab | 412.3s |
When I route I should get
| from | to | route | time |
| b | a | ab,ab | 505.9s |
When I route I should get
| from | to | route | time |
| a | a | ab,ab | 0s |
When I request a travel time matrix I should get
| | a | b |
| a | 0 | 412.3 |
| b | 505.9 | 0 |
+22 -2
View File
@@ -63,6 +63,13 @@ namespace api
*/
struct BaseParameters
{
enum class SnappingType
{
Default,
Any
};
std::vector<util::Coordinate> coordinates;
std::vector<boost::optional<Hint>> hints;
std::vector<boost::optional<double>> radiuses;
@@ -73,21 +80,34 @@ struct BaseParameters
// Adds hints to response which can be included in subsequent requests, see `hints` above.
bool generate_hints = true;
SnappingType snapping = SnappingType::Default;
double min_stoppage_penalty = INVALID_MINIMUM_STOPPAGE_PENALTY;
double max_stoppage_penalty = INVALID_MAXIMUM_STOPPAGE_PENALTY;
BaseParameters(const std::vector<util::Coordinate> coordinates_ = {},
const std::vector<boost::optional<Hint>> hints_ = {},
std::vector<boost::optional<double>> radiuses_ = {},
std::vector<boost::optional<Bearing>> bearings_ = {},
std::vector<boost::optional<Approach>> approaches_ = {},
bool generate_hints_ = true,
std::vector<std::string> exclude = {})
std::vector<std::string> exclude = {},
const SnappingType snapping_ = SnappingType::Default,
double min_stoppage_penalty_ = INVALID_MINIMUM_STOPPAGE_PENALTY,
double max_stoppage_penalty_ = INVALID_MAXIMUM_STOPPAGE_PENALTY)
: 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_), min_stoppage_penalty(min_stoppage_penalty_),
max_stoppage_penalty(max_stoppage_penalty_)
{
}
// FIXME add validation for invalid bearing values
bool IsValid() const
{
if (min_stoppage_penalty <= 0 || max_stoppage_penalty <= 0 ||
min_stoppage_penalty > max_stoppage_penalty)
return false;
return (hints.empty() || hints.size() == coordinates.size()) &&
(bearings.empty() || bearings.size() == coordinates.size()) &&
(radiuses.empty() || radiuses.size() == coordinates.size()) &&
+29
View File
@@ -31,6 +31,15 @@ namespace api
class TableAPI final : public BaseAPI
{
public:
struct TableCellRef
{
TableCellRef(const std::size_t &row, const std::size_t &column) : row{row}, column{column}
{
}
std::size_t row;
std::size_t column;
};
TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters &parameters_)
: BaseAPI(facade_, parameters_), parameters(parameters_)
{
@@ -39,6 +48,7 @@ class TableAPI final : public BaseAPI
virtual void
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
const std::vector<PhantomNode> &phantoms,
const std::vector<TableCellRef> &fallback_speed_cells,
util::json::Object &response) const
{
auto number_of_sources = parameters.sources.size();
@@ -77,6 +87,11 @@ class TableAPI final : public BaseAPI
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";
}
@@ -163,6 +178,20 @@ class TableAPI final : public BaseAPI
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;
};
+12 -6
View File
@@ -59,7 +59,7 @@ struct TableParameters : public BaseParameters
{
std::vector<std::size_t> sources;
std::vector<std::size_t> destinations;
double fallback_speed = 0;
double fallback_speed = INVALID_FALLBACK_SPEED;
enum class FallbackCoordinateType
{
@@ -78,6 +78,7 @@ struct TableParameters : public BaseParameters
};
AnnotationsType annotations = AnnotationsType::Duration;
double scale_factor = 1;
TableParameters() = default;
template <typename... Args>
@@ -105,10 +106,12 @@ struct TableParameters : public BaseParameters
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_}
fallback_coordinate_type{fallback_coordinate_type_}, annotations{annotations_},
scale_factor{scale_factor_}
{
}
@@ -132,7 +135,10 @@ struct TableParameters : public BaseParameters
if (std::any_of(begin(destinations), end(destinations), not_in_range))
return false;
if (fallback_speed < 0)
if (fallback_speed <= 0)
return false;
if (scale_factor <= 0)
return false;
return true;
@@ -158,8 +164,8 @@ inline TableParameters::AnnotationsType &operator|=(TableParameters::Annotations
{
return lhs = lhs | rhs;
}
}
}
}
} // namespace api
} // namespace engine
} // namespace osrm
#endif // ENGINE_API_TABLE_PARAMETERS_HPP
@@ -312,12 +312,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance,
const Approach approach) const override final
const Approach approach,
const bool use_all_edges) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange(
input_coordinate, max_distance, approach);
input_coordinate, max_distance, approach, use_all_edges);
}
std::vector<PhantomNodeWithDistance>
@@ -325,12 +326,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
const float max_distance,
const int bearing,
const int bearing_range,
const Approach approach) const override final
const Approach approach,
const bool use_all_edges) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodesInRange(
input_coordinate, max_distance, bearing, bearing_range, approach);
input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
}
std::vector<PhantomNodeWithDistance>
@@ -382,50 +384,84 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
input_coordinate, max_results, max_distance, bearing, bearing_range, approach);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const override final
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, approach);
input_coordinate,
approach,
use_all_edges,
minimum_stoppage_penalty,
maximum_stoppage_penalty);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach) const override final
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, approach);
input_coordinate,
max_distance,
approach,
use_all_edges,
minimum_stoppage_penalty,
maximum_stoppage_penalty);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach) const override final
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, bearing, bearing_range, approach);
input_coordinate,
max_distance,
bearing,
bearing_range,
approach,
use_all_edges,
minimum_stoppage_penalty,
maximum_stoppage_penalty);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach) const override final
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, bearing, bearing_range, approach);
input_coordinate,
bearing,
bearing_range,
approach,
use_all_edges,
minimum_stoppage_penalty,
maximum_stoppage_penalty);
}
std::uint32_t GetCheckSum() const override final { return m_check_sum; }
+34 -20
View File
@@ -126,11 +126,13 @@ class BaseDataFacade
const float max_distance,
const int bearing,
const int bearing_range,
const Approach approach) const = 0;
const Approach approach,
const bool use_all_edges) const = 0;
virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance,
const Approach approach) const = 0;
const Approach approach,
const bool use_all_edges) const = 0;
virtual std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
@@ -155,24 +157,36 @@ class BaseDataFacade
const double max_distance,
const Approach approach) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach) const = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const = 0;
virtual bool HasLaneData(const EdgeID id) const = 0;
virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0;
+153 -51
View File
@@ -53,13 +53,15 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach) const
const Approach approach,
const bool use_all_edges) const
{
auto results = rtree.Nearest(
input_coordinate,
[this, approach, &input_coordinate](const CandidateSegment &segment) {
return boolPairAnd(boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)),
CheckApproach(input_coordinate, segment, approach));
[this, approach, &input_coordinate, use_all_edges](const CandidateSegment &segment) {
return boolPairAnd(
boolPairAnd(HasValidEdge(segment, use_all_edges), CheckSegmentExclude(segment)),
CheckApproach(input_coordinate, segment, approach));
},
[this, max_distance, input_coordinate](const std::size_t,
const CandidateSegment &segment) {
@@ -76,15 +78,17 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach) const
const Approach approach,
const bool use_all_edges) const
{
auto results = rtree.Nearest(
input_coordinate,
[this, approach, &input_coordinate, bearing, bearing_range](
[this, approach, &input_coordinate, bearing, bearing_range, use_all_edges](
const CandidateSegment &segment) {
auto use_direction =
boolPairAnd(CheckSegmentBearing(segment, bearing, bearing_range),
boolPairAnd(HasValidEdge(segment), CheckSegmentExclude(segment)));
boolPairAnd(HasValidEdge(segment, use_all_edges),
CheckSegmentExclude(segment)));
use_direction =
boolPairAnd(use_direction, CheckApproach(input_coordinate, segment, approach));
return use_direction;
@@ -201,18 +205,25 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance,
const Approach approach) const
const Approach approach,
const bool use_all_edges,
const double min_stoppage_penalty,
const double max_stoppage_penalty) const
{
bool has_small_component = false;
bool has_big_component = false;
auto results = rtree.Nearest(
input_coordinate,
[this, approach, &input_coordinate, &has_big_component, &has_small_component](
const CandidateSegment &segment) {
[this,
approach,
&input_coordinate,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment);
const auto valid_edges = HasValidEdge(segment);
const auto valid_edges = HasValidEdge(segment, use_all_edges);
const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(use_directions, valid_edges);
@@ -239,27 +250,39 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
}
BOOST_ASSERT(results.size() == 1 || results.size() == 2);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
return std::make_pair(
MakePhantomNode(
input_coordinate, results.front(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node,
MakePhantomNode(
input_coordinate, results.back(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const
const Approach approach,
const bool use_all_edges,
const double min_stoppage_penalty,
const double max_stoppage_penalty) const
{
bool has_small_component = false;
bool has_big_component = false;
auto results = rtree.Nearest(
input_coordinate,
[this, approach, &input_coordinate, &has_big_component, &has_small_component](
const CandidateSegment &segment) {
[this,
approach,
&input_coordinate,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment);
const auto valid_edges = HasValidEdge(segment);
const auto valid_edges = HasValidEdge(segment, use_all_edges);
const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(use_directions, valid_edges);
@@ -284,8 +307,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
}
BOOST_ASSERT(results.size() == 1 || results.size() == 2);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
return std::make_pair(
MakePhantomNode(
input_coordinate, results.front(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node,
MakePhantomNode(
input_coordinate, results.back(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
@@ -294,7 +322,10 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach) const
const Approach approach,
const bool use_all_edges,
const double min_stoppage_penalty,
const double max_stoppage_penalty) const
{
bool has_small_component = false;
bool has_big_component = false;
@@ -306,12 +337,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
bearing,
bearing_range,
&has_big_component,
&has_small_component](const CandidateSegment &segment) {
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment);
const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, HasValidEdge(segment));
use_directions = boolPairAnd(use_directions, HasValidEdge(segment, use_all_edges));
if (use_segment)
{
@@ -341,8 +373,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
}
BOOST_ASSERT(results.size() > 0);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
return std::make_pair(
MakePhantomNode(
input_coordinate, results.front(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node,
MakePhantomNode(
input_coordinate, results.back(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
@@ -352,7 +389,10 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const double max_distance,
const int bearing,
const int bearing_range,
const Approach approach) const
const Approach approach,
const bool use_all_edges,
const double min_stoppage_penalty,
const double max_stoppage_penalty) const
{
bool has_small_component = false;
bool has_big_component = false;
@@ -364,12 +404,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
bearing,
bearing_range,
&has_big_component,
&has_small_component](const CandidateSegment &segment) {
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment);
const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, HasValidEdge(segment));
use_directions = boolPairAnd(use_directions, HasValidEdge(segment, use_all_edges));
if (use_segment)
{
@@ -401,8 +442,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
}
BOOST_ASSERT(results.size() > 0);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
return std::make_pair(
MakePhantomNode(
input_coordinate, results.front(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node,
MakePhantomNode(
input_coordinate, results.back(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node);
}
private:
@@ -421,7 +467,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
}
PhantomNodeWithDistance MakePhantomNode(const util::Coordinate input_coordinate,
const EdgeData &data) const
const EdgeData &data,
const double min_stoppage_penalty = 0,
const double max_stoppage_penalty = 0) const
{
util::Coordinate point_on_segment;
double ratio;
@@ -460,15 +508,21 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
forward_durations.begin() + data.fwd_segment_position,
EdgeDuration{0});
EdgeDistance forward_distance_offset = 0;
for (auto current = forward_geometry.begin();
current < forward_geometry.begin() + data.fwd_segment_position;
++current)
{
forward_distance_offset += util::coordinate_calculation::fccApproximateDistance(
datafacade.GetCoordinateOfNode(*current),
datafacade.GetCoordinateOfNode(*std::next(current)));
}
// For measuring distance from begin up to end
const auto appx_distance = [this](decltype(forward_geometry.begin()) begin,
decltype(forward_geometry.begin()) end) {
EdgeDistance dist = 0;
for (; begin != end; ++begin)
{
dist += util::coordinate_calculation::fccApproximateDistance(
datafacade.GetCoordinateOfNode(*begin),
datafacade.GetCoordinateOfNode(*std::next(begin)));
}
return dist;
};
EdgeDistance forward_distance_offset = appx_distance(
forward_geometry.begin(), forward_geometry.begin() + data.fwd_segment_position);
BOOST_ASSERT(data.fwd_segment_position <
std::distance(forward_durations.begin(), forward_durations.end()));
@@ -489,15 +543,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
reverse_durations.end() - data.fwd_segment_position - 1,
EdgeDuration{0});
EdgeDistance reverse_distance_offset = 0;
for (auto current = forward_geometry.begin();
current < forward_geometry.end() - data.fwd_segment_position - 2;
++current)
{
reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance(
datafacade.GetCoordinateOfNode(*current),
datafacade.GetCoordinateOfNode(*std::next(current)));
}
EdgeDistance reverse_distance_offset =
appx_distance(forward_geometry.begin() + data.fwd_segment_position + 1,
std::prev(forward_geometry.end()));
EdgeWeight reverse_weight =
reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1];
@@ -507,16 +555,64 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
point_on_segment,
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1)));
// where does this speed lie with respect to the min/max penalizable speeds
auto penalty_range = min_stoppage_penalty != INVALID_MINIMUM_STOPPAGE_PENALTY &&
max_stoppage_penalty != INVALID_MAXIMUM_STOPPAGE_PENALTY
? max_stoppage_penalty - min_stoppage_penalty
: 0;
auto stoppage_penalty =
[penalty_range, min_stoppage_penalty, max_stoppage_penalty](double speed) -> double {
// You're so slow already you don't get a penalty
if (speed < MINIMAL_ACCEL_DECEL_PENALIZABLE_SPEED)
return 0;
// Find where it is on the scale
constexpr auto max =
MAXIMAL_ACCEL_DECEL_PENALIZABLE_SPEED - MINIMAL_ACCEL_DECEL_PENALIZABLE_SPEED;
auto ratio = (speed - MINIMAL_ACCEL_DECEL_PENALIZABLE_SPEED) / max;
// You're faster than the max so you get the max
if (ratio >= 1)
return max_stoppage_penalty;
// You're in between so you get a linear combination
return min_stoppage_penalty + ratio * penalty_range;
};
// We may end up adding a stoppage penalty
EdgeDuration forward_stoppage_penalty = 0;
EdgeDuration reverse_stoppage_penalty = 0;
auto total_distance = penalty_range > 0 ? appx_distance(forward_geometry.begin(),
std::prev(forward_geometry.end()))
: 0.0;
ratio = std::min(1.0, std::max(0.0, ratio));
if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
{
forward_weight = static_cast<EdgeWeight>(forward_weight * ratio);
forward_duration = static_cast<EdgeDuration>(forward_duration * ratio);
// Stoppage penalty based on speed
if (data.forward_segment_id.enabled && penalty_range > 0)
{
const auto total_duration = std::accumulate(
forward_durations.begin(), forward_durations.end(), EdgeDuration{0});
const auto speed = total_distance / (total_duration * 0.1);
forward_stoppage_penalty =
static_cast<EdgeDuration>((stoppage_penalty(speed) * 10) + .5);
}
}
if (data.reverse_segment_id.id != SPECIAL_SEGMENTID)
{
reverse_weight -= static_cast<EdgeWeight>(reverse_weight * ratio);
reverse_duration -= static_cast<EdgeDuration>(reverse_duration * ratio);
// Stoppage penalty based on speed
if (data.reverse_segment_id.enabled && penalty_range > 0)
{
const auto total_duration = std::accumulate(
reverse_durations.begin(), reverse_durations.end(), EdgeDuration{0});
const auto speed = total_distance / (total_duration * 0.1);
reverse_stoppage_penalty =
static_cast<EdgeDuration>((stoppage_penalty(speed) * 10) + .5);
}
}
// check phantom node segments validity
@@ -547,6 +643,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
reverse_duration,
forward_duration_offset,
reverse_duration_offset,
forward_stoppage_penalty,
reverse_stoppage_penalty,
is_forward_valid_source,
is_forward_valid_target,
is_reverse_valid_source,
@@ -628,7 +726,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
* which means that this edge is not currently traversible. If this is the case,
* then we shouldn't snap to this edge.
*/
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment) const
std::pair<bool, bool> HasValidEdge(const CandidateSegment &segment,
const bool use_all_edges = false) const
{
bool forward_edge_valid = false;
@@ -652,6 +751,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
reverse_edge_valid = data.reverse_segment_id.enabled;
}
forward_edge_valid = forward_edge_valid && (data.is_startpoint || use_all_edges);
reverse_edge_valid = reverse_edge_valid && (data.is_startpoint || use_all_edges);
return std::make_pair(forward_edge_valid, reverse_edge_valid);
}
@@ -693,7 +795,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const CoordinateList &coordinates;
DataFacadeT &datafacade;
};
}
}
} // namespace engine
} // namespace osrm
#endif
+9 -2
View File
@@ -122,7 +122,7 @@ std::array<std::uint32_t, SegmentNumber> summarizeRoute(const datafacade::BaseDa
[](const NamedSegment &segment) { return segment.name_id; });
return summary;
}
}
} // namespace detail
inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
const std::vector<PathData> &route_data,
@@ -166,7 +166,7 @@ inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
// `forward_duration`: duration of (d,t)
// `forward_offset`: duration of (c, d)
// path_data will have entries for (s,b), (b, c), (c, d) but (d, t) is only
// caputed by the phantom node. So we need to add the target duration here.
// captured by the phantom node. So we need to add the target duration here.
// On local segments, the target duration is already part of the duration, however.
duration = duration + target_duration;
@@ -182,6 +182,13 @@ inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
duration = std::max(0, duration);
}
// Add start and stop penalties
if (distance > 0)
duration +=
(target_traversed_in_reverse
? source_node.reverse_duration_penalty + target_node.reverse_duration_penalty
: source_node.forward_duration_penalty + target_node.forward_duration_penalty);
std::string summary;
if (needs_summary)
{
+4 -4
View File
@@ -63,11 +63,11 @@ struct Hint
friend std::ostream &operator<<(std::ostream &, const Hint &);
};
static_assert(sizeof(Hint) == 80 + 4, "Hint is bigger than expected");
constexpr std::size_t ENCODED_HINT_SIZE = 112;
static_assert(sizeof(Hint) == sizeof(PhantomNode) + 4, "Hint is bigger than expected");
constexpr std::size_t ENCODED_HINT_SIZE = 124;
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
"ENCODED_HINT_SIZE does not match size of Hint");
}
}
} // namespace engine
} // namespace osrm
#endif
+24 -16
View File
@@ -50,9 +50,10 @@ struct PhantomNode
forward_distance(INVALID_EDGE_DISTANCE), reverse_distance(INVALID_EDGE_DISTANCE),
forward_distance_offset(0), reverse_distance_offset(0),
forward_duration(MAXIMAL_EDGE_DURATION), reverse_duration(MAXIMAL_EDGE_DURATION),
forward_duration_offset(0), reverse_duration_offset(0), fwd_segment_position(0),
is_valid_forward_source{false}, is_valid_forward_target{false},
is_valid_reverse_source{false}, is_valid_reverse_target{false}, bearing(0)
forward_duration_offset(0), reverse_duration_offset(0), forward_duration_penalty(0),
reverse_duration_penalty(0), fwd_segment_position(0), is_valid_forward_source{false},
is_valid_forward_target{false}, is_valid_reverse_source{false},
is_valid_reverse_target{false}, bearing(0)
{
}
@@ -69,13 +70,13 @@ struct PhantomNode
return reverse_weight_offset + reverse_weight;
}
EdgeWeight GetForwardDuration() const
EdgeDuration GetForwardDuration() const
{
BOOST_ASSERT(forward_segment_id.enabled);
return forward_duration + forward_duration_offset;
}
EdgeWeight GetReverseDuration() const
EdgeDuration GetReverseDuration() const
{
BOOST_ASSERT(reverse_segment_id.enabled);
return reverse_duration + reverse_duration_offset;
@@ -163,10 +164,12 @@ struct PhantomNode
EdgeDistance reverse_distance,
EdgeDistance forward_distance_offset,
EdgeDistance reverse_distance_offset,
EdgeWeight forward_duration,
EdgeWeight reverse_duration,
EdgeWeight forward_duration_offset,
EdgeWeight reverse_duration_offset,
EdgeDuration forward_duration,
EdgeDuration reverse_duration,
EdgeDuration forward_duration_offset,
EdgeDuration reverse_duration_offset,
EdgeDuration forward_duration_penalty,
EdgeDuration reverse_duration_penalty,
bool is_valid_forward_source,
bool is_valid_forward_target,
bool is_valid_reverse_source,
@@ -182,6 +185,8 @@ struct PhantomNode
reverse_distance_offset{reverse_distance_offset}, forward_duration{forward_duration},
reverse_duration{reverse_duration}, forward_duration_offset{forward_duration_offset},
reverse_duration_offset{reverse_duration_offset},
forward_duration_penalty{forward_duration_penalty},
reverse_duration_penalty{reverse_duration_penalty},
component{component.id, component.is_tiny}, location{location},
input_location{input_location}, fwd_segment_position{other.fwd_segment_position},
is_valid_forward_source{is_valid_forward_source},
@@ -201,10 +206,13 @@ struct PhantomNode
EdgeDistance reverse_distance;
EdgeDistance forward_distance_offset; // TODO: try to remove -> requires path unpacking changes
EdgeDistance reverse_distance_offset; // TODO: try to remove -> requires path unpacking changes
EdgeWeight forward_duration;
EdgeWeight reverse_duration;
EdgeWeight forward_duration_offset; // TODO: try to remove -> requires path unpacking changes
EdgeWeight reverse_duration_offset; // TODO: try to remove -> requires path unpacking changes
EdgeDuration forward_duration;
EdgeDuration reverse_duration;
EdgeDuration forward_duration_offset; // TODO: try to remove -> requires path unpacking changes
EdgeDuration reverse_duration_offset; // TODO: try to remove -> requires path unpacking changes
EdgeDuration forward_duration_penalty;
EdgeDuration reverse_duration_penalty;
ComponentID component;
util::Coordinate location; // this is the coordinate of x
@@ -219,7 +227,7 @@ struct PhantomNode
unsigned short bearing : 12;
};
static_assert(sizeof(PhantomNode) == 80, "PhantomNode has more padding then expected");
static_assert(sizeof(PhantomNode) == 88, "PhantomNode has more padding then expected");
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
@@ -234,7 +242,7 @@ struct PhantomNodes
PhantomNode source_phantom;
PhantomNode target_phantom;
};
}
}
} // namespace engine
} // namespace osrm
#endif // PHANTOM_NODES_H
+25 -7
View File
@@ -138,7 +138,8 @@ class BasePlugin
std::vector<std::vector<PhantomNodeWithDistance>>
GetPhantomNodesInRange(const datafacade::BaseDataFacade &facade,
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(
parameters.coordinates.size());
@@ -171,12 +172,13 @@ class BasePlugin
radiuses[i],
parameters.bearings[i]->bearing,
parameters.bearings[i]->range,
approach);
approach,
use_all_edges);
}
else
{
phantom_nodes[i] = facade.NearestPhantomNodesInRange(
parameters.coordinates[i], radiuses[i], approach);
parameters.coordinates[i], radiuses[i], approach, use_all_edges);
}
}
@@ -268,6 +270,7 @@ class BasePlugin
const bool use_bearings = !parameters.bearings.empty();
const bool use_radiuses = !parameters.radiuses.empty();
const bool use_approaches = !parameters.approaches.empty();
const bool use_all_edges = parameters.snapping == api::BaseParameters::SnappingType::Any;
BOOST_ASSERT(parameters.IsValid());
for (const auto i : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
@@ -294,7 +297,10 @@ class BasePlugin
*parameters.radiuses[i],
parameters.bearings[i]->bearing,
parameters.bearings[i]->range,
approach);
approach,
use_all_edges,
parameters.min_stoppage_penalty,
parameters.max_stoppage_penalty);
}
else
{
@@ -303,7 +309,10 @@ class BasePlugin
parameters.coordinates[i],
parameters.bearings[i]->bearing,
parameters.bearings[i]->range,
approach);
approach,
use_all_edges,
parameters.min_stoppage_penalty,
parameters.max_stoppage_penalty);
}
}
else
@@ -312,13 +321,22 @@ class BasePlugin
{
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], *parameters.radiuses[i], approach);
parameters.coordinates[i],
*parameters.radiuses[i],
approach,
use_all_edges,
parameters.min_stoppage_penalty,
parameters.max_stoppage_penalty);
}
else
{
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], approach);
parameters.coordinates[i],
approach,
use_all_edges,
parameters.min_stoppage_penalty,
parameters.max_stoppage_penalty);
}
}
@@ -86,7 +86,7 @@ void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id,
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDuration() + phantom_node.forward_duration_penalty,
-phantom_node.GetForwardDistance()});
}
if (phantom_node.IsValidReverseSource())
@@ -94,7 +94,7 @@ void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDuration() + phantom_node.reverse_duration_penalty,
-phantom_node.GetReverseDistance()});
}
}
@@ -107,7 +107,7 @@ void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id,
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDuration() + phantom_node.forward_duration_penalty,
phantom_node.GetForwardDistance()});
}
if (phantom_node.IsValidReverseTarget())
@@ -115,7 +115,7 @@ void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id,
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDuration() + phantom_node.reverse_duration_penalty,
phantom_node.GetReverseDistance()});
}
}
@@ -89,7 +89,6 @@ class EdgeBasedGraphFactory
// The following get access functions destroy the content in the factory
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes);
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations);
void GetEdgeBasedNodeDistances(std::vector<EdgeDistance> &output_node_distances);
@@ -112,10 +111,6 @@ class EdgeBasedGraphFactory
std::vector<ConditionalTurnPenalty>
IndexConditionals(std::vector<Conditional> &&conditionals) const;
//! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
//! graph
std::vector<bool> m_edge_based_node_is_startpoint;
//! node weights that indicate the length of the segment (node based) represented by the
//! edge-based node
std::vector<EdgeWeight> m_edge_based_node_weights;
@@ -22,7 +22,9 @@ struct EdgeBasedNodeSegment
EdgeBasedNodeSegment()
: forward_segment_id{SPECIAL_SEGMENTID, false},
reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID), v(SPECIAL_NODEID),
fwd_segment_position(std::numeric_limits<unsigned short>::max())
fwd_segment_position(std::numeric_limits<unsigned short>::max() >>
1), // >> 1 because we've only got 15 bits
is_startpoint(false)
{
}
@@ -30,9 +32,10 @@ struct EdgeBasedNodeSegment
const SegmentID reverse_segment_id_,
NodeID u,
NodeID v,
unsigned short fwd_segment_position)
unsigned short fwd_segment_position,
bool is_startpoint_)
: forward_segment_id(forward_segment_id_), reverse_segment_id(reverse_segment_id_), u(u),
v(v), fwd_segment_position(fwd_segment_position)
v(v), fwd_segment_position(fwd_segment_position), is_startpoint(is_startpoint_)
{
BOOST_ASSERT(forward_segment_id.enabled || reverse_segment_id.enabled);
}
@@ -41,7 +44,8 @@ struct EdgeBasedNodeSegment
SegmentID reverse_segment_id; // edge-based graph node ID in reverse direction (v->u if exists)
NodeID u; // node-based graph node ID of the start node
NodeID v; // node-based graph node ID of the target node
unsigned short fwd_segment_position; // segment id in a compressed geometry
unsigned short fwd_segment_position : 15; // segment id in a compressed geometry
bool is_startpoint : 1;
};
}
}
-2
View File
@@ -85,7 +85,6 @@ class Extractor
// output data
EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
std::vector<EdgeDuration> &edge_based_node_durations,
std::vector<EdgeDistance> &edge_based_node_distances,
@@ -97,7 +96,6 @@ class Extractor
const std::vector<EdgeBasedNodeSegment> &input_node_segments,
EdgeBasedNodeDataContainer &nodes_container) const;
void BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments,
std::vector<bool> node_is_startpoint,
const std::vector<util::Coordinate> &coordinates);
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
+81
View File
@@ -0,0 +1,81 @@
#include "util/typedefs.h"
namespace osrm
{
namespace extractor
{
namespace
{
constexpr int 5_MINUTE_BUCKETS_PER_WEEK = 2016;
constexpr int 1_HOUR_BUCKETS_PER_WEEK = 168;
} // namespace
/**
* Represents a simple piecewise linear function
* (https://en.wikipedia.org/wiki/Piecewise_linear_function)
* in the form of a regularly spaced set of buckets.
* Assumes that the spacing between buckets is equal.
*/
template <typename DataType, int BUCKETCOUNT> struct PiecewiseLinearFunction
{
std::array<DataType, BUCKETCOUNT> sample;
inline DataType getAt(float position)
{
// Range check
assert(position >= 0);
assert(position < BUCKETCOUNT - 1);
}
PiecewiseLinearFunction<DataType, BUCKETCOUNT>
merge(PiecewiseLinearFunction<DataType, BUCKETCOUNT> &other, float offset)
{
PiecewiseLinearFunction result;
for (int i = 0; i < BUCKETCOUNT; i++)
{
for (int j = offset; j < BUCKETCOUNT + offset; j++)
{
result.sample[i] = sample[i] + other.sample[j % BUCKETCOUNT];
}
}
return std::move(result);
}
}
/**
* Represents variances in the default `.duration` of an edge
* over the space of a week.
*/
struct WeeklySpeedProfile
{
using Multiplier = std::uint8_t;
private:
PiecewiseLinearFunction<Multiplier, 1_HOUR_BUCKETS_PER_WEEK> fn;
public:
SpeedProfile() : min(0), max(0) { multipliers.fill(0); }
SpeedProfile(const std::array<Multiplier, BUCKETS> &other)
{
fn.samples = other;
min = std::min(samples);
max = std::max(samples);
}
inline EdgeDuration adjust(const EdgeDuration &original, const int bucket) const
{
// Treat Multiplier as an 8-bit fixed-point value.
EdgeDuration new_value = (original * multipliers[bucket]);
}
inline EdgeDuration min(const EdgeDuration original) const {}
inline EdgeDuration max(const EdgeDuration original) const {}
duration = m * e1 + m2 * e2
};
} // namespace extractor
} // namespace osrm
+93 -1
View File
@@ -692,6 +692,80 @@ 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("stoppage_penalty").ToLocalChecked()))
{
v8::Local<v8::Value> stoppage_penalty =
obj->Get(Nan::New("stoppage_penalty").ToLocalChecked());
if (stoppage_penalty.IsEmpty())
return false;
if (!stoppage_penalty->IsArray())
{
Nan::ThrowError("Stoppage penalty must be an array of 2 numbers [min,max]");
return false;
}
auto stoppage_penalty_array = v8::Local<v8::Array>::Cast(stoppage_penalty);
if (stoppage_penalty_array->Length() != 2)
{
Nan::ThrowError("Stoppage penalty must be an array of 2 numbers [min,max]");
return false;
}
if (!stoppage_penalty_array->Get(0)->IsNumber() ||
!stoppage_penalty_array->Get(1)->IsNumber())
{
Nan::ThrowError("Stoppage penalty must be an array of 2 numbers [min,max]");
return false;
}
const auto min = static_cast<short>(stoppage_penalty_array->Get(0)->NumberValue());
const auto max = static_cast<short>(stoppage_penalty_array->Get(1)->NumberValue());
if (min < 0 || max < 0)
{
Nan::ThrowError("Stoppage penalty min/max can't be less than zero");
return false;
}
if (max < min)
{
Nan::ThrowError("Stoppage penalty max must be larger than min");
return false;
}
params->max_stoppage_penalty = min;
params->min_stoppage_penalty = max;
}
return true;
}
@@ -1192,7 +1266,7 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
Nan::ThrowError("fallback_speed must be a number");
return table_parameters_ptr();
}
else if (fallback_speed->NumberValue() < 0)
else if (fallback_speed->NumberValue() <= 0)
{
Nan::ThrowError("fallback_speed must be > 0");
return table_parameters_ptr();
@@ -1229,6 +1303,24 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
}
}
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;
}
+23 -1
View File
@@ -135,6 +135,16 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
},
qi::_1)];
stoppage_rule = qi::lit("stoppage_penalty=") >
(qi::double_ > ',' > qi::double_)[ph::bind(
[](engine::api::BaseParameters &params, double min, double max) {
params.min_stoppage_penalty = min;
params.max_stoppage_penalty = max;
},
qi::_r1,
qi::_1,
qi::_2)];
query_rule =
((location_rule % ';') | polyline_rule |
polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1];
@@ -162,6 +172,13 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
(-approach_type %
';')[ph::bind(&engine::api::BaseParameters::approaches, qi::_r1) = qi::_1];
snapping_type.add("default", engine::api::BaseParameters::SnappingType::Default)(
"any", engine::api::BaseParameters::SnappingType::Any);
snapping_rule =
qi::lit("snapping=") >
snapping_type[ph::bind(&engine::api::BaseParameters::snapping, qi::_r1) = qi::_1];
exclude_rule = qi::lit("exclude=") >
(qi::as_string[+qi::char_("a-zA-Z0-9")] %
',')[ph::bind(&engine::api::BaseParameters::exclude, qi::_r1) = qi::_1];
@@ -171,7 +188,9 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
| bearings_rule(qi::_r1) //
| generate_hints_rule(qi::_r1) //
| approach_rule(qi::_r1) //
| exclude_rule(qi::_r1);
| exclude_rule(qi::_r1) //
| snapping_rule(qi::_r1) //
| stoppage_rule(qi::_r1); //
}
protected:
@@ -188,6 +207,7 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::rule<Iterator, Signature> generate_hints_rule;
qi::rule<Iterator, Signature> approach_rule;
qi::rule<Iterator, Signature> exclude_rule;
qi::rule<Iterator, Signature> stoppage_rule;
qi::rule<Iterator, osrm::engine::Bearing()> bearing_rule;
qi::rule<Iterator, osrm::util::Coordinate()> location_rule;
@@ -197,8 +217,10 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::rule<Iterator, unsigned char()> base64_char;
qi::rule<Iterator, std::string()> polyline_chars;
qi::rule<Iterator, double()> unlimited_rule;
qi::rule<Iterator, Signature> snapping_rule;
qi::symbols<char, engine::Approach> approach_type;
qi::symbols<char, engine::api::BaseParameters::SnappingType> snapping_type;
};
}
}
+17 -12
View File
@@ -18,7 +18,7 @@ namespace
{
namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi;
}
} // namespace
template <typename Iterator = std::string::iterator,
typename Signature = void(engine::api::TableParameters &)>
@@ -56,16 +56,20 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
engine::api::TableParameters::FallbackCoordinateType::Input)(
"snapped", engine::api::TableParameters::FallbackCoordinateType::Snapped);
scale_factor_rule =
qi::lit("scale_factor=") >
(double_)[ph::bind(&engine::api::TableParameters::scale_factor, qi::_r1) = qi::_1];
table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1);
root_rule =
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
-('?' > (table_rule(qi::_r1) | base_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])) %
'&');
root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
-('?' > (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_)
@@ -94,6 +98,7 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
qi::rule<Iterator, Signature> sources_rule;
qi::rule<Iterator, Signature> destinations_rule;
qi::rule<Iterator, Signature> fallback_speed_rule;
qi::rule<Iterator, Signature> scale_factor_rule;
qi::rule<Iterator, std::size_t()> size_t_;
qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations;
qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list;
@@ -101,8 +106,8 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
fallback_coordinate_type;
qi::real_parser<double, json_policy> double_;
};
}
}
}
} // namespace api
} // namespace server
} // namespace osrm
#endif
+2 -2
View File
@@ -488,8 +488,8 @@ inline void Prettify(char *buffer, int length, int k)
inline void dtoa_milo(double value, char *buffer)
{
// Not handling NaN and inf
assert(!isnan(value));
assert(!isinf(value));
assert(!std::isnan(value));
assert(!std::isinf(value));
if (value == 0)
{
+6 -1
View File
@@ -48,7 +48,7 @@ struct osm_way_id
struct duplicated_node
{
};
}
} // namespace tag
using OSMNodeID = osrm::Alias<std::uint64_t, tag::osm_node_id>;
static_assert(std::is_pod<OSMNodeID>(), "OSMNodeID is not a valid alias");
using OSMWayID = osrm::Alias<std::uint64_t, tag::osm_way_id>;
@@ -116,6 +116,11 @@ static const EdgeDuration MAXIMAL_EDGE_DURATION = std::numeric_limits<EdgeDurati
static const EdgeDistance MAXIMAL_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::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_FALLBACK_SPEED = std::numeric_limits<EdgeDistance>::max();
constexpr EdgeDuration INVALID_MINIMUM_STOPPAGE_PENALTY = std::numeric_limits<EdgeDuration>::max();
constexpr EdgeDuration INVALID_MAXIMUM_STOPPAGE_PENALTY = std::numeric_limits<EdgeDuration>::max();
constexpr double MINIMAL_ACCEL_DECEL_PENALIZABLE_SPEED = 10; // metres/second
constexpr double MAXIMAL_ACCEL_DECEL_PENALIZABLE_SPEED = 40; // metres/sec
// 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
+3520 -3532
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -1,13 +1,13 @@
{
"name": "osrm",
"version": "5.20.0-latest.1",
"version": "5.21.0-customsnapping.2",
"private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": {
"mkdirp": "^0.5.1",
"nan": "^2.11.1",
"node-cmake": "^2.3.2",
"node-pre-gyp": "^0.6.36",
"node-pre-gyp": "^0.12.0",
"rimraf": "^2.5.4"
},
"browserify": {
@@ -47,14 +47,14 @@
"csv-stringify": "^3.0.0",
"cucumber": "^1.2.1",
"d3-queue": "^2.0.3",
"docbox": "^1.0.6",
"docbox": "^1.0.11",
"documentation": "^4.0.0-rc.1",
"eslint": "^2.4.0",
"eslint": "^5.10.0",
"faucet": "^0.0.1",
"jsonpath": "^1.0.0",
"node-timeout": "0.0.4",
"polyline": "^0.2.0",
"request": "^2.69.0",
"request": "^2.88.0",
"tape": "^4.7.0",
"turf": "^3.0.14",
"xmlbuilder": "^4.2.1"
+4 -17
View File
@@ -7,6 +7,7 @@ Sequence = require('lib/sequence')
Handlers = require("lib/way_handlers")
find_access_tag = require("lib/access").find_access_tag
limit = require("lib/maxspeed").limit
Measure = require("lib/measure")
function setup()
local default_speed = 15
@@ -206,20 +207,6 @@ function setup()
}
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)
-- parse access and barrier tags
local highway = node:get_value_by_key("highway")
@@ -276,9 +263,9 @@ function handle_bicycle_tags(profile,way,result,data)
-- other tags
data.junction = way:get_value_by_key("junction")
data.maxspeed = parse_maxspeed(way:get_value_by_key ( "maxspeed") )
data.maxspeed_forward = parse_maxspeed(way:get_value_by_key( "maxspeed:forward"))
data.maxspeed_backward = parse_maxspeed(way:get_value_by_key( "maxspeed:backward"))
data.maxspeed = Measure.get_max_speed(way:get_value_by_key ("maxspeed")) or 0
data.maxspeed_forward = Measure.get_max_speed(way:get_value_by_key("maxspeed:forward")) or 0
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.oneway = way:get_value_by_key("oneway")
data.oneway_bicycle = way:get_value_by_key("oneway:bicycle")
+1
View File
@@ -269,6 +269,7 @@ function setup()
["at:rural"] = 100,
["at:trunk"] = 100,
["be:motorway"] = 120,
["be-vlg:rural"] = 70,
["by:urban"] = 60,
["by:motorway"] = 110,
["ch:rural"] = 80,
+19
View File
@@ -6,6 +6,18 @@ Measure = {}
local inch_to_meters = 0.0254
local feet_to_inches = 12
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.
--- according to http://wiki.openstreetmap.org/wiki/Key:maxheight
@@ -42,6 +54,13 @@ function Measure.parse_value_kilograms(value)
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
local default_maxheight = 4.5
-- 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
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)
forward = WayHandlers.parse_maxspeed(forward,profile)
backward = WayHandlers.parse_maxspeed(backward,profile)
@@ -450,12 +450,9 @@ function WayHandlers.parse_maxspeed(source,profile)
if not source then
return 0
end
local n = tonumber(source:match("%d*"))
if n then
if string.match(source, "mph") or string.match(source, "mp/h") then
n = (n*1609)/1000
end
else
local n = Measure.get_max_speed(source)
if not n then
-- parse maxspeed like FR:urban
source = string.lower(source)
n = profile.maxspeed_table[source]
+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);
if (std::all_of(candidates_lists.begin(),
+35 -6
View File
@@ -95,8 +95,12 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("NoTable", "No table found", result);
}
std::vector<api::TableAPI::TableCellRef> estimated_pairs;
// Scan table for null results - if any exist, replace with distance estimates
if (params.fallback_speed > 0)
if (params.fallback_speed != INVALID_FALLBACK_SPEED || params.scale_factor != 1 ||
(params.min_stoppage_penalty != INVALID_MINIMUM_STOPPAGE_PENALTY &&
params.max_stoppage_penalty != INVALID_MAXIMUM_STOPPAGE_PENALTY))
{
for (std::size_t row = 0; row < num_sources; row++)
{
@@ -104,7 +108,12 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
{
const auto &table_index = row * num_destinations + column;
BOOST_ASSERT(table_index < result_tables_pair.first.size());
if (result_tables_pair.first[table_index] == MAXIMAL_EDGE_DURATION)
// Zero out the diagonal
if (result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION && row == column)
result_tables_pair.first[table_index] = 0;
// 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]];
@@ -126,16 +135,36 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
{
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);
}
}
}
}
}
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;
}
}
}
}
} // namespace plugins
} // namespace engine
} // namespace osrm
+12 -1
View File
@@ -294,6 +294,7 @@ struct SpeedLayer : public vtzero::layer_builder
vtzero::index_value key_duration;
vtzero::index_value key_name;
vtzero::index_value key_rate;
vtzero::index_value key_is_startpoint;
SpeedLayer(vtzero::tile_builder &tile)
: 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_weight(add_key_without_dup_check("weight")),
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_is_startpoint(bool value)
{
add_property(m_layer.key_is_startpoint, m_layer.bool_index(value));
}
}; // class SpeedLayerFeatureBuilder
struct TurnsLayer : public vtzero::layer_builder
@@ -485,6 +492,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
const auto reverse_datasource_idx = reverse_datasource_range(
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 name_id = facade.GetNameIndex(edge.forward_segment_id.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_name(name);
fbuilder.set_rate(forward_rate / 10.0);
fbuilder.set_is_startpoint(is_startpoint);
fbuilder.commit();
}
@@ -549,6 +559,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
fbuilder.set_duration(reverse_duration / 10.0);
fbuilder.set_name(name);
fbuilder.set_rate(reverse_rate / 10.0);
fbuilder.set_is_startpoint(is_startpoint);
fbuilder.commit();
}
+2 -10
View File
@@ -95,12 +95,6 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSe
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)
{
using std::swap; // Koenig swap
@@ -229,10 +223,9 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_2]),
current_edge_source_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;
}
@@ -427,7 +420,6 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
}
}
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_durations.size());
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_distances.size());
+8 -23
View File
@@ -239,7 +239,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
EdgeBasedNodeDataContainer edge_based_nodes_container;
std::vector<EdgeBasedNodeSegment> edge_based_node_segments;
util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
std::vector<bool> node_is_startpoint;
std::vector<EdgeWeight> edge_based_node_weights;
std::vector<EdgeDuration> edge_based_node_durations;
std::vector<EdgeDistance> edge_based_node_distances;
@@ -320,7 +319,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
scripting_environment,
edge_based_nodes_container,
edge_based_node_segments,
node_is_startpoint,
edge_based_node_weights,
edge_based_node_durations,
edge_based_node_distances,
@@ -362,7 +360,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
util::Log() << "Building r-tree ...";
TIMER_START(rtree);
BuildRTree(std::move(edge_based_node_segments), std::move(node_is_startpoint), coordinates);
BuildRTree(std::move(edge_based_node_segments), coordinates);
TIMER_STOP(rtree);
@@ -737,7 +735,6 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
// output data
EdgeBasedNodeDataContainer &edge_based_nodes_container,
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
std::vector<EdgeDuration> &edge_based_node_durations,
std::vector<EdgeDistance> &edge_based_node_distances,
@@ -788,7 +785,6 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
edge_based_graph_factory.GetEdgeBasedNodeSegments(edge_based_node_segments);
edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
edge_based_graph_factory.GetEdgeBasedNodeDurations(edge_based_node_durations);
edge_based_graph_factory.GetEdgeBasedNodeDistances(edge_based_node_distances);
@@ -803,35 +799,24 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
Saves tree into '.ramIndex' and leaves into '.fileIndex'.
*/
void Extractor::BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_segments,
std::vector<bool> node_is_startpoint,
const std::vector<util::Coordinate> &coordinates)
{
util::Log() << "Constructing r-tree of " << edge_based_node_segments.size()
<< " segments build on-top of " << coordinates.size() << " coordinates";
BOOST_ASSERT(node_is_startpoint.size() == edge_based_node_segments.size());
// Filter node based edges based on startpoint
auto out_iter = edge_based_node_segments.begin();
auto in_iter = edge_based_node_segments.begin();
for (auto index : util::irange<std::size_t>(0UL, node_is_startpoint.size()))
{
BOOST_ASSERT(in_iter != edge_based_node_segments.end());
if (node_is_startpoint[index])
{
*out_iter = *in_iter;
out_iter++;
}
in_iter++;
}
auto new_size = out_iter - edge_based_node_segments.begin();
if (new_size == 0)
auto start_point_count = std::accumulate(edge_based_node_segments.begin(),
edge_based_node_segments.end(),
0,
[](const size_t so_far, const auto &segment) {
return so_far + (segment.is_startpoint ? 1 : 0);
});
if (start_point_count == 0)
{
throw util::exception("There are no snappable edges left after processing. Are you "
"setting travel modes correctly in the profile? Cannot continue." +
SOURCE_REF);
}
edge_based_node_segments.resize(new_size);
TIMER_START(construction);
util::StaticRTree<EdgeBasedNodeSegment> rtree(
+6 -1
View File
@@ -56,11 +56,16 @@ std::string getWrongOptionHelp(const engine::api::TableParameters &parameters)
help = "Number of coordinates needs to be at least two.";
}
if (parameters.fallback_speed < 0)
if (parameters.fallback_speed <= 0)
{
help = "fallback_speed must be > 0";
}
if (parameters.scale_factor <= 0)
{
help = "scale_factor must be > 0";
}
return help;
}
} // anon. ns
+1
View File
@@ -148,6 +148,7 @@
{"key": "maxspeed", "value": "AT:rural"},
{"key": "maxspeed", "value": "AT:trunk"},
{"key": "maxspeed", "value": "BE:motorway"},
{"key": "maxspeed", "value": "BE-VLG:rural"},
{"key": "maxspeed", "value": "BY:urban"},
{"key": "maxspeed", "value": "BY:motorway"},
{"key": "maxspeed", "value": "CH:rural"},
+1 -1
View File
@@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956],
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
exports.test_tile = {'at': [17059, 11948, 15], 'size': 148750};
exports.test_tile = {'at': [17059, 11948, 15], 'size': 156624};
// Test files generated by the routing engine; check test/data
if (process.env.OSRM_DATA_PATH !== undefined) {
+20
View File
@@ -606,3 +606,23 @@ test('route: route in Monaco without motorways', function(assert) {
});
});
test('route: throws on invalid snapping values', function (assert) {
assert.plan(1);
var osrm = new OSRM(monaco_path);
var options = {
steps: true,
coordinates: three_test_coordinates.concat(three_test_coordinates),
snapping: "zing"
};
assert.throws(function () { osrm.route(options, function (err, response) { console.error(`response: ${response}`); console.error(`error: ${err}`); }); },
/'snapping' param must be one of \[default, any\]/);
});
test('route: snapping parameter passed through OK', function(assert) {
assert.plan(2);
var osrm = new OSRM(monaco_path);
osrm.route({snapping: "any", coordinates: [[7.448205209414596,43.754001097311544],[7.447122039202185,43.75306156811368]]}, function(err, route) {
assert.ifError(err);
assert.equal(Math.round(route.routes[0].distance * 10), 1314); // Round it to nearest 0.1m to eliminate floating point comparison error
});
});
+88 -2
View File
@@ -48,6 +48,21 @@ test('table: test annotations paramater combination', function(assert) {
});
});
test('table: snapping parameter passed through OK', function(assert) {
assert.plan(2);
var osrm = new OSRM(data_path);
var options = {
coordinates: [[7.448205209414596,43.754001097311544],[7.447122039202185,43.75306156811368]],
annotations: ['duration', 'distance'],
snapping: 'any'
};
console.log(options);
osrm.table(options, function(err, result) {
assert.ifError(err);
assert.equal(Math.round(result.distances[0][1] * 10), 1315); // Round it to nearest 0.1m to eliminate floating point comparison error
});
});
test('table: returns buffer', function(assert) {
assert.plan(3);
var osrm = new OSRM(data_path);
@@ -234,7 +249,7 @@ tables.forEach(function(annotation) {
});
test('table: ' + annotation + ' table in Monaco without motorways', function(assert) {
assert.plan(1);
assert.plan(2);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
@@ -243,11 +258,12 @@ tables.forEach(function(annotation) {
};
osrm.table(options, function(err, response) {
assert.equal(response[annotation].length, 2);
assert.strictEqual(response.fallback_speed_cells, undefined);
});
});
test('table: ' + annotation + ' table in Monaco with fallback speeds', function(assert) {
assert.plan(1);
assert.plan(2);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
@@ -257,8 +273,78 @@ tables.forEach(function(annotation) {
};
osrm.table(options, function(err, response) {
assert.equal(response[annotation].length, 2);
assert.equal(response['fallback_speed_cells'].length, 0);
});
});
test('table: ' + annotation + ' table in Monaco with invalid fallback speeds and fallback coordinates', function(assert) {
assert.plan(4);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
annotations: [annotation.slice(0,-1)],
fallback_speed: -1
};
assert.throws(()=>osrm.table(options, (err, res) => {}), /fallback_speed must be > 0/, "should throw on invalid fallback_speeds");
options.fallback_speed = '10';
assert.throws(()=>osrm.table(options, (err, res) => {}), /fallback_speed must be a number/, "should throw on invalid fallback_speeds");
options.fallback_speed = 10;
options.fallback_coordinate = 'bla';
assert.throws(()=>osrm.table(options, (err, res) => {}), /fallback_coordinate' param must be one of \[input, snapped\]/, "should throw on invalid fallback_coordinate");
options.fallback_coordinate = 10;
assert.throws(()=>osrm.table(options, (err, res) => {}), /fallback_coordinate must be a string: \[input, snapped\]/, "should throw on invalid fallback_coordinate");
});
test('table: ' + annotation + ' table in Monaco with invalid scale factor', function(assert) {
assert.plan(3);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
annotations: [annotation.slice(0,-1)],
scale_factor: -1
};
assert.throws(()=>osrm.table(options, (err, res) => {}), /scale_factor must be > 0/, "should throw on invalid scale_factor value");
options.scale_factor = '-1';
assert.throws(()=>osrm.table(options, (err, res) => {}), /scale_factor must be a number/, "should throw on invalid scale_factor value");
options.scale_factor = 0;
assert.throws(()=>osrm.table(options, (err, res) => {}), /scale_factor must be > 0/, "should throw on invalid scale_factor value");
});
test('table: ' + annotation + ' table in Monaco with stoppage_penalty values', function(assert) {
assert.plan(6);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
annotations: [annotation.slice(0,-1)],
stoppage_penalty: [],
};
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty must be an array of 2 numbers/, "should throw on empty array");
options.stoppage_penalty = ['a',1];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty must be an array of 2 numbers/, "should throw on non-numeric value");
options.stoppage_penalty = [1,2,3];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty must be an array of 2 numbers/, "should throw on too many values");
options.stoppage_penalty = [1];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty must be an array of 2 numbers/, "should throw on not enough values");
options.stoppage_penalty = [2,1];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty max must be larger than min/, "should throw on max < min");
options.stoppage_penalty = [-1,2];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty min\/max can't be less than zero/, "should throw on negative value");
});
});
+34 -20
View File
@@ -229,7 +229,8 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
const float /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
const Approach /*approach*/,
const bool /*use_all_edges*/) const override
{
return {};
}
@@ -237,7 +238,8 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/,
const Approach /*approach*/) const override
const Approach /*approach*/,
const bool /*use_all_edges*/) const override
{
return {};
}
@@ -280,36 +282,48 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const Approach /*approach*/) const override
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/,
const Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const Approach /*approach*/) const override
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{
return {};
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/) const override
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/,
const int /*bearing*/,
const int /*bearing_range*/,
const Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{
return {};
}
+6 -3
View File
@@ -36,7 +36,7 @@ void validate_feature_layer(vtzero::layer layer)
BOOST_CHECK_EQUAL(layer.version(), 2);
BOOST_CHECK_EQUAL(to_string(layer.name()), "speeds");
BOOST_CHECK_EQUAL(layer.extent(), osrm::util::vector_tile::EXTENT);
BOOST_CHECK_EQUAL(layer.key_table().size(), 7);
BOOST_CHECK_EQUAL(layer.key_table().size(), 8);
BOOST_CHECK(layer.num_features() > 2500);
while (auto feature = layer.next_feature())
@@ -62,6 +62,9 @@ void validate_feature_layer(vtzero::layer layer)
BOOST_CHECK(props.find("is_small") != props.end());
BOOST_CHECK(props["is_small"].type() == typeid(bool));
BOOST_CHECK(props.find("is_startpoint") != props.end());
BOOST_CHECK(props["is_startpoint"].type() == typeid(bool));
BOOST_CHECK(props.find("datasource") != props.end());
BOOST_CHECK(props["datasource"].type() == typeid(std::string));
@@ -73,7 +76,7 @@ void validate_feature_layer(vtzero::layer layer)
std::count_if(layer.value_table().begin(), layer.value_table().end(), [](auto v) {
return v.type() == vtzero::property_value_type::uint_value;
});
BOOST_CHECK_EQUAL(number_of_uint_values, 77);
BOOST_CHECK_EQUAL(number_of_uint_values, 78);
}
void validate_turn_layer(vtzero::layer layer)
@@ -125,7 +128,7 @@ void validate_node_layer(vtzero::layer layer)
BOOST_CHECK_EQUAL(to_string(layer.name()), "osmnodes");
BOOST_CHECK_EQUAL(layer.extent(), osrm::util::vector_tile::EXTENT);
BOOST_CHECK_EQUAL(layer.key_table().size(), 0);
BOOST_CHECK_EQUAL(layer.num_features(), 1791);
BOOST_CHECK_EQUAL(layer.num_features(), 1810);
while (auto feature = layer.next_feature())
{
+20 -6
View File
@@ -113,7 +113,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
const float /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const engine::Approach /*approach*/) const override
const engine::Approach /*approach*/,
const bool /*use_all_edges*/) const override
{
return {};
}
@@ -121,7 +122,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
std::vector<engine::PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
const float /*max_distance*/,
const engine::Approach /*approach*/) const override
const engine::Approach /*approach*/,
const bool /*use_all_edges*/) const override
{
return {};
}
@@ -167,7 +169,10 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/,
const engine::Approach /*approach*/) const override
const engine::Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{
return {};
}
@@ -176,7 +181,10 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/,
const engine::Approach /*approach*/) const override
const engine::Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{
return {};
}
@@ -187,7 +195,10 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
const double /*max_distance*/,
const int /*bearing*/,
const int /*bearing_range*/,
const engine::Approach /*approach*/) const override
const engine::Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{
return {};
}
@@ -197,7 +208,10 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
const util::Coordinate /*input_coordinate*/,
const int /*bearing*/,
const int /*bearing_range*/,
const engine::Approach /*approach*/) const override
const engine::Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{
return {};
}
+55
View File
@@ -91,6 +91,23 @@ BOOST_AUTO_TEST_CASE(invalid_table_urls)
49UL);
BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?fallback_coordinate=asdf"),
28UL);
BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?fallback_coordinate=10"), 28UL);
BOOST_CHECK_EQUAL(
testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&scale_factor=-1"), 28UL);
BOOST_CHECK_EQUAL(
testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&scale_factor=0"), 28UL);
BOOST_CHECK_EQUAL(
testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&fallback_speed=0"),
28UL);
BOOST_CHECK_EQUAL(
testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&fallback_speed=-1"),
28UL);
BOOST_CHECK_EQUAL(
testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&fallback_speed=0"),
28UL);
BOOST_CHECK_EQUAL(
testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&fallback_speed=-1"),
28UL);
}
BOOST_AUTO_TEST_CASE(valid_route_hint)
@@ -565,6 +582,44 @@ BOOST_AUTO_TEST_CASE(valid_table_urls)
BOOST_CHECK_EQUAL(result_7->annotations & TableParameters::AnnotationsType::Distance, true);
CHECK_EQUAL_RANGE(reference_7.sources, result_7->sources);
CHECK_EQUAL_RANGE(reference_7.destinations, result_7->destinations);
TableParameters reference_8{};
reference_8.coordinates = coords_1;
auto result_8 =
parseParameters<TableParameters>("1,2;3,4?annotations=distance&fallback_speed=2.5");
BOOST_CHECK(result_8);
BOOST_CHECK_EQUAL(result_8->annotations & TableParameters::AnnotationsType::Distance, true);
CHECK_EQUAL_RANGE(reference_8.sources, result_8->sources);
CHECK_EQUAL_RANGE(reference_8.destinations, result_8->destinations);
TableParameters reference_9{};
reference_9.coordinates = coords_1;
auto result_9 = parseParameters<TableParameters>(
"1,2;3,4?annotations=distance&fallback_speed=2.5&fallback_coordinate=input");
BOOST_CHECK(result_9);
BOOST_CHECK_EQUAL(result_9->annotations & TableParameters::AnnotationsType::Distance, true);
CHECK_EQUAL_RANGE(reference_9.sources, result_9->sources);
CHECK_EQUAL_RANGE(reference_9.destinations, result_9->destinations);
TableParameters reference_10{};
reference_10.coordinates = coords_1;
auto result_10 = parseParameters<TableParameters>(
"1,2;3,4?annotations=distance&fallback_speed=20&fallback_coordinate=snapped");
BOOST_CHECK(result_10);
BOOST_CHECK_EQUAL(result_10->annotations & TableParameters::AnnotationsType::Distance, true);
CHECK_EQUAL_RANGE(reference_10.sources, result_10->sources);
CHECK_EQUAL_RANGE(reference_10.destinations, result_10->destinations);
auto result_11 = parseParameters<TableParameters>("1,2;3,4?sources=all&destinations=all&"
"annotations=duration&fallback_speed=1&"
"fallback_coordinate=snapped&scale_factor=2");
BOOST_CHECK(result_11);
CHECK_EQUAL_RANGE(reference_1.sources, result_11->sources);
CHECK_EQUAL_RANGE(reference_1.destinations, result_11->destinations);
CHECK_EQUAL_RANGE(reference_1.bearings, result_11->bearings);
CHECK_EQUAL_RANGE(reference_1.radiuses, result_11->radiuses);
CHECK_EQUAL_RANGE(reference_1.approaches, result_11->approaches);
CHECK_EQUAL_RANGE(reference_1.coordinates, result_11->coordinates);
}
BOOST_AUTO_TEST_CASE(valid_match_urls)
+53 -19
View File
@@ -135,6 +135,7 @@ template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
TestData data;
data.u = edge_udist(g);
data.v = edge_udist(g);
data.is_startpoint = true;
if (used_edges.find(std::pair<unsigned, unsigned>(
std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end())
{
@@ -151,7 +152,7 @@ template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
struct GraphFixture
{
GraphFixture(const std::vector<std::pair<FloatLongitude, FloatLatitude>> &input_coords,
const std::vector<std::pair<unsigned, unsigned>> &input_edges)
const std::vector<std::tuple<unsigned, unsigned, bool>> &input_edges)
{
for (unsigned i = 0; i < input_coords.size(); i++)
@@ -162,15 +163,16 @@ struct GraphFixture
for (const auto &pair : input_edges)
{
TestData d;
d.u = pair.first;
d.v = pair.second;
d.u = std::get<0>(pair);
d.v = std::get<1>(pair);
// We set the forward nodes to the target node-based-node IDs, just
// so we have something to test against. Because this isn't a real
// graph, the actual values aren't important, we just need something
// to examine during tests.
d.forward_segment_id = {pair.second, true};
d.reverse_segment_id = {pair.first, true};
d.forward_segment_id = {std::get<1>(pair), true};
d.reverse_segment_id = {std::get<0>(pair), true};
d.fwd_segment_position = 0;
d.is_startpoint = std::get<2>(pair);
edges.emplace_back(d);
}
}
@@ -299,7 +301,7 @@ BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_M
BOOST_AUTO_TEST_CASE(regression_test)
{
using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::pair<unsigned, unsigned>;
using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture(
{
Coord{FloatLongitude{0.0}, FloatLatitude{40.0}}, //
@@ -313,7 +315,7 @@ BOOST_AUTO_TEST_CASE(regression_test)
Coord{FloatLongitude{105.0}, FloatLatitude{5.0}}, //
Coord{FloatLongitude{110.0}, FloatLatitude{0.0}}, //
},
{Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)});
{Edge(0, 1, true), Edge(2, 3, true), Edge(4, 5, true), Edge(6, 7, true), Edge(8, 9, true)});
TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);
@@ -335,13 +337,13 @@ BOOST_AUTO_TEST_CASE(regression_test)
BOOST_AUTO_TEST_CASE(radius_regression_test)
{
using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::pair<unsigned, unsigned>;
using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture(
{
Coord(FloatLongitude{0.0}, FloatLatitude{0.0}),
Coord(FloatLongitude{10.0}, FloatLatitude{10.0}),
},
{Edge(0, 1), Edge(1, 0)});
{Edge(0, 1, true), Edge(1, 0, true)});
TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);
@@ -352,22 +354,54 @@ BOOST_AUTO_TEST_CASE(radius_regression_test)
Coordinate input(FloatLongitude{5.2}, FloatLatitude{5.0});
{
auto results =
query.NearestPhantomNodesInRange(input, 0.01, osrm::engine::Approach::UNRESTRICTED);
auto results = query.NearestPhantomNodesInRange(
input, 0.01, osrm::engine::Approach::UNRESTRICTED, true);
BOOST_CHECK_EQUAL(results.size(), 0);
}
}
BOOST_AUTO_TEST_CASE(permissive_edge_snapping)
{
using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture(
{
Coord(FloatLongitude{0.0}, FloatLatitude{0.0}),
Coord(FloatLongitude{0.001}, FloatLatitude{0.001}),
},
{Edge(0, 1, true), Edge(1, 0, false)});
TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);
TestDataFacade mockfacade;
engine::GeospatialQuery<MiniStaticRTree, TestDataFacade> query(
rtree, fixture.coords, mockfacade);
Coordinate input(FloatLongitude{0.0005}, FloatLatitude{0.0005});
{
auto results = query.NearestPhantomNodesInRange(
input, 1000, osrm::engine::Approach::UNRESTRICTED, false);
BOOST_CHECK_EQUAL(results.size(), 1);
}
{
auto results = query.NearestPhantomNodesInRange(
input, 1000, osrm::engine::Approach::UNRESTRICTED, true);
BOOST_CHECK_EQUAL(results.size(), 2);
}
}
BOOST_AUTO_TEST_CASE(bearing_tests)
{
using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::pair<unsigned, unsigned>;
using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture(
{
Coord(FloatLongitude{0.0}, FloatLatitude{0.0}),
Coord(FloatLongitude{10.0}, FloatLatitude{10.0}),
},
{Edge(0, 1), Edge(1, 0)});
{Edge(0, 1, true), Edge(1, 0, true)});
TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);
@@ -405,20 +439,20 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
}
{
auto results =
query.NearestPhantomNodesInRange(input, 11000, osrm::engine::Approach::UNRESTRICTED);
auto results = query.NearestPhantomNodesInRange(
input, 11000, osrm::engine::Approach::UNRESTRICTED, true);
BOOST_CHECK_EQUAL(results.size(), 2);
}
{
auto results = query.NearestPhantomNodesInRange(
input, 11000, 270, 10, osrm::engine::Approach::UNRESTRICTED);
input, 11000, 270, 10, osrm::engine::Approach::UNRESTRICTED, true);
BOOST_CHECK_EQUAL(results.size(), 0);
}
{
auto results = query.NearestPhantomNodesInRange(
input, 11000, 45, 10, osrm::engine::Approach::UNRESTRICTED);
input, 11000, 45, 10, osrm::engine::Approach::UNRESTRICTED, true);
BOOST_CHECK_EQUAL(results.size(), 2);
BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
@@ -434,7 +468,7 @@ BOOST_AUTO_TEST_CASE(bearing_tests)
BOOST_AUTO_TEST_CASE(bbox_search_tests)
{
using Coord = std::pair<FloatLongitude, FloatLatitude>;
using Edge = std::pair<unsigned, unsigned>;
using Edge = std::tuple<unsigned, unsigned, bool>;
GraphFixture fixture(
{
@@ -444,7 +478,7 @@ BOOST_AUTO_TEST_CASE(bbox_search_tests)
Coord(FloatLongitude{3.0}, FloatLatitude{3.0}),
Coord(FloatLongitude{4.0}, FloatLatitude{4.0}),
},
{Edge(0, 1), Edge(1, 2), Edge(2, 3), Edge(3, 4)});
{Edge(0, 1, true), Edge(1, 2, true), Edge(2, 3, true), Edge(3, 4, true)});
TemporaryFile tmp;
auto rtree = make_rtree<MiniStaticRTree>(tmp.path, fixture);
-7040
View File
File diff suppressed because it is too large Load Diff