Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9234b2ae76 | |||
| 8b5ade3861 | |||
| baa8214270 | |||
| d41b03b778 | |||
| 31d8ff7a74 | |||
| cb2532d0da | |||
| e222fcfb17 | |||
| 7a5b6dbede | |||
| c08953c0e6 | |||
| 973837207b | |||
| 364e35af06 | |||
| 985ab58f45 | |||
| e5a6c73fdf | |||
| cb1db646f2 | |||
| a67c4bf84d | |||
| 498259b220 | |||
| 5327f8da4e | |||
| 802ccfb497 | |||
| ec369d560a | |||
| 535647e439 | |||
| 954121634f | |||
| 594a45e7e0 | |||
| 96c7b47afe | |||
| b7e7d32361 | |||
| 2f9cb44368 | |||
| d80318f8ea | |||
| b1791d1ab3 | |||
| a53da9095a | |||
| 72e03f9af9 | |||
| 5597415f28 | |||
| 5476f6ab27 | |||
| 0971f06193 |
+58
-1
@@ -13,6 +13,7 @@ notifications:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- "5.20"
|
||||
# enable building tags
|
||||
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||
|
||||
@@ -154,6 +155,14 @@ matrix:
|
||||
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev', 'ccache']
|
||||
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.2
|
||||
compiler: "mason-osx-release-node-10"
|
||||
# we use the xcode provides clang and don't install our own
|
||||
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="10"
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.2
|
||||
compiler: "mason-osx-release-node-8"
|
||||
@@ -276,6 +285,54 @@ matrix:
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-10-mason-linux-release"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="10"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: "node-10-mason-linux-debug"
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['libstdc++-4.9-dev']
|
||||
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="10"
|
||||
install:
|
||||
- pushd ${OSRM_BUILD_DIR}
|
||||
- |
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
|
||||
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
|
||||
-DENABLE_CCACHE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
|
||||
-DENABLE_GLIBC_WORKAROUND=ON
|
||||
- make --jobs=${JOBS}
|
||||
- popd
|
||||
script:
|
||||
- npm run nodejs-tests
|
||||
after_success:
|
||||
- ./scripts/travis/publish.sh
|
||||
|
||||
before_install:
|
||||
- source $NVM_DIR/nvm.sh
|
||||
- nvm install $NODE
|
||||
@@ -296,7 +353,7 @@ before_install:
|
||||
fi
|
||||
- |
|
||||
if [[ ! -f $(which yarn) ]]; then
|
||||
npm install -g yarn
|
||||
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")
|
||||
|
||||
+22
-3
@@ -1,11 +1,30 @@
|
||||
# UNRELEASED
|
||||
# 5.20.0
|
||||
- Changes from 5.19.0:
|
||||
- Table:
|
||||
- CHANGED: switch to pre-calculated distances for table responses for large speedup and 10% memory increase. [#5251](https://github.com/Project-OSRM/osrm-backend/pull/5251)
|
||||
- ADDED: new parameter `fallback_speed` which will fill `null` cells with estimated value [#5257](https://github.com/Project-OSRM/osrm-backend/pull/5257)
|
||||
- CHANGED: Remove API check for matrix sources/destination length to be less than or equal to coordinates length. [#5298](https://github.com/Project-OSRM/osrm-backend/pull/5289)
|
||||
- FIXED: Fix crashing bug when using fallback_speed parameter with more sources than destinations. [#5291](https://github.com/Project-OSRM/osrm-backend/pull/5291)
|
||||
- Features:
|
||||
- ADDED: direct mmapping of datafiles is now supported via the `--mmap` switch. [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
|
||||
- REMOVED: the previous `--memory_file` switch is now deprecated and will fallback to `--mmap` [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
|
||||
- ADDED: Now publishing Node 10.x LTS binary modules [#5246](https://github.com/Project-OSRM/osrm-backend/pull/5246)
|
||||
- Windows:
|
||||
- FIXED: Windows builds again. [#5249](https://github.com/Project-OSRM/osrm-backend/pull/5249)
|
||||
|
||||
# 5.19.0
|
||||
- Changes from 5.18.0:
|
||||
- Optimizations:
|
||||
- CHANGED: Map matching is now almost twice as fast. [#5060](https://github.com/Project-OSRM/osrm-backend/pull/5060)
|
||||
- CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188)
|
||||
- ADDED: Node bindings can return pre-rendered JSON buffer. [#5189](https://github.com/Project-OSRM/osrm-backend/pull/5189)
|
||||
- Profiles:
|
||||
- CHANGED: Bicycle profile now blacklists barriers instead of whitelisting them [#5076
|
||||
](https://github.com/Project-OSRM/osrm-backend/pull/5076/)
|
||||
- CHANGED: Foot profile now blacklists barriers instead of whitelisting them [#5077
|
||||
](https://github.com/Project-OSRM/osrm-backend/pull/5077/)
|
||||
- CHANGED: Support maxlength and maxweight in car profile [#5101](https://github.com/Project-OSRM/osrm-backend/pull/5101]
|
||||
- Bugfixes:
|
||||
- FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114)
|
||||
- FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106)
|
||||
- Misc:
|
||||
- CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185)
|
||||
|
||||
|
||||
+3
-2
@@ -236,8 +236,9 @@ 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.
|
||||
|
|
||||
|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.|
|
||||
|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.|
|
||||
|
||||
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
|
||||
to number of input locations;
|
||||
|
||||
+44
-19
@@ -25,7 +25,9 @@ var osrm = new OSRM('network.osrm');
|
||||
Make sure you prepared the dataset with the correct toolchain.
|
||||
- `options.shared_memory` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Connects to the persistent shared memory datastore.
|
||||
This requires you to run `osrm-datastore` prior to creating an `OSRM` object.
|
||||
- `options.memory_file` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Path to a file on disk to store the memory using mmap.
|
||||
- `options.memory_file` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** *DEPRECATED*
|
||||
Old behaviour: Path to a file on disk to store the memory using mmap. Current behaviour: setting this value is the same as setting `mmap_memory: true`.
|
||||
- `options.mmap_memory` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Map on-disk files to virtual memory addresses (mmap), rather than loading into RAM.
|
||||
- `options.path` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true.
|
||||
- `options.max_locations_trip` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in trip query (default: unlimited).
|
||||
- `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query (default: unlimited).
|
||||
@@ -56,7 +58,7 @@ Returns the fastest route between two or more coordinates while visiting the way
|
||||
- `options.continue_straight` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile.
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
`null`/`true`/`false`
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -88,7 +90,7 @@ Note: `coordinates` in the general options only supports a single `{longitude},{
|
||||
- `options.number` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Number of nearest segments that should be returned.
|
||||
Must be an integer greater than or equal to `1`. (optional, default `1`)
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -127,7 +129,9 @@ tables. Optionally returns distance table.
|
||||
- `options.destinations` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer <
|
||||
#coordinates`) to use location with given index as destination. Default is to use all.
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `options.fallback_speed` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second.
|
||||
- `options.fallback_coordinate` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies diestance between two points.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -167,7 +171,7 @@ and what weights they have applied.
|
||||
- `ZXY` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** an array consisting of `x`, `y`, and `z` values representing tile coordinates like
|
||||
[wiki.openstreetmap.org/wiki/Slippy_map_tilenames](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames)
|
||||
and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -204,7 +208,7 @@ if they can not be matched successfully.
|
||||
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`.
|
||||
- `options.gaps` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore` (optional, default `split`).
|
||||
- `options.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`).
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -268,7 +272,7 @@ Right now, the following combinations are possible:
|
||||
- `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route starts at `any` or `first` coordinate. (optional, default `any`)
|
||||
- `options.destination` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route ends at `any` or `last` coordinate. (optional, default `any`)
|
||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||
|
||||
**Examples**
|
||||
|
||||
@@ -297,9 +301,30 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
|
||||
2) `waypoint_index`: index of the point in the trip.
|
||||
**`trips`**: an array of [`Route`](#route) objects that assemble the trace.
|
||||
|
||||
## Responses
|
||||
## Plugin behaviour
|
||||
|
||||
Responses
|
||||
All plugins support a second additional object that is available to configure some NodeJS specific behaviours.
|
||||
|
||||
- `plugin_config` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query.
|
||||
- `plugin_config.format` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The format of the result object to various API calls. Valid options are `object` (default), which returns a standard Javascript object, as described above, and `json_buffer`, which will return a NodeJS **[Buffer](https://nodejs.org/api/buffer.html)** object, containing a JSON string. The latter has the advantage that it can be immediately serialized to disk/sent over the network, and the generation of the string is performed outside the main NodeJS event loop. This option is ignored by the `tile` plugin.
|
||||
|
||||
**Examples**
|
||||
|
||||
```javascript
|
||||
var osrm = new OSRM('network.osrm');
|
||||
var options = {
|
||||
coordinates: [
|
||||
[13.36761474609375, 52.51663871100423],
|
||||
[13.374481201171875, 52.506191342034576]
|
||||
]
|
||||
};
|
||||
osrm.route(options, { format: "json_buffer" }, function(err, response) {
|
||||
if (err) throw err;
|
||||
console.log(response.toString("utf-8"));
|
||||
});
|
||||
```
|
||||
|
||||
## Responses
|
||||
|
||||
### Route
|
||||
|
||||
@@ -307,8 +332,8 @@ Represents a route through (potentially multiple) waypoints.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](../http.md#route)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#route-object)
|
||||
|
||||
### RouteLeg
|
||||
|
||||
@@ -316,8 +341,8 @@ Represents a route between two waypoints.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](../http.md#routeleg)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#routeleg-object)
|
||||
|
||||
### RouteStep
|
||||
|
||||
@@ -326,15 +351,15 @@ single way to the subsequent step.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#routestep)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#routestep-object)
|
||||
|
||||
### StepManeuver
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#stepmaneuver)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#stepmaneuver-object)
|
||||
|
||||
### Waypoint
|
||||
|
||||
@@ -342,5 +367,5 @@ Object used to describe waypoint on a route.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `exteral` **documentation** in
|
||||
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#waypoint)
|
||||
- **documentation** in
|
||||
[`osrm-backend`](../http.md#waypoint-object)
|
||||
|
||||
@@ -84,7 +84,47 @@ class OSRMDirectLoader extends OSRMBaseLoader {
|
||||
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd));
|
||||
}
|
||||
});
|
||||
callback();
|
||||
|
||||
this.child.readyFunc = (data) => {
|
||||
if (/running and waiting for requests/.test(data)) {
|
||||
this.child.stdout.removeListener('data', this.child.readyFunc);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
this.child.stdout.on('data',this.child.readyFunc);
|
||||
}
|
||||
};
|
||||
|
||||
class OSRMmmapLoader extends OSRMBaseLoader {
|
||||
constructor (scope) {
|
||||
super(scope);
|
||||
}
|
||||
|
||||
load (inputFile, callback) {
|
||||
this.inputFile = inputFile;
|
||||
this.shutdown(() => {
|
||||
this.launch(callback);
|
||||
});
|
||||
}
|
||||
|
||||
osrmUp (callback) {
|
||||
if (this.osrmIsRunning()) return callback(new Error("osrm-routed already running!"));
|
||||
|
||||
const command_arguments = util.format('%s -p %d -i %s -a %s --mmap', this.inputFile, this.scope.OSRM_PORT, this.scope.OSRM_IP, this.scope.ROUTING_ALGORITHM);
|
||||
this.child = this.scope.runBin('osrm-routed', command_arguments, this.scope.environment, (err) => {
|
||||
if (err && err.signal !== 'SIGINT') {
|
||||
this.child = null;
|
||||
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd));
|
||||
}
|
||||
});
|
||||
|
||||
this.child.readyFunc = (data) => {
|
||||
if (/running and waiting for requests/.test(data)) {
|
||||
this.child.stdout.removeListener('data', this.child.readyFunc);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
this.child.stdout.on('data',this.child.readyFunc);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -135,22 +175,32 @@ class OSRMLoader {
|
||||
this.scope = scope;
|
||||
this.sharedLoader = new OSRMDatastoreLoader(this.scope);
|
||||
this.directLoader = new OSRMDirectLoader(this.scope);
|
||||
this.mmapLoader = new OSRMmmapLoader(this.scope);
|
||||
this.method = scope.DEFAULT_LOAD_METHOD;
|
||||
}
|
||||
|
||||
load (inputFile, callback) {
|
||||
if (!this.loader) {
|
||||
this.loader = {shutdown: (cb) => cb() };
|
||||
}
|
||||
if (this.method === 'datastore') {
|
||||
this.directLoader.shutdown((err) => {
|
||||
this.loader.shutdown((err) => {
|
||||
if (err) return callback(err);
|
||||
this.loader = this.sharedLoader;
|
||||
this.sharedLoader.load(inputFile, callback);
|
||||
});
|
||||
} else if (this.method === 'directly') {
|
||||
this.sharedLoader.shutdown((err) => {
|
||||
this.loader.shutdown((err) => {
|
||||
if (err) return callback(err);
|
||||
this.loader = this.directLoader;
|
||||
this.directLoader.load(inputFile, callback);
|
||||
});
|
||||
} else if (this.method === 'mmap') {
|
||||
this.loader.shutdown((err) => {
|
||||
if (err) return callback(err);
|
||||
this.loader = this.mmapLoader;
|
||||
this.mmapLoader.load(inputFile, callback);
|
||||
});
|
||||
} else {
|
||||
callback(new Error('*** Unknown load method ' + method));
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ module.exports = function () {
|
||||
this.DEFAULT_ENVIRONMENT = Object.assign({STXXLCFG: stxxl_config}, process.env);
|
||||
this.DEFAULT_PROFILE = 'bicycle';
|
||||
this.DEFAULT_INPUT_FORMAT = 'osm';
|
||||
this.DEFAULT_LOAD_METHOD = 'datastore';
|
||||
this.DEFAULT_LOAD_METHOD = process.argv[process.argv.indexOf('-m') +1].match('mmap') ? 'mmap' : 'datastore';
|
||||
this.DEFAULT_ORIGIN = [1,1];
|
||||
this.OSM_USER = 'osrm';
|
||||
this.OSM_UID = 1;
|
||||
@@ -80,7 +80,7 @@ module.exports = function () {
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(util.format('Node Version', process.version));
|
||||
if (parseInt(process.version.match(/v(\d)/)[1]) < 4) throw new Error('*** Please upgrade to Node 4.+ to run OSRM cucumber tests');
|
||||
if (parseInt(process.version.match(/v(\d+)/)[1]) < 4) throw new Error('*** Please upgrade to Node 4.+ to run OSRM cucumber tests');
|
||||
|
||||
fs.exists(this.TEST_PATH, (exists) => {
|
||||
if (exists)
|
||||
|
||||
@@ -5,21 +5,49 @@ Feature: Basic Distance Matrix
|
||||
Background:
|
||||
Given the profile "testbot"
|
||||
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network
|
||||
Scenario: Testbot - Travel distance matrix of small grid
|
||||
Given the node map
|
||||
"""
|
||||
a b
|
||||
a b c
|
||||
d e f
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| abc |
|
||||
| def |
|
||||
| ad |
|
||||
| be |
|
||||
| cf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 100+-1 |
|
||||
| b | 100+-1 | 0 |
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
| e | 199.5 | 99.4 | 0 | 100.1 |
|
||||
| f | 299.5 | 199.5 | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network exact distances
|
||||
Given the node map
|
||||
"""
|
||||
a z
|
||||
b
|
||||
c
|
||||
d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| az |
|
||||
| zbcd |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | z | b | c | d |
|
||||
| a | 0 | 100.1 | 199.5 | 298.9 | 398.3 |
|
||||
| z | 100.1 | 0 | 99.4 | 198.8 | 298.2 |
|
||||
| b | 199.5 | 99.4 | 0 | 99.4 | 198.8 |
|
||||
| c | 298.9 | 198.8 | 99.4 | 0 | 99.4 |
|
||||
| d | 398.3 | 298.2 | 198.8 | 99.4 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network with toll exclude
|
||||
Given the query options
|
||||
@@ -39,11 +67,11 @@ Feature: Basic Distance Matrix
|
||||
| bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100+-1 | | |
|
||||
| b | 100+-1 | 0 | | |
|
||||
| c | | | 0 | 100+-1 |
|
||||
| d | | | 100+-1 | 0 |
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100.1 | | |
|
||||
| b | 100.1 | 0 | | |
|
||||
| c | | | 0 | 100.1 |
|
||||
| d | | | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude
|
||||
Given the query options
|
||||
@@ -63,8 +91,8 @@ Feature: Basic Distance Matrix
|
||||
| bd | residential | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 300+-2 | 100+-2 | 200+-2 |
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 298.9 | 99.4 | 199.5 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude
|
||||
Given the query options
|
||||
@@ -84,8 +112,8 @@ Feature: Basic Distance Matrix
|
||||
| efgh | residential | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e |
|
||||
| a | 0 | 50+-1 | |
|
||||
| | a | b | e |
|
||||
| a | 0 | 50.1 | |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes
|
||||
Given the query options
|
||||
@@ -106,7 +134,7 @@ Feature: Basic Distance Matrix
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | g |
|
||||
| a | 0 | 100+-1 | | |
|
||||
| a | 0 | 100.1 | | |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix with different way speeds
|
||||
Given the node map
|
||||
@@ -121,22 +149,22 @@ Feature: Basic Distance Matrix
|
||||
| cd | tertiary |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||
| c | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||
| d | 300+-1 | 200+-1 | 100+-1 | 0 |
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100.1 | 200.1 | 300.2 |
|
||||
| b | 100.1 | 0 | 100.1 | 200.1 |
|
||||
| c | 200.1 | 100.1 | 0 | 100.1 |
|
||||
| d | 300.2 | 200.1 | 100.1 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 100.1 | 200.1 | 300.2 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 100+-1 |
|
||||
| c | 200+-1 |
|
||||
| d | 300+-1 |
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 100.1 |
|
||||
| c | 200.1 |
|
||||
| d | 300.2 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of small grid
|
||||
Given the node map
|
||||
@@ -154,11 +182,11 @@ Feature: Basic Distance Matrix
|
||||
| cf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||
| f | 300+-1 | 200+-1 | 100+-1 | 0 |
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
| e | 199.5 | 99.4 | 0 | 100.1 |
|
||||
| f | 299.5 | 199.5 | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of network with unroutable parts
|
||||
Given the node map
|
||||
@@ -172,7 +200,7 @@ Feature: Basic Distance Matrix
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 100+-1 |
|
||||
| a | 0 | 100.1 |
|
||||
| b | | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix of network with oneways
|
||||
@@ -189,11 +217,11 @@ Feature: Basic Distance Matrix
|
||||
| by | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | x | y | d | e |
|
||||
| x | 0 | 300+-2 | 400+-2 | 300+-2 |
|
||||
| y | 500+-2 | 0 | 300+-2 | 200+-2 |
|
||||
| d | 200+-2 | 300+-2 | 0 | 300+-2 |
|
||||
| e | 300+-2 | 400+-2 | 100+-2 | 0 |
|
||||
| | x | y | d | e |
|
||||
| x | 0 | 300.2 | 399.6 | 299.5 |
|
||||
| y | 499 | 0 | 299.5 | 199.5 |
|
||||
| d | 199.5 | 299.5 | 0 | 298.9 |
|
||||
| e | 299.5 | 399.6 | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Rectangular travel distance matrix
|
||||
Given the node map
|
||||
@@ -212,53 +240,53 @@ Feature: Basic Distance Matrix
|
||||
|
||||
When I route I should get
|
||||
| from | to | distance |
|
||||
| e | a | 200m +- 1 |
|
||||
| e | b | 100m +- 1 |
|
||||
| f | a | 300m +- 1 |
|
||||
| f | b | 200m +- 1 |
|
||||
| e | a | 200m |
|
||||
| e | b | 100m |
|
||||
| f | a | 299.9m |
|
||||
| f | b | 200m |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 100+-1 |
|
||||
| e | 200+-1 |
|
||||
| f | 300+-1 |
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 100.1 |
|
||||
| e | 199.5 |
|
||||
| f | 299.5 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b |
|
||||
| a | 0 | 100+-1 |
|
||||
| b | 100+-1 | 0 |
|
||||
| e | 200+-1 | 100+-1 |
|
||||
| f | 300+-1 | 200+-1 |
|
||||
| | a | b |
|
||||
| a | 0 | 100.1 |
|
||||
| b | 100.1 | 0 |
|
||||
| e | 199.5 | 99.4 |
|
||||
| f | 299.5 | 199.5 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
| e | 199.5 | 99.4 | 0 | 100.1 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e |
|
||||
| a | 0 | 100+-1 | 200+-1 |
|
||||
| b | 100+-1 | 0 | 100+-1 |
|
||||
| e | 200+-1 | 100+-1 | 0 |
|
||||
| f | 300+-1 | 200+-1 | 100+-1 |
|
||||
| | a | b | e |
|
||||
| a | 0 | 100.1 | 199.5 |
|
||||
| b | 100.1 | 0 | 99.4 |
|
||||
| e | 199.5 | 99.4 | 0 |
|
||||
| f | 299.5 | 199.5 | 100.1 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
|
||||
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||
| f | 300+-1 | 200+-1 | 100+-1 | 0 |
|
||||
| | a | b | e | f |
|
||||
| a | 0 | 100.1 | 199.5 | 299.5 |
|
||||
| b | 100.1 | 0 | 99.4 | 199.5 |
|
||||
| e | 199.5 | 99.4 | 0 | 100.1 |
|
||||
| f | 299.5 | 199.5 | 100.1 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance 3x2 matrix
|
||||
Given the node map
|
||||
@@ -277,9 +305,9 @@ Feature: Basic Distance Matrix
|
||||
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | b | e | f |
|
||||
| a | 100+-1 | 200+-1 | 300+-1 |
|
||||
| b | 0 | 100+-1 | 200+-1 |
|
||||
| | b | e | f |
|
||||
| a | 100.1 | 199.5 | 299.5 |
|
||||
| b | 0 | 99.4 | 199.5 |
|
||||
|
||||
Scenario: Testbot - All coordinates are from same small component
|
||||
Given a grid size of 300 meters
|
||||
@@ -299,9 +327,9 @@ Feature: Basic Distance Matrix
|
||||
| fg |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | f | g |
|
||||
| f | 0 | 300+-2 |
|
||||
| g | 300+-2 | 0 |
|
||||
| | f | g |
|
||||
| f | 0 | 298.2 |
|
||||
| g | 298.2 | 0 |
|
||||
|
||||
Scenario: Testbot - Coordinates are from different small component and snap to big CC
|
||||
Given a grid size of 300 meters
|
||||
@@ -333,11 +361,11 @@ Feature: Basic Distance Matrix
|
||||
| i | h | 300m |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | f | g | h | i |
|
||||
| f | 0 | 300+-2 | 0 | 300+-2 |
|
||||
| g | 300+-2 | 0 | 300+-2 | 0 |
|
||||
| h | 0 | 300+-2 | 0 | 300+-2 |
|
||||
| i | 300+-2 | 0 | 300+-2 | 0 |
|
||||
| | f | g | h | i |
|
||||
| f | 0 | 298.2 | 0 | 298.2 |
|
||||
| g | 298.2 | 0 | 298.2 | 0 |
|
||||
| h | 0 | 298.2 | 0 | 298.2 |
|
||||
| i | 298.2 | 0 | 298.2 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix with loops
|
||||
Given the node map
|
||||
@@ -354,11 +382,11 @@ Feature: Basic Distance Matrix
|
||||
| da | yes |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | 1 | 2 | 3 | 4 |
|
||||
| 1 | 0 | 100+-1 | 400+-1 | 500+-1 |
|
||||
| 2 | 700+-1 | 0 | 300+-1 | 400+-1 |
|
||||
| 3 | 400+-1 | 500+-1 | 0 | 100+-1 |
|
||||
| 4 | 300+-1 | 400+-1 | 700+-1 | 0 |
|
||||
| | 1 | 2 | 3 | 4 |
|
||||
| 1 | 0 | 100.1 | 399.6 | 499.7 |
|
||||
| 2 | 699.1 | 0 | 299.5 | 399.6 |
|
||||
| 3 | 399.6 | 499.7 | 0 | 100.1 |
|
||||
| 4 | 299.5 | 399.6 | 699.1 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Travel distance matrix based on segment durations
|
||||
@@ -395,12 +423,12 @@ Feature: Basic Distance Matrix
|
||||
| ce |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d | e |
|
||||
| a | 0 | 100+-2 | 200+-2 | 300+-2 | 400+-2 |
|
||||
| b | 100+-2 | 0 | 100+-2 | 200+-2 | 300+-2 |
|
||||
| c | 200+-2 | 100+-2 | 0 | 100+-2 | 200+-2 |
|
||||
| d | 300+-2 | 200+-2 | 100+-2 | 0 | 300+-2 |
|
||||
| e | 400+-2 | 300+-2 | 200+-2 | 300+-2 | 0 |
|
||||
| | a | b | c | d | e |
|
||||
| a | 0 | 100.1 | 200.1 | 300.2 | 398.9 |
|
||||
| b | 100.1 | 0 | 100.1 | 200.1 | 298.9 |
|
||||
| c | 200.1 | 100.1 | 0 | 100.1 | 198.8 |
|
||||
| d | 300.2 | 200.1 | 100.1 | 0 | 298.9 |
|
||||
| e | 398.9 | 298.9 | 198.8 | 298.9 | 0 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix for alternative loop paths
|
||||
Given the profile file
|
||||
@@ -439,26 +467,26 @@ Feature: Basic Distance Matrix
|
||||
| ca | yes |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
||||
| 1 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 |
|
||||
| 2 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 |
|
||||
| 3 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 |
|
||||
| 4 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 |
|
||||
| 5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 |
|
||||
| 6 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 |
|
||||
| 7 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 |
|
||||
| 8 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 |
|
||||
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
||||
| 1 | 0 | 1096.7 | 298.9 | 199.5 | 598.4 | 498.3 | 897.3 | 797.9 |
|
||||
| 2 | 100.1 | 0 | 398.9 | 299.5 | 698.5 | 598.4 | 997.3 | 897.9 |
|
||||
| 3 | 897.9 | 797.9 | 0 | 1097.4 | 299.5 | 199.5 | 598.4 | 499 |
|
||||
| 4 | 997.3 | 897.3 | 99.4 | 0 | 398.9 | 298.9 | 697.8 | 598.4 |
|
||||
| 5 | 598.4 | 498.3 | 897.3 | 797.9 | 0 | 1096.7 | 298.9 | 199.5 |
|
||||
| 6 | 698.5 | 598.4 | 997.3 | 897.9 | 100.1 | 0 | 398.9 | 299.5 |
|
||||
| 7 | 299.5 | 199.5 | 598.4 | 499 | 897.9 | 797.9 | 0 | 1097.4 |
|
||||
| 8 | 398.9 | 298.9 | 697.8 | 598.4 | 997.3 | 897.3 | 99.4 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | 1 |
|
||||
| 1 | 0 |
|
||||
| 2 | 100+-5 |
|
||||
| 3 | 900+-5 |
|
||||
| 4 | 1000+-5 |
|
||||
| 5 | 600+-5 |
|
||||
| 6 | 700+-5 |
|
||||
| 7 | 300+-5 |
|
||||
| 8 | 400+-5 |
|
||||
| | 1 |
|
||||
| 1 | 0 |
|
||||
| 2 | 100.1 |
|
||||
| 3 | 897.9 |
|
||||
| 4 | 997.3 |
|
||||
| 5 | 598.4 |
|
||||
| 6 | 698.5 |
|
||||
| 7 | 299.5 |
|
||||
| 8 | 398.9 |
|
||||
|
||||
Scenario: Testbot - Travel distance matrix with ties
|
||||
Given the node map
|
||||
@@ -480,26 +508,26 @@ Feature: Basic Distance Matrix
|
||||
| a | c | ac,ac | 200m | 20s | 20 |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | distance |
|
||||
| a | b | ab,ab | 450m |
|
||||
| a | c | ac,ac | 200m |
|
||||
| a | d | ac,dc,dc | 500m +- 1 |
|
||||
| from | to | route | distance |
|
||||
| a | b | ab,ab | 450m |
|
||||
| a | c | ac,ac | 200m |
|
||||
| a | d | ac,dc,dc | 499.9m |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 450+-2 | 200+-2 | 500+-2 |
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 450.3 | 198.8 | 499 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 450+-2 |
|
||||
| c | 200+-2 |
|
||||
| d | 500+-2 |
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 450.3 |
|
||||
| c | 198.8 |
|
||||
| d | 499 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | c |
|
||||
| a | 0 | 200+-2 |
|
||||
| c | 200+-2 | 0 |
|
||||
| | a | c |
|
||||
| a | 0 | 198.8 |
|
||||
| c | 198.8 | 0 |
|
||||
|
||||
|
||||
# Check rounding errors
|
||||
@@ -515,8 +543,8 @@ Feature: Basic Distance Matrix
|
||||
| abcd |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 1000+-3 | 2000+-3 | 3000+-3 |
|
||||
| | a | b | c | d |
|
||||
| a | 0 | 1000.7 | 2001.4 | 3002.1 |
|
||||
|
||||
|
||||
Scenario: Testbot - OneToMany vs ManyToOne
|
||||
@@ -560,10 +588,127 @@ Feature: Basic Distance Matrix
|
||||
| fd | |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | c | d | e | f |
|
||||
| a | 0 | 100+-1 | 300+-1 | 650+-1 | 1930+-1 | 1533+-1 |
|
||||
| b | 760+-1 | 0 | 200+-1 | 550+-1 | 1830+-1 | 1433+-1 |
|
||||
| c | 560+-2 | 660+-2 | 0 | 350+-1 | 1630+-1 | 1233+-1 |
|
||||
| d | 1480+-2 | 1580+-1 | 1780+-1 | 0 | 1280+-1 | 883+-1 |
|
||||
| e | 200+-2 | 300+-2 | 500+-1 | 710+-1 | 0 | 1593+-1 |
|
||||
| f | 597+-1 | 696+-1 | 896+-1 | 1108+-1 | 400+-3 | 0 |
|
||||
| | a | b | c | d | e | f |
|
||||
| a | 0 | 100.1 | 300.2 | 650.5 | 1930.6 | 1533 |
|
||||
| b | 759 | 0 | 200.1 | 550.4 | 1830.5 | 1432.9 |
|
||||
| c | 558.8 | 658.9 | 0 | 350.3 | 1630.4 | 1232.8 |
|
||||
| d | 1478.9 | 1579 | 1779.1 | 0 | 1280.1 | 882.5 |
|
||||
| e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 |
|
||||
| f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 |
|
||||
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1501.1 |
|
||||
| b | 300.2 | 0 | 600.5 | 1200.9 |
|
||||
| f | 900.7 | 600.5 | 0 | 302.2 |
|
||||
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates - use input coordinate
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | input |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1501.1 |
|
||||
| b | 300.2 | 0 | 600.5 | 1200.9 |
|
||||
| f | 900.7 | 600.5 | 0 | 302.2 |
|
||||
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | snapped |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 300.2 | 900.7 | 1200.9 |
|
||||
| b | 300.2 | 0 | 600.5 | 900.7 |
|
||||
| f | 900.7 | 600.5 | 0 | 302.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 |
|
||||
| a | 0 |
|
||||
| b | 300.2 |
|
||||
| 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 |
|
||||
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 |
|
||||
|
||||
@@ -510,3 +510,74 @@ Feature: Basic Duration Matrix
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| b | 24.1 |
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 30 |
|
||||
| b | 30 | 0 | 12 | 24 |
|
||||
| f | 18 | 12 | 0 | 30 |
|
||||
| 1 | 30 | 24 | 30 | 0 |
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates - use input coordinate
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | input |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 30 |
|
||||
| b | 30 | 0 | 12 | 24 |
|
||||
| f | 18 | 12 | 0 | 30 |
|
||||
| 1 | 30 | 24 | 30 | 0 |
|
||||
|
||||
Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate
|
||||
Given a grid size of 300 meters
|
||||
Given the extract extra arguments "--small-component-size 4"
|
||||
Given the query options
|
||||
| fallback_speed | 5 |
|
||||
| fallback_coordinate | snapped |
|
||||
Given the node map
|
||||
"""
|
||||
a b f h 1
|
||||
d e g i
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| abeda |
|
||||
| fhigf |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | b | f | 1 |
|
||||
| a | 0 | 30 | 18 | 24 |
|
||||
| b | 30 | 0 | 12 | 18 |
|
||||
| f | 18 | 12 | 0 | 30 |
|
||||
| 1 | 24 | 18 | 30 | 0 |
|
||||
@@ -792,4 +792,4 @@ Feature: Basic Map Matching
|
||||
When I match I should get
|
||||
| trace | geometry | a:distance | a:duration | a:weight | duration |
|
||||
| 2345 | 1.00018,1,1.000315,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
|
||||
| 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
|
||||
| 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
|
||||
@@ -38,15 +38,15 @@ Feature: Multi level routing
|
||||
Scenario: Testbot - Multi level routing
|
||||
Given the node map
|
||||
"""
|
||||
a───b e───f
|
||||
│ │ │ │
|
||||
a────b e─────f
|
||||
\ │ │ /
|
||||
d───c h───g
|
||||
╲ ╱
|
||||
╳
|
||||
╱ ╲
|
||||
i───j m───n
|
||||
│ │ │ │
|
||||
l───k───p───o
|
||||
/ │ │ \
|
||||
l─────k───p─────o
|
||||
"""
|
||||
|
||||
And the nodes
|
||||
@@ -67,78 +67,76 @@ Feature: Multi level routing
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | time |
|
||||
| a | b | abcda,abcda | 20s |
|
||||
| a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 229.4s |
|
||||
| a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 144.7s |
|
||||
| a | o | abcda,cm,mnopm,mnopm,mnopm | 124.7s |
|
||||
| f | l | efghe,hj,ijkli,ijkli,ijkli | 124.7s |
|
||||
| f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 144.7s |
|
||||
| l | o | ijkli,kp,mnopm,mnopm | 60s |
|
||||
| a | b | abcda,abcda | 25s |
|
||||
| a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 239.2s |
|
||||
| a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 157.1s |
|
||||
| a | o | abcda,cm,mnopm,mnopm,mnopm | 137.1s |
|
||||
| f | l | efghe,hj,ijkli,ijkli | 136.7s |
|
||||
| f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 162.1s |
|
||||
| l | o | ijkli,kp,mnopm,mnopm | 80s |
|
||||
| c | m | cm,cm | 44.7s |
|
||||
| f | a | efghe,hj,ijkli,kp,mnopm,cm,abcda,abcda | 239.2s |
|
||||
| l | a | ijkli,kp,mnopm,cm,abcda,abcda | 157.1s |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 229.4 | 144.7 | 124.7 |
|
||||
| f | 229.4 | 0 | 124.7 | 144.7 |
|
||||
| l | 144.7 | 124.7 | 0 | 60 |
|
||||
| o | 124.7 | 144.7 | 60 | 0 |
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 239.2 | 157.1 | 137.1 |
|
||||
| f | 239.2 | 0 | 136.7 | 162.1 |
|
||||
| l | 157.1 | 136.7 | 0 | 80 |
|
||||
| o | 137.1 | 162.1 | 80 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 229.4 | 144.7 | 124.7 |
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 239.2 | 157.1 | 137.1 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| f | 229.4 |
|
||||
| l | 144.7 |
|
||||
| o | 124.7 |
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| f | 239.2 |
|
||||
| l | 157.1 |
|
||||
| o | 137.1 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 229.4 | 144.7 | 124.7 |
|
||||
| o | 124.7 | 144.7 | 60 | 0 |
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 239.2 | 157.1 | 137.1 |
|
||||
| o | 137.1 | 162.1 | 80 | 0 |
|
||||
|
||||
When I request a travel time matrix I should get
|
||||
| | a | o |
|
||||
| a | 0 | 124.7 |
|
||||
| f | 229.4 | 144.7 |
|
||||
| l | 144.7 | 60 |
|
||||
| o | 124.7 | 0 |
|
||||
|
||||
| a | 0 | 137.1 |
|
||||
| f | 239.2 | 162.1 |
|
||||
| l | 157.1 | 80 |
|
||||
| o | 137.1 | 0 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0+-2 | 2287+-2 | 1443+-2 | 1243+-2 |
|
||||
| f | 2284+-2 | 0+-2 | 1241+-2 | 1443+-2 |
|
||||
| l | 1443+-2 | 1244+-2 | 0+-2 | 600+-2 |
|
||||
| o | 1243+-2 | 1444+-2 | 600+-2 | 0+-2 |
|
||||
| | 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 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 2287.2+-2 | 1443+-2 | 1243+-2 |
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| f | 2284.5+-2 |
|
||||
| l | 1443.1 |
|
||||
| o | 1243 |
|
||||
| | a |
|
||||
| a | 0 |
|
||||
| f | 2339.9 |
|
||||
| l | 1618.3 |
|
||||
| o | 1418.2 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 2287+-2 | 1443+-2 | 1243+-2 |
|
||||
| o | 1243 | 1444+-2 | 600+-2 | 0+-2 |
|
||||
|
||||
| | a | f | l | o |
|
||||
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
|
||||
| f | 2339.9 | 0 | 1198.1 | 1522.1 |
|
||||
|
||||
When I request a travel distance matrix I should get
|
||||
| | a | o |
|
||||
| a | 0+-2 | 1243+-2 |
|
||||
| f | 2284+-2 | 1443+-2 |
|
||||
| l | 1443+-2 | 600+-2 |
|
||||
| o | 1243+-2 | 0+-2 |
|
||||
|
||||
|
||||
| | a | o |
|
||||
| a | 0 | 1366.8 |
|
||||
| f | 2339.9 | 1522.1 |
|
||||
| l | 1618.3 | 800.5 |
|
||||
| o | 1418.2 | 0 |
|
||||
|
||||
Scenario: Testbot - Multi level routing: horizontal road
|
||||
Given the node map
|
||||
|
||||
@@ -72,14 +72,8 @@ struct ContractorConfig final : storage::IOConfig
|
||||
// The remaining vertices form the core of the hierarchy
|
||||
//(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%)
|
||||
double core_factor;
|
||||
|
||||
// Whether to store distances for CH edges in addition to duration/weight
|
||||
// Defaults to false. Setting to true will require more storage/memory,
|
||||
// but avoids the need for path unpacking to learn the distance of a CH
|
||||
// route (useful for faster distance results in table queries)
|
||||
bool cache_distances;
|
||||
};
|
||||
} // namespace contractor
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EXTRACTOR_OPTIONS_HPP
|
||||
|
||||
@@ -77,7 +77,7 @@ struct QueryEdge
|
||||
data.distance == right.data.distance);
|
||||
}
|
||||
};
|
||||
} // namespace contractor
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QUERYEDGE_HPP
|
||||
|
||||
@@ -22,6 +22,7 @@ class CellCustomizer
|
||||
{
|
||||
bool from_clique;
|
||||
EdgeDuration duration;
|
||||
EdgeDistance distance;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -60,7 +61,7 @@ class CellCustomizer
|
||||
}
|
||||
}
|
||||
heap.Clear();
|
||||
heap.Insert(source, 0, {false, 0});
|
||||
heap.Insert(source, 0, {false, 0, 0});
|
||||
|
||||
// explore search space
|
||||
while (!heap.Empty() && !destinations_set.empty())
|
||||
@@ -68,8 +69,18 @@ class CellCustomizer
|
||||
const NodeID node = heap.DeleteMin();
|
||||
const EdgeWeight weight = heap.GetKey(node);
|
||||
const EdgeDuration duration = heap.GetData(node).duration;
|
||||
const EdgeDistance distance = heap.GetData(node).distance;
|
||||
|
||||
RelaxNode(graph, cells, allowed_nodes, metric, heap, level, node, weight, duration);
|
||||
RelaxNode(graph,
|
||||
cells,
|
||||
allowed_nodes,
|
||||
metric,
|
||||
heap,
|
||||
level,
|
||||
node,
|
||||
weight,
|
||||
duration,
|
||||
distance);
|
||||
|
||||
destinations_set.erase(node);
|
||||
}
|
||||
@@ -77,21 +88,27 @@ class CellCustomizer
|
||||
// fill a map of destination nodes to placeholder pointers
|
||||
auto weights = cell.GetOutWeight(source);
|
||||
auto durations = cell.GetOutDuration(source);
|
||||
auto distances = cell.GetOutDistance(source);
|
||||
for (auto &destination : destinations)
|
||||
{
|
||||
BOOST_ASSERT(!weights.empty());
|
||||
BOOST_ASSERT(!durations.empty());
|
||||
BOOST_ASSERT(!distances.empty());
|
||||
|
||||
const bool inserted = heap.WasInserted(destination);
|
||||
weights.front() = inserted ? heap.GetKey(destination) : INVALID_EDGE_WEIGHT;
|
||||
durations.front() =
|
||||
inserted ? heap.GetData(destination).duration : MAXIMAL_EDGE_DURATION;
|
||||
distances.front() =
|
||||
inserted ? heap.GetData(destination).distance : INVALID_EDGE_DISTANCE;
|
||||
|
||||
weights.advance_begin(1);
|
||||
durations.advance_begin(1);
|
||||
distances.advance_begin(1);
|
||||
}
|
||||
BOOST_ASSERT(weights.empty());
|
||||
BOOST_ASSERT(durations.empty());
|
||||
BOOST_ASSERT(distances.empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +145,8 @@ class CellCustomizer
|
||||
LevelID level,
|
||||
NodeID node,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration) const
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance) const
|
||||
{
|
||||
auto first_level = level == 1;
|
||||
BOOST_ASSERT(heap.WasInserted(node));
|
||||
@@ -149,6 +167,7 @@ class CellCustomizer
|
||||
auto subcell = cells.GetCell(metric, level - 1, subcell_id);
|
||||
auto subcell_destination = subcell.GetDestinationNodes().begin();
|
||||
auto subcell_duration = subcell.GetOutDuration(node).begin();
|
||||
auto subcell_distance = subcell.GetOutDistance(node).begin();
|
||||
for (auto subcell_weight : subcell.GetOutWeight(node))
|
||||
{
|
||||
if (subcell_weight != INVALID_EDGE_WEIGHT)
|
||||
@@ -161,20 +180,24 @@ class CellCustomizer
|
||||
|
||||
const EdgeWeight to_weight = weight + subcell_weight;
|
||||
const EdgeDuration to_duration = duration + *subcell_duration;
|
||||
const EdgeDistance to_distance = distance + *subcell_distance;
|
||||
if (!heap.WasInserted(to))
|
||||
{
|
||||
heap.Insert(to, to_weight, {true, to_duration});
|
||||
heap.Insert(to, to_weight, {true, to_duration, to_distance});
|
||||
}
|
||||
else if (std::tie(to_weight, to_duration) <
|
||||
std::tie(heap.GetKey(to), heap.GetData(to).duration))
|
||||
else if (std::tie(to_weight, to_duration, to_distance) <
|
||||
std::tie(heap.GetKey(to),
|
||||
heap.GetData(to).duration,
|
||||
heap.GetData(to).distance))
|
||||
{
|
||||
heap.DecreaseKey(to, to_weight);
|
||||
heap.GetData(to) = {true, to_duration};
|
||||
heap.GetData(to) = {true, to_duration, to_distance};
|
||||
}
|
||||
}
|
||||
|
||||
++subcell_destination;
|
||||
++subcell_duration;
|
||||
++subcell_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,15 +218,18 @@ class CellCustomizer
|
||||
{
|
||||
const EdgeWeight to_weight = weight + data.weight;
|
||||
const EdgeDuration to_duration = duration + data.duration;
|
||||
const EdgeDistance to_distance = distance + data.distance;
|
||||
if (!heap.WasInserted(to))
|
||||
{
|
||||
heap.Insert(to, to_weight, {false, duration + data.duration});
|
||||
heap.Insert(
|
||||
to, to_weight, {false, duration + data.duration, distance + data.distance});
|
||||
}
|
||||
else if (std::tie(to_weight, to_duration) <
|
||||
std::tie(heap.GetKey(to), heap.GetData(to).duration))
|
||||
else if (std::tie(to_weight, to_duration, to_distance) <
|
||||
std::tie(
|
||||
heap.GetKey(to), heap.GetData(to).duration, heap.GetData(to).distance))
|
||||
{
|
||||
heap.DecreaseKey(to, to_weight);
|
||||
heap.GetData(to) = {false, to_duration};
|
||||
heap.GetData(to) = {false, to_duration, to_distance};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ template <storage::Ownership Ownership> struct CellMetricImpl
|
||||
|
||||
Vector<EdgeWeight> weights;
|
||||
Vector<EdgeDuration> durations;
|
||||
Vector<EdgeDistance> distances;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -58,8 +58,10 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
|
||||
|
||||
MultiLevelGraph(PartitionerGraphT &&graph,
|
||||
Vector<EdgeWeight> node_weights_,
|
||||
Vector<EdgeDuration> node_durations_)
|
||||
: node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_))
|
||||
Vector<EdgeDuration> node_durations_,
|
||||
Vector<EdgeDistance> node_distances_)
|
||||
: node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
|
||||
node_distances(std::move(node_distances_))
|
||||
{
|
||||
util::ViewOrVector<PartitionerGraphT::EdgeArrayEntry, storage::Ownership::Container>
|
||||
original_edge_array;
|
||||
@@ -83,11 +85,13 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
|
||||
Vector<EdgeOffset> node_to_edge_offset_,
|
||||
Vector<EdgeWeight> node_weights_,
|
||||
Vector<EdgeDuration> node_durations_,
|
||||
Vector<EdgeDistance> node_distances_,
|
||||
Vector<bool> is_forward_edge_,
|
||||
Vector<bool> is_backward_edge_)
|
||||
: SuperT(std::move(node_array_), std::move(edge_array_), std::move(node_to_edge_offset_)),
|
||||
node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
|
||||
is_forward_edge(is_forward_edge_), is_backward_edge(is_backward_edge_)
|
||||
node_distances(std::move(node_distances_)), is_forward_edge(is_forward_edge_),
|
||||
is_backward_edge(is_backward_edge_)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -95,6 +99,8 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
|
||||
|
||||
EdgeWeight GetNodeDuration(NodeID node) const { return node_durations[node]; }
|
||||
|
||||
EdgeDistance GetNodeDistance(NodeID node) const { return node_distances[node]; }
|
||||
|
||||
bool IsForwardEdge(EdgeID edge) const { return is_forward_edge[edge]; }
|
||||
|
||||
bool IsBackwardEdge(EdgeID edge) const { return is_backward_edge[edge]; }
|
||||
@@ -111,6 +117,7 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
|
||||
protected:
|
||||
Vector<EdgeWeight> node_weights;
|
||||
Vector<EdgeDuration> node_durations;
|
||||
Vector<EdgeDistance> node_distances;
|
||||
Vector<bool> is_forward_edge;
|
||||
Vector<bool> is_backward_edge;
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ inline void read(storage::tar::FileReader &reader,
|
||||
{
|
||||
storage::serialization::read(reader, name + "/weights", metric.weights);
|
||||
storage::serialization::read(reader, name + "/durations", metric.durations);
|
||||
storage::serialization::read(reader, name + "/distances", metric.distances);
|
||||
}
|
||||
|
||||
template <storage::Ownership Ownership>
|
||||
@@ -32,6 +33,7 @@ inline void write(storage::tar::FileWriter &writer,
|
||||
{
|
||||
storage::serialization::write(writer, name + "/weights", metric.weights);
|
||||
storage::serialization::write(writer, name + "/durations", metric.durations);
|
||||
storage::serialization::write(writer, name + "/distances", metric.distances);
|
||||
}
|
||||
|
||||
template <typename EdgeDataT, storage::Ownership Ownership>
|
||||
@@ -42,6 +44,7 @@ inline void read(storage::tar::FileReader &reader,
|
||||
storage::serialization::read(reader, name + "/node_array", graph.node_array);
|
||||
storage::serialization::read(reader, name + "/node_weights", graph.node_weights);
|
||||
storage::serialization::read(reader, name + "/node_durations", graph.node_durations);
|
||||
storage::serialization::read(reader, name + "/node_distances", graph.node_distances);
|
||||
storage::serialization::read(reader, name + "/edge_array", graph.edge_array);
|
||||
storage::serialization::read(reader, name + "/is_forward_edge", graph.is_forward_edge);
|
||||
storage::serialization::read(reader, name + "/is_backward_edge", graph.is_backward_edge);
|
||||
@@ -56,6 +59,7 @@ inline void write(storage::tar::FileWriter &writer,
|
||||
storage::serialization::write(writer, name + "/node_array", graph.node_array);
|
||||
storage::serialization::write(writer, name + "/node_weights", graph.node_weights);
|
||||
storage::serialization::write(writer, name + "/node_durations", graph.node_durations);
|
||||
storage::serialization::write(writer, name + "/node_distances", graph.node_distances);
|
||||
storage::serialization::write(writer, name + "/edge_array", graph.edge_array);
|
||||
storage::serialization::write(writer, name + "/is_forward_edge", graph.is_forward_edge);
|
||||
storage::serialization::write(writer, name + "/is_backward_edge", graph.is_backward_edge);
|
||||
|
||||
@@ -59,6 +59,15 @@ struct TableParameters : public BaseParameters
|
||||
{
|
||||
std::vector<std::size_t> sources;
|
||||
std::vector<std::size_t> destinations;
|
||||
double fallback_speed = 0;
|
||||
|
||||
enum class FallbackCoordinateType
|
||||
{
|
||||
Input = 0,
|
||||
Snapped = 1
|
||||
};
|
||||
|
||||
FallbackCoordinateType fallback_coordinate_type = FallbackCoordinateType::Input;
|
||||
|
||||
enum class AnnotationsType
|
||||
{
|
||||
@@ -90,6 +99,19 @@ struct TableParameters : public BaseParameters
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
TableParameters(std::vector<std::size_t> sources_,
|
||||
std::vector<std::size_t> destinations_,
|
||||
const AnnotationsType annotations_,
|
||||
double fallback_speed_,
|
||||
FallbackCoordinateType fallback_coordinate_type_,
|
||||
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_}
|
||||
{
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
if (!BaseParameters::IsValid())
|
||||
@@ -101,14 +123,7 @@ struct TableParameters : public BaseParameters
|
||||
|
||||
// 1/ The user is able to specify duplicates in srcs and dsts, in that case it's their fault
|
||||
|
||||
// 2/ len(srcs) and len(dsts) smaller or equal to len(locations)
|
||||
if (sources.size() > coordinates.size())
|
||||
return false;
|
||||
|
||||
if (destinations.size() > coordinates.size())
|
||||
return false;
|
||||
|
||||
// 3/ 0 <= index < len(locations)
|
||||
// 2/ 0 <= index < len(locations)
|
||||
const auto not_in_range = [this](const std::size_t x) { return x >= coordinates.size(); };
|
||||
|
||||
if (std::any_of(begin(sources), end(sources), not_in_range))
|
||||
@@ -117,6 +132,9 @@ struct TableParameters : public BaseParameters
|
||||
if (std::any_of(begin(destinations), end(destinations), not_in_range))
|
||||
return false;
|
||||
|
||||
if (fallback_speed < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -78,6 +78,8 @@ template <> class AlgorithmDataFacade<MLD>
|
||||
|
||||
virtual EdgeWeight GetNodeDuration(const NodeID node) const = 0; // TODO: to be removed
|
||||
|
||||
virtual EdgeDistance GetNodeDistance(const NodeID node) const = 0;
|
||||
|
||||
virtual bool IsForwardEdge(EdgeID edge) const = 0;
|
||||
|
||||
virtual bool IsBackwardEdge(EdgeID edge) const = 0;
|
||||
|
||||
@@ -697,6 +697,11 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
|
||||
return query_graph.GetNodeDuration(node);
|
||||
}
|
||||
|
||||
EdgeDistance GetNodeDistance(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.GetNodeDistance(node);
|
||||
}
|
||||
|
||||
bool IsForwardEdge(const NodeID node) const override final
|
||||
{
|
||||
return query_graph.IsForwardEdge(node);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <boost/iostreams/device/mapped_file.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -24,8 +25,7 @@ namespace datafacade
|
||||
class MMapMemoryAllocator : public ContiguousBlockAllocator
|
||||
{
|
||||
public:
|
||||
explicit MMapMemoryAllocator(const storage::StorageConfig &config,
|
||||
const boost::filesystem::path &memory_file);
|
||||
explicit MMapMemoryAllocator(const storage::StorageConfig &config);
|
||||
~MMapMemoryAllocator() override final;
|
||||
|
||||
// interface to give access to the datafacades
|
||||
@@ -33,8 +33,8 @@ class MMapMemoryAllocator : public ContiguousBlockAllocator
|
||||
|
||||
private:
|
||||
storage::SharedDataIndex index;
|
||||
util::vector_view<char> mapped_memory;
|
||||
boost::iostreams::mapped_file mapped_memory_file;
|
||||
std::vector<boost::iostreams::mapped_file> mapped_memory_files;
|
||||
std::string rtree_filename;
|
||||
};
|
||||
|
||||
} // namespace datafacade
|
||||
|
||||
@@ -32,9 +32,8 @@ class ExternalProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
|
||||
public:
|
||||
using Facade = typename DataFacadeProvider<AlgorithmT, FacadeT>::Facade;
|
||||
|
||||
ExternalProvider(const storage::StorageConfig &config,
|
||||
const boost::filesystem::path &memory_file)
|
||||
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config, memory_file))
|
||||
ExternalProvider(const storage::StorageConfig &config)
|
||||
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -63,12 +63,16 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
||||
<< "\" with algorithm " << routing_algorithms::name<Algorithm>();
|
||||
facade_provider = std::make_unique<WatchingProvider<Algorithm>>(config.dataset_name);
|
||||
}
|
||||
else if (!config.memory_file.empty())
|
||||
else if (!config.memory_file.empty() || config.use_mmap)
|
||||
{
|
||||
util::Log(logDEBUG) << "Using memory mapped filed at " << config.memory_file
|
||||
<< " with algorithm " << routing_algorithms::name<Algorithm>();
|
||||
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config,
|
||||
config.memory_file);
|
||||
if (!config.memory_file.empty())
|
||||
{
|
||||
util::Log(logWARNING)
|
||||
<< "The 'memory_file' option is DEPRECATED - using direct mmaping instead";
|
||||
}
|
||||
util::Log(logDEBUG) << "Using direct memory mapping with algorithm "
|
||||
<< routing_algorithms::name<Algorithm>();
|
||||
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -89,6 +89,7 @@ struct EngineConfig final
|
||||
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
||||
bool use_shared_memory = true;
|
||||
boost::filesystem::path memory_file;
|
||||
bool use_mmap = true;
|
||||
Algorithm algorithm = Algorithm::CH;
|
||||
std::string verbosity;
|
||||
std::string dataset_name;
|
||||
|
||||
@@ -449,7 +449,6 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id);
|
||||
|
||||
const auto forward_geometry = datafacade.GetUncompressedForwardGeometry(geometry_id);
|
||||
const auto reverse_geometry = datafacade.GetUncompressedReverseGeometry(geometry_id);
|
||||
|
||||
const auto forward_weight_offset =
|
||||
std::accumulate(forward_weights.begin(),
|
||||
@@ -480,19 +479,19 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position)),
|
||||
point_on_segment);
|
||||
|
||||
const auto rev_segment_position = reverse_weights.size() - data.fwd_segment_position - 1;
|
||||
|
||||
const auto reverse_weight_offset = std::accumulate(
|
||||
reverse_weights.begin(), reverse_weights.begin() + rev_segment_position, EdgeWeight{0});
|
||||
const auto reverse_weight_offset =
|
||||
std::accumulate(reverse_weights.begin(),
|
||||
reverse_weights.end() - data.fwd_segment_position - 1,
|
||||
EdgeWeight{0});
|
||||
|
||||
const auto reverse_duration_offset =
|
||||
std::accumulate(reverse_durations.begin(),
|
||||
reverse_durations.begin() + rev_segment_position,
|
||||
reverse_durations.end() - data.fwd_segment_position - 1,
|
||||
EdgeDuration{0});
|
||||
|
||||
EdgeDistance reverse_distance_offset = 0;
|
||||
for (auto current = reverse_geometry.begin();
|
||||
current < reverse_geometry.begin() + rev_segment_position;
|
||||
for (auto current = forward_geometry.begin();
|
||||
current < forward_geometry.end() - data.fwd_segment_position - 2;
|
||||
++current)
|
||||
{
|
||||
reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance(
|
||||
@@ -500,11 +499,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
datafacade.GetCoordinateOfNode(*std::next(current)));
|
||||
}
|
||||
|
||||
EdgeWeight reverse_weight = reverse_weights[rev_segment_position];
|
||||
EdgeDuration reverse_duration = reverse_durations[rev_segment_position];
|
||||
EdgeWeight reverse_weight =
|
||||
reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1];
|
||||
EdgeDuration reverse_duration =
|
||||
reverse_durations[reverse_durations.size() - data.fwd_segment_position - 1];
|
||||
EdgeDistance reverse_distance = util::coordinate_calculation::fccApproximateDistance(
|
||||
point_on_segment,
|
||||
datafacade.GetCoordinateOfNode(reverse_geometry(rev_segment_position)));
|
||||
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1)));
|
||||
|
||||
ratio = std::min(1.0, std::max(0.0, ratio));
|
||||
if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
|
||||
@@ -692,7 +693,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
const CoordinateList &coordinates;
|
||||
DataFacadeT &datafacade;
|
||||
};
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -34,8 +34,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
@@ -46,15 +44,14 @@ namespace engine
|
||||
struct PhantomNode
|
||||
{
|
||||
PhantomNode()
|
||||
: forward_segment_id{SPECIAL_SEGMENTID, false}, reverse_segment_id{SPECIAL_SEGMENTID,
|
||||
false},
|
||||
forward_weight(INVALID_EDGE_WEIGHT), reverse_weight(INVALID_EDGE_WEIGHT),
|
||||
forward_weight_offset(0), reverse_weight_offset(0),
|
||||
: forward_segment_id{SPECIAL_SEGMENTID, false},
|
||||
reverse_segment_id{SPECIAL_SEGMENTID, false}, forward_weight(INVALID_EDGE_WEIGHT),
|
||||
reverse_weight(INVALID_EDGE_WEIGHT), forward_weight_offset(0), reverse_weight_offset(0),
|
||||
forward_distance(INVALID_EDGE_DISTANCE), reverse_distance(INVALID_EDGE_DISTANCE),
|
||||
forward_distance_offset(0), reverse_distance_offset(0),
|
||||
forward_duration(MAXIMAL_EDGE_DURATION), reverse_duration(MAXIMAL_EDGE_DURATION),
|
||||
forward_duration_offset(0), reverse_duration_offset(0),
|
||||
fwd_segment_position(0), is_valid_forward_source{false}, is_valid_forward_target{false},
|
||||
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)
|
||||
|
||||
{
|
||||
@@ -112,9 +109,8 @@ struct PhantomNode
|
||||
|
||||
bool IsValid(const unsigned number_of_nodes) const
|
||||
{
|
||||
return location.IsValid() &&
|
||||
((forward_segment_id.id < number_of_nodes) ||
|
||||
(reverse_segment_id.id < number_of_nodes)) &&
|
||||
return location.IsValid() && ((forward_segment_id.id < number_of_nodes) ||
|
||||
(reverse_segment_id.id < number_of_nodes)) &&
|
||||
((forward_weight != INVALID_EDGE_WEIGHT) ||
|
||||
(reverse_weight != INVALID_EDGE_WEIGHT)) &&
|
||||
((forward_duration != MAXIMAL_EDGE_DURATION) ||
|
||||
@@ -238,7 +234,7 @@ struct PhantomNodes
|
||||
PhantomNode source_phantom;
|
||||
PhantomNode target_phantom;
|
||||
};
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PHANTOM_NODES_H
|
||||
|
||||
@@ -34,8 +34,7 @@ class RoutingAlgorithmsInterface
|
||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration) const = 0;
|
||||
const bool calculate_distance) const = 0;
|
||||
|
||||
virtual routing_algorithms::SubMatchingList
|
||||
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
|
||||
@@ -88,8 +87,7 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
||||
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration) const final override;
|
||||
const bool calculate_distance) const final override;
|
||||
|
||||
routing_algorithms::SubMatchingList
|
||||
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
|
||||
@@ -198,8 +196,7 @@ std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &_source_indices,
|
||||
const std::vector<std::size_t> &_target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration) const
|
||||
const bool calculate_distance) const
|
||||
{
|
||||
BOOST_ASSERT(!phantom_nodes.empty());
|
||||
|
||||
@@ -222,8 +219,7 @@ RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &p
|
||||
phantom_nodes,
|
||||
std::move(source_indices),
|
||||
std::move(target_indices),
|
||||
calculate_distance,
|
||||
calculate_duration);
|
||||
calculate_distance);
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
|
||||
@@ -97,8 +97,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration);
|
||||
const bool calculate_distance);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
|
||||
@@ -44,13 +44,44 @@ bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &ta
|
||||
bool needsLoopForward(const PhantomNodes &phantoms);
|
||||
bool needsLoopBackwards(const PhantomNodes &phantoms);
|
||||
|
||||
namespace detail
|
||||
template <typename Heap>
|
||||
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
|
||||
{
|
||||
template <typename Algorithm>
|
||||
void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
const auto &source = nodes.source_phantom;
|
||||
if (source.IsValidForwardSource())
|
||||
{
|
||||
forward_heap.Insert(source.forward_segment_id.id,
|
||||
-source.GetForwardWeightPlusOffset(),
|
||||
source.forward_segment_id.id);
|
||||
}
|
||||
|
||||
if (source.IsValidReverseSource())
|
||||
{
|
||||
forward_heap.Insert(source.reverse_segment_id.id,
|
||||
-source.GetReverseWeightPlusOffset(),
|
||||
source.reverse_segment_id.id);
|
||||
}
|
||||
|
||||
const auto &target = nodes.target_phantom;
|
||||
if (target.IsValidForwardTarget())
|
||||
{
|
||||
reverse_heap.Insert(target.forward_segment_id.id,
|
||||
target.GetForwardWeightPlusOffset(),
|
||||
target.forward_segment_id.id);
|
||||
}
|
||||
|
||||
if (target.IsValidReverseTarget())
|
||||
{
|
||||
reverse_heap.Insert(target.reverse_segment_id.id,
|
||||
target.GetReverseWeightPlusOffset(),
|
||||
target.reverse_segment_id.id);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ManyToManyQueryHeap>
|
||||
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
@@ -58,7 +89,7 @@ void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHea
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance()});
|
||||
}
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
@@ -68,9 +99,8 @@ void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHea
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
void insertTargetInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
template <typename ManyToManyQueryHeap>
|
||||
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
{
|
||||
@@ -90,109 +120,6 @@ void insertTargetInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHea
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
void insertSourceInHeap(typename SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.forward_segment_id.id);
|
||||
}
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.reverse_segment_id.id);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
void insertTargetInHeap(typename SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.forward_segment_id.id);
|
||||
}
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.reverse_segment_id.id);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline void insertTargetInHeap(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
detail::insertTargetInHeap<mld::Algorithm>(heap, phantom_node);
|
||||
}
|
||||
inline void insertTargetInHeap(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
detail::insertTargetInHeap<ch::Algorithm>(heap, phantom_node);
|
||||
}
|
||||
inline void insertTargetInHeap(typename SearchEngineData<mld::Algorithm>::QueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
detail::insertTargetInHeap<mld::Algorithm>(heap, phantom_node);
|
||||
}
|
||||
inline void insertTargetInHeap(typename SearchEngineData<ch::Algorithm>::QueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
detail::insertTargetInHeap<ch::Algorithm>(heap, phantom_node);
|
||||
}
|
||||
inline void insertSourceInHeap(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
detail::insertSourceInHeap<mld::Algorithm>(heap, phantom_node);
|
||||
}
|
||||
inline void insertSourceInHeap(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
detail::insertSourceInHeap<ch::Algorithm>(heap, phantom_node);
|
||||
}
|
||||
inline void insertSourceInHeap(typename SearchEngineData<mld::Algorithm>::QueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
detail::insertSourceInHeap<mld::Algorithm>(heap, phantom_node);
|
||||
}
|
||||
inline void insertSourceInHeap(typename SearchEngineData<ch::Algorithm>::QueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
detail::insertSourceInHeap<ch::Algorithm>(heap, phantom_node);
|
||||
}
|
||||
|
||||
template <typename Heap>
|
||||
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
|
||||
{
|
||||
insertSourceInHeap(forward_heap, nodes.source_phantom);
|
||||
insertTargetInHeap(reverse_heap, nodes.target_phantom);
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()});
|
||||
}
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
{phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FacadeT>
|
||||
void annotatePath(const FacadeT &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
@@ -402,10 +329,58 @@ void annotatePath(const FacadeT &facade,
|
||||
}
|
||||
}
|
||||
|
||||
EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector<NodeID> &path,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const EdgeDistance distance);
|
||||
template <typename Algorithm>
|
||||
double getPathDistance(const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PathData> unpacked_path,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom)
|
||||
{
|
||||
using util::coordinate_calculation::detail::DEGREE_TO_RAD;
|
||||
using util::coordinate_calculation::detail::EARTH_RADIUS;
|
||||
|
||||
double distance = 0;
|
||||
double prev_lat =
|
||||
static_cast<double>(util::toFloating(source_phantom.location.lat)) * DEGREE_TO_RAD;
|
||||
double prev_lon =
|
||||
static_cast<double>(util::toFloating(source_phantom.location.lon)) * DEGREE_TO_RAD;
|
||||
double prev_cos = std::cos(prev_lat);
|
||||
for (const auto &p : unpacked_path)
|
||||
{
|
||||
const auto current_coordinate = facade.GetCoordinateOfNode(p.turn_via_node);
|
||||
|
||||
const double current_lat =
|
||||
static_cast<double>(util::toFloating(current_coordinate.lat)) * DEGREE_TO_RAD;
|
||||
const double current_lon =
|
||||
static_cast<double>(util::toFloating(current_coordinate.lon)) * DEGREE_TO_RAD;
|
||||
const double current_cos = std::cos(current_lat);
|
||||
|
||||
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
|
||||
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
|
||||
|
||||
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
|
||||
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
|
||||
distance += EARTH_RADIUS * charv;
|
||||
|
||||
prev_lat = current_lat;
|
||||
prev_lon = current_lon;
|
||||
prev_cos = current_cos;
|
||||
}
|
||||
|
||||
const double current_lat =
|
||||
static_cast<double>(util::toFloating(target_phantom.location.lat)) * DEGREE_TO_RAD;
|
||||
const double current_lon =
|
||||
static_cast<double>(util::toFloating(target_phantom.location.lon)) * DEGREE_TO_RAD;
|
||||
const double current_cos = std::cos(current_lat);
|
||||
|
||||
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
|
||||
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
|
||||
|
||||
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
|
||||
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
|
||||
distance += EARTH_RADIUS * charv;
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
template <typename AlgorithmT>
|
||||
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
||||
|
||||
@@ -186,7 +186,7 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
|
||||
template <bool UseDuration>
|
||||
std::tuple<EdgeWeight,EdgeDistance> getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
||||
std::tuple<EdgeWeight, EdgeDistance> getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
||||
{
|
||||
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT;
|
||||
EdgeDistance loop_distance = MAXIMAL_EDGE_DISTANCE;
|
||||
|
||||
@@ -97,6 +97,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
const std::vector<std::size_t> &phantom_indices)
|
||||
{
|
||||
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
|
||||
|
||||
const auto &forward_segment = phantom_node.forward_segment_id;
|
||||
const auto forward_level =
|
||||
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
|
||||
@@ -119,7 +120,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
}
|
||||
|
||||
// Heaps only record for each node its predecessor ("parent") on the shortest path.
|
||||
// For re-constructing the actual path we need to trace back all parent "pointers".
|
||||
@@ -390,27 +391,21 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
EdgeWeight weight_upper_bound,
|
||||
Args... args)
|
||||
{
|
||||
if (forward_heap.Empty() && reverse_heap.Empty())
|
||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||
{
|
||||
return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector<NodeID>(), std::vector<EdgeID>());
|
||||
}
|
||||
|
||||
const auto &partition = facade.GetMultiLevelPartition();
|
||||
|
||||
BOOST_ASSERT(forward_heap.Empty() || forward_heap.MinKey() < INVALID_EDGE_WEIGHT);
|
||||
BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() < INVALID_EDGE_WEIGHT);
|
||||
BOOST_ASSERT(!forward_heap.Empty() && forward_heap.MinKey() < INVALID_EDGE_WEIGHT);
|
||||
BOOST_ASSERT(!reverse_heap.Empty() && reverse_heap.MinKey() < INVALID_EDGE_WEIGHT);
|
||||
|
||||
// run two-Target Dijkstra routing step.
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
EdgeWeight weight = weight_upper_bound;
|
||||
|
||||
EdgeWeight forward_heap_min = 0;
|
||||
if (!forward_heap.Empty())
|
||||
forward_heap_min = forward_heap.MinKey();
|
||||
EdgeWeight reverse_heap_min = 0;
|
||||
if (!reverse_heap.Empty())
|
||||
reverse_heap_min = reverse_heap.MinKey();
|
||||
|
||||
EdgeWeight forward_heap_min = forward_heap.MinKey();
|
||||
EdgeWeight reverse_heap_min = reverse_heap.MinKey();
|
||||
while (forward_heap.Size() + reverse_heap.Size() > 0 &&
|
||||
forward_heap_min + reverse_heap_min < weight)
|
||||
{
|
||||
@@ -514,90 +509,6 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
|
||||
}
|
||||
|
||||
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
|
||||
// This gives us a packed path (node ids) from the base graph around s and t,
|
||||
// and overlay node ids otherwise. We then have to unpack the overlay clique
|
||||
// edges by recursively descending unpacking the path down to the base graph.
|
||||
|
||||
using UnpackedNodes = std::vector<NodeID>;
|
||||
using UnpackedEdges = std::vector<EdgeID>;
|
||||
using UnpackedPath = std::tuple<EdgeWeight, UnpackedNodes, UnpackedEdges>;
|
||||
|
||||
template <typename Algorithm, typename... Args>
|
||||
UnpackedPath
|
||||
unpackPathAndCalculateDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
EdgeWeight weight_upper_bound,
|
||||
PackedPath packed_path,
|
||||
NodeID middle,
|
||||
Args... args)
|
||||
{
|
||||
EdgeWeight weight = weight_upper_bound;
|
||||
const auto &partition = facade.GetMultiLevelPartition();
|
||||
const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle;
|
||||
|
||||
// Unpack path
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
std::vector<EdgeID> unpacked_edges;
|
||||
unpacked_nodes.reserve(packed_path.size());
|
||||
unpacked_edges.reserve(packed_path.size());
|
||||
|
||||
unpacked_nodes.push_back(source_node);
|
||||
|
||||
for (auto const &packed_edge : packed_path)
|
||||
{
|
||||
NodeID source, target;
|
||||
bool overlay_edge;
|
||||
std::tie(source, target, overlay_edge) = packed_edge;
|
||||
if (!overlay_edge)
|
||||
{ // a base graph edge
|
||||
unpacked_nodes.push_back(target);
|
||||
unpacked_edges.push_back(facade.FindEdge(source, target));
|
||||
}
|
||||
else
|
||||
{ // an overlay graph edge
|
||||
LevelID level = getNodeQueryLevel(partition, source, args...);
|
||||
CellID parent_cell_id = partition.GetCell(level, source);
|
||||
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
|
||||
|
||||
LevelID sublevel = level - 1;
|
||||
|
||||
// Here heaps can be reused, let's go deeper!
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
forward_heap.Insert(source, 0, {source});
|
||||
reverse_heap.Insert(target, 0, {target});
|
||||
|
||||
// TODO: when structured bindings will be allowed change to
|
||||
// auto [subpath_weight, subpath_source, subpath_target, subpath] = ...
|
||||
EdgeWeight subpath_weight;
|
||||
std::vector<NodeID> subpath_nodes;
|
||||
std::vector<EdgeID> subpath_edges;
|
||||
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
force_loop_forward,
|
||||
force_loop_reverse,
|
||||
weight_upper_bound,
|
||||
sublevel,
|
||||
parent_cell_id);
|
||||
BOOST_ASSERT(!subpath_edges.empty());
|
||||
BOOST_ASSERT(subpath_nodes.size() > 1);
|
||||
BOOST_ASSERT(subpath_nodes.front() == source);
|
||||
BOOST_ASSERT(subpath_nodes.back() == target);
|
||||
unpacked_nodes.insert(
|
||||
unpacked_nodes.end(), std::next(subpath_nodes.begin()), subpath_nodes.end());
|
||||
unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end());
|
||||
}
|
||||
}
|
||||
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
|
||||
}
|
||||
|
||||
// Alias to be compatible with the CH-based search
|
||||
template <typename Algorithm>
|
||||
inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
@@ -662,7 +573,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const PhantomNode &target_phantom,
|
||||
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
const PhantomNodes phantom_nodes{source_phantom, target_phantom};
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
||||
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
@@ -681,22 +596,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
|
||||
EdgeDistance distance = 0;
|
||||
std::vector<PathData> unpacked_path;
|
||||
|
||||
if (!unpacked_nodes.empty())
|
||||
{
|
||||
distance = std::accumulate(unpacked_nodes.begin(),
|
||||
std::prev(unpacked_nodes.end()),
|
||||
EdgeDistance{0},
|
||||
[&](const EdgeDistance distance, const auto node_id) {
|
||||
return distance + computeEdgeDistance(facade, node_id);
|
||||
});
|
||||
}
|
||||
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
|
||||
|
||||
distance = adjustPathDistanceToPhantomNodes(
|
||||
unpacked_nodes, phantom_nodes.source_phantom, phantom_nodes.target_phantom, distance);
|
||||
|
||||
return distance;
|
||||
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
|
||||
}
|
||||
|
||||
} // namespace mld
|
||||
|
||||
@@ -120,7 +120,7 @@ template <> struct SearchEngineData<routing_algorithms::mld::Algorithm>
|
||||
void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes,
|
||||
unsigned number_of_boundary_nodes);
|
||||
};
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SEARCH_ENGINE_DATA_HPP
|
||||
|
||||
@@ -82,7 +82,7 @@ class CompressedEdgeContainer
|
||||
std::unordered_map<EdgeID, unsigned> m_reverse_edge_id_to_zipped_index_map;
|
||||
std::unique_ptr<SegmentDataContainer> segment_data;
|
||||
};
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GEOMETRY_COMPRESSOR_HPP_
|
||||
|
||||
@@ -96,7 +96,7 @@ inline bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
|
||||
return std::tie(source, target, data.weight, unidirectional) <
|
||||
std::tie(other.source, other.target, other.data.weight, other_is_unidirectional);
|
||||
}
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
} // ns extractor
|
||||
} // ns osrm
|
||||
|
||||
#endif /* EDGE_BASED_EDGE_HPP */
|
||||
|
||||
@@ -92,6 +92,7 @@ class EdgeBasedGraphFactory
|
||||
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
|
||||
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
|
||||
void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations);
|
||||
void GetEdgeBasedNodeDistances(std::vector<EdgeDistance> &output_node_distances);
|
||||
std::uint32_t GetConnectivityChecksum() const;
|
||||
|
||||
std::uint64_t GetNumberOfEdgeBasedNodes() const;
|
||||
@@ -119,6 +120,7 @@ class EdgeBasedGraphFactory
|
||||
//! edge-based node
|
||||
std::vector<EdgeWeight> m_edge_based_node_weights;
|
||||
std::vector<EdgeDuration> m_edge_based_node_durations;
|
||||
std::vector<EdgeDistance> m_edge_based_node_distances;
|
||||
|
||||
//! list of edge based nodes (compressed segments)
|
||||
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
|
||||
|
||||
@@ -88,6 +88,7 @@ class Extractor
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
std::vector<EdgeDuration> &edge_based_node_durations,
|
||||
std::vector<EdgeDistance> &edge_based_node_distances,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::uint32_t &connectivity_checksum);
|
||||
|
||||
|
||||
@@ -453,8 +453,8 @@ void writeNames(const boost::filesystem::path &path, const NameTableT &table)
|
||||
serialization::write(writer, "/common/names", table);
|
||||
}
|
||||
|
||||
template <typename NodeWeigtsVectorT>
|
||||
void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVectorT &weights)
|
||||
template <typename NodeWeightsVectorT>
|
||||
void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeightsVectorT &weights)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
|
||||
storage::tar::FileReader reader{path, fingerprint};
|
||||
@@ -462,9 +462,33 @@ void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVec
|
||||
storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights);
|
||||
}
|
||||
|
||||
template <typename NodeWeigtsVectorT, typename NodeDurationsVectorT>
|
||||
template <typename NodeDistancesVectorT>
|
||||
void readEdgeBasedNodeDistances(const boost::filesystem::path &path,
|
||||
NodeDistancesVectorT &distances)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
|
||||
storage::tar::FileReader reader{path, fingerprint};
|
||||
|
||||
storage::serialization::read(reader, "/extractor/edge_based_node_distances", distances);
|
||||
}
|
||||
|
||||
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT, typename NodeDistancesVectorT>
|
||||
void writeEdgeBasedNodeWeightsDurationsDistances(const boost::filesystem::path &path,
|
||||
const NodeWeightsVectorT &weights,
|
||||
const NodeDurationsVectorT &durations,
|
||||
const NodeDistancesVectorT &distances)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
|
||||
storage::tar::FileWriter writer{path, fingerprint};
|
||||
|
||||
storage::serialization::write(writer, "/extractor/edge_based_node_weights", weights);
|
||||
storage::serialization::write(writer, "/extractor/edge_based_node_durations", durations);
|
||||
storage::serialization::write(writer, "/extractor/edge_based_node_distances", distances);
|
||||
}
|
||||
|
||||
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT>
|
||||
void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
|
||||
NodeWeigtsVectorT &weights,
|
||||
NodeWeightsVectorT &weights,
|
||||
NodeDurationsVectorT &durations)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
|
||||
@@ -474,9 +498,9 @@ void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
|
||||
storage::serialization::read(reader, "/extractor/edge_based_node_durations", durations);
|
||||
}
|
||||
|
||||
template <typename NodeWeigtsVectorT, typename NodeDurationsVectorT>
|
||||
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT>
|
||||
void writeEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
|
||||
const NodeWeigtsVectorT &weights,
|
||||
const NodeWeightsVectorT &weights,
|
||||
const NodeDurationsVectorT &durations)
|
||||
{
|
||||
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
|
||||
|
||||
@@ -49,7 +49,7 @@ struct ByEdgeOrByMeterValue
|
||||
using value_type = float;
|
||||
value_type value;
|
||||
};
|
||||
} // namespace detail
|
||||
}
|
||||
|
||||
struct InternalExtractorEdge
|
||||
{
|
||||
@@ -113,7 +113,7 @@ struct InternalExtractorEdge
|
||||
return v;
|
||||
}
|
||||
};
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INTERNAL_EXTRACTOR_EDGE_HPP
|
||||
|
||||
@@ -206,7 +206,7 @@ static_assert(sizeof(extractor::NodeBasedEdge) == 32,
|
||||
"bigger than expected. This will influence "
|
||||
"memory consumption.");
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
} // ns extractor
|
||||
} // ns osrm
|
||||
|
||||
#endif /* NODE_BASED_EDGE_HPP */
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define OSRM_BINDINGS_NODE_SUPPORT_HPP
|
||||
|
||||
#include "nodejs/json_v8_renderer.hpp"
|
||||
#include "util/json_renderer.hpp"
|
||||
|
||||
#include "osrm/approach.hpp"
|
||||
#include "osrm/bearing.hpp"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -42,6 +44,13 @@ using match_parameters_ptr = std::unique_ptr<osrm::MatchParameters>;
|
||||
using nearest_parameters_ptr = std::unique_ptr<osrm::NearestParameters>;
|
||||
using table_parameters_ptr = std::unique_ptr<osrm::TableParameters>;
|
||||
|
||||
struct PluginParameters
|
||||
{
|
||||
bool renderJSONToBuffer = false;
|
||||
};
|
||||
|
||||
using ObjectOrString = typename mapbox::util::variant<osrm::json::Object, std::string>;
|
||||
|
||||
template <typename ResultT> inline v8::Local<v8::Value> render(const ResultT &result);
|
||||
|
||||
template <> v8::Local<v8::Value> inline render(const std::string &result)
|
||||
@@ -49,11 +58,21 @@ template <> v8::Local<v8::Value> inline render(const std::string &result)
|
||||
return Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked();
|
||||
}
|
||||
|
||||
template <> v8::Local<v8::Value> inline render(const osrm::json::Object &result)
|
||||
template <> v8::Local<v8::Value> inline render(const ObjectOrString &result)
|
||||
{
|
||||
v8::Local<v8::Value> value;
|
||||
renderToV8(value, result);
|
||||
return value;
|
||||
if (result.is<osrm::json::Object>())
|
||||
{
|
||||
// Convert osrm::json object tree into matching v8 object tree
|
||||
v8::Local<v8::Value> value;
|
||||
renderToV8(value, result.get<osrm::json::Object>());
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return the string object as a node Buffer
|
||||
return Nan::CopyBuffer(result.get<std::string>().data(), result.get<std::string>().size())
|
||||
.ToLocalChecked();
|
||||
}
|
||||
}
|
||||
|
||||
inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result)
|
||||
@@ -123,6 +142,10 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
||||
if (shared_memory.IsEmpty())
|
||||
return engine_config_ptr();
|
||||
|
||||
auto mmap_memory = params->Get(Nan::New("mmap_memory").ToLocalChecked());
|
||||
if (mmap_memory.IsEmpty())
|
||||
return engine_config_ptr();
|
||||
|
||||
if (!memory_file->IsUndefined())
|
||||
{
|
||||
if (path->IsUndefined())
|
||||
@@ -171,6 +194,18 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
||||
return engine_config_ptr();
|
||||
}
|
||||
}
|
||||
if (!mmap_memory->IsUndefined())
|
||||
{
|
||||
if (mmap_memory->IsBoolean())
|
||||
{
|
||||
engine_config->use_mmap = Nan::To<bool>(mmap_memory).FromJust();
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("mmap_memory option must be a boolean");
|
||||
return engine_config_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
if (path->IsUndefined() && !engine_config->use_shared_memory)
|
||||
{
|
||||
@@ -814,6 +849,50 @@ inline bool parseCommonParameters(const v8::Local<v8::Object> &obj, ParamType &p
|
||||
return true;
|
||||
}
|
||||
|
||||
inline PluginParameters
|
||||
argumentsToPluginParameters(const Nan::FunctionCallbackInfo<v8::Value> &args)
|
||||
{
|
||||
if (args.Length() < 3 || !args[1]->IsObject())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
v8::Local<v8::Object> obj = Nan::To<v8::Object>(args[1]).ToLocalChecked();
|
||||
if (obj->Has(Nan::New("format").ToLocalChecked()))
|
||||
{
|
||||
|
||||
v8::Local<v8::Value> format = obj->Get(Nan::New("format").ToLocalChecked());
|
||||
if (format.IsEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!format->IsString())
|
||||
{
|
||||
Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\"");
|
||||
return {};
|
||||
}
|
||||
|
||||
const Nan::Utf8String format_utf8str(format);
|
||||
std::string format_str{*format_utf8str, *format_utf8str + format_utf8str.length()};
|
||||
|
||||
if (format_str == "object")
|
||||
{
|
||||
return {false};
|
||||
}
|
||||
else if (format_str == "json_buffer")
|
||||
{
|
||||
return {true};
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\"");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
inline route_parameters_ptr
|
||||
argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
bool requires_multiple_coordinates)
|
||||
@@ -1104,6 +1183,52 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->Has(Nan::New("fallback_speed").ToLocalChecked()))
|
||||
{
|
||||
auto fallback_speed = obj->Get(Nan::New("fallback_speed").ToLocalChecked());
|
||||
|
||||
if (!fallback_speed->IsNumber())
|
||||
{
|
||||
Nan::ThrowError("fallback_speed must be a number");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
else if (fallback_speed->NumberValue() < 0)
|
||||
{
|
||||
Nan::ThrowError("fallback_speed must be > 0");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
|
||||
params->fallback_speed = static_cast<double>(fallback_speed->NumberValue());
|
||||
}
|
||||
|
||||
if (obj->Has(Nan::New("fallback_coordinate").ToLocalChecked()))
|
||||
{
|
||||
auto fallback_coordinate = obj->Get(Nan::New("fallback_coordinate").ToLocalChecked());
|
||||
|
||||
if (!fallback_coordinate->IsString())
|
||||
{
|
||||
Nan::ThrowError("fallback_coordinate must be a string: [input, snapped]");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
|
||||
std::string fallback_coordinate_str = *v8::String::Utf8Value(fallback_coordinate);
|
||||
|
||||
if (fallback_coordinate_str == "snapped")
|
||||
{
|
||||
params->fallback_coordinate_type =
|
||||
osrm::TableParameters::FallbackCoordinateType::Snapped;
|
||||
}
|
||||
else if (fallback_coordinate_str == "input")
|
||||
{
|
||||
params->fallback_coordinate_type = osrm::TableParameters::FallbackCoordinateType::Input;
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("'fallback_coordinate' param must be one of [input, snapped]");
|
||||
return table_parameters_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -1357,6 +1482,6 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
return params;
|
||||
}
|
||||
|
||||
} // ns node_osrm
|
||||
} // namespace node_osrm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -75,28 +75,35 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
|
||||
// Implementation of the cell view. We need a template parameter here
|
||||
// because we need to derive a read-only and read-write view from this.
|
||||
template <typename WeightValueT, typename DurationValueT> class CellImpl
|
||||
template <typename WeightValueT, typename DurationValueT, typename DistanceValueT>
|
||||
class CellImpl
|
||||
{
|
||||
private:
|
||||
using WeightPtrT = WeightValueT *;
|
||||
using DurationPtrT = DurationValueT *;
|
||||
using DistancePtrT = DistanceValueT *;
|
||||
BoundarySize num_source_nodes;
|
||||
BoundarySize num_destination_nodes;
|
||||
|
||||
WeightPtrT const weights;
|
||||
DurationPtrT const durations;
|
||||
DistancePtrT const distances;
|
||||
const NodeID *const source_boundary;
|
||||
const NodeID *const destination_boundary;
|
||||
|
||||
using RowIterator = WeightPtrT;
|
||||
// Possibly replace with
|
||||
// http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/reference/adaptors/reference/strided.html
|
||||
class ColumnIterator : public boost::iterator_facade<ColumnIterator,
|
||||
WeightValueT,
|
||||
|
||||
template <typename ValuePtrT>
|
||||
class ColumnIterator : public boost::iterator_facade<ColumnIterator<ValuePtrT>,
|
||||
decltype(*std::declval<ValuePtrT>()),
|
||||
boost::random_access_traversal_tag>
|
||||
{
|
||||
typedef boost::iterator_facade<ColumnIterator,
|
||||
WeightValueT,
|
||||
|
||||
using ValueT = decltype(*std::declval<ValuePtrT>());
|
||||
typedef boost::iterator_facade<ColumnIterator<ValueT>,
|
||||
ValueT,
|
||||
boost::random_access_traversal_tag>
|
||||
base_t;
|
||||
|
||||
@@ -108,7 +115,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
|
||||
explicit ColumnIterator() : current(nullptr), stride(1) {}
|
||||
|
||||
explicit ColumnIterator(WeightPtrT begin, std::size_t row_length)
|
||||
explicit ColumnIterator(ValuePtrT begin, std::size_t row_length)
|
||||
: current(begin), stride(row_length)
|
||||
{
|
||||
BOOST_ASSERT(begin != nullptr);
|
||||
@@ -126,7 +133,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
}
|
||||
|
||||
friend class ::boost::iterator_core_access;
|
||||
WeightPtrT current;
|
||||
ValuePtrT current;
|
||||
const std::size_t stride;
|
||||
};
|
||||
|
||||
@@ -147,12 +154,13 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
auto iter =
|
||||
std::find(destination_boundary, destination_boundary + num_destination_nodes, node);
|
||||
if (iter == destination_boundary + num_destination_nodes)
|
||||
return boost::make_iterator_range(ColumnIterator{}, ColumnIterator{});
|
||||
return boost::make_iterator_range(ColumnIterator<ValuePtr>{},
|
||||
ColumnIterator<ValuePtr>{});
|
||||
|
||||
auto column = std::distance(destination_boundary, iter);
|
||||
auto begin = ColumnIterator{ptr + column, num_destination_nodes};
|
||||
auto end = ColumnIterator{ptr + column + num_source_nodes * num_destination_nodes,
|
||||
num_destination_nodes};
|
||||
auto begin = ColumnIterator<ValuePtr>{ptr + column, num_destination_nodes};
|
||||
auto end = ColumnIterator<ValuePtr>{
|
||||
ptr + column + num_source_nodes * num_destination_nodes, num_destination_nodes};
|
||||
return boost::make_iterator_range(begin, end);
|
||||
}
|
||||
|
||||
@@ -165,6 +173,10 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
|
||||
auto GetInDuration(NodeID node) const { return GetInRange(durations, node); }
|
||||
|
||||
auto GetInDistance(NodeID node) const { return GetInRange(distances, node); }
|
||||
|
||||
auto GetOutDistance(NodeID node) const { return GetOutRange(distances, node); }
|
||||
|
||||
auto GetSourceNodes() const
|
||||
{
|
||||
return boost::make_iterator_range(source_boundary, source_boundary + num_source_nodes);
|
||||
@@ -179,17 +191,20 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
CellImpl(const CellData &data,
|
||||
WeightPtrT const all_weights,
|
||||
DurationPtrT const all_durations,
|
||||
DistancePtrT const all_distances,
|
||||
const NodeID *const all_sources,
|
||||
const NodeID *const all_destinations)
|
||||
: num_source_nodes{data.num_source_nodes},
|
||||
num_destination_nodes{data.num_destination_nodes},
|
||||
weights{all_weights + data.value_offset},
|
||||
durations{all_durations + data.value_offset},
|
||||
distances{all_distances + data.value_offset},
|
||||
source_boundary{all_sources + data.source_boundary_offset},
|
||||
destination_boundary{all_destinations + data.destination_boundary_offset}
|
||||
{
|
||||
BOOST_ASSERT(all_weights != nullptr);
|
||||
BOOST_ASSERT(all_durations != nullptr);
|
||||
BOOST_ASSERT(all_distances != nullptr);
|
||||
BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr);
|
||||
BOOST_ASSERT(num_destination_nodes == 0 || all_destinations != nullptr);
|
||||
}
|
||||
@@ -201,7 +216,8 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
const NodeID *const all_destinations)
|
||||
: num_source_nodes{data.num_source_nodes},
|
||||
num_destination_nodes{data.num_destination_nodes}, weights{nullptr},
|
||||
durations{nullptr}, source_boundary{all_sources + data.source_boundary_offset},
|
||||
durations{nullptr}, distances{nullptr},
|
||||
source_boundary{all_sources + data.source_boundary_offset},
|
||||
destination_boundary{all_destinations + data.destination_boundary_offset}
|
||||
{
|
||||
BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr);
|
||||
@@ -212,8 +228,8 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
std::size_t LevelIDToIndex(LevelID level) const { return level - 1; }
|
||||
|
||||
public:
|
||||
using Cell = CellImpl<EdgeWeight, EdgeDuration>;
|
||||
using ConstCell = CellImpl<const EdgeWeight, const EdgeDuration>;
|
||||
using Cell = CellImpl<EdgeWeight, EdgeDuration, EdgeDistance>;
|
||||
using ConstCell = CellImpl<const EdgeWeight, const EdgeDuration, const EdgeDistance>;
|
||||
|
||||
CellStorageImpl() {}
|
||||
|
||||
@@ -361,6 +377,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
|
||||
metric.weights.resize(total_size + 1, INVALID_EDGE_WEIGHT);
|
||||
metric.durations.resize(total_size + 1, MAXIMAL_EDGE_DURATION);
|
||||
metric.distances.resize(total_size + 1, INVALID_EDGE_DISTANCE);
|
||||
|
||||
return metric;
|
||||
}
|
||||
@@ -388,6 +405,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
return ConstCell{cells[cell_index],
|
||||
metric.weights.data(),
|
||||
metric.durations.data(),
|
||||
metric.distances.data(),
|
||||
source_boundary.empty() ? nullptr : source_boundary.data(),
|
||||
destination_boundary.empty() ? nullptr : destination_boundary.data()};
|
||||
}
|
||||
@@ -415,6 +433,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
|
||||
return Cell{cells[cell_index],
|
||||
metric.weights.data(),
|
||||
metric.durations.data(),
|
||||
metric.distances.data(),
|
||||
source_boundary.data(),
|
||||
destination_boundary.data()};
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_reduce.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -200,7 +198,7 @@ inline DynamicEdgeBasedGraph LoadEdgeBasedGraph(const boost::filesystem::path &p
|
||||
return DynamicEdgeBasedGraph(number_of_edge_based_nodes, std::move(tidied), checksum);
|
||||
}
|
||||
|
||||
} // namespace partitioner
|
||||
} // namespace osrm
|
||||
} // ns partition
|
||||
} // ns osrm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -178,6 +178,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
qi::rule<Iterator, Signature> base_rule;
|
||||
qi::rule<Iterator, Signature> query_rule;
|
||||
|
||||
qi::real_parser<double, json_policy> double_;
|
||||
|
||||
private:
|
||||
qi::rule<Iterator, Signature> bearings_rule;
|
||||
qi::rule<Iterator, Signature> radiuses_rule;
|
||||
@@ -195,7 +197,6 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
||||
qi::rule<Iterator, unsigned char()> base64_char;
|
||||
qi::rule<Iterator, std::string()> polyline_chars;
|
||||
qi::rule<Iterator, double()> unlimited_rule;
|
||||
qi::real_parser<double, json_policy> double_;
|
||||
|
||||
qi::symbols<char, engine::Approach> approach_type;
|
||||
};
|
||||
|
||||
@@ -48,10 +48,24 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
|
||||
(qi::lit("all") |
|
||||
(size_t_ % ';')[ph::bind(&engine::api::TableParameters::sources, qi::_r1) = qi::_1]);
|
||||
|
||||
fallback_speed_rule =
|
||||
qi::lit("fallback_speed=") >
|
||||
(double_)[ph::bind(&engine::api::TableParameters::fallback_speed, qi::_r1) = qi::_1];
|
||||
|
||||
fallback_coordinate_type.add("input",
|
||||
engine::api::TableParameters::FallbackCoordinateType::Input)(
|
||||
"snapped", engine::api::TableParameters::FallbackCoordinateType::Snapped);
|
||||
|
||||
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)) % '&');
|
||||
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])) %
|
||||
'&');
|
||||
}
|
||||
|
||||
TableParametersGrammar(qi::rule<Iterator, Signature> &root_rule_) : BaseGrammar(root_rule_)
|
||||
@@ -73,13 +87,19 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
|
||||
qi::rule<Iterator, Signature> base_rule;
|
||||
|
||||
private:
|
||||
using json_policy = no_trailing_dot_policy<double, 'j', 's', 'o', 'n'>;
|
||||
|
||||
qi::rule<Iterator, Signature> root_rule;
|
||||
qi::rule<Iterator, Signature> table_rule;
|
||||
qi::rule<Iterator, Signature> sources_rule;
|
||||
qi::rule<Iterator, Signature> destinations_rule;
|
||||
qi::rule<Iterator, Signature> fallback_speed_rule;
|
||||
qi::rule<Iterator, std::size_t()> size_t_;
|
||||
qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations;
|
||||
qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list;
|
||||
qi::symbols<char, engine::api::TableParameters::FallbackCoordinateType>
|
||||
fallback_coordinate_type;
|
||||
qi::real_parser<double, json_policy> double_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,15 @@ struct Block
|
||||
{
|
||||
std::uint64_t num_entries;
|
||||
std::uint64_t byte_size;
|
||||
std::uint64_t offset;
|
||||
|
||||
Block() : num_entries(0), byte_size(0) {}
|
||||
Block() : num_entries(0), byte_size(0), offset(0) {}
|
||||
Block(std::uint64_t num_entries, std::uint64_t byte_size, std::uint64_t offset)
|
||||
: num_entries(num_entries), byte_size(byte_size), offset(offset)
|
||||
{
|
||||
}
|
||||
Block(std::uint64_t num_entries, std::uint64_t byte_size)
|
||||
: num_entries(num_entries), byte_size(byte_size)
|
||||
: num_entries(num_entries), byte_size(byte_size), offset(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -29,7 +34,7 @@ using NamedBlock = std::tuple<std::string, Block>;
|
||||
template <typename T> Block make_block(uint64_t num_entries)
|
||||
{
|
||||
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
|
||||
return Block{num_entries, sizeof(T) * num_entries};
|
||||
return Block{num_entries, sizeof(T) * num_entries, 0};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "storage/shared_datatype.hpp"
|
||||
#include "storage/tar.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
#include <boost/iterator/function_input_iterator.hpp>
|
||||
|
||||
@@ -30,22 +31,37 @@ namespace serialization
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename BlockT = unsigned char>
|
||||
inline BlockT packBits(const T &data, std::size_t index, std::size_t count)
|
||||
inline BlockT packBits(const T &data, std::size_t base_index, const std::size_t count)
|
||||
{
|
||||
static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool");
|
||||
static_assert(std::is_unsigned<BlockT>::value, "BlockT must be unsigned type");
|
||||
static_assert(std::is_integral<BlockT>::value, "BlockT must be an integral type");
|
||||
static_assert(CHAR_BIT == 8, "Non-8-bit bytes not supported, sorry!");
|
||||
BOOST_ASSERT(sizeof(BlockT) * CHAR_BIT >= count);
|
||||
|
||||
// Note: if this packing is changed, be sure to update vector_view<bool>
|
||||
// as well, so that on-disk and in-memory layouts match.
|
||||
BlockT value = 0;
|
||||
for (std::size_t bit = 0; bit < count; ++bit, ++index)
|
||||
value = (value << 1) | data[index];
|
||||
for (std::size_t bit = 0; bit < count; ++bit)
|
||||
{
|
||||
value |= (data[base_index + bit] ? BlockT{1} : BlockT{0}) << bit;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, typename BlockT = unsigned char>
|
||||
inline void unpackBits(T &data, std::size_t index, std::size_t count, BlockT value)
|
||||
inline void
|
||||
unpackBits(T &data, const std::size_t base_index, const std::size_t count, const BlockT value)
|
||||
{
|
||||
static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool");
|
||||
const BlockT mask = BlockT{1} << (count - 1);
|
||||
for (std::size_t bit = 0; bit < count; value <<= 1, ++bit, ++index)
|
||||
data[index] = value & mask;
|
||||
static_assert(std::is_unsigned<BlockT>::value, "BlockT must be unsigned type");
|
||||
static_assert(std::is_integral<BlockT>::value, "BlockT must be an integral type");
|
||||
static_assert(CHAR_BIT == 8, "Non-8-bit bytes not supported, sorry!");
|
||||
BOOST_ASSERT(sizeof(BlockT) * CHAR_BIT >= count);
|
||||
for (std::size_t bit = 0; bit < count; ++bit)
|
||||
{
|
||||
data[base_index + bit] = value & (BlockT{1} << bit);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VectorT>
|
||||
@@ -55,15 +71,16 @@ void readBoolVector(tar::FileReader &reader, const std::string &name, VectorT &d
|
||||
data.resize(count);
|
||||
std::uint64_t index = 0;
|
||||
|
||||
constexpr std::uint64_t WORD_BITS = CHAR_BIT * sizeof(std::uint64_t);
|
||||
using BlockType = std::uint64_t;
|
||||
constexpr std::uint64_t BLOCK_BITS = CHAR_BIT * sizeof(BlockType);
|
||||
|
||||
const auto decode = [&](const std::uint64_t block) {
|
||||
auto read_size = std::min<std::size_t>(count - index, WORD_BITS);
|
||||
unpackBits<VectorT, std::uint64_t>(data, index, read_size, block);
|
||||
index += WORD_BITS;
|
||||
const auto decode = [&](const BlockType block) {
|
||||
auto read_size = std::min<std::size_t>(count - index, BLOCK_BITS);
|
||||
unpackBits<VectorT, BlockType>(data, index, read_size, block);
|
||||
index += BLOCK_BITS;
|
||||
};
|
||||
|
||||
reader.ReadStreaming<std::uint64_t>(name, boost::make_function_output_iterator(decode));
|
||||
reader.ReadStreaming<BlockType>(name, boost::make_function_output_iterator(decode));
|
||||
}
|
||||
|
||||
template <typename VectorT>
|
||||
@@ -73,19 +90,20 @@ void writeBoolVector(tar::FileWriter &writer, const std::string &name, const Vec
|
||||
writer.WriteElementCount64(name, count);
|
||||
std::uint64_t index = 0;
|
||||
|
||||
constexpr std::uint64_t WORD_BITS = CHAR_BIT * sizeof(std::uint64_t);
|
||||
using BlockType = std::uint64_t;
|
||||
constexpr std::uint64_t BLOCK_BITS = CHAR_BIT * sizeof(BlockType);
|
||||
|
||||
// FIXME on old boost version the function_input_iterator does not work with lambdas
|
||||
// so we need to wrap it in a function here.
|
||||
const std::function<std::uint64_t()> encode_function = [&]() -> std::uint64_t {
|
||||
auto write_size = std::min<std::size_t>(count - index, WORD_BITS);
|
||||
auto packed = packBits<VectorT, std::uint64_t>(data, index, write_size);
|
||||
index += WORD_BITS;
|
||||
const std::function<BlockType()> encode_function = [&]() -> BlockType {
|
||||
auto write_size = std::min<std::size_t>(count - index, BLOCK_BITS);
|
||||
auto packed = packBits<VectorT, BlockType>(data, index, write_size);
|
||||
index += BLOCK_BITS;
|
||||
return packed;
|
||||
};
|
||||
|
||||
std::uint64_t number_of_blocks = (count + WORD_BITS - 1) / WORD_BITS;
|
||||
writer.WriteStreaming<std::uint64_t>(
|
||||
std::uint64_t number_of_blocks = (count + BLOCK_BITS - 1) / BLOCK_BITS;
|
||||
writer.WriteStreaming<BlockType>(
|
||||
name,
|
||||
boost::make_function_input_iterator(encode_function, boost::infinite()),
|
||||
number_of_blocks);
|
||||
@@ -266,9 +284,9 @@ template <typename K, typename V> void write(io::BufferWriter &writer, const std
|
||||
}
|
||||
}
|
||||
|
||||
inline void read(io::BufferReader &reader, DataLayout &layout) { read(reader, layout.blocks); }
|
||||
inline void read(io::BufferReader &reader, BaseDataLayout &layout) { read(reader, layout.blocks); }
|
||||
|
||||
inline void write(io::BufferWriter &writer, const DataLayout &layout)
|
||||
inline void write(io::BufferWriter &writer, const BaseDataLayout &layout)
|
||||
{
|
||||
write(writer, layout.blocks);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace osrm
|
||||
@@ -19,8 +20,8 @@ class SharedDataIndex
|
||||
public:
|
||||
struct AllocatedRegion
|
||||
{
|
||||
char *memory_ptr;
|
||||
DataLayout layout;
|
||||
void *memory_ptr;
|
||||
std::unique_ptr<BaseDataLayout> layout;
|
||||
};
|
||||
|
||||
SharedDataIndex() = default;
|
||||
@@ -29,10 +30,10 @@ class SharedDataIndex
|
||||
// Build mapping from block name to region
|
||||
for (auto index : util::irange<std::uint32_t>(0, regions.size()))
|
||||
{
|
||||
regions[index].layout.List("",
|
||||
boost::make_function_output_iterator([&](const auto &name) {
|
||||
block_to_region[name] = index;
|
||||
}));
|
||||
regions[index].layout->List("",
|
||||
boost::make_function_output_iterator([&](const auto &name) {
|
||||
block_to_region[name] = index;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,32 +41,44 @@ class SharedDataIndex
|
||||
{
|
||||
for (const auto ®ion : regions)
|
||||
{
|
||||
region.layout.List(name_prefix, out);
|
||||
region.layout->List(name_prefix, out);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> auto GetBlockPtr(const std::string &name) const
|
||||
{
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||
// is_tivially_copyable only exists in GCC >=5
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Block-based data must be a trivially copyable type");
|
||||
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
|
||||
#endif
|
||||
const auto ®ion = GetBlockRegion(name);
|
||||
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
|
||||
return reinterpret_cast<T *>(region.layout->GetBlockPtr(region.memory_ptr, name));
|
||||
}
|
||||
|
||||
template <typename T> auto GetBlockPtr(const std::string &name)
|
||||
{
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||
// is_tivially_copyable only exists in GCC >=5
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Block-based data must be a trivially copyable type");
|
||||
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
|
||||
#endif
|
||||
const auto ®ion = GetBlockRegion(name);
|
||||
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
|
||||
return reinterpret_cast<T *>(region.layout->GetBlockPtr(region.memory_ptr, name));
|
||||
}
|
||||
|
||||
std::size_t GetBlockEntries(const std::string &name) const
|
||||
{
|
||||
const auto ®ion = GetBlockRegion(name);
|
||||
return region.layout.GetBlockEntries(name);
|
||||
return region.layout->GetBlockEntries(name);
|
||||
}
|
||||
|
||||
std::size_t GetBlockSize(const std::string &name) const
|
||||
{
|
||||
const auto ®ion = GetBlockRegion(name);
|
||||
return region.layout.GetBlockSize(name);
|
||||
return region.layout->GetBlockSize(name);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace osrm
|
||||
namespace storage
|
||||
{
|
||||
|
||||
class DataLayout;
|
||||
class BaseDataLayout;
|
||||
namespace serialization
|
||||
{
|
||||
inline void read(io::BufferReader &reader, DataLayout &layout);
|
||||
inline void read(io::BufferReader &reader, BaseDataLayout &layout);
|
||||
|
||||
inline void write(io::BufferWriter &writer, const DataLayout &layout);
|
||||
inline void write(io::BufferWriter &writer, const BaseDataLayout &layout);
|
||||
} // namespace serialization
|
||||
|
||||
namespace detail
|
||||
@@ -54,44 +54,28 @@ inline std::string trimName(const std::string &name_prefix, const std::string &n
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
class DataLayout
|
||||
class BaseDataLayout
|
||||
{
|
||||
public:
|
||||
DataLayout() : blocks{} {}
|
||||
virtual ~BaseDataLayout() = default;
|
||||
|
||||
inline void SetBlock(const std::string &name, Block block) { blocks[name] = std::move(block); }
|
||||
|
||||
inline uint64_t GetBlockEntries(const std::string &name) const
|
||||
inline std::uint64_t GetBlockEntries(const std::string &name) const
|
||||
{
|
||||
return GetBlock(name).num_entries;
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockSize(const std::string &name) const { return GetBlock(name).byte_size; }
|
||||
inline std::uint64_t GetBlockSize(const std::string &name) const
|
||||
{
|
||||
return GetBlock(name).byte_size;
|
||||
}
|
||||
|
||||
inline bool HasBlock(const std::string &name) const
|
||||
{
|
||||
return blocks.find(name) != blocks.end();
|
||||
}
|
||||
|
||||
inline uint64_t GetSizeOfLayout() const
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (const auto &name_and_block : blocks)
|
||||
{
|
||||
result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T> inline T *GetBlockPtr(char *shared_memory, const std::string &name) const
|
||||
{
|
||||
static_assert(BLOCK_ALIGNMENT % std::alignment_of<T>::value == 0,
|
||||
"Datatype does not fit alignment constraints.");
|
||||
|
||||
char *ptr = (char *)GetAlignedBlockPtr(shared_memory, name);
|
||||
return (T *)ptr;
|
||||
}
|
||||
|
||||
// Depending on the name prefix this function either lists all blocks with the same prefix
|
||||
// or all entries in the sub-directory.
|
||||
// '/ch/edge' -> '/ch/edge_filter/0/blocks', '/ch/edge_filter/1/blocks'
|
||||
@@ -115,10 +99,10 @@ class DataLayout
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
friend void serialization::read(io::BufferReader &reader, DataLayout &layout);
|
||||
friend void serialization::write(io::BufferWriter &writer, const DataLayout &layout);
|
||||
virtual inline void *GetBlockPtr(void *base_ptr, const std::string &name) const = 0;
|
||||
virtual inline std::uint64_t GetSizeOfLayout() const = 0;
|
||||
|
||||
protected:
|
||||
const Block &GetBlock(const std::string &name) const
|
||||
{
|
||||
auto iter = blocks.find(name);
|
||||
@@ -130,10 +114,42 @@ class DataLayout
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout);
|
||||
friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout);
|
||||
|
||||
std::map<std::string, Block> blocks;
|
||||
};
|
||||
|
||||
class ContiguousDataLayout final : public BaseDataLayout
|
||||
{
|
||||
public:
|
||||
inline std::uint64_t GetSizeOfLayout() const override final
|
||||
{
|
||||
std::uint64_t result = 0;
|
||||
for (const auto &name_and_block : blocks)
|
||||
{
|
||||
result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final
|
||||
{
|
||||
// TODO: re-enable this alignment checking somehow
|
||||
// static_assert(BLOCK_ALIGNMENT % std::alignment_of<T>::value == 0,
|
||||
// "Datatype does not fit alignment constraints.");
|
||||
|
||||
return GetAlignedBlockPtr(base_ptr, name);
|
||||
}
|
||||
|
||||
private:
|
||||
friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout);
|
||||
friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout);
|
||||
|
||||
// Fit aligned storage in buffer to 64 bytes to conform with AVX 512 types
|
||||
inline void *align(void *&ptr) const noexcept
|
||||
{
|
||||
const auto intptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
const auto intptr = reinterpret_cast<std::uintptr_t>(ptr);
|
||||
const auto aligned = (intptr - 1u + BLOCK_ALIGNMENT) & -BLOCK_ALIGNMENT;
|
||||
return ptr = reinterpret_cast<void *>(aligned);
|
||||
}
|
||||
@@ -157,7 +173,27 @@ class DataLayout
|
||||
}
|
||||
|
||||
static constexpr std::size_t BLOCK_ALIGNMENT = 64;
|
||||
std::map<std::string, Block> blocks;
|
||||
};
|
||||
|
||||
class TarDataLayout final : public BaseDataLayout
|
||||
{
|
||||
public:
|
||||
inline std::uint64_t GetSizeOfLayout() const override final
|
||||
{
|
||||
std::uint64_t result = 0;
|
||||
for (const auto &name_and_block : blocks)
|
||||
{
|
||||
result += GetBlockSize(name_and_block.first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final
|
||||
{
|
||||
auto offset = GetBlock(name).offset;
|
||||
const auto offset_address = reinterpret_cast<std::uintptr_t>(base_ptr) + offset;
|
||||
return reinterpret_cast<void *>(offset_address);
|
||||
}
|
||||
};
|
||||
|
||||
struct SharedRegion
|
||||
|
||||
@@ -35,22 +35,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace storage
|
||||
{
|
||||
|
||||
void populateLayoutFromFile(const boost::filesystem::path &path, storage::BaseDataLayout &layout);
|
||||
|
||||
class Storage
|
||||
{
|
||||
public:
|
||||
Storage(StorageConfig config);
|
||||
|
||||
int Run(int max_wait, const std::string &name, bool only_metric);
|
||||
|
||||
void PopulateStaticLayout(DataLayout &layout);
|
||||
void PopulateUpdatableLayout(DataLayout &layout);
|
||||
void PopulateStaticData(const SharedDataIndex &index);
|
||||
void PopulateUpdatableData(const SharedDataIndex &index);
|
||||
void PopulateLayout(storage::BaseDataLayout &layout,
|
||||
const std::vector<std::pair<bool, boost::filesystem::path>> &files);
|
||||
std::string PopulateLayoutWithRTree(storage::BaseDataLayout &layout);
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> GetUpdatableFiles();
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> GetStaticFiles();
|
||||
|
||||
private:
|
||||
StorageConfig config;
|
||||
|
||||
@@ -294,11 +294,14 @@ inline auto make_filtered_cell_metric_view(const SharedDataIndex &index,
|
||||
auto prefix = name + "/exclude/" + std::to_string(exclude_index);
|
||||
auto weights_block_id = prefix + "/weights";
|
||||
auto durations_block_id = prefix + "/durations";
|
||||
auto distances_block_id = prefix + "/distances";
|
||||
|
||||
auto weights = make_vector_view<EdgeWeight>(index, weights_block_id);
|
||||
auto durations = make_vector_view<EdgeDuration>(index, durations_block_id);
|
||||
auto distances = make_vector_view<EdgeDistance>(index, distances_block_id);
|
||||
|
||||
return customizer::CellMetricView{std::move(weights), std::move(durations)};
|
||||
return customizer::CellMetricView{
|
||||
std::move(weights), std::move(durations), std::move(distances)};
|
||||
}
|
||||
|
||||
inline auto make_cell_metric_view(const SharedDataIndex &index, const std::string &name)
|
||||
@@ -311,12 +314,14 @@ inline auto make_cell_metric_view(const SharedDataIndex &index, const std::strin
|
||||
{
|
||||
auto weights_block_id = prefix + "/weights";
|
||||
auto durations_block_id = prefix + "/durations";
|
||||
auto distances_block_id = prefix + "/distances";
|
||||
|
||||
auto weights = make_vector_view<EdgeWeight>(index, weights_block_id);
|
||||
auto durations = make_vector_view<EdgeDuration>(index, durations_block_id);
|
||||
auto distances = make_vector_view<EdgeDistance>(index, distances_block_id);
|
||||
|
||||
cell_metric_excludes.push_back(
|
||||
customizer::CellMetricView{std::move(weights), std::move(durations)});
|
||||
cell_metric_excludes.push_back(customizer::CellMetricView{
|
||||
std::move(weights), std::move(durations), std::move(distances)});
|
||||
}
|
||||
|
||||
return cell_metric_excludes;
|
||||
@@ -332,6 +337,7 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std:
|
||||
index, name + "/node_to_edge_offset");
|
||||
auto node_weights = make_vector_view<EdgeWeight>(index, name + "/node_weights");
|
||||
auto node_durations = make_vector_view<EdgeDuration>(index, name + "/node_durations");
|
||||
auto node_distances = make_vector_view<EdgeDistance>(index, name + "/node_distances");
|
||||
auto is_forward_edge = make_vector_view<bool>(index, name + "/is_forward_edge");
|
||||
auto is_backward_edge = make_vector_view<bool>(index, name + "/is_backward_edge");
|
||||
|
||||
@@ -340,6 +346,7 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std:
|
||||
std::move(node_to_offset),
|
||||
std::move(node_weights),
|
||||
std::move(node_durations),
|
||||
std::move(node_distances),
|
||||
std::move(is_forward_edge),
|
||||
std::move(is_backward_edge));
|
||||
}
|
||||
|
||||
@@ -22,11 +22,17 @@ class Updater
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::uint32_t &connectivity_checksum) const;
|
||||
|
||||
EdgeID
|
||||
LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::vector<EdgeDuration> &node_durations, // TODO: to be deleted
|
||||
std::uint32_t &connectivity_checksum) const;
|
||||
EdgeID LoadAndUpdateEdgeExpandedGraph(
|
||||
std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::vector<EdgeDuration> &node_durations, // TODO: remove when optional
|
||||
std::uint32_t &connectivity_checksum) const;
|
||||
EdgeID LoadAndUpdateEdgeExpandedGraph(
|
||||
std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::vector<EdgeDuration> &node_durations, // TODO: remove when optional
|
||||
std::vector<EdgeDistance> &node_distances, // TODO: remove when optional
|
||||
std::uint32_t &connectivity_checksum) const;
|
||||
|
||||
private:
|
||||
UpdaterConfig config;
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace detail
|
||||
{
|
||||
const constexpr double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
|
||||
const constexpr double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
|
||||
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
|
||||
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
|
||||
const constexpr long double EARTH_RADIUS = 6372797.560856;
|
||||
|
||||
inline double degToRad(const double degree)
|
||||
{
|
||||
|
||||
+13
-14
@@ -27,7 +27,7 @@ inline std::ostream &operator<<(std::ostream &out, const Coordinate &coordinate)
|
||||
<< toFloating(coordinate.lat) << "}";
|
||||
return out;
|
||||
}
|
||||
} // namespace util
|
||||
}
|
||||
|
||||
namespace engine
|
||||
{
|
||||
@@ -62,8 +62,8 @@ inline std::ostream &operator<<(std::ostream &out, const RouteStep &step)
|
||||
|
||||
return out;
|
||||
}
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
}
|
||||
}
|
||||
|
||||
namespace guidance
|
||||
{
|
||||
@@ -76,7 +76,7 @@ inline std::ostream &operator<<(std::ostream &out, const ConnectedRoad &road)
|
||||
<< static_cast<std::int32_t>(road.lane_data_id) << "}";
|
||||
return out;
|
||||
}
|
||||
} // namespace guidance
|
||||
}
|
||||
|
||||
namespace extractor
|
||||
{
|
||||
@@ -95,7 +95,7 @@ inline std::ostream &operator<<(std::ostream &out, const IntersectionViewData &v
|
||||
<< " angle: " << view.angle << " bearing: " << view.perceived_bearing << "}";
|
||||
return out;
|
||||
}
|
||||
} // namespace intersection
|
||||
}
|
||||
|
||||
namespace TurnLaneType
|
||||
{
|
||||
@@ -125,9 +125,9 @@ inline std::ostream &operator<<(std::ostream &out, const Mask lane_type)
|
||||
|
||||
return out;
|
||||
}
|
||||
} // namespace TurnLaneType
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
@@ -147,7 +147,7 @@ inline std::ostream &operator<<(std::ostream &out,
|
||||
|
||||
return out;
|
||||
}
|
||||
} // namespace std
|
||||
}
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -186,8 +186,8 @@ inline std::ostream &operator<<(std::ostream &out, const LaneDataVector &turn_la
|
||||
|
||||
return out;
|
||||
}
|
||||
} // namespace lanes
|
||||
} // namespace guidance
|
||||
}
|
||||
}
|
||||
|
||||
namespace extractor
|
||||
{
|
||||
@@ -204,8 +204,7 @@ inline std::ostream &operator<<(std::ostream &out, const EdgeBasedEdge &edge)
|
||||
out << "}";
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*OSRM_ENGINE_GUIDANCE_DEBUG_HPP_*/
|
||||
|
||||
@@ -29,7 +29,7 @@ THE SOFTWARE.
|
||||
#include <math.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include "msinttypes/stdint.h"
|
||||
#include "rapidjson/msinttypes/stdint.h"
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
|
||||
+17
-16
@@ -15,14 +15,14 @@ namespace util
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename RegionT>
|
||||
util::vector_view<T> mmapFile(const boost::filesystem::path &file, RegionT ®ion)
|
||||
template <typename T, typename MmapContainerT>
|
||||
util::vector_view<T> mmapFile(const boost::filesystem::path &file, MmapContainerT &mmap_container)
|
||||
{
|
||||
try
|
||||
{
|
||||
region.open(file);
|
||||
std::size_t num_objects = region.size() / sizeof(T);
|
||||
auto data_ptr = region.data();
|
||||
mmap_container.open(file);
|
||||
std::size_t num_objects = mmap_container.size() / sizeof(T);
|
||||
auto data_ptr = mmap_container.data();
|
||||
BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0);
|
||||
return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects);
|
||||
}
|
||||
@@ -34,9 +34,10 @@ util::vector_view<T> mmapFile(const boost::filesystem::path &file, RegionT ®i
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename RegionT>
|
||||
util::vector_view<T>
|
||||
mmapFile(const boost::filesystem::path &file, RegionT ®ion, const std::size_t size)
|
||||
template <typename T, typename MmapContainerT>
|
||||
util::vector_view<T> mmapFile(const boost::filesystem::path &file,
|
||||
MmapContainerT &mmap_container,
|
||||
const std::size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -45,10 +46,10 @@ mmapFile(const boost::filesystem::path &file, RegionT ®ion, const std::size_t
|
||||
params.path = file.string();
|
||||
params.flags = boost::iostreams::mapped_file::readwrite;
|
||||
params.new_file_size = size;
|
||||
region.open(params);
|
||||
mmap_container.open(params);
|
||||
|
||||
std::size_t num_objects = size / sizeof(T);
|
||||
auto data_ptr = region.data();
|
||||
auto data_ptr = mmap_container.data();
|
||||
BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0);
|
||||
return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects);
|
||||
}
|
||||
@@ -63,24 +64,24 @@ mmapFile(const boost::filesystem::path &file, RegionT ®ion, const std::size_t
|
||||
|
||||
template <typename T>
|
||||
util::vector_view<const T> mmapFile(const boost::filesystem::path &file,
|
||||
boost::iostreams::mapped_file_source ®ion)
|
||||
boost::iostreams::mapped_file_source &mmap_container)
|
||||
{
|
||||
return detail::mmapFile<const T>(file, region);
|
||||
return detail::mmapFile<const T>(file, mmap_container);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
util::vector_view<T> mmapFile(const boost::filesystem::path &file,
|
||||
boost::iostreams::mapped_file ®ion)
|
||||
boost::iostreams::mapped_file &mmap_container)
|
||||
{
|
||||
return detail::mmapFile<T>(file, region);
|
||||
return detail::mmapFile<T>(file, mmap_container);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
util::vector_view<T> mmapFile(const boost::filesystem::path &file,
|
||||
boost::iostreams::mapped_file ®ion,
|
||||
boost::iostreams::mapped_file &mmap_container,
|
||||
std::size_t size)
|
||||
{
|
||||
return detail::mmapFile<T>(file, region, size);
|
||||
return detail::mmapFile<T>(file, mmap_container, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
@@ -89,14 +90,14 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
|
||||
|
||||
BOOST_ASSERT(output_edge.data.weight > 0);
|
||||
BOOST_ASSERT(output_edge.data.duration > 0);
|
||||
BOOST_ASSERT(output_edge.data.distance > 0);
|
||||
BOOST_ASSERT(output_edge.data.distance >= 0);
|
||||
});
|
||||
|
||||
tbb::parallel_sort(edges_list.begin(), edges_list.end());
|
||||
|
||||
return NodeBasedDynamicGraph(number_of_nodes, edges_list);
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NODE_BASED_GRAPH_HPP
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -195,7 +195,10 @@ template <> class vector_view<bool>
|
||||
{
|
||||
BOOST_ASSERT_MSG(index < m_size, "invalid size");
|
||||
const std::size_t bucket = index / WORD_BITS;
|
||||
// Note: ordering of bits here should match packBits in storage/serialization.hpp
|
||||
// so that directly mmap-ing data is possible
|
||||
const auto offset = index % WORD_BITS;
|
||||
BOOST_ASSERT(WORD_BITS > offset);
|
||||
return m_ptr[bucket] & (static_cast<Word>(1) << offset);
|
||||
}
|
||||
|
||||
@@ -224,11 +227,23 @@ template <> class vector_view<bool>
|
||||
{
|
||||
BOOST_ASSERT(index < m_size);
|
||||
const auto bucket = index / WORD_BITS;
|
||||
// Note: ordering of bits here should match packBits in storage/serialization.hpp
|
||||
// so that directly mmap-ing data is possible
|
||||
const auto offset = index % WORD_BITS;
|
||||
BOOST_ASSERT(WORD_BITS > offset);
|
||||
return reference{m_ptr + bucket, static_cast<Word>(1) << offset};
|
||||
}
|
||||
|
||||
template <typename T> friend void swap(vector_view<T> &, vector_view<T> &) noexcept;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const vector_view<bool> &rhs)
|
||||
{
|
||||
for (std::size_t i = 0; i < rhs.size(); ++i)
|
||||
{
|
||||
os << (i > 0 ? " " : "") << rhs.at(i);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
// Both vector_view<T> and the vector_view<bool> specializations share this impl.
|
||||
|
||||
Generated
+4483
-636
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "osrm",
|
||||
"version": "5.20.0-alpha.1",
|
||||
"version": "5.20.0",
|
||||
"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.6.2",
|
||||
"nan": "^2.11.1",
|
||||
"node-cmake": "^2.3.2",
|
||||
"node-pre-gyp": "^0.6.36",
|
||||
"rimraf": "^2.5.4"
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "node ./node_modules/eslint/bin/eslint.js -c ./.eslintrc features/step_definitions/ features/support/",
|
||||
"test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld",
|
||||
"test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify -m mmap && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld -m mmap",
|
||||
"clean": "rm -rf test/cache",
|
||||
"docs": "./scripts/build_api_docs.sh",
|
||||
"install": "node-pre-gyp install --fallback-to-build=false || ./scripts/node_install.sh",
|
||||
|
||||
@@ -120,6 +120,9 @@ function setup()
|
||||
|
||||
-- classes to support for exclude flags
|
||||
excludable = Sequence {
|
||||
Set {'toll'},
|
||||
Set {'motorway'},
|
||||
Set {'ferry'}
|
||||
},
|
||||
|
||||
avoid = Set {
|
||||
|
||||
+6
-2
@@ -6,8 +6,12 @@ var fs = require('fs');
|
||||
var name = process.argv[2];
|
||||
var cmd = process.argv.slice(3).join(' ');
|
||||
var start = Date.now();
|
||||
exec(cmd, (err) => {
|
||||
if (err) return console.log(err);
|
||||
exec(cmd, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
return process.exit(err.code);
|
||||
}
|
||||
var stop = +new Date();
|
||||
var time = (stop - start) / 1000.;
|
||||
fs.appendFileSync('/tmp/osrm.timings', `${name}\t${time}`, 'utf-8');
|
||||
|
||||
@@ -102,7 +102,6 @@ int Contractor::Run()
|
||||
QueryGraph query_graph;
|
||||
std::vector<std::vector<bool>> edge_filters;
|
||||
std::vector<std::vector<bool>> cores;
|
||||
|
||||
std::tie(query_graph, edge_filters) = contractExcludableGraph(
|
||||
toContractorGraph(number_of_edge_based_nodes, std::move(edge_based_edge_list)),
|
||||
std::move(node_weights),
|
||||
|
||||
@@ -560,7 +560,7 @@ bool IsNodeIndependent(const util::XORFastHash<> &hash,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
}
|
||||
|
||||
std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||
std::vector<bool> node_is_uncontracted_,
|
||||
|
||||
@@ -76,6 +76,7 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
|
||||
const partitioner::MultiLevelPartition &mlp,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::vector<EdgeDuration> &node_durations,
|
||||
std::vector<EdgeDistance> &node_distances,
|
||||
std::uint32_t &connectivity_checksum)
|
||||
{
|
||||
updater::Updater updater(config.updater_config);
|
||||
@@ -84,6 +85,8 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
|
||||
EdgeID num_nodes = updater.LoadAndUpdateEdgeExpandedGraph(
|
||||
edge_based_edge_list, node_weights, node_durations, connectivity_checksum);
|
||||
|
||||
extractor::files::readEdgeBasedNodeDistances(config.GetPath(".osrm.enw"), node_distances);
|
||||
|
||||
auto directed = partitioner::splitBidirectionalEdges(edge_based_edge_list);
|
||||
|
||||
auto tidied = partitioner::prepareEdgesForUsageInGraph<
|
||||
@@ -124,10 +127,11 @@ int Customizer::Run(const CustomizationConfig &config)
|
||||
partitioner::files::readPartition(config.GetPath(".osrm.partition"), mlp);
|
||||
|
||||
std::vector<EdgeWeight> node_weights;
|
||||
std::vector<EdgeDuration> node_durations; // TODO: to be removed later
|
||||
std::vector<EdgeDuration> node_durations; // TODO: remove when durations are optional
|
||||
std::vector<EdgeDistance> node_distances; // TODO: remove when distances are optional
|
||||
std::uint32_t connectivity_checksum = 0;
|
||||
auto graph = LoadAndUpdateEdgeExpandedGraph(
|
||||
config, mlp, node_weights, node_durations, connectivity_checksum);
|
||||
config, mlp, node_weights, node_durations, node_distances, connectivity_checksum);
|
||||
BOOST_ASSERT(graph.GetNumberOfNodes() == node_weights.size());
|
||||
std::for_each(node_weights.begin(), node_weights.end(), [](auto &w) { w &= 0x7fffffff; });
|
||||
util::Log() << "Loaded edge based graph: " << graph.GetNumberOfEdges() << " edges, "
|
||||
@@ -166,8 +170,10 @@ int Customizer::Run(const CustomizationConfig &config)
|
||||
util::Log() << "MLD customization writing took " << TIMER_SEC(writing_mld_data) << " seconds";
|
||||
|
||||
TIMER_START(writing_graph);
|
||||
MultiLevelEdgeBasedGraph shaved_graph{
|
||||
std::move(graph), std::move(node_weights), std::move(node_durations)};
|
||||
MultiLevelEdgeBasedGraph shaved_graph{std::move(graph),
|
||||
std::move(node_weights),
|
||||
std::move(node_durations),
|
||||
std::move(node_distances)};
|
||||
customizer::files::writeGraph(
|
||||
config.GetPath(".osrm.mldgr"), shaved_graph, connectivity_checksum);
|
||||
TIMER_STOP(writing_graph);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "engine/datafacade/mmap_memory_allocator.hpp"
|
||||
|
||||
#include "storage/block.hpp"
|
||||
#include "storage/io.hpp"
|
||||
#include "storage/serialization.hpp"
|
||||
#include "storage/storage.hpp"
|
||||
@@ -7,7 +8,7 @@
|
||||
#include "util/log.hpp"
|
||||
#include "util/mmap_file.hpp"
|
||||
|
||||
#include "boost/assert.hpp"
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -16,46 +17,50 @@ namespace engine
|
||||
namespace datafacade
|
||||
{
|
||||
|
||||
MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config,
|
||||
const boost::filesystem::path &memory_file)
|
||||
MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config)
|
||||
{
|
||||
storage::Storage storage(config);
|
||||
std::vector<storage::SharedDataIndex::AllocatedRegion> allocated_regions;
|
||||
|
||||
if (!boost::filesystem::exists(memory_file))
|
||||
{
|
||||
storage::DataLayout initial_layout;
|
||||
storage.PopulateStaticLayout(initial_layout);
|
||||
storage.PopulateUpdatableLayout(initial_layout);
|
||||
std::unique_ptr<storage::BaseDataLayout> fake_layout =
|
||||
std::make_unique<storage::TarDataLayout>();
|
||||
|
||||
auto data_size = initial_layout.GetSizeOfLayout();
|
||||
// Convert the boost::filesystem::path object into a plain string
|
||||
// that's stored as a member of this allocator object
|
||||
rtree_filename = storage.PopulateLayoutWithRTree(*fake_layout);
|
||||
|
||||
storage::io::BufferWriter writer;
|
||||
storage::serialization::write(writer, initial_layout);
|
||||
auto encoded_layout = writer.GetBuffer();
|
||||
|
||||
auto total_size = data_size + encoded_layout.size();
|
||||
|
||||
mapped_memory = util::mmapFile<char>(memory_file, mapped_memory_file, total_size);
|
||||
|
||||
std::copy(encoded_layout.begin(), encoded_layout.end(), mapped_memory.data());
|
||||
|
||||
index = storage::SharedDataIndex(
|
||||
{{mapped_memory.data() + encoded_layout.size(), std::move(initial_layout)}});
|
||||
|
||||
storage.PopulateStaticData(index);
|
||||
storage.PopulateUpdatableData(index);
|
||||
// Now, we add one more AllocatedRegion, with it's start address as the start
|
||||
// of the rtree_filename string we've saved. In the fake_layout, we've
|
||||
// stated that the data is at offset 0, which is where the string starts
|
||||
// at it's own memory address.
|
||||
// The syntax &(rtree_filename[0]) gets the memory address of the first char.
|
||||
// We can't use the convenient `.data()` or `.c_str()` methods, because
|
||||
// prior to C++17 (which we're not using), those return a `const char *`,
|
||||
// which isn't compatible with the `char *` that AllocatedRegion expects
|
||||
// for it's memory_ptr
|
||||
allocated_regions.push_back({&(rtree_filename[0]), std::move(fake_layout)});
|
||||
}
|
||||
else
|
||||
|
||||
auto files = storage.GetStaticFiles();
|
||||
auto updatable_files = storage.GetUpdatableFiles();
|
||||
files.insert(files.end(), updatable_files.begin(), updatable_files.end());
|
||||
|
||||
for (const auto &file : files)
|
||||
{
|
||||
mapped_memory = util::mmapFile<char>(memory_file, mapped_memory_file);
|
||||
|
||||
storage::DataLayout layout;
|
||||
storage::io::BufferReader reader(mapped_memory.data(), mapped_memory.size());
|
||||
storage::serialization::read(reader, layout);
|
||||
auto layout_size = reader.GetPosition();
|
||||
|
||||
index = storage::SharedDataIndex({{mapped_memory.data() + layout_size, std::move(layout)}});
|
||||
if (boost::filesystem::exists(file.second))
|
||||
{
|
||||
std::unique_ptr<storage::BaseDataLayout> layout =
|
||||
std::make_unique<storage::TarDataLayout>();
|
||||
boost::iostreams::mapped_file mapped_memory_file;
|
||||
util::mmapFile<char>(file.second, mapped_memory_file);
|
||||
mapped_memory_files.push_back(std::move(mapped_memory_file));
|
||||
storage::populateLayoutFromFile(file.second, *layout);
|
||||
allocated_regions.push_back({mapped_memory_file.data(), std::move(layout)});
|
||||
}
|
||||
}
|
||||
|
||||
index = storage::SharedDataIndex{std::move(allocated_regions)};
|
||||
}
|
||||
|
||||
MMapMemoryAllocator::~MMapMemoryAllocator() {}
|
||||
|
||||
@@ -15,14 +15,20 @@ ProcessMemoryAllocator::ProcessMemoryAllocator(const storage::StorageConfig &con
|
||||
storage::Storage storage(config);
|
||||
|
||||
// Calculate the layout/size of the memory block
|
||||
storage::DataLayout layout;
|
||||
storage.PopulateStaticLayout(layout);
|
||||
storage.PopulateUpdatableLayout(layout);
|
||||
auto static_files = storage.GetStaticFiles();
|
||||
auto updatable_files = storage.GetUpdatableFiles();
|
||||
std::unique_ptr<storage::BaseDataLayout> layout =
|
||||
std::make_unique<storage::ContiguousDataLayout>();
|
||||
storage.PopulateLayoutWithRTree(*layout);
|
||||
storage.PopulateLayout(*layout, static_files);
|
||||
storage.PopulateLayout(*layout, updatable_files);
|
||||
|
||||
// Allocate the memory block, then load data from files into it
|
||||
internal_memory = std::make_unique<char[]>(layout.GetSizeOfLayout());
|
||||
internal_memory = std::make_unique<char[]>(layout->GetSizeOfLayout());
|
||||
|
||||
index = storage::SharedDataIndex({{internal_memory.get(), std::move(layout)}});
|
||||
std::vector<storage::SharedDataIndex::AllocatedRegion> regions;
|
||||
regions.push_back({internal_memory.get(), std::move(layout)});
|
||||
index = {std::move(regions)};
|
||||
|
||||
storage.PopulateStaticData(index);
|
||||
storage.PopulateUpdatableData(index);
|
||||
|
||||
@@ -25,8 +25,9 @@ SharedMemoryAllocator::SharedMemoryAllocator(
|
||||
auto mem = storage::makeSharedMemory(shm_key);
|
||||
|
||||
storage::io::BufferReader reader(reinterpret_cast<char *>(mem->Ptr()), mem->Size());
|
||||
storage::DataLayout layout;
|
||||
storage::serialization::read(reader, layout);
|
||||
std::unique_ptr<storage::BaseDataLayout> layout =
|
||||
std::make_unique<storage::ContiguousDataLayout>();
|
||||
storage::serialization::read(reader, *layout);
|
||||
auto layout_size = reader.GetPosition();
|
||||
|
||||
regions.push_back({reinterpret_cast<char *>(mem->Ptr()) + layout_size, std::move(layout)});
|
||||
|
||||
@@ -23,7 +23,9 @@ bool EngineConfig::IsValid() const
|
||||
unlimited_or_more_than(max_results_nearest, 0) &&
|
||||
max_alternatives >= 0;
|
||||
|
||||
return ((use_shared_memory && all_path_are_empty) || storage_config.IsValid()) && limits_valid;
|
||||
return ((use_shared_memory && all_path_are_empty) || (use_mmap && storage_config.IsValid()) ||
|
||||
storage_config.IsValid()) &&
|
||||
limits_valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "engine/api/table_parameters.hpp"
|
||||
#include "engine/routing_algorithms/many_to_many.hpp"
|
||||
#include "engine/search_engine_data.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/json_container.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
|
||||
@@ -86,7 +87,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
||||
|
||||
auto result_tables_pair = algorithms.ManyToManySearch(
|
||||
snapped_phantoms, params.sources, params.destinations, request_distance, request_duration);
|
||||
snapped_phantoms, params.sources, params.destinations, request_distance);
|
||||
|
||||
if ((request_duration && result_tables_pair.first.empty()) ||
|
||||
(request_distance && result_tables_pair.second.empty()))
|
||||
@@ -94,6 +95,42 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
return Error("NoTable", "No table found", result);
|
||||
}
|
||||
|
||||
// Scan table for null results - if any exist, replace with distance estimates
|
||||
if (params.fallback_speed > 0)
|
||||
{
|
||||
for (std::size_t row = 0; row < num_sources; row++)
|
||||
{
|
||||
for (std::size_t column = 0; column < num_destinations; column++)
|
||||
{
|
||||
const auto &table_index = row * num_destinations + column;
|
||||
BOOST_ASSERT(table_index < result_tables_pair.first.size());
|
||||
if (result_tables_pair.first[table_index] == MAXIMAL_EDGE_DURATION)
|
||||
{
|
||||
const auto &source =
|
||||
snapped_phantoms[params.sources.empty() ? row : params.sources[row]];
|
||||
const auto &destination =
|
||||
snapped_phantoms[params.destinations.empty() ? column
|
||||
: params.destinations[column]];
|
||||
|
||||
auto distance_estimate =
|
||||
params.fallback_coordinate_type ==
|
||||
api::TableParameters::FallbackCoordinateType::Input
|
||||
? util::coordinate_calculation::fccApproximateDistance(
|
||||
source.input_location, destination.input_location)
|
||||
: util::coordinate_calculation::fccApproximateDistance(
|
||||
source.location, destination.location);
|
||||
|
||||
result_tables_pair.first[table_index] =
|
||||
distance_estimate / (double)params.fallback_speed;
|
||||
if (!result_tables_pair.second.empty())
|
||||
{
|
||||
result_tables_pair.second[table_index] = distance_estimate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
api::TableAPI table_api{facade, params};
|
||||
table_api.MakeResponse(result_tables_pair, snapped_phantoms, result);
|
||||
|
||||
|
||||
@@ -217,10 +217,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
|
||||
// compute the duration table of all phantom nodes
|
||||
auto result_duration_table = util::DistTableWrapper<EdgeWeight>(
|
||||
algorithms
|
||||
.ManyToManySearch(
|
||||
snapped_phantoms, {}, {}, /*requestDistance*/ false, /*requestDuration*/ true)
|
||||
.first,
|
||||
algorithms.ManyToManySearch(snapped_phantoms, {}, {}, /*requestDistance*/ false).first,
|
||||
number_of_locations);
|
||||
|
||||
if (result_duration_table.size() == 0)
|
||||
|
||||
@@ -558,7 +558,7 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
}
|
||||
return (upper_bound <= t_test_path_weight);
|
||||
}
|
||||
} // namespace
|
||||
} // anon. namespace
|
||||
|
||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
@@ -853,4 +853,4 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
} // namespace osrm}
|
||||
|
||||
@@ -120,8 +120,13 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const auto target_distance = current_bucket.distance;
|
||||
|
||||
auto ¤t_weight = weights_table[row_index * number_of_targets + column_index];
|
||||
|
||||
EdgeDistance nulldistance = 0;
|
||||
|
||||
auto ¤t_duration = durations_table[row_index * number_of_targets + column_index];
|
||||
auto ¤t_distance = distances_table[row_index * number_of_targets + column_index];
|
||||
auto ¤t_distance =
|
||||
distances_table.empty() ? nulldistance
|
||||
: distances_table[row_index * number_of_targets + column_index];
|
||||
|
||||
// Check if new weight is better
|
||||
auto new_weight = source_weight + target_weight;
|
||||
@@ -173,98 +178,6 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
|
||||
} // namespace ch
|
||||
|
||||
void retrievePackedPathFromSearchSpace(const NodeID middle_node_id,
|
||||
const unsigned column_index,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<NodeID> &packed_leg)
|
||||
{
|
||||
auto bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||
search_space_with_buckets.end(),
|
||||
middle_node_id,
|
||||
NodeBucket::ColumnCompare(column_index));
|
||||
|
||||
NodeID current_node_id = middle_node_id;
|
||||
|
||||
BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1,
|
||||
"The pointers are not pointing to the same element.");
|
||||
|
||||
while (bucket_list.first->parent_node != current_node_id &&
|
||||
bucket_list.first != search_space_with_buckets.end())
|
||||
{
|
||||
current_node_id = bucket_list.first->parent_node;
|
||||
|
||||
packed_leg.emplace_back(current_node_id);
|
||||
|
||||
bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||
search_space_with_buckets.end(),
|
||||
current_node_id,
|
||||
NodeBucket::ColumnCompare(column_index));
|
||||
}
|
||||
}
|
||||
|
||||
void calculateDistances(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const std::size_t row_index,
|
||||
const std::size_t source_index,
|
||||
const PhantomNode &source_phantom,
|
||||
const std::size_t number_of_targets,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<EdgeDistance> &distances_table,
|
||||
const std::vector<NodeID> &middle_nodes_table)
|
||||
{
|
||||
std::vector<NodeID> packed_leg;
|
||||
|
||||
for (auto column_index : util::irange<std::size_t>(0, number_of_targets))
|
||||
{
|
||||
const auto target_index = target_indices[column_index];
|
||||
const auto &target_phantom = phantom_nodes[target_index];
|
||||
|
||||
if (source_index == target_index)
|
||||
{
|
||||
distances_table[row_index * number_of_targets + column_index] = 0.0;
|
||||
continue;
|
||||
}
|
||||
|
||||
NodeID middle_node_id = middle_nodes_table[row_index * number_of_targets + column_index];
|
||||
|
||||
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
|
||||
{
|
||||
distances_table[row_index * number_of_targets + column_index] = INVALID_EDGE_DISTANCE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 1: Find path from source to middle node
|
||||
ch::retrievePackedPathFromSingleManyToManyHeap(query_heap, middle_node_id, packed_leg);
|
||||
std::reverse(packed_leg.begin(), packed_leg.end());
|
||||
|
||||
packed_leg.push_back(middle_node_id);
|
||||
|
||||
// Step 2: Find path from middle to target node
|
||||
retrievePackedPathFromSearchSpace(
|
||||
middle_node_id, column_index, search_space_with_buckets, packed_leg);
|
||||
|
||||
if (packed_leg.size() == 1 && (needsLoopForward(source_phantom, target_phantom) ||
|
||||
needsLoopBackwards(source_phantom, target_phantom)))
|
||||
{
|
||||
auto weight = ch::getLoopWeight<false>(facade, packed_leg.front());
|
||||
if (std::get<0>(weight) != INVALID_EDGE_WEIGHT)
|
||||
packed_leg.push_back(packed_leg.front());
|
||||
}
|
||||
if (!packed_leg.empty())
|
||||
{
|
||||
EdgeDistance annotation =
|
||||
ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end());
|
||||
annotation = adjustPathDistanceToPhantomNodes(
|
||||
packed_leg, source_phantom, target_phantom, annotation);
|
||||
|
||||
distances_table[row_index * number_of_targets + column_index] = annotation;
|
||||
}
|
||||
packed_leg.clear();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
@@ -272,18 +185,16 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration)
|
||||
const bool calculate_distance)
|
||||
{
|
||||
(void)calculate_duration; // TODO: stub to use when computing durations become optional
|
||||
|
||||
const auto number_of_sources = source_indices.size();
|
||||
const auto number_of_targets = target_indices.size();
|
||||
const auto number_of_entries = number_of_sources * number_of_targets;
|
||||
|
||||
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table(number_of_entries, MAXIMAL_EDGE_DISTANCE);
|
||||
std::vector<EdgeDistance> distances_table(calculate_distance ? number_of_entries : 0,
|
||||
MAXIMAL_EDGE_DISTANCE);
|
||||
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
|
||||
|
||||
std::vector<NodeBucket> search_space_with_buckets;
|
||||
@@ -336,26 +247,6 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
middle_nodes_table,
|
||||
source_phantom);
|
||||
}
|
||||
|
||||
if (calculate_distance)
|
||||
{
|
||||
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
|
||||
// TODO: this is a hack to work around stuff
|
||||
if (number_of_entries == 0)
|
||||
{
|
||||
calculateDistances(query_heap,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
target_indices,
|
||||
row_index,
|
||||
source_index,
|
||||
source_phantom,
|
||||
number_of_targets,
|
||||
search_space_with_buckets,
|
||||
distances_table,
|
||||
middle_nodes_table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(durations_table, distances_table);
|
||||
|
||||
@@ -41,7 +41,7 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
const NodeID node,
|
||||
const EdgeWeight weight,
|
||||
const EdgeDuration duration,
|
||||
const EdgeDistance /* distance TODO use this */,
|
||||
const EdgeDistance distance,
|
||||
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
Args... args)
|
||||
{
|
||||
@@ -66,65 +66,77 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
{ // Shortcuts in forward direction
|
||||
auto destination = cell.GetDestinationNodes().begin();
|
||||
auto shortcut_durations = cell.GetOutDuration(node);
|
||||
auto shortcut_distances = cell.GetOutDistance(node);
|
||||
for (auto shortcut_weight : cell.GetOutWeight(node))
|
||||
{
|
||||
BOOST_ASSERT(destination != cell.GetDestinationNodes().end());
|
||||
BOOST_ASSERT(!shortcut_durations.empty());
|
||||
BOOST_ASSERT(!shortcut_distances.empty());
|
||||
const NodeID to = *destination;
|
||||
|
||||
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
|
||||
{
|
||||
const auto to_weight = weight + shortcut_weight;
|
||||
const auto to_duration = duration + shortcut_durations.front();
|
||||
const auto to_distance = distance + shortcut_distances.front();
|
||||
if (!query_heap.WasInserted(to))
|
||||
{
|
||||
query_heap.Insert(to, to_weight, {node, true, to_duration, 0});
|
||||
query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance});
|
||||
}
|
||||
else if (std::tie(to_weight, to_duration, node) <
|
||||
else if (std::tie(to_weight, to_duration, to_distance, node) <
|
||||
std::tie(query_heap.GetKey(to),
|
||||
query_heap.GetData(to).duration,
|
||||
query_heap.GetData(to).distance,
|
||||
query_heap.GetData(to).parent))
|
||||
{
|
||||
query_heap.GetData(to) = {node, true, to_duration, 0};
|
||||
query_heap.GetData(to) = {node, true, to_duration, to_distance};
|
||||
query_heap.DecreaseKey(to, to_weight);
|
||||
}
|
||||
}
|
||||
++destination;
|
||||
shortcut_durations.advance_begin(1);
|
||||
shortcut_distances.advance_begin(1);
|
||||
}
|
||||
BOOST_ASSERT(shortcut_durations.empty());
|
||||
BOOST_ASSERT(shortcut_distances.empty());
|
||||
}
|
||||
else
|
||||
{ // Shortcuts in backward direction
|
||||
auto source = cell.GetSourceNodes().begin();
|
||||
auto shortcut_durations = cell.GetInDuration(node);
|
||||
auto shortcut_distances = cell.GetInDistance(node);
|
||||
for (auto shortcut_weight : cell.GetInWeight(node))
|
||||
{
|
||||
BOOST_ASSERT(source != cell.GetSourceNodes().end());
|
||||
BOOST_ASSERT(!shortcut_durations.empty());
|
||||
BOOST_ASSERT(!shortcut_distances.empty());
|
||||
const NodeID to = *source;
|
||||
|
||||
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
|
||||
{
|
||||
const auto to_weight = weight + shortcut_weight;
|
||||
const auto to_duration = duration + shortcut_durations.front();
|
||||
const auto to_distance = distance + shortcut_distances.front();
|
||||
if (!query_heap.WasInserted(to))
|
||||
{
|
||||
query_heap.Insert(to, to_weight, {node, true, to_duration, 0});
|
||||
query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance});
|
||||
}
|
||||
else if (std::tie(to_weight, to_duration, node) <
|
||||
else if (std::tie(to_weight, to_duration, to_distance, node) <
|
||||
std::tie(query_heap.GetKey(to),
|
||||
query_heap.GetData(to).duration,
|
||||
query_heap.GetData(to).distance,
|
||||
query_heap.GetData(to).parent))
|
||||
{
|
||||
query_heap.GetData(to) = {node, true, to_duration, 0};
|
||||
query_heap.GetData(to) = {node, true, to_duration, to_distance};
|
||||
query_heap.DecreaseKey(to, to_weight);
|
||||
}
|
||||
}
|
||||
++source;
|
||||
shortcut_durations.advance_begin(1);
|
||||
shortcut_distances.advance_begin(1);
|
||||
}
|
||||
BOOST_ASSERT(shortcut_durations.empty());
|
||||
BOOST_ASSERT(shortcut_distances.empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,25 +156,28 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge);
|
||||
const auto node_weight = facade.GetNodeWeight(node_id);
|
||||
const auto node_duration = facade.GetNodeDuration(node_id);
|
||||
const auto node_distance = facade.GetNodeDistance(node_id);
|
||||
const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id);
|
||||
const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||
|
||||
BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid");
|
||||
const auto to_weight = weight + turn_weight;
|
||||
const auto to_duration = duration + turn_duration;
|
||||
const auto to_distance = distance + node_distance;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!query_heap.WasInserted(to))
|
||||
{
|
||||
query_heap.Insert(to, to_weight, {node, false, to_duration, 0});
|
||||
query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance});
|
||||
}
|
||||
// Found a shorter Path -> Update weight and set new parent
|
||||
else if (std::tie(to_weight, to_duration, node) <
|
||||
else if (std::tie(to_weight, to_duration, to_distance, node) <
|
||||
std::tie(query_heap.GetKey(to),
|
||||
query_heap.GetData(to).duration,
|
||||
query_heap.GetData(to).distance,
|
||||
query_heap.GetData(to).parent))
|
||||
{
|
||||
query_heap.GetData(to) = {node, false, to_duration, 0};
|
||||
query_heap.GetData(to) = {node, false, to_duration, to_distance};
|
||||
query_heap.DecreaseKey(to, to_weight);
|
||||
}
|
||||
}
|
||||
@@ -179,11 +194,12 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
std::size_t phantom_index,
|
||||
const std::vector<std::size_t> &phantom_indices,
|
||||
const bool /* calculate_distance */)
|
||||
const bool calculate_distance)
|
||||
{
|
||||
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table(phantom_indices.size(), MAXIMAL_EDGE_DISTANCE);
|
||||
std::vector<EdgeDistance> distances_table(calculate_distance ? phantom_indices.size() : 0,
|
||||
MAXIMAL_EDGE_DISTANCE);
|
||||
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID);
|
||||
|
||||
// Collect destination (source) nodes into a map
|
||||
@@ -245,7 +261,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
std::size_t index;
|
||||
EdgeWeight target_weight;
|
||||
EdgeDuration target_duration;
|
||||
EdgeDuration target_distance;
|
||||
EdgeDistance target_distance;
|
||||
std::tie(index, target_weight, target_duration, target_distance) = it->second;
|
||||
|
||||
const auto path_weight = weight + target_weight;
|
||||
@@ -254,12 +270,16 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const auto path_duration = duration + target_duration;
|
||||
const auto path_distance = distance + target_distance;
|
||||
|
||||
if (std::tie(path_weight, path_duration) <
|
||||
std::tie(weights[index], durations[index]))
|
||||
EdgeDistance nulldistance = 0;
|
||||
auto ¤t_distance =
|
||||
distances_table.empty() ? nulldistance : distances_table[index];
|
||||
|
||||
if (std::tie(path_weight, path_duration, path_distance) <
|
||||
std::tie(weights[index], durations[index], current_distance))
|
||||
{
|
||||
weights[index] = path_weight;
|
||||
durations[index] = path_duration;
|
||||
distances_table[index] = path_distance;
|
||||
current_distance = path_distance;
|
||||
middle_nodes_table[index] = node;
|
||||
}
|
||||
|
||||
@@ -277,6 +297,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
EdgeWeight initial_weight,
|
||||
EdgeDuration initial_duration,
|
||||
EdgeDistance initial_distance) {
|
||||
|
||||
// Update single node paths
|
||||
update_values(node, initial_weight, initial_duration, initial_distance);
|
||||
|
||||
@@ -303,7 +324,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
facade.GetWeightPenaltyForEdgeID(turn_id);
|
||||
const auto edge_duration = initial_duration + facade.GetNodeDuration(node_id) +
|
||||
facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||
const auto edge_distance = initial_distance;
|
||||
const auto edge_distance = initial_distance + facade.GetNodeDistance(node_id);
|
||||
|
||||
query_heap.Insert(to, edge_weight, {node, edge_duration, edge_distance});
|
||||
}
|
||||
@@ -374,128 +395,6 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
phantom_indices);
|
||||
}
|
||||
|
||||
// TODO: re-enable this if we need to fallback
|
||||
// if (calculate_distance)
|
||||
if (false)
|
||||
{
|
||||
// Initialize unpacking heaps
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||
|
||||
distances_table.resize(phantom_indices.size(), INVALID_EDGE_DISTANCE);
|
||||
|
||||
for (unsigned location = 0; location < phantom_indices.size(); ++location)
|
||||
{
|
||||
// Get the "middle" node that is the last node of a path
|
||||
const NodeID middle_node_id = middle_nodes_table[location];
|
||||
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Retrieve the packed path from the heap
|
||||
PackedPath packed_path = mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(
|
||||
query_heap, middle_node_id);
|
||||
|
||||
// ... and reverse it to have packed edges in the correct order,
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
}
|
||||
|
||||
// ... unpack path
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
std::vector<EdgeID> unpacked_edges;
|
||||
|
||||
std::tie(weight, unpacked_nodes, unpacked_edges) =
|
||||
unpackPathAndCalculateDistance(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
packed_path,
|
||||
middle_node_id,
|
||||
phantom_nodes,
|
||||
phantom_index,
|
||||
phantom_indices);
|
||||
|
||||
// Accumulate the path length without the last node
|
||||
auto annotation = 0.0;
|
||||
|
||||
BOOST_ASSERT(!unpacked_nodes.empty());
|
||||
for (auto node = unpacked_nodes.begin(), last_node = std::prev(unpacked_nodes.end());
|
||||
node != last_node;
|
||||
++node)
|
||||
{
|
||||
annotation += computeEdgeDistance(facade, *node);
|
||||
}
|
||||
|
||||
// ... and add negative source and positive target offsets
|
||||
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
|
||||
// Get source and target phantom nodes
|
||||
// * 1-to-N: source is a single index, target is the corresponding from the indices list
|
||||
// * N-to-1: source is the corresponding from the indices list, target is a single index
|
||||
auto source_phantom_index = phantom_index;
|
||||
auto target_phantom_index = phantom_indices[location];
|
||||
if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
std::swap(source_phantom_index, target_phantom_index);
|
||||
}
|
||||
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||
const NodeID source_node = unpacked_nodes.front();
|
||||
const NodeID target_node = unpacked_nodes.back();
|
||||
|
||||
EdgeDistance source_offset = 0., target_offset = 0.;
|
||||
if (source_phantom.IsValidForwardSource() &&
|
||||
source_phantom.forward_segment_id.id == source_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// -->s <-- subtract offset to start at source
|
||||
// ......... <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
source_offset = source_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (source_phantom.IsValidReverseSource() &&
|
||||
source_phantom.reverse_segment_id.id == source_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// s<------- <-- subtract offset to start at source
|
||||
// ... <-- want this distance
|
||||
// entry 0---1---2---3 <-- 3 is exit node
|
||||
source_offset = source_phantom.GetReverseDistance();
|
||||
}
|
||||
if (target_phantom.IsValidForwardTarget() &&
|
||||
target_phantom.forward_segment_id.id == target_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// ++>t <-- add offset to get to target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
target_offset = target_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (target_phantom.IsValidReverseTarget() &&
|
||||
target_phantom.reverse_segment_id.id == target_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// <++t <-- add offset to get from target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
target_offset = target_phantom.GetReverseDistance();
|
||||
}
|
||||
|
||||
distances_table[location] = -source_offset + annotation + target_offset;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(durations, distances_table);
|
||||
}
|
||||
|
||||
@@ -511,6 +410,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<EdgeWeight> &weights_table,
|
||||
std::vector<EdgeDuration> &durations_table,
|
||||
std::vector<EdgeDistance> &distances_table,
|
||||
std::vector<NodeID> &middle_nodes_table,
|
||||
const PhantomNode &phantom_node)
|
||||
{
|
||||
@@ -530,6 +430,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const auto column_idx = current_bucket.column_index;
|
||||
const auto target_weight = current_bucket.weight;
|
||||
const auto target_duration = current_bucket.duration;
|
||||
const auto target_distance = current_bucket.distance;
|
||||
|
||||
// Get the value location in the results tables:
|
||||
// * row-major direct (row_idx, column_idx) index for forward direction
|
||||
@@ -540,15 +441,21 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
auto ¤t_weight = weights_table[location];
|
||||
auto ¤t_duration = durations_table[location];
|
||||
|
||||
EdgeDistance nulldistance = 0;
|
||||
auto ¤t_distance = distances_table.empty() ? nulldistance : distances_table[location];
|
||||
|
||||
// Check if new weight is better
|
||||
auto new_weight = source_weight + target_weight;
|
||||
auto new_duration = source_duration + target_duration;
|
||||
auto new_distance = source_distance + target_distance;
|
||||
|
||||
if (new_weight >= 0 &&
|
||||
std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration))
|
||||
std::tie(new_weight, new_duration, new_distance) <
|
||||
std::tie(current_weight, current_duration, current_distance))
|
||||
{
|
||||
current_weight = new_weight;
|
||||
current_duration = new_duration;
|
||||
current_distance = new_distance;
|
||||
middle_nodes_table[location] = node;
|
||||
}
|
||||
}
|
||||
@@ -573,7 +480,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
|
||||
// Store settled nodes in search space bucket
|
||||
search_space_with_buckets.emplace_back(
|
||||
node, parent, from_clique_arc, column_idx, target_weight, target_duration);
|
||||
node, parent, from_clique_arc, column_idx, target_weight, target_duration, target_distance);
|
||||
|
||||
const auto &partition = facade.GetMultiLevelPartition();
|
||||
const auto maximal_level = partition.GetNumberOfLevels() - 1;
|
||||
@@ -624,182 +531,6 @@ void retrievePackedPathFromSearchSpace(NodeID middle_node_id,
|
||||
}
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
void calculateDistances(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const unsigned row_idx,
|
||||
const std::size_t source_index,
|
||||
const unsigned number_of_sources,
|
||||
const unsigned number_of_targets,
|
||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||
std::vector<EdgeDistance> &distances_table,
|
||||
const std::vector<NodeID> &middle_nodes_table,
|
||||
SearchEngineData<mld::Algorithm> &engine_working_data)
|
||||
{
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
|
||||
facade.GetMaxBorderNodeID() + 1);
|
||||
|
||||
for (unsigned column_idx = 0; column_idx < number_of_targets; ++column_idx)
|
||||
{
|
||||
// Step 1: Get source and target phantom nodes that were used in the bucketed search
|
||||
auto source_phantom_index = source_index;
|
||||
auto target_phantom_index = target_indices[column_idx];
|
||||
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||
|
||||
const auto location = DIRECTION == FORWARD_DIRECTION
|
||||
? row_idx * number_of_targets + column_idx
|
||||
: row_idx + column_idx * number_of_sources;
|
||||
|
||||
if (source_phantom_index == target_phantom_index)
|
||||
{
|
||||
distances_table[location] = 0.0;
|
||||
continue;
|
||||
}
|
||||
|
||||
NodeID middle_node_id = middle_nodes_table[location];
|
||||
|
||||
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
|
||||
{
|
||||
distances_table[location] = INVALID_EDGE_DISTANCE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 2: Find path from source to middle node
|
||||
PackedPath packed_path =
|
||||
mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(query_heap, middle_node_id);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
}
|
||||
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> unpacked_nodes_from_source;
|
||||
std::vector<EdgeID> unpacked_edges;
|
||||
std::tie(weight, unpacked_nodes_from_source, unpacked_edges) =
|
||||
unpackPathAndCalculateDistance(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
packed_path,
|
||||
middle_node_id,
|
||||
source_phantom);
|
||||
|
||||
// Step 3: Find path from middle to target node
|
||||
packed_path.clear();
|
||||
retrievePackedPathFromSearchSpace<DIRECTION>(
|
||||
middle_node_id, column_idx, search_space_with_buckets, packed_path);
|
||||
|
||||
if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
}
|
||||
|
||||
std::vector<NodeID> unpacked_nodes_to_target;
|
||||
std::tie(weight, unpacked_nodes_to_target, unpacked_edges) =
|
||||
unpackPathAndCalculateDistance(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
packed_path,
|
||||
middle_node_id,
|
||||
target_phantom);
|
||||
|
||||
if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
std::swap(unpacked_nodes_to_target, unpacked_nodes_from_source);
|
||||
}
|
||||
|
||||
// Step 4: Compute annotation value along the path nodes without the target node
|
||||
auto annotation = 0.0;
|
||||
|
||||
for (auto node = unpacked_nodes_from_source.begin(),
|
||||
last_node = std::prev(unpacked_nodes_from_source.end());
|
||||
node != last_node;
|
||||
++node)
|
||||
{
|
||||
annotation += computeEdgeDistance(facade, *node);
|
||||
}
|
||||
|
||||
for (auto node = unpacked_nodes_to_target.begin(),
|
||||
last_node = std::prev(unpacked_nodes_to_target.end());
|
||||
node != last_node;
|
||||
++node)
|
||||
{
|
||||
annotation += computeEdgeDistance(facade, *node);
|
||||
}
|
||||
|
||||
// Step 5: Get phantom node offsets and compute the annotation value
|
||||
EdgeDistance source_offset = 0., target_offset = 0.;
|
||||
{
|
||||
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
|
||||
if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
std::swap(source_phantom_index, target_phantom_index);
|
||||
}
|
||||
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||
|
||||
NodeID source_node = unpacked_nodes_from_source.front();
|
||||
NodeID target_node = unpacked_nodes_to_target.back();
|
||||
|
||||
if (source_phantom.IsValidForwardSource() &&
|
||||
source_phantom.forward_segment_id.id == source_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// -->s <-- subtract offset to start at source
|
||||
// ......... <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
source_offset = source_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (source_phantom.IsValidReverseSource() &&
|
||||
source_phantom.reverse_segment_id.id == source_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// s<------- <-- subtract offset to start at source
|
||||
// ... <-- want this distance
|
||||
// entry 0---1---2---3 <-- 3 is exit node
|
||||
source_offset = source_phantom.GetReverseDistance();
|
||||
}
|
||||
|
||||
if (target_phantom.IsValidForwardTarget() &&
|
||||
target_phantom.forward_segment_id.id == target_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// ++>t <-- add offset to get to target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
target_offset = target_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (target_phantom.IsValidReverseTarget() &&
|
||||
target_phantom.reverse_segment_id.id == target_node)
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||
// to 3
|
||||
// <++t <-- add offset to get from target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
target_offset = target_phantom.GetReverseDistance();
|
||||
}
|
||||
}
|
||||
|
||||
distances_table[location] = -source_offset + annotation + target_offset;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
@@ -815,7 +546,8 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table;
|
||||
std::vector<EdgeDistance> distances_table(calculate_distance ? number_of_entries : 0,
|
||||
INVALID_EDGE_DISTANCE);
|
||||
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
|
||||
|
||||
std::vector<NodeBucket> search_space_with_buckets;
|
||||
@@ -874,25 +606,9 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
search_space_with_buckets,
|
||||
weights_table,
|
||||
durations_table,
|
||||
middle_nodes_table,
|
||||
source_phantom);
|
||||
}
|
||||
|
||||
if (calculate_distance)
|
||||
{
|
||||
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
|
||||
calculateDistances<DIRECTION>(query_heap,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
target_indices, // source_indices
|
||||
row_idx,
|
||||
source_index,
|
||||
number_of_sources,
|
||||
number_of_targets,
|
||||
search_space_with_buckets,
|
||||
distances_table,
|
||||
middle_nodes_table,
|
||||
engine_working_data);
|
||||
source_phantom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,12 +636,8 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance,
|
||||
const bool calculate_duration)
|
||||
const bool calculate_distance)
|
||||
{
|
||||
(void)calculate_duration; // flag stub to use for calculating distances in matrix in mld in the
|
||||
// future
|
||||
|
||||
if (source_indices.size() == 1)
|
||||
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
||||
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||
|
||||
@@ -227,9 +227,6 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
{
|
||||
continue;
|
||||
}
|
||||
forward_heap.Clear();
|
||||
const auto &source_phantom = prev_unbroken_timestamps_list[s].phantom_node;
|
||||
insertSourceInHeap(forward_heap, source_phantom);
|
||||
|
||||
for (const auto s_prime : util::irange<std::size_t>(0UL, current_viterbi.size()))
|
||||
{
|
||||
@@ -240,19 +237,14 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
continue;
|
||||
}
|
||||
|
||||
reverse_heap.Clear();
|
||||
const auto &target_phantom = current_timestamps_list[s_prime].phantom_node;
|
||||
insertTargetInHeap(reverse_heap, target_phantom);
|
||||
|
||||
double network_distance = getNetworkDistance(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
source_phantom,
|
||||
target_phantom,
|
||||
weight_upper_bound);
|
||||
|
||||
network_distance = std::round(network_distance * 10) / 10;
|
||||
double network_distance =
|
||||
getNetworkDistance(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
prev_unbroken_timestamps_list[s].phantom_node,
|
||||
current_timestamps_list[s_prime].phantom_node,
|
||||
weight_upper_bound);
|
||||
|
||||
// get distance diff between loc1/2 and locs/s_prime
|
||||
const auto d_t = std::abs(network_distance - haversine_distance);
|
||||
|
||||
@@ -33,79 +33,6 @@ bool needsLoopBackwards(const PhantomNodes &phantoms)
|
||||
return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom);
|
||||
}
|
||||
|
||||
EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector<NodeID> &path,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const EdgeDistance uncorrected_distance)
|
||||
{
|
||||
EdgeDistance distance = uncorrected_distance;
|
||||
if (!path.empty())
|
||||
{
|
||||
|
||||
// check the direction of travel to figure out how to calculate the offset to/from
|
||||
// the source/target
|
||||
if (source_phantom.forward_segment_id.id == path.front())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// -->s <-- subtract offset to start at source
|
||||
// ......... <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
distance -= source_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (source_phantom.reverse_segment_id.id == path.front())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// s<------- <-- subtract offset to start at source
|
||||
// ... <-- want this distance
|
||||
// entry 0---1---2---3 <-- 3 is exit node
|
||||
distance -= source_phantom.GetReverseDistance();
|
||||
}
|
||||
if (target_phantom.forward_segment_id.id == path.back())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// ++>t <-- add offset to get to target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
distance += target_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (target_phantom.reverse_segment_id.id == path.back())
|
||||
{
|
||||
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||
// <++t <-- add offset to get from target
|
||||
// ................ <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
distance += target_phantom.GetReverseDistance();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is no shortcut to unpack. source and target are on the same EBG Node.
|
||||
// if the offset of the target is greater than the offset of the source, subtract it
|
||||
if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance())
|
||||
{
|
||||
// --------->t <-- offsets
|
||||
// ->s <-- subtract source offset from target offset
|
||||
// ......... <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
distance = target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance();
|
||||
}
|
||||
else
|
||||
{
|
||||
// s<--- <-- offsets
|
||||
// t<--------- <-- subtract source offset from target offset
|
||||
// ...... <-- want this distance as result
|
||||
// entry 0---1---2---3--- <-- 3 is exit node
|
||||
distance = target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance();
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(distance >= 0 || distance > -1.0f,
|
||||
"Distance correction generated negative number");
|
||||
// guard against underflow errors caused by rounding
|
||||
distance = std::max(EdgeDistance{0}, distance);
|
||||
return distance;
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
@@ -100,7 +100,7 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
const PhantomNodes & /*phantom_nodes*/,
|
||||
const EdgeWeight weight_upper_bound)
|
||||
{
|
||||
if (forward_heap.Empty() && reverse_heap.Empty())
|
||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||
{
|
||||
weight = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
@@ -110,14 +110,10 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
weight = weight_upper_bound;
|
||||
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
EdgeWeight min_edge_offset = 0;
|
||||
if (forward_heap.Size() > 0)
|
||||
{
|
||||
min_edge_offset = std::min(min_edge_offset, forward_heap.MinKey());
|
||||
BOOST_ASSERT(min_edge_offset <= 0);
|
||||
}
|
||||
const auto min_edge_offset = std::min(0, forward_heap.MinKey());
|
||||
BOOST_ASSERT(min_edge_offset <= 0);
|
||||
// we only every insert negative offsets for nodes in the forward heap
|
||||
BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() >= 0);
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
||||
|
||||
// run two-Target Dijkstra routing step.
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
@@ -180,6 +176,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const PhantomNode &target_phantom,
|
||||
EdgeWeight weight_upper_bound)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom});
|
||||
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_path;
|
||||
search(engine_working_data,
|
||||
@@ -198,31 +199,14 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
|
||||
EdgeDistance distance = 0;
|
||||
std::vector<PathData> unpacked_path;
|
||||
unpackPath(facade,
|
||||
packed_path.begin(),
|
||||
packed_path.end(),
|
||||
{source_phantom, target_phantom},
|
||||
unpacked_path);
|
||||
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
unpacked_nodes.reserve(packed_path.size());
|
||||
if (!packed_path.empty())
|
||||
{
|
||||
unpacked_nodes.push_back(packed_path.front());
|
||||
unpackPath(
|
||||
facade, packed_path.begin(), packed_path.end(), [&](const auto &edge, const auto &) {
|
||||
BOOST_ASSERT(edge.first == unpacked_nodes.back());
|
||||
unpacked_nodes.push_back(edge.second);
|
||||
});
|
||||
|
||||
distance = std::accumulate(unpacked_nodes.begin(),
|
||||
std::prev(unpacked_nodes.end()),
|
||||
EdgeDistance{0},
|
||||
[&](const EdgeDistance distance, const auto node_id) {
|
||||
return distance + computeEdgeDistance(facade, node_id);
|
||||
});
|
||||
}
|
||||
|
||||
distance =
|
||||
adjustPathDistanceToPhantomNodes(unpacked_nodes, source_phantom, target_phantom, distance);
|
||||
|
||||
return distance;
|
||||
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
|
||||
}
|
||||
} // namespace ch
|
||||
|
||||
|
||||
@@ -396,5 +396,5 @@ std::unique_ptr<SegmentDataContainer> CompressedEdgeContainer::ToSegmentData()
|
||||
|
||||
return std::move(segment_data);
|
||||
}
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ template <> struct hash<std::pair<NodeID, NodeID>>
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
}
|
||||
|
||||
// Buffer size of turn_indexes_write_buffer to reduce number of write(v) syscals
|
||||
const constexpr int TURN_INDEX_WRITE_BUFFER_SIZE = 1000;
|
||||
@@ -114,6 +114,13 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeDurations(
|
||||
swap(m_edge_based_node_durations, output_node_durations);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedNodeDistances(
|
||||
std::vector<EdgeDistance> &output_node_distances)
|
||||
{
|
||||
using std::swap; // Koenig swap
|
||||
swap(m_edge_based_node_distances, output_node_distances);
|
||||
}
|
||||
|
||||
std::uint32_t EdgeBasedGraphFactory::GetConnectivityChecksum() const
|
||||
{
|
||||
return m_connectivity_checksum;
|
||||
@@ -291,8 +298,12 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
|
||||
{
|
||||
// heuristic: node-based graph node is a simple intersection with four edges
|
||||
// (edge-based nodes)
|
||||
m_edge_based_node_weights.reserve(4 * m_node_based_graph.GetNumberOfNodes());
|
||||
m_edge_based_node_durations.reserve(4 * m_node_based_graph.GetNumberOfNodes());
|
||||
constexpr std::size_t ESTIMATED_EDGE_COUNT = 4;
|
||||
m_edge_based_node_weights.reserve(ESTIMATED_EDGE_COUNT * m_node_based_graph.GetNumberOfNodes());
|
||||
m_edge_based_node_durations.reserve(ESTIMATED_EDGE_COUNT *
|
||||
m_node_based_graph.GetNumberOfNodes());
|
||||
m_edge_based_node_distances.reserve(ESTIMATED_EDGE_COUNT *
|
||||
m_node_based_graph.GetNumberOfNodes());
|
||||
nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID);
|
||||
|
||||
// renumber edge based node of outgoing edges
|
||||
@@ -310,6 +321,7 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
|
||||
|
||||
m_edge_based_node_weights.push_back(edge_data.weight);
|
||||
m_edge_based_node_durations.push_back(edge_data.duration);
|
||||
m_edge_based_node_distances.push_back(edge_data.distance);
|
||||
|
||||
BOOST_ASSERT(numbered_edges_count < m_node_based_graph.GetNumberOfEdges());
|
||||
nbe_to_ebn_mapping[current_edge] = numbered_edges_count;
|
||||
@@ -407,6 +419,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
|
||||
m_edge_based_node_weights.push_back(ebn_weight);
|
||||
m_edge_based_node_durations.push_back(
|
||||
m_edge_based_node_durations[nbe_to_ebn_mapping[eid]]);
|
||||
m_edge_based_node_distances.push_back(
|
||||
m_edge_based_node_distances[nbe_to_ebn_mapping[eid]]);
|
||||
|
||||
edge_based_node_id++;
|
||||
progress.PrintStatus(progress_counter++);
|
||||
@@ -416,6 +430,7 @@ 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());
|
||||
|
||||
util::Log() << "Generated " << m_number_of_edge_based_nodes << " nodes ("
|
||||
<< way_restriction_map.NumberOfDuplicatedNodes()
|
||||
@@ -555,21 +570,22 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
&scripting_environment,
|
||||
weight_multiplier,
|
||||
&conditional_restriction_map](
|
||||
// what nodes will be used? In most cases this will be the id
|
||||
// stored in the edge_data. In case of duplicated nodes (e.g.
|
||||
// due to via-way restrictions), one/both of these might
|
||||
// refer to a newly added edge based node
|
||||
const auto edge_based_node_from,
|
||||
const auto edge_based_node_to,
|
||||
// the situation of the turn
|
||||
const auto node_along_road_entering,
|
||||
const auto node_based_edge_from,
|
||||
const auto intersection_node,
|
||||
const auto node_based_edge_to,
|
||||
const auto &turn_angle,
|
||||
const auto &road_legs_on_the_right,
|
||||
const auto &road_legs_on_the_left,
|
||||
const auto &edge_geometries) {
|
||||
// what nodes will be used? In most cases this will be the id
|
||||
// stored in the edge_data. In case of duplicated nodes (e.g.
|
||||
// due to via-way restrictions), one/both of these might
|
||||
// refer to a newly added edge based node
|
||||
const auto edge_based_node_from,
|
||||
const auto edge_based_node_to,
|
||||
// the situation of the turn
|
||||
const auto node_along_road_entering,
|
||||
const auto node_based_edge_from,
|
||||
const auto intersection_node,
|
||||
const auto node_based_edge_to,
|
||||
const auto &turn_angle,
|
||||
const auto &road_legs_on_the_right,
|
||||
const auto &road_legs_on_the_left,
|
||||
const auto &edge_geometries) {
|
||||
|
||||
const auto node_restricted =
|
||||
isRestricted(node_along_road_entering,
|
||||
intersection_node,
|
||||
@@ -693,6 +709,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
//
|
||||
tbb::filter_t<tbb::blocked_range<NodeID>, EdgesPipelineBufferPtr> processor_stage(
|
||||
tbb::filter::parallel, [&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
||||
|
||||
auto buffer = std::make_shared<EdgesPipelineBuffer>();
|
||||
buffer->nodes_processed = intersection_node_range.size();
|
||||
|
||||
@@ -890,7 +907,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// TODO: this loop is not optimized - once we have a few
|
||||
// overrides available, we should index this for faster
|
||||
// lookups
|
||||
for (auto &override : unresolved_maneuver_overrides)
|
||||
for (auto & override : unresolved_maneuver_overrides)
|
||||
{
|
||||
for (auto &turn : override.turn_sequence)
|
||||
{
|
||||
@@ -1031,6 +1048,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
std::vector<EdgeWithData> delayed_data;
|
||||
tbb::filter_t<EdgesPipelineBufferPtr, void> output_stage(
|
||||
tbb::filter::serial_in_order, [&](auto buffer) {
|
||||
|
||||
routing_progress.PrintAddition(buffer->nodes_processed);
|
||||
|
||||
m_connectivity_checksum = buffer->checksum.update_checksum(m_connectivity_checksum);
|
||||
|
||||
@@ -99,7 +99,7 @@ inline NodeID mapExternalToInternalNodeID(Iter first, Iter last, const OSMNodeID
|
||||
return (it == last || value < *it) ? SPECIAL_NODEID
|
||||
: static_cast<NodeID>(std::distance(first, it));
|
||||
}
|
||||
} // namespace
|
||||
}
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -277,8 +277,8 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
{
|
||||
if (edge_iterator->result.osm_source_id < node_iterator->node_id)
|
||||
{
|
||||
util::Log(logDEBUG)
|
||||
<< "Found invalid node reference " << edge_iterator->result.source;
|
||||
util::Log(logDEBUG) << "Found invalid node reference "
|
||||
<< edge_iterator->result.source;
|
||||
edge_iterator->result.source = SPECIAL_NODEID;
|
||||
++edge_iterator;
|
||||
continue;
|
||||
@@ -744,6 +744,7 @@ void ExtractionContainers::PrepareManeuverOverrides()
|
||||
**/
|
||||
auto const find_turn_from_way_tofrom_nodes = [&](auto const &from_segment,
|
||||
auto const &to_segment) {
|
||||
|
||||
if (from_segment.first_segment_source_id == to_segment.first_segment_source_id)
|
||||
{
|
||||
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.first_segment_target_id),
|
||||
@@ -860,6 +861,7 @@ void ExtractionContainers::PrepareManeuverOverrides()
|
||||
// Later, the UnresolvedManeuverOverride will be converted into a final ManeuverOverride
|
||||
// once the edge-based-node IDs are generated by the edge-based-graph-factory
|
||||
const auto transform = [&](const auto &external, auto &internal) {
|
||||
|
||||
// Create a stub override
|
||||
auto maneuver_override =
|
||||
UnresolvedManeuverOverride{{},
|
||||
@@ -1038,9 +1040,8 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
// translate the turn from one segment onto another into a node restriction (the ways can
|
||||
// only
|
||||
// be connected at a single location)
|
||||
auto const get_node_restriction_from_OSM_ids = [&](auto const from_id,
|
||||
auto const to_id,
|
||||
const OSMNodeID via_node) {
|
||||
auto const get_node_restriction_from_OSM_ids = [&](
|
||||
auto const from_id, auto const to_id, const OSMNodeID via_node) {
|
||||
auto const from_segment_itr = referenced_ways.find(from_id);
|
||||
if (from_segment_itr->second.way_id != from_id)
|
||||
{
|
||||
|
||||
@@ -242,6 +242,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
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;
|
||||
std::uint32_t ebg_connectivity_checksum = 0;
|
||||
|
||||
// Create a node-based graph from the OSRM file
|
||||
@@ -322,6 +323,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
node_is_startpoint,
|
||||
edge_based_node_weights,
|
||||
edge_based_node_durations,
|
||||
edge_based_node_distances,
|
||||
edge_based_edge_list,
|
||||
ebg_connectivity_checksum);
|
||||
|
||||
@@ -345,8 +347,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
|
||||
util::Log() << "Saving edge-based node weights to file.";
|
||||
TIMER_START(timer_write_node_weights);
|
||||
extractor::files::writeEdgeBasedNodeWeightsDurations(
|
||||
config.GetPath(".osrm.enw"), edge_based_node_weights, edge_based_node_durations);
|
||||
extractor::files::writeEdgeBasedNodeWeightsDurationsDistances(config.GetPath(".osrm.enw"),
|
||||
edge_based_node_weights,
|
||||
edge_based_node_durations,
|
||||
edge_based_node_distances);
|
||||
TIMER_STOP(timer_write_node_weights);
|
||||
util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")";
|
||||
|
||||
@@ -736,6 +740,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
std::vector<EdgeDuration> &edge_based_node_durations,
|
||||
std::vector<EdgeDistance> &edge_based_node_distances,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::uint32_t &connectivity_checksum)
|
||||
{
|
||||
@@ -786,6 +791,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
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);
|
||||
connectivity_checksum = edge_based_graph_factory.GetConnectivityChecksum();
|
||||
|
||||
return number_of_edge_based_nodes;
|
||||
|
||||
@@ -75,7 +75,7 @@ void ExtractorCallbacks::ProcessRestriction(const InputConditionalTurnRestrictio
|
||||
// util::Log() << restriction.toString();
|
||||
}
|
||||
|
||||
void ExtractorCallbacks::ProcessManeuverOverride(const InputManeuverOverride &override)
|
||||
void ExtractorCallbacks::ProcessManeuverOverride(const InputManeuverOverride & override)
|
||||
{
|
||||
external_memory.external_maneuver_overrides_list.push_back(override);
|
||||
}
|
||||
|
||||
@@ -185,18 +185,17 @@ void GraphCompressor::Compress(
|
||||
* just
|
||||
* like a barrier.
|
||||
*/
|
||||
const auto selectAnnotation =
|
||||
[&node_data_container](const AnnotationID front_annotation,
|
||||
const AnnotationID back_annotation) {
|
||||
// A lane has tags: u - (front) - v - (back) - w
|
||||
// During contraction, we keep only one of the tags. Usually the one closer
|
||||
// to the intersection is preferred. If its empty, however, we keep the
|
||||
// non-empty one
|
||||
if (node_data_container[back_annotation].lane_description_id ==
|
||||
INVALID_LANE_DESCRIPTIONID)
|
||||
return front_annotation;
|
||||
return back_annotation;
|
||||
};
|
||||
const auto selectAnnotation = [&node_data_container](
|
||||
const AnnotationID front_annotation, const AnnotationID back_annotation) {
|
||||
// A lane has tags: u - (front) - v - (back) - w
|
||||
// During contraction, we keep only one of the tags. Usually the one closer
|
||||
// to the intersection is preferred. If its empty, however, we keep the
|
||||
// non-empty one
|
||||
if (node_data_container[back_annotation].lane_description_id ==
|
||||
INVALID_LANE_DESCRIPTIONID)
|
||||
return front_annotation;
|
||||
return back_annotation;
|
||||
};
|
||||
|
||||
graph.GetEdgeData(forward_e1).annotation_data = selectAnnotation(
|
||||
fwd_edge_data1.annotation_data, fwd_edge_data2.annotation_data);
|
||||
@@ -260,7 +259,6 @@ void GraphCompressor::Compress(
|
||||
const auto forward_weight2 = fwd_edge_data2.weight;
|
||||
const auto forward_duration1 = fwd_edge_data1.duration;
|
||||
const auto forward_duration2 = fwd_edge_data2.duration;
|
||||
// const auto forward_distance1 = fwd_edge_data1.distance;
|
||||
const auto forward_distance2 = fwd_edge_data2.distance;
|
||||
|
||||
BOOST_ASSERT(0 != forward_weight1);
|
||||
@@ -270,9 +268,18 @@ void GraphCompressor::Compress(
|
||||
const auto reverse_weight2 = rev_edge_data2.weight;
|
||||
const auto reverse_duration1 = rev_edge_data1.duration;
|
||||
const auto reverse_duration2 = rev_edge_data2.duration;
|
||||
// const auto reverse_distance1 = rev_edge_data1.distance;
|
||||
const auto reverse_distance2 = rev_edge_data2.distance;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Because distances are symmetrical, we only need one
|
||||
// per edge - here we double-check that they match
|
||||
// their mirrors.
|
||||
const auto reverse_distance1 = rev_edge_data1.distance;
|
||||
const auto forward_distance1 = fwd_edge_data1.distance;
|
||||
BOOST_ASSERT(forward_distance1 == reverse_distance2);
|
||||
BOOST_ASSERT(forward_distance2 == reverse_distance1);
|
||||
#endif
|
||||
|
||||
BOOST_ASSERT(0 != reverse_weight1);
|
||||
BOOST_ASSERT(0 != reverse_weight2);
|
||||
|
||||
@@ -284,7 +291,7 @@ void GraphCompressor::Compress(
|
||||
graph.GetEdgeData(forward_e1).duration += forward_duration2;
|
||||
graph.GetEdgeData(reverse_e1).duration += reverse_duration2;
|
||||
|
||||
// add duration of e2's to e1
|
||||
// add distance of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).distance += forward_distance2;
|
||||
graph.GetEdgeData(reverse_e1).distance += reverse_distance2;
|
||||
|
||||
@@ -369,5 +376,5 @@ void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
|
||||
util::Log() << "Node compression ratio: " << new_node_count / (double)original_number_of_nodes;
|
||||
util::Log() << "Edge compression ratio: " << new_edge_count / (double)original_number_of_edges;
|
||||
}
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
}
|
||||
}
|
||||
|
||||
+93
-12
@@ -9,12 +9,15 @@
|
||||
#include "osrm/trip_parameters.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "nodejs/node_osrm.hpp"
|
||||
#include "nodejs/node_osrm_support.hpp"
|
||||
|
||||
#include "util/json_renderer.hpp"
|
||||
|
||||
namespace node_osrm
|
||||
{
|
||||
|
||||
@@ -122,6 +125,8 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
|
||||
if (!params)
|
||||
return;
|
||||
|
||||
auto pluginParams = argumentsToPluginParameters(info);
|
||||
|
||||
BOOST_ASSERT(params->IsValid());
|
||||
|
||||
if (!info[info.Length() - 1]->IsFunction())
|
||||
@@ -137,9 +142,89 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
|
||||
Worker(std::shared_ptr<osrm::OSRM> osrm_,
|
||||
ParamPtr params_,
|
||||
ServiceMemFn service,
|
||||
Nan::Callback *callback)
|
||||
Nan::Callback *callback,
|
||||
PluginParameters pluginParams_)
|
||||
: Base(callback), osrm{std::move(osrm_)}, service{std::move(service)},
|
||||
params{std::move(params_)}
|
||||
params{std::move(params_)}, pluginParams{std::move(pluginParams_)}
|
||||
{
|
||||
}
|
||||
|
||||
void Execute() override try
|
||||
{
|
||||
osrm::json::Object r;
|
||||
const auto status = ((*osrm).*(service))(*params, r);
|
||||
ParseResult(status, r);
|
||||
if (pluginParams.renderJSONToBuffer)
|
||||
{
|
||||
std::ostringstream buf;
|
||||
osrm::util::json::render(buf, r);
|
||||
result = buf.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = r;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
SetErrorMessage(e.what());
|
||||
}
|
||||
|
||||
void HandleOKCallback() override
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
|
||||
const constexpr auto argc = 2u;
|
||||
v8::Local<v8::Value> argv[argc] = {Nan::Null(), render(result)};
|
||||
|
||||
callback->Call(argc, argv);
|
||||
}
|
||||
|
||||
// Keeps the OSRM object alive even after shutdown until we're done with callback
|
||||
std::shared_ptr<osrm::OSRM> osrm;
|
||||
ServiceMemFn service;
|
||||
const ParamPtr params;
|
||||
const PluginParameters pluginParams;
|
||||
|
||||
ObjectOrString result;
|
||||
};
|
||||
|
||||
auto *callback = new Nan::Callback{info[info.Length() - 1].As<v8::Function>()};
|
||||
Nan::AsyncQueueWorker(
|
||||
new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)});
|
||||
}
|
||||
|
||||
template <typename ParameterParser, typename ServiceMemFn>
|
||||
inline void asyncForTiles(const Nan::FunctionCallbackInfo<v8::Value> &info,
|
||||
ParameterParser argsToParams,
|
||||
ServiceMemFn service,
|
||||
bool requires_multiple_coordinates)
|
||||
{
|
||||
auto params = argsToParams(info, requires_multiple_coordinates);
|
||||
if (!params)
|
||||
return;
|
||||
|
||||
auto pluginParams = argumentsToPluginParameters(info);
|
||||
|
||||
BOOST_ASSERT(params->IsValid());
|
||||
|
||||
if (!info[info.Length() - 1]->IsFunction())
|
||||
return Nan::ThrowTypeError("last argument must be a callback function");
|
||||
|
||||
auto *const self = Nan::ObjectWrap::Unwrap<Engine>(info.Holder());
|
||||
using ParamPtr = decltype(params);
|
||||
|
||||
struct Worker final : Nan::AsyncWorker
|
||||
{
|
||||
using Base = Nan::AsyncWorker;
|
||||
|
||||
Worker(std::shared_ptr<osrm::OSRM> osrm_,
|
||||
ParamPtr params_,
|
||||
ServiceMemFn service,
|
||||
Nan::Callback *callback,
|
||||
PluginParameters pluginParams_)
|
||||
: Base(callback), osrm{std::move(osrm_)}, service{std::move(service)},
|
||||
params{std::move(params_)}, pluginParams{std::move(pluginParams_)}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -167,18 +252,14 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
|
||||
std::shared_ptr<osrm::OSRM> osrm;
|
||||
ServiceMemFn service;
|
||||
const ParamPtr params;
|
||||
const PluginParameters pluginParams;
|
||||
|
||||
// All services return json::Object .. except for Tile!
|
||||
using ObjectOrString =
|
||||
typename std::conditional<std::is_same<ParamPtr, tile_parameters_ptr>::value,
|
||||
std::string,
|
||||
osrm::json::Object>::type;
|
||||
|
||||
ObjectOrString result;
|
||||
std::string result;
|
||||
};
|
||||
|
||||
auto *callback = new Nan::Callback{info[info.Length() - 1].As<v8::Function>()};
|
||||
Nan::AsyncQueueWorker(new Worker{self->this_, std::move(params), service, callback});
|
||||
Nan::AsyncQueueWorker(
|
||||
new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)});
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@@ -282,7 +363,7 @@ NAN_METHOD(Engine::nearest) //
|
||||
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @returns {Object} containing `durations`, `sources`, and `destinations`.
|
||||
* @returns {Object} containing `durations`, `distances`, `sources`, and `destinations`.
|
||||
* **`durations`**: array of arrays that stores the matrix in row-major order. `durations[i][j]` gives the travel time from the i-th waypoint to the j-th waypoint.
|
||||
* Values are given in seconds.
|
||||
* **`distances`**: array of arrays that stores the matrix in row-major order. `distances[i][j]` gives the travel time from the i-th waypoint to the j-th waypoint.
|
||||
@@ -341,7 +422,7 @@ NAN_METHOD(Engine::table) //
|
||||
// clang-format on
|
||||
NAN_METHOD(Engine::tile)
|
||||
{
|
||||
async(info, &argumentsToTileParameters, &osrm::OSRM::Tile, {/*unused*/});
|
||||
asyncForTiles(info, &argumentsToTileParameters, &osrm::OSRM::Tile, {/*unused*/});
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
@@ -147,12 +147,15 @@ int Partitioner::Run(const PartitionerConfig &config)
|
||||
{
|
||||
std::vector<EdgeWeight> node_weights;
|
||||
std::vector<EdgeDuration> node_durations;
|
||||
std::vector<EdgeDuration> node_distances;
|
||||
extractor::files::readEdgeBasedNodeWeightsDurations(
|
||||
config.GetPath(".osrm.enw"), node_weights, node_durations);
|
||||
extractor::files::readEdgeBasedNodeDistances(config.GetPath(".osrm.enw"), node_distances);
|
||||
util::inplacePermutation(node_weights.begin(), node_weights.end(), permutation);
|
||||
util::inplacePermutation(node_durations.begin(), node_durations.end(), permutation);
|
||||
extractor::files::writeEdgeBasedNodeWeightsDurations(
|
||||
config.GetPath(".osrm.enw"), node_weights, node_durations);
|
||||
util::inplacePermutation(node_distances.begin(), node_distances.end(), permutation);
|
||||
extractor::files::writeEdgeBasedNodeWeightsDurationsDistances(
|
||||
config.GetPath(".osrm.enw"), node_weights, node_durations, node_distances);
|
||||
}
|
||||
{
|
||||
const auto &filename = config.GetPath(".osrm.maneuver_overrides");
|
||||
|
||||
@@ -56,6 +56,11 @@ std::string getWrongOptionHelp(const engine::api::TableParameters ¶meters)
|
||||
help = "Number of coordinates needs to be at least two.";
|
||||
}
|
||||
|
||||
if (parameters.fallback_speed < 0)
|
||||
{
|
||||
help = "fallback_speed must be > 0";
|
||||
}
|
||||
|
||||
return help;
|
||||
}
|
||||
} // anon. ns
|
||||
|
||||
+87
-72
@@ -44,24 +44,6 @@ namespace
|
||||
{
|
||||
using Monitor = SharedMonitor<SharedRegionRegister>;
|
||||
|
||||
void readBlocks(const boost::filesystem::path &path, DataLayout &layout)
|
||||
{
|
||||
tar::FileReader reader(path, tar::FileReader::VerifyFingerprint);
|
||||
|
||||
std::vector<tar::FileReader::FileEntry> entries;
|
||||
reader.List(std::back_inserter(entries));
|
||||
|
||||
for (const auto &entry : entries)
|
||||
{
|
||||
const auto name_end = entry.name.rfind(".meta");
|
||||
if (name_end == std::string::npos)
|
||||
{
|
||||
auto number_of_elements = reader.ReadElementCount64(entry.name);
|
||||
layout.SetBlock(entry.name, Block{number_of_elements, entry.size});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RegionHandle
|
||||
{
|
||||
std::unique_ptr<SharedMemory> memory;
|
||||
@@ -69,7 +51,8 @@ struct RegionHandle
|
||||
std::uint16_t shm_key;
|
||||
};
|
||||
|
||||
auto setupRegion(SharedRegionRegister &shared_register, const DataLayout &layout)
|
||||
RegionHandle setupRegion(SharedRegionRegister &shared_register,
|
||||
const storage::BaseDataLayout &layout)
|
||||
{
|
||||
// This is safe because we have an exclusive lock for all osrm-datastore processes.
|
||||
auto shm_key = shared_register.ReserveKey();
|
||||
@@ -184,6 +167,24 @@ bool swapData(Monitor &monitor,
|
||||
}
|
||||
}
|
||||
|
||||
void populateLayoutFromFile(const boost::filesystem::path &path, storage::BaseDataLayout &layout)
|
||||
{
|
||||
tar::FileReader reader(path, tar::FileReader::VerifyFingerprint);
|
||||
|
||||
std::vector<tar::FileReader::FileEntry> entries;
|
||||
reader.List(std::back_inserter(entries));
|
||||
|
||||
for (const auto &entry : entries)
|
||||
{
|
||||
const auto name_end = entry.name.rfind(".meta");
|
||||
if (name_end == std::string::npos)
|
||||
{
|
||||
auto number_of_elements = reader.ReadElementCount64(entry.name);
|
||||
layout.SetBlock(entry.name, Block{number_of_elements, entry.size, entry.offset});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Storage::Storage(StorageConfig config_) : config(std::move(config_)) {}
|
||||
|
||||
int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric)
|
||||
@@ -243,29 +244,35 @@ int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric
|
||||
auto static_region = shared_register.GetRegion(region_id);
|
||||
auto static_memory = makeSharedMemory(static_region.shm_key);
|
||||
|
||||
DataLayout static_layout;
|
||||
std::unique_ptr<storage::BaseDataLayout> static_layout =
|
||||
std::make_unique<storage::ContiguousDataLayout>();
|
||||
io::BufferReader reader(reinterpret_cast<char *>(static_memory->Ptr()),
|
||||
static_memory->Size());
|
||||
serialization::read(reader, static_layout);
|
||||
serialization::read(reader, *static_layout);
|
||||
auto layout_size = reader.GetPosition();
|
||||
auto *data_ptr = reinterpret_cast<char *>(static_memory->Ptr()) + layout_size;
|
||||
|
||||
regions.push_back({data_ptr, static_layout});
|
||||
regions.push_back({data_ptr, std::move(static_layout)});
|
||||
readonly_handles.push_back({std::move(static_memory), data_ptr, static_region.shm_key});
|
||||
}
|
||||
else
|
||||
{
|
||||
DataLayout static_layout;
|
||||
PopulateStaticLayout(static_layout);
|
||||
auto static_handle = setupRegion(shared_register, static_layout);
|
||||
regions.push_back({static_handle.data_ptr, static_layout});
|
||||
std::unique_ptr<storage::BaseDataLayout> static_layout =
|
||||
std::make_unique<storage::ContiguousDataLayout>();
|
||||
Storage::PopulateLayoutWithRTree(*static_layout);
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> files = Storage::GetStaticFiles();
|
||||
Storage::PopulateLayout(*static_layout, files);
|
||||
auto static_handle = setupRegion(shared_register, *static_layout);
|
||||
regions.push_back({static_handle.data_ptr, std::move(static_layout)});
|
||||
handles[dataset_name + "/static"] = std::move(static_handle);
|
||||
}
|
||||
|
||||
DataLayout updatable_layout;
|
||||
PopulateUpdatableLayout(updatable_layout);
|
||||
auto updatable_handle = setupRegion(shared_register, updatable_layout);
|
||||
regions.push_back({updatable_handle.data_ptr, updatable_layout});
|
||||
std::unique_ptr<storage::BaseDataLayout> updatable_layout =
|
||||
std::make_unique<storage::ContiguousDataLayout>();
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> files = Storage::GetUpdatableFiles();
|
||||
Storage::PopulateLayout(*updatable_layout, files);
|
||||
auto updatable_handle = setupRegion(shared_register, *updatable_layout);
|
||||
regions.push_back({updatable_handle.data_ptr, std::move(updatable_layout)});
|
||||
handles[dataset_name + "/updatable"] = std::move(updatable_handle);
|
||||
|
||||
SharedDataIndex index{std::move(regions)};
|
||||
@@ -281,24 +288,12 @@ int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function examines all our data files and figures out how much
|
||||
* memory needs to be allocated, and the position of each data structure
|
||||
* in that big block. It updates the fields in the DataLayout parameter.
|
||||
*/
|
||||
void Storage::PopulateStaticLayout(DataLayout &static_layout)
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> Storage::GetStaticFiles()
|
||||
{
|
||||
{
|
||||
auto absolute_file_index_path =
|
||||
boost::filesystem::absolute(config.GetPath(".osrm.fileIndex"));
|
||||
|
||||
static_layout.SetBlock("/common/rtree/file_index_path",
|
||||
make_block<char>(absolute_file_index_path.string().length() + 1));
|
||||
}
|
||||
|
||||
constexpr bool REQUIRED = true;
|
||||
constexpr bool OPTIONAL = false;
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> tar_files = {
|
||||
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> files = {
|
||||
{OPTIONAL, config.GetPath(".osrm.cells")},
|
||||
{OPTIONAL, config.GetPath(".osrm.partition")},
|
||||
{REQUIRED, config.GetPath(".osrm.icd")},
|
||||
@@ -310,53 +305,73 @@ void Storage::PopulateStaticLayout(DataLayout &static_layout)
|
||||
{REQUIRED, config.GetPath(".osrm.maneuver_overrides")},
|
||||
{REQUIRED, config.GetPath(".osrm.edges")},
|
||||
{REQUIRED, config.GetPath(".osrm.names")},
|
||||
{REQUIRED, config.GetPath(".osrm.ramIndex")},
|
||||
};
|
||||
{REQUIRED, config.GetPath(".osrm.ramIndex")}};
|
||||
|
||||
for (const auto &file : tar_files)
|
||||
for (const auto &file : files)
|
||||
{
|
||||
if (boost::filesystem::exists(file.second))
|
||||
if (file.first == REQUIRED && !boost::filesystem::exists(file.second))
|
||||
{
|
||||
readBlocks(file.second, static_layout);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file.first == REQUIRED)
|
||||
{
|
||||
throw util::exception("Could not find required filed: " +
|
||||
std::get<1>(file).string());
|
||||
}
|
||||
throw util::exception("Could not find required filed: " + std::get<1>(file).string());
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
void Storage::PopulateUpdatableLayout(DataLayout &updatable_layout)
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> Storage::GetUpdatableFiles()
|
||||
{
|
||||
constexpr bool REQUIRED = true;
|
||||
constexpr bool OPTIONAL = false;
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> tar_files = {
|
||||
|
||||
std::vector<std::pair<bool, boost::filesystem::path>> files = {
|
||||
{OPTIONAL, config.GetPath(".osrm.mldgr")},
|
||||
{OPTIONAL, config.GetPath(".osrm.cell_metrics")},
|
||||
{OPTIONAL, config.GetPath(".osrm.hsgr")},
|
||||
{REQUIRED, config.GetPath(".osrm.datasource_names")},
|
||||
{REQUIRED, config.GetPath(".osrm.geometry")},
|
||||
{REQUIRED, config.GetPath(".osrm.turn_weight_penalties")},
|
||||
{REQUIRED, config.GetPath(".osrm.turn_duration_penalties")},
|
||||
};
|
||||
{REQUIRED, config.GetPath(".osrm.turn_duration_penalties")}};
|
||||
|
||||
for (const auto &file : tar_files)
|
||||
for (const auto &file : files)
|
||||
{
|
||||
if (file.first == REQUIRED && !boost::filesystem::exists(file.second))
|
||||
{
|
||||
throw util::exception("Could not find required filed: " + std::get<1>(file).string());
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
std::string Storage::PopulateLayoutWithRTree(storage::BaseDataLayout &layout)
|
||||
{
|
||||
// Figure out the path to the rtree file (it's not a tar file)
|
||||
auto absolute_file_index_path = boost::filesystem::absolute(config.GetPath(".osrm.fileIndex"));
|
||||
|
||||
// Convert the boost::filesystem::path object into a plain string
|
||||
// that can then be stored as a member of an allocator object
|
||||
auto rtree_filename = absolute_file_index_path.string();
|
||||
|
||||
// Here, we hardcode the special file_index_path block name.
|
||||
// The important bit here is that the "offset" is set to zero
|
||||
layout.SetBlock("/common/rtree/file_index_path", make_block<char>(rtree_filename.length() + 1));
|
||||
|
||||
return rtree_filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function examines all our data files and figures out how much
|
||||
* memory needs to be allocated, and the position of each data structure
|
||||
* in that big block. It updates the fields in the layout parameter.
|
||||
*/
|
||||
void Storage::PopulateLayout(storage::BaseDataLayout &layout,
|
||||
const std::vector<std::pair<bool, boost::filesystem::path>> &files)
|
||||
{
|
||||
for (const auto &file : files)
|
||||
{
|
||||
if (boost::filesystem::exists(file.second))
|
||||
{
|
||||
readBlocks(file.second, updatable_layout);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file.first == REQUIRED)
|
||||
{
|
||||
throw util::exception("Could not find required filed: " +
|
||||
std::get<1>(file).string());
|
||||
}
|
||||
populateLayoutFromFile(file.second, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +81,7 @@ return_code parseArguments(int argc,
|
||||
"time-zone-file",
|
||||
boost::program_options::value<std::string>(&contractor_config.updater_config.tz_file_path),
|
||||
"Required for conditional turn restriction parsing, provide a geojson file containing "
|
||||
"time zone boundaries")("cache-distances",boost::program_options::bool_switch(&contractor_config.cache_distances)->default_value(false),
|
||||
"Store distances for CH edges, avoiding the need for query-time re-calculation.");
|
||||
"time zone boundaries");
|
||||
|
||||
// hidden options, will be allowed on command line, but will not be shown to the user
|
||||
boost::program_options::options_description hidden_options("Hidden options");
|
||||
|
||||
+13
-14
@@ -70,8 +70,8 @@ std::istream &operator>>(std::istream &in, EngineConfig::Algorithm &algorithm)
|
||||
throw util::RuntimeError(token, ErrorCode::UnknownAlgorithm, SOURCE_REF);
|
||||
return in;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
// generate boost::program_options object for the routing part
|
||||
inline unsigned generateServerProgramOptions(const int argc,
|
||||
@@ -119,7 +119,10 @@ inline unsigned generateServerProgramOptions(const int argc,
|
||||
"Load data from shared memory") //
|
||||
("memory_file",
|
||||
value<boost::filesystem::path>(&config.memory_file),
|
||||
"Store data in a memory mapped file rather than in process memory.") //
|
||||
"DEPRECATED: Will behave the same as --mmap.")(
|
||||
"mmap,m",
|
||||
value<bool>(&config.use_mmap)->implicit_value(true)->default_value(false),
|
||||
"Map datafiles directly, do not use any additional memory.") //
|
||||
("dataset-name",
|
||||
value<std::string>(&config.dataset_name),
|
||||
"Name of the shared memory dataset to connect to.") //
|
||||
@@ -273,10 +276,12 @@ int main(int argc, const char *argv[]) try
|
||||
|
||||
#ifndef _WIN32
|
||||
int sig = 0;
|
||||
sigset_t new_mask;
|
||||
sigset_t old_mask;
|
||||
sigfillset(&new_mask);
|
||||
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
|
||||
sigset_t wait_mask;
|
||||
sigemptyset(&wait_mask);
|
||||
sigaddset(&wait_mask, SIGINT);
|
||||
sigaddset(&wait_mask, SIGQUIT);
|
||||
sigaddset(&wait_mask, SIGTERM);
|
||||
pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr); // only block necessary signals
|
||||
#endif
|
||||
|
||||
auto service_handler = std::make_unique<server::ServiceHandler>(config);
|
||||
@@ -298,19 +303,13 @@ int main(int argc, const char *argv[]) try
|
||||
std::thread server_thread(std::move(server_task));
|
||||
|
||||
#ifndef _WIN32
|
||||
sigset_t wait_mask;
|
||||
pthread_sigmask(SIG_SETMASK, &old_mask, nullptr);
|
||||
sigemptyset(&wait_mask);
|
||||
sigaddset(&wait_mask, SIGINT);
|
||||
sigaddset(&wait_mask, SIGQUIT);
|
||||
sigaddset(&wait_mask, SIGTERM);
|
||||
pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr);
|
||||
util::Log() << "running and waiting for requests";
|
||||
if (std::getenv("SIGNAL_PARENT_WHEN_READY"))
|
||||
{
|
||||
kill(getppid(), SIGUSR1);
|
||||
}
|
||||
sigwait(&wait_mask, &sig);
|
||||
util::Log() << "received signal " << sig;
|
||||
#else
|
||||
// Set console control handler to allow server to be stopped.
|
||||
console_ctrl_function = std::bind(&server::Server::Stop, routing_server);
|
||||
|
||||
+4
-4
@@ -52,14 +52,14 @@ void listRegions(bool show_blocks)
|
||||
auto memory = makeSharedMemory(region.shm_key);
|
||||
io::BufferReader reader(reinterpret_cast<char *>(memory->Ptr()), memory->Size());
|
||||
|
||||
DataLayout layout;
|
||||
serialization::read(reader, layout);
|
||||
std::unique_ptr<BaseDataLayout> layout = std::make_unique<ContiguousDataLayout>();
|
||||
serialization::read(reader, *layout);
|
||||
|
||||
std::vector<std::string> block_names;
|
||||
layout.List("", std::back_inserter(block_names));
|
||||
layout->List("", std::back_inserter(block_names));
|
||||
for (auto &name : block_names)
|
||||
{
|
||||
osrm::util::Log() << " " << name << " " << layout.GetBlockSize(name);
|
||||
osrm::util::Log() << " " << name << " " << layout->GetBlockSize(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,6 @@ namespace coordinate_calculation
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
|
||||
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
|
||||
const constexpr double EARTH_RADIUS = 6372797.560856;
|
||||
|
||||
class CheapRulerContainer
|
||||
{
|
||||
public:
|
||||
@@ -117,7 +112,7 @@ double haversineDistance(const Coordinate coordinate_1, const Coordinate coordin
|
||||
const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) +
|
||||
std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2);
|
||||
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
|
||||
return EARTH_RADIUS * charv;
|
||||
return detail::EARTH_RADIUS * charv;
|
||||
}
|
||||
|
||||
double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
|
||||
@@ -138,7 +133,7 @@ double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coord
|
||||
|
||||
const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0);
|
||||
const double y_value = float_lat2 - float_lat1;
|
||||
return std::hypot(x_value, y_value) * EARTH_RADIUS;
|
||||
return std::hypot(x_value, y_value) * detail::EARTH_RADIUS;
|
||||
}
|
||||
|
||||
double perpendicularDistance(const Coordinate segment_source,
|
||||
|
||||
@@ -25,6 +25,28 @@ test('match: match in Monaco', function(assert) {
|
||||
});
|
||||
});
|
||||
|
||||
test('match: match in Monaco returning a buffer', function(assert) {
|
||||
assert.plan(6);
|
||||
var osrm = new OSRM(data_path);
|
||||
var options = {
|
||||
coordinates: three_test_coordinates,
|
||||
timestamps: [1424684612, 1424684616, 1424684620]
|
||||
};
|
||||
osrm.match(options, { format: 'json_buffer' }, function(err, response) {
|
||||
assert.ifError(err);
|
||||
assert.ok(response instanceof Buffer);
|
||||
response = JSON.parse(response);
|
||||
assert.equal(response.matchings.length, 1);
|
||||
assert.ok(response.matchings.every(function(m) {
|
||||
return !!m.distance && !!m.duration && Array.isArray(m.legs) && !!m.geometry && m.confidence > 0;
|
||||
}))
|
||||
assert.equal(response.tracepoints.length, 3);
|
||||
assert.ok(response.tracepoints.every(function(t) {
|
||||
return !!t.hint && !isNaN(t.matchings_index) && !isNaN(t.waypoint_index) && !!t.name;
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
test('match: match in Monaco without timestamps', function(assert) {
|
||||
assert.plan(3);
|
||||
var osrm = new OSRM(data_path);
|
||||
@@ -225,6 +247,16 @@ test('match: throws on invalid tidy param', function(assert) {
|
||||
/tidy must be of type Boolean/);
|
||||
});
|
||||
|
||||
test('match: throws on invalid config param', function(assert) {
|
||||
assert.plan(1);
|
||||
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
|
||||
var options = {
|
||||
coordinates: three_test_coordinates,
|
||||
};
|
||||
assert.throws(function() { osrm.match(options, { format: 'invalid' }, function(err, response) {}) },
|
||||
/format must be a string:/);
|
||||
});
|
||||
|
||||
test('match: match in Monaco without motorways', function(assert) {
|
||||
assert.plan(3);
|
||||
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
|
||||
|
||||
+20
-1
@@ -19,6 +19,21 @@ test('nearest', function(assert) {
|
||||
});
|
||||
});
|
||||
|
||||
test('nearest', function(assert) {
|
||||
assert.plan(5);
|
||||
var osrm = new OSRM(data_path);
|
||||
osrm.nearest({
|
||||
coordinates: [three_test_coordinates[0]]
|
||||
}, { format: 'json_buffer' }, function(err, result) {
|
||||
assert.ifError(err);
|
||||
assert.ok(result instanceof Buffer);
|
||||
result = JSON.parse(result);
|
||||
assert.equal(result.waypoints.length, 1);
|
||||
assert.equal(result.waypoints[0].location.length, 2);
|
||||
assert.ok(result.waypoints[0].hasOwnProperty('name'));
|
||||
});
|
||||
});
|
||||
|
||||
test('nearest: can ask for multiple nearest pts', function(assert) {
|
||||
assert.plan(2);
|
||||
var osrm = new OSRM(data_path);
|
||||
@@ -32,7 +47,7 @@ test('nearest: can ask for multiple nearest pts', function(assert) {
|
||||
});
|
||||
|
||||
test('nearest: throws on invalid args', function(assert) {
|
||||
assert.plan(6);
|
||||
assert.plan(7);
|
||||
var osrm = new OSRM(data_path);
|
||||
var options = {};
|
||||
assert.throws(function() { osrm.nearest(options); },
|
||||
@@ -52,6 +67,10 @@ test('nearest: throws on invalid args', function(assert) {
|
||||
options.number = 0;
|
||||
assert.throws(function() { osrm.nearest(options, function(err, res) {}); },
|
||||
/Number must be an integer greater than or equal to 1/);
|
||||
|
||||
options.number = 1;
|
||||
assert.throws(function() { osrm.nearest(options, { format: 'invalid' }, function(err, res) {}); },
|
||||
/format must be a string:/);
|
||||
});
|
||||
|
||||
test('nearest: nearest in Monaco without motorways', function(assert) {
|
||||
|
||||
+17
-1
@@ -43,8 +43,22 @@ test('route: routes Monaco on CoreCH', function(assert) {
|
||||
});
|
||||
});
|
||||
|
||||
test('route: routes Monaco and returns a JSON buffer', function(assert) {
|
||||
assert.plan(6);
|
||||
var osrm = new OSRM({path: monaco_corech_path, algorithm: 'CoreCH'});
|
||||
osrm.route({coordinates: [[13.43864,52.51993],[13.415852,52.513191]]}, { format: 'json_buffer'}, function(err, result) {
|
||||
assert.ifError(err);
|
||||
assert.ok(result instanceof Buffer);
|
||||
const route = JSON.parse(result);
|
||||
assert.ok(route.waypoints);
|
||||
assert.ok(route.routes);
|
||||
assert.ok(route.routes.length);
|
||||
assert.ok(route.routes[0].geometry);
|
||||
});
|
||||
});
|
||||
|
||||
test('route: throws with too few or invalid args', function(assert) {
|
||||
assert.plan(3);
|
||||
assert.plan(4);
|
||||
var osrm = new OSRM(monaco_path);
|
||||
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}) },
|
||||
/Two arguments required/);
|
||||
@@ -52,6 +66,8 @@ test('route: throws with too few or invalid args', function(assert) {
|
||||
/First arg must be an object/);
|
||||
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, true)},
|
||||
/last argument must be a callback function/);
|
||||
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, route) {})},
|
||||
/format must be a string:/);
|
||||
});
|
||||
|
||||
test('route: provides no alternatives by default, but when requested it may (not guaranteed)', function(assert) {
|
||||
|
||||
+33
-1
@@ -48,6 +48,20 @@ test('table: test annotations paramater combination', function(assert) {
|
||||
});
|
||||
});
|
||||
|
||||
test('table: returns buffer', function(assert) {
|
||||
assert.plan(3);
|
||||
var osrm = new OSRM(data_path);
|
||||
var options = {
|
||||
coordinates: [three_test_coordinates[0], three_test_coordinates[1]],
|
||||
};
|
||||
osrm.table(options, { format: 'json_buffer' }, function(err, table) {
|
||||
assert.ifError(err);
|
||||
assert.ok(table instanceof Buffer);
|
||||
table = JSON.parse(table);
|
||||
assert.ok(table['durations'], 'distances table result should exist');
|
||||
});
|
||||
});
|
||||
|
||||
var tables = ['distances', 'durations'];
|
||||
|
||||
tables.forEach(function(annotation) {
|
||||
@@ -116,7 +130,7 @@ tables.forEach(function(annotation) {
|
||||
});
|
||||
|
||||
test('table: ' + annotation + ' throws on invalid arguments', function(assert) {
|
||||
assert.plan(14);
|
||||
assert.plan(15);
|
||||
var osrm = new OSRM(data_path);
|
||||
var options = {annotations: [annotation.slice(0,-1)]};
|
||||
assert.throws(function() { osrm.table(options); },
|
||||
@@ -135,6 +149,9 @@ tables.forEach(function(annotation) {
|
||||
/Coordinates must be an array of \(lon\/lat\) pairs/);
|
||||
|
||||
options.coordinates = two_test_coordinates;
|
||||
assert.throws(function() { osrm.table(options, { format: 'invalid' }, function(err, response) {}) },
|
||||
/format must be a string:/);
|
||||
|
||||
options.sources = true;
|
||||
assert.throws(function() { osrm.table(options, function(err, response) {}) },
|
||||
/Sources must be an array of indices \(or undefined\)/);
|
||||
@@ -228,5 +245,20 @@ tables.forEach(function(annotation) {
|
||||
assert.equal(response[annotation].length, 2);
|
||||
});
|
||||
});
|
||||
|
||||
test('table: ' + annotation + ' table in Monaco with fallback speeds', function(assert) {
|
||||
assert.plan(1);
|
||||
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
|
||||
var options = {
|
||||
coordinates: two_test_coordinates,
|
||||
annotations: [annotation.slice(0,-1)],
|
||||
fallback_speed: 1,
|
||||
fallback_coordinate: 'input'
|
||||
};
|
||||
osrm.table(options, function(err, response) {
|
||||
assert.equal(response[annotation].length, 2);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
+16
-1
@@ -17,6 +17,19 @@ test('trip: trip in Monaco', function(assert) {
|
||||
});
|
||||
});
|
||||
|
||||
test('trip: trip in Monaco as a buffer', function(assert) {
|
||||
assert.plan(3);
|
||||
var osrm = new OSRM(data_path);
|
||||
osrm.trip({coordinates: two_test_coordinates}, { format: 'json_buffer' }, function(err, trip) {
|
||||
assert.ifError(err);
|
||||
assert.ok(trip instanceof Buffer);
|
||||
trip = JSON.parse(trip);
|
||||
for (t = 0; t < trip.trips.length; t++) {
|
||||
assert.ok(trip.trips[t].geometry);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('trip: trip with many locations in Monaco', function(assert) {
|
||||
assert.plan(2);
|
||||
|
||||
@@ -33,12 +46,14 @@ test('trip: trip with many locations in Monaco', function(assert) {
|
||||
});
|
||||
|
||||
test('trip: throws with too few or invalid args', function(assert) {
|
||||
assert.plan(2);
|
||||
assert.plan(3);
|
||||
var osrm = new OSRM(data_path);
|
||||
assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}) },
|
||||
/Two arguments required/);
|
||||
assert.throws(function() { osrm.trip(null, function(err, trip) {}) },
|
||||
/First arg must be an object/);
|
||||
assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, trip) {}) },
|
||||
/format must be a string:/);
|
||||
});
|
||||
|
||||
test('trip: throws with bad params', function(assert) {
|
||||
|
||||
@@ -17,7 +17,8 @@ bool operator!=(const QueryEdge &lhs, const QueryEdge &rhs) { return !(lhs == rh
|
||||
std::ostream &operator<<(std::ostream &out, const QueryEdge::EdgeData &data)
|
||||
{
|
||||
out << "{" << data.turn_id << ", " << data.shortcut << ", " << data.duration << ", "
|
||||
<< data.weight << ", " << data.forward << ", " << data.backward << "}";
|
||||
<< data.distance << ", " << data.weight << ", " << data.forward << ", " << data.backward
|
||||
<< "}";
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -36,31 +37,31 @@ BOOST_AUTO_TEST_CASE(merge_edge_of_multiple_graph)
|
||||
ContractedEdgeContainer container;
|
||||
|
||||
std::vector<QueryEdge> edges;
|
||||
edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{2, 0, {3, false, 3, 6, false, true}});
|
||||
edges.push_back(QueryEdge{2, 1, {4, false, 3, 6, false, true}});
|
||||
edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{2, 0, {3, false, 3, 3, 6, false, true}});
|
||||
edges.push_back(QueryEdge{2, 1, {4, false, 3, 3, 6, false, true}});
|
||||
container.Insert(edges);
|
||||
|
||||
edges.clear();
|
||||
edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}});
|
||||
edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}});
|
||||
edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}});
|
||||
edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}});
|
||||
container.Merge(edges);
|
||||
|
||||
edges.clear();
|
||||
edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}});
|
||||
container.Merge(edges);
|
||||
|
||||
std::vector<QueryEdge> reference_edges;
|
||||
reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{2, 0, {3, false, 3, 6, false, true}});
|
||||
reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}});
|
||||
reference_edges.push_back(QueryEdge{2, 1, {4, false, 3, 6, false, true}});
|
||||
reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}});
|
||||
reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{2, 0, {3, false, 3, 3, 6, false, true}});
|
||||
reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}});
|
||||
reference_edges.push_back(QueryEdge{2, 1, {4, false, 3, 3, 6, false, true}});
|
||||
reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}});
|
||||
CHECK_EQUAL_COLLECTIONS(container.edges, reference_edges);
|
||||
|
||||
auto filters = container.MakeEdgeFilters();
|
||||
@@ -78,22 +79,22 @@ BOOST_AUTO_TEST_CASE(merge_edge_of_multiple_disjoint_graph)
|
||||
ContractedEdgeContainer container;
|
||||
|
||||
std::vector<QueryEdge> edges;
|
||||
edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}});
|
||||
edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}});
|
||||
edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}});
|
||||
edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}});
|
||||
container.Merge(edges);
|
||||
|
||||
edges.clear();
|
||||
edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}});
|
||||
edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}});
|
||||
container.Merge(edges);
|
||||
|
||||
std::vector<QueryEdge> reference_edges;
|
||||
reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}});
|
||||
reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}});
|
||||
reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}});
|
||||
reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}});
|
||||
reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}});
|
||||
CHECK_EQUAL_COLLECTIONS(container.edges, reference_edges);
|
||||
|
||||
auto filters = container.MakeEdgeFilters();
|
||||
|
||||
@@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(contract_graph)
|
||||
reference_graph.DeleteEdgesTo(1, 3);
|
||||
reference_graph.DeleteEdgesTo(4, 3);
|
||||
// Insert shortcut
|
||||
reference_graph.InsertEdge(4, 1, {2, 4, 3, 0, true, true, false});
|
||||
reference_graph.InsertEdge(4, 1, {2, 4, 1.0, 3, 0, true, true, false});
|
||||
|
||||
/* After contracting 4:
|
||||
*
|
||||
|
||||
@@ -20,15 +20,19 @@ inline contractor::ContractorGraph makeGraph(const std::vector<TestEdge> &edges)
|
||||
unsigned target;
|
||||
int weight;
|
||||
std::tie(start, target, weight) = edge;
|
||||
int duration = weight * 2;
|
||||
float distance = 1.0;
|
||||
max_id = std::max(std::max(start, target), max_id);
|
||||
input_edges.push_back(contractor::ContractorEdge{
|
||||
start,
|
||||
target,
|
||||
contractor::ContractorEdgeData{weight, weight * 2, id++, 0, false, true, false}});
|
||||
contractor::ContractorEdgeData{
|
||||
weight, duration, distance, id++, 0, false, true, false}});
|
||||
input_edges.push_back(contractor::ContractorEdge{
|
||||
target,
|
||||
start,
|
||||
contractor::ContractorEdgeData{weight, weight * 2, id++, 0, false, false, true}});
|
||||
contractor::ContractorEdgeData{
|
||||
weight, duration, distance, id++, 0, false, false, true}});
|
||||
}
|
||||
std::sort(input_edges.begin(), input_edges.end());
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ auto makeGraph(const MultiLevelPartition &mlp, const std::vector<MockEdge> &mock
|
||||
{
|
||||
EdgeWeight weight;
|
||||
EdgeDuration duration;
|
||||
EdgeDistance distance;
|
||||
bool forward;
|
||||
bool backward;
|
||||
};
|
||||
@@ -36,8 +37,20 @@ auto makeGraph(const MultiLevelPartition &mlp, const std::vector<MockEdge> &mock
|
||||
for (const auto &m : mock_edges)
|
||||
{
|
||||
max_id = std::max<std::size_t>(max_id, std::max(m.start, m.target));
|
||||
edges.push_back(Edge{m.start, m.target, m.weight, 2 * m.weight, true, false});
|
||||
edges.push_back(Edge{m.target, m.start, m.weight, 2 * m.weight, false, true});
|
||||
edges.push_back(Edge{m.start,
|
||||
m.target,
|
||||
m.weight,
|
||||
2 * m.weight,
|
||||
static_cast<EdgeDistance>(1.0),
|
||||
true,
|
||||
false});
|
||||
edges.push_back(Edge{m.target,
|
||||
m.start,
|
||||
m.weight,
|
||||
2 * m.weight,
|
||||
static_cast<EdgeDistance>(1.0),
|
||||
false,
|
||||
true});
|
||||
}
|
||||
std::sort(edges.begin(), edges.end());
|
||||
return partitioner::MultiLevelGraph<EdgeData, osrm::storage::Ownership::Container>(
|
||||
|
||||
@@ -31,6 +31,7 @@ inline InputEdge MakeUnitEdge(const NodeID from, const NodeID to)
|
||||
to, // target
|
||||
1, // weight
|
||||
1, // duration
|
||||
1, // distance
|
||||
GeometryID{0, false}, // geometry_id
|
||||
false, // reversed
|
||||
NodeBasedEdgeClassification(), // default flags
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user