Add feature to fill null table entries with as-the-crow-flies estimates.
This commit is contained in:
parent
cb1db646f2
commit
985ab58f45
@ -2,6 +2,7 @@
|
|||||||
- Changes from 5.19.0:
|
- Changes from 5.19.0:
|
||||||
- Table:
|
- 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)
|
- 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)
|
||||||
- Features:
|
- Features:
|
||||||
- ADDED: direct mmapping of datafiles is now supported via the `--mmap` switch. [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
|
- 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)
|
- REMOVED: the previous `--memory_file` switch is now deprecated and will fallback to `--mmap` [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
|
||||||
|
10
docs/http.md
10
docs/http.md
@ -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. |
|
|sources |`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as source. |
|
||||||
|destinations|`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as destination.|
|
|destinations|`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as destination.|
|
||||||
|annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned.
|
|annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. 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**
|
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
|
||||||
to number of input locations;
|
to number of input locations;
|
||||||
@ -283,6 +284,7 @@ curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397
|
|||||||
the i-th waypoint to the j-th waypoint. Values are given in meters. Can be `null` if no route between `i` and `j` can be found. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned.
|
the i-th waypoint to the j-th waypoint. Values are given in meters. Can be `null` if no route between `i` and `j` can be found. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned.
|
||||||
- `sources` array of `Waypoint` objects describing all sources in order
|
- `sources` array of `Waypoint` objects describing all sources in order
|
||||||
- `destinations` array of `Waypoint` objects describing all destinations in order
|
- `destinations` array of `Waypoint` objects describing all destinations in order
|
||||||
|
- `estimated_cells` (optional) array of arrays containing `i,j` pairs indicating which cells contain estimated values based on `fallback_speed`. Will be absent if `fallback_speed` is not used.
|
||||||
|
|
||||||
In case of error the following `code`s are supported in addition to the general ones:
|
In case of error the following `code`s are supported in addition to the general ones:
|
||||||
|
|
||||||
@ -383,6 +385,10 @@ All other properties might be undefined.
|
|||||||
2361.73,
|
2361.73,
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
|
],
|
||||||
|
"estimated_cells": [
|
||||||
|
[ 0, 1 ],
|
||||||
|
[ 1, 0 ]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -129,6 +129,8 @@ tables. Optionally returns distance table.
|
|||||||
- `options.destinations` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer <
|
- `options.destinations` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer <
|
||||||
#coordinates`) to use location with given index as destination. Default is to use all.
|
#coordinates`) to use location with given index as destination. Default is to use all.
|
||||||
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
|
||||||
|
- `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)**
|
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
|
||||||
|
|
||||||
**Examples**
|
**Examples**
|
||||||
@ -154,6 +156,7 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
|
|||||||
Values are given in seconds.
|
Values are given in seconds.
|
||||||
**`sources`**: array of [`Ẁaypoint`](#waypoint) objects describing all sources in order.
|
**`sources`**: array of [`Ẁaypoint`](#waypoint) objects describing all sources in order.
|
||||||
**`destinations`**: array of [`Ẁaypoint`](#waypoint) objects describing all destinations in order.
|
**`destinations`**: array of [`Ẁaypoint`](#waypoint) objects describing all destinations in order.
|
||||||
|
**`estimated_cells`**: (optional) if `fallback_speed` is used, will be an array of arrays of `row,column` values, indicating which cells contain estimated values.
|
||||||
|
|
||||||
### tile
|
### tile
|
||||||
|
|
||||||
|
@ -3,22 +3,25 @@ var util = require('util');
|
|||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
const durationsRegex = new RegExp(/^I request a travel time matrix I should get$/);
|
const durationsRegex = new RegExp(/^I request a travel time matrix I should get$/);
|
||||||
const distancesRegex = new RegExp(/^I request a travel distance matrix I should get$/);
|
const distancesRegex = new RegExp(/^I request a travel distance matrix I should get$/);
|
||||||
|
const estimatesRegex = new RegExp(/^I request a travel time matrix I should get estimates for$/);
|
||||||
|
|
||||||
const DURATIONS_NO_ROUTE = 2147483647; // MAX_INT
|
const DURATIONS_NO_ROUTE = 2147483647; // MAX_INT
|
||||||
const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT
|
const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT
|
||||||
|
|
||||||
this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', callback);}.bind(this));
|
this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', callback);}.bind(this));
|
||||||
this.When(distancesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', callback);}.bind(this));
|
this.When(distancesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', callback);}.bind(this));
|
||||||
|
this.When(estimatesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'estimated_cells', callback);}.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
const durationsParse = function(v) { return isNaN(parseInt(v)); };
|
const durationsParse = function(v) { return isNaN(parseInt(v)); };
|
||||||
const distancesParse = function(v) { return isNaN(parseFloat(v)); };
|
const distancesParse = function(v) { return isNaN(parseFloat(v)); };
|
||||||
|
const estimatesParse = function(v) { return isNaN(parseFloat(v)); };
|
||||||
|
|
||||||
function tableParse(table, noRoute, annotation, callback) {
|
function tableParse(table, noRoute, annotation, callback) {
|
||||||
|
|
||||||
const parse = annotation == 'distances' ? distancesParse : durationsParse;
|
const parse = annotation == 'distances' ? distancesParse : (annotation == 'durations' ? durationsParse : estimatesParse);
|
||||||
const params = this.queryParams;
|
const params = this.queryParams;
|
||||||
params.annotations = annotation == 'distances' ? 'distance' : 'duration';
|
params.annotations = ['durations','estimated_cells'].includes(annotation) ? 'duration' : 'distance';
|
||||||
|
|
||||||
var tableRows = table.raw();
|
var tableRows = table.raw();
|
||||||
|
|
||||||
@ -61,11 +64,26 @@ function tableParse(table, noRoute, annotation, callback) {
|
|||||||
|
|
||||||
var json = JSON.parse(response.body);
|
var json = JSON.parse(response.body);
|
||||||
|
|
||||||
var result = json[annotation].map(row => {
|
var result = {};
|
||||||
var hashes = {};
|
if (annotation === 'estimated_cells') {
|
||||||
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; });
|
result = table.raw().map(row => row.map(cell => ''));
|
||||||
return hashes;
|
json[annotation].forEach(pair => {
|
||||||
});
|
result[pair[0]+1][pair[1]+1] = 'Y';
|
||||||
|
});
|
||||||
|
result = result.slice(1).map(row => {
|
||||||
|
var hashes = {};
|
||||||
|
row.slice(1).forEach((v,i) => {
|
||||||
|
hashes[tableRows[0][i+1]] = v;
|
||||||
|
});
|
||||||
|
return hashes;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result = json[annotation].map(row => {
|
||||||
|
var hashes = {};
|
||||||
|
row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; });
|
||||||
|
return hashes;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var testRow = (row, ri, cb) => {
|
var testRow = (row, ri, cb) => {
|
||||||
for (var k in result[ri]) {
|
for (var k in result[ri]) {
|
||||||
|
@ -595,3 +595,75 @@ Feature: Basic Distance Matrix
|
|||||||
| d | 1478.9 | 1579 | 1779.1 | 0 | 1280.1 | 882.5 |
|
| d | 1478.9 | 1579 | 1779.1 | 0 | 1280.1 | 882.5 |
|
||||||
| e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 |
|
| e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 |
|
||||||
| f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 |
|
| f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
||||||
|
Given a grid size of 300 meters
|
||||||
|
Given the extract extra arguments "--small-component-size 4"
|
||||||
|
Given the query options
|
||||||
|
| fallback_speed | 5 |
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b f h 1
|
||||||
|
d e g i
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abeda |
|
||||||
|
| fhigf |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | f | 1 |
|
||||||
|
| a | 0 | 300.2 | 900.7 | 1501.1 |
|
||||||
|
| b | 300.2 | 0 | 600.5 | 1200.9 |
|
||||||
|
| f | 900.7 | 600.5 | 0 | 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 |
|
@ -510,3 +510,81 @@ Feature: Basic Duration Matrix
|
|||||||
| | a |
|
| | a |
|
||||||
| a | 0 |
|
| a | 0 |
|
||||||
| b | 24.1 |
|
| b | 24.1 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
|
||||||
|
Given a grid size of 300 meters
|
||||||
|
Given the extract extra arguments "--small-component-size 4"
|
||||||
|
Given the query options
|
||||||
|
| fallback_speed | 5 |
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b f h 1
|
||||||
|
d e g i
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abeda |
|
||||||
|
| fhigf |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | f | 1 |
|
||||||
|
| a | 0 | 30 | 18 | 30 |
|
||||||
|
| b | 30 | 0 | 12 | 24 |
|
||||||
|
| f | 18 | 12 | 0 | 30 |
|
||||||
|
| 1 | 30 | 24 | 30 | 0 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get estimates for
|
||||||
|
| | a | b | f | 1 |
|
||||||
|
| a | | | Y | Y |
|
||||||
|
| b | | | Y | Y |
|
||||||
|
| f | Y | Y | | |
|
||||||
|
| 1 | Y | Y | | |
|
||||||
|
|
||||||
|
Scenario: Testbot - Filling in noroutes with estimates - use input coordinate
|
||||||
|
Given a grid size of 300 meters
|
||||||
|
Given the extract extra arguments "--small-component-size 4"
|
||||||
|
Given the query options
|
||||||
|
| fallback_speed | 5 |
|
||||||
|
| fallback_coordinate | input |
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b f h 1
|
||||||
|
d e g i
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| abeda |
|
||||||
|
| fhigf |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | f | 1 |
|
||||||
|
| a | 0 | 30 | 18 | 30 |
|
||||||
|
| b | 30 | 0 | 12 | 24 |
|
||||||
|
| f | 18 | 12 | 0 | 30 |
|
||||||
|
| 1 | 30 | 24 | 30 | 0 |
|
||||||
|
|
||||||
|
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 |
|
@ -31,6 +31,15 @@ namespace api
|
|||||||
class TableAPI final : public BaseAPI
|
class TableAPI final : public BaseAPI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct TableCellRef
|
||||||
|
{
|
||||||
|
TableCellRef(const std::size_t &row, const std::size_t &column) : row{row}, column{column}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
std::size_t row;
|
||||||
|
std::size_t column;
|
||||||
|
};
|
||||||
|
|
||||||
TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters ¶meters_)
|
TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters ¶meters_)
|
||||||
: BaseAPI(facade_, parameters_), parameters(parameters_)
|
: BaseAPI(facade_, parameters_), parameters(parameters_)
|
||||||
{
|
{
|
||||||
@ -39,6 +48,7 @@ class TableAPI final : public BaseAPI
|
|||||||
virtual void
|
virtual void
|
||||||
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
MakeResponse(const std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>> &tables,
|
||||||
const std::vector<PhantomNode> &phantoms,
|
const std::vector<PhantomNode> &phantoms,
|
||||||
|
const std::vector<TableCellRef> &estimated_cells,
|
||||||
util::json::Object &response) const
|
util::json::Object &response) const
|
||||||
{
|
{
|
||||||
auto number_of_sources = parameters.sources.size();
|
auto number_of_sources = parameters.sources.size();
|
||||||
@ -77,6 +87,11 @@ class TableAPI final : public BaseAPI
|
|||||||
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations);
|
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parameters.fallback_speed > 0)
|
||||||
|
{
|
||||||
|
response.values["estimated_cells"] = MakeEstimatesTable(estimated_cells);
|
||||||
|
}
|
||||||
|
|
||||||
response.values["code"] = "Ok";
|
response.values["code"] = "Ok";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +178,19 @@ class TableAPI final : public BaseAPI
|
|||||||
return json_table;
|
return json_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual util::json::Array
|
||||||
|
MakeEstimatesTable(const std::vector<TableCellRef> &estimated_cells) const
|
||||||
|
{
|
||||||
|
util::json::Array json_table;
|
||||||
|
std::for_each(estimated_cells.begin(), estimated_cells.end(), [&](const auto &cell) {
|
||||||
|
util::json::Array row;
|
||||||
|
row.values.push_back(util::json::Number(cell.row));
|
||||||
|
row.values.push_back(util::json::Number(cell.column));
|
||||||
|
json_table.values.push_back(std::move(row));
|
||||||
|
});
|
||||||
|
return json_table;
|
||||||
|
}
|
||||||
|
|
||||||
const TableParameters ¶meters;
|
const TableParameters ¶meters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,6 +59,15 @@ struct TableParameters : public BaseParameters
|
|||||||
{
|
{
|
||||||
std::vector<std::size_t> sources;
|
std::vector<std::size_t> sources;
|
||||||
std::vector<std::size_t> destinations;
|
std::vector<std::size_t> destinations;
|
||||||
|
double fallback_speed = 0;
|
||||||
|
|
||||||
|
enum class FallbackCoordinateType
|
||||||
|
{
|
||||||
|
Input = 0,
|
||||||
|
Snapped = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
FallbackCoordinateType fallback_coordinate_type = FallbackCoordinateType::Input;
|
||||||
|
|
||||||
enum class AnnotationsType
|
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
|
bool IsValid() const
|
||||||
{
|
{
|
||||||
if (!BaseParameters::IsValid())
|
if (!BaseParameters::IsValid())
|
||||||
@ -117,6 +139,9 @@ struct TableParameters : public BaseParameters
|
|||||||
if (std::any_of(begin(destinations), end(destinations), not_in_range))
|
if (std::any_of(begin(destinations), end(destinations), not_in_range))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (fallback_speed < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1183,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;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +178,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
|||||||
qi::rule<Iterator, Signature> base_rule;
|
qi::rule<Iterator, Signature> base_rule;
|
||||||
qi::rule<Iterator, Signature> query_rule;
|
qi::rule<Iterator, Signature> query_rule;
|
||||||
|
|
||||||
|
qi::real_parser<double, json_policy> double_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qi::rule<Iterator, Signature> bearings_rule;
|
qi::rule<Iterator, Signature> bearings_rule;
|
||||||
qi::rule<Iterator, Signature> radiuses_rule;
|
qi::rule<Iterator, Signature> radiuses_rule;
|
||||||
@ -195,7 +197,6 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
|
|||||||
qi::rule<Iterator, unsigned char()> base64_char;
|
qi::rule<Iterator, unsigned char()> base64_char;
|
||||||
qi::rule<Iterator, std::string()> polyline_chars;
|
qi::rule<Iterator, std::string()> polyline_chars;
|
||||||
qi::rule<Iterator, double()> unlimited_rule;
|
qi::rule<Iterator, double()> unlimited_rule;
|
||||||
qi::real_parser<double, json_policy> double_;
|
|
||||||
|
|
||||||
qi::symbols<char, engine::Approach> approach_type;
|
qi::symbols<char, engine::Approach> approach_type;
|
||||||
};
|
};
|
||||||
|
@ -48,10 +48,24 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
|
|||||||
(qi::lit("all") |
|
(qi::lit("all") |
|
||||||
(size_t_ % ';')[ph::bind(&engine::api::TableParameters::sources, qi::_r1) = qi::_1]);
|
(size_t_ % ';')[ph::bind(&engine::api::TableParameters::sources, qi::_r1) = qi::_1]);
|
||||||
|
|
||||||
|
fallback_speed_rule =
|
||||||
|
qi::lit("fallback_speed=") >
|
||||||
|
(double_)[ph::bind(&engine::api::TableParameters::fallback_speed, qi::_r1) = qi::_1];
|
||||||
|
|
||||||
|
fallback_coordinate_type.add("input",
|
||||||
|
engine::api::TableParameters::FallbackCoordinateType::Input)(
|
||||||
|
"snapped", engine::api::TableParameters::FallbackCoordinateType::Snapped);
|
||||||
|
|
||||||
table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1);
|
table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1);
|
||||||
|
|
||||||
root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
|
root_rule =
|
||||||
-('?' > (table_rule(qi::_r1) | base_rule(qi::_r1)) % '&');
|
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_)
|
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;
|
qi::rule<Iterator, Signature> base_rule;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using json_policy = no_trailing_dot_policy<double, 'j', 's', 'o', 'n'>;
|
||||||
|
|
||||||
qi::rule<Iterator, Signature> root_rule;
|
qi::rule<Iterator, Signature> root_rule;
|
||||||
qi::rule<Iterator, Signature> table_rule;
|
qi::rule<Iterator, Signature> table_rule;
|
||||||
qi::rule<Iterator, Signature> sources_rule;
|
qi::rule<Iterator, Signature> sources_rule;
|
||||||
qi::rule<Iterator, Signature> destinations_rule;
|
qi::rule<Iterator, Signature> destinations_rule;
|
||||||
|
qi::rule<Iterator, Signature> fallback_speed_rule;
|
||||||
qi::rule<Iterator, std::size_t()> size_t_;
|
qi::rule<Iterator, std::size_t()> size_t_;
|
||||||
qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations;
|
qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations;
|
||||||
qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list;
|
qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list;
|
||||||
|
qi::symbols<char, engine::api::TableParameters::FallbackCoordinateType>
|
||||||
|
fallback_coordinate_type;
|
||||||
|
qi::real_parser<double, json_policy> double_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "engine/api/table_parameters.hpp"
|
#include "engine/api/table_parameters.hpp"
|
||||||
#include "engine/routing_algorithms/many_to_many.hpp"
|
#include "engine/routing_algorithms/many_to_many.hpp"
|
||||||
#include "engine/search_engine_data.hpp"
|
#include "engine/search_engine_data.hpp"
|
||||||
|
#include "util/coordinate_calculation.hpp"
|
||||||
#include "util/json_container.hpp"
|
#include "util/json_container.hpp"
|
||||||
#include "util/string_util.hpp"
|
#include "util/string_util.hpp"
|
||||||
|
|
||||||
@ -94,8 +95,47 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
return Error("NoTable", "No table found", result);
|
return Error("NoTable", "No table found", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<api::TableAPI::TableCellRef> estimated_pairs;
|
||||||
|
|
||||||
|
// 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_sources + column;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
estimated_pairs.emplace_back(row, column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
api::TableAPI table_api{facade, params};
|
api::TableAPI table_api{facade, params};
|
||||||
table_api.MakeResponse(result_tables_pair, snapped_phantoms, result);
|
table_api.MakeResponse(result_tables_pair, snapped_phantoms, estimated_pairs, result);
|
||||||
|
|
||||||
return Status::Ok;
|
return Status::Ok;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,11 @@ std::string getWrongOptionHelp(const engine::api::TableParameters ¶meters)
|
|||||||
help = "Number of coordinates needs to be at least two.";
|
help = "Number of coordinates needs to be at least two.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parameters.fallback_speed < 0)
|
||||||
|
{
|
||||||
|
help = "fallback_speed must be > 0";
|
||||||
|
}
|
||||||
|
|
||||||
return help;
|
return help;
|
||||||
}
|
}
|
||||||
} // anon. ns
|
} // anon. ns
|
||||||
|
@ -234,7 +234,7 @@ tables.forEach(function(annotation) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('table: ' + annotation + ' table in Monaco without motorways', function(assert) {
|
test('table: ' + annotation + ' table in Monaco without motorways', function(assert) {
|
||||||
assert.plan(1);
|
assert.plan(2);
|
||||||
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
|
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
|
||||||
var options = {
|
var options = {
|
||||||
coordinates: two_test_coordinates,
|
coordinates: two_test_coordinates,
|
||||||
@ -243,7 +243,24 @@ tables.forEach(function(annotation) {
|
|||||||
};
|
};
|
||||||
osrm.table(options, function(err, response) {
|
osrm.table(options, function(err, response) {
|
||||||
assert.equal(response[annotation].length, 2);
|
assert.equal(response[annotation].length, 2);
|
||||||
|
assert.strictEqual(response.estimated_cells, undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('table: ' + annotation + ' table in Monaco with fallback speeds', function(assert) {
|
||||||
|
assert.plan(2);
|
||||||
|
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);
|
||||||
|
assert.equal(response['estimated_cells'].length, 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -89,6 +89,8 @@ BOOST_AUTO_TEST_CASE(invalid_table_urls)
|
|||||||
BOOST_CHECK_EQUAL(
|
BOOST_CHECK_EQUAL(
|
||||||
testInvalidOptions<TableParameters>("1,2;3,4?sources=all&destinations=all&annotations=bla"),
|
testInvalidOptions<TableParameters>("1,2;3,4?sources=all&destinations=all&annotations=bla"),
|
||||||
49UL);
|
49UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?fallback_coordinate=asdf"),
|
||||||
|
28UL);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(valid_route_hint)
|
BOOST_AUTO_TEST_CASE(valid_route_hint)
|
||||||
|
Loading…
Reference in New Issue
Block a user