From 985ab58f45876c8c57960bbf4eff50c9d43ff054 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Wed, 31 Oct 2018 22:02:54 -0700 Subject: [PATCH] Add feature to fill null table entries with as-the-crow-flies estimates. --- CHANGELOG.md | 1 + docs/http.md | 10 ++- docs/nodejs/api.md | 3 + features/step_definitions/distance_matrix.js | 32 ++++++-- features/testbot/distance_matrix.feature | 72 +++++++++++++++++ features/testbot/duration_matrix.feature | 78 +++++++++++++++++++ include/engine/api/table_api.hpp | 28 +++++++ include/engine/api/table_parameters.hpp | 25 ++++++ include/nodejs/node_osrm_support.hpp | 46 +++++++++++ .../server/api/base_parameters_grammar.hpp | 3 +- .../server/api/table_parameter_grammar.hpp | 24 +++++- src/engine/plugins/table.cpp | 42 +++++++++- src/server/service/table_service.cpp | 5 ++ test/nodejs/table.js | 19 ++++- unit_tests/server/parameters_parser.cpp | 2 + 15 files changed, 376 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ed1826aa..27a416808 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - 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) - 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) diff --git a/docs/http.md b/docs/http.md index 3cb2b811b..78f9ba459 100644 --- a/docs/http.md +++ b/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. | |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; @@ -283,6 +284,7 @@ curl 'http://router.project-osrm.org/table/v1/driving/13.388860,52.517037;13.397 the i-th waypoint to the j-th waypoint. Values are given in meters. Can be `null` if no route between `i` and `j` can be found. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned. - `sources` array of `Waypoint` objects describing all sources in order - `destinations` array of `Waypoint` objects describing all destinations in order +- `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: @@ -383,6 +385,10 @@ All other properties might be undefined. 2361.73, 0 ] + ], + "estimated_cells": [ + [ 0, 1 ], + [ 1, 0 ] ] } ``` diff --git a/docs/nodejs/api.md b/docs/nodejs/api.md index 49cad3920..e7bb6e9de 100644 --- a/docs/nodejs/api.md +++ b/docs/nodejs/api.md @@ -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 < #coordinates`) to use location with given index as destination. Default is to use all. - `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + - `options.fallback_speed` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second. + - `options.fallback_coordinate` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies diestance between two points. - `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** **Examples** @@ -154,6 +156,7 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer Values are given in seconds. **`sources`**: array of [`Ẁaypoint`](#waypoint) objects describing all sources in order. **`destinations`**: array of [`Ẁaypoint`](#waypoint) objects describing all destinations in order. +**`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 diff --git a/features/step_definitions/distance_matrix.js b/features/step_definitions/distance_matrix.js index fde80679f..aac4f3183 100644 --- a/features/step_definitions/distance_matrix.js +++ b/features/step_definitions/distance_matrix.js @@ -3,22 +3,25 @@ var util = require('util'); module.exports = function () { const durationsRegex = new RegExp(/^I request a travel time matrix I should get$/); const distancesRegex = new RegExp(/^I request a travel distance matrix I should get$/); + const estimatesRegex = new RegExp(/^I request a travel time matrix I should get estimates for$/); const DURATIONS_NO_ROUTE = 2147483647; // MAX_INT const DISTANCES_NO_ROUTE = 3.40282e+38; // MAX_FLOAT this.When(durationsRegex, function(table, callback) {tableParse.call(this, table, DURATIONS_NO_ROUTE, 'durations', callback);}.bind(this)); this.When(distancesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'distances', callback);}.bind(this)); + this.When(estimatesRegex, function(table, callback) {tableParse.call(this, table, DISTANCES_NO_ROUTE, 'estimated_cells', callback);}.bind(this)); }; const durationsParse = function(v) { return isNaN(parseInt(v)); }; const distancesParse = function(v) { return isNaN(parseFloat(v)); }; +const estimatesParse = function(v) { return isNaN(parseFloat(v)); }; function tableParse(table, noRoute, annotation, callback) { - const parse = annotation == 'distances' ? distancesParse : durationsParse; + const parse = annotation == 'distances' ? distancesParse : (annotation == 'durations' ? durationsParse : estimatesParse); const params = this.queryParams; - params.annotations = annotation == 'distances' ? 'distance' : 'duration'; + params.annotations = ['durations','estimated_cells'].includes(annotation) ? 'duration' : 'distance'; var tableRows = table.raw(); @@ -61,11 +64,26 @@ function tableParse(table, noRoute, annotation, callback) { var json = JSON.parse(response.body); - var result = json[annotation].map(row => { - var hashes = {}; - row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; }); - return hashes; - }); + var result = {}; + if (annotation === 'estimated_cells') { + result = table.raw().map(row => row.map(cell => '')); + json[annotation].forEach(pair => { + result[pair[0]+1][pair[1]+1] = 'Y'; + }); + result = result.slice(1).map(row => { + var hashes = {}; + row.slice(1).forEach((v,i) => { + hashes[tableRows[0][i+1]] = v; + }); + return hashes; + }); + } else { + result = json[annotation].map(row => { + var hashes = {}; + row.forEach((v, i) => { hashes[tableRows[0][i+1]] = parse(v) ? '' : v; }); + return hashes; + }); + } var testRow = (row, ri, cb) => { for (var k in result[ri]) { diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature index 0b9e7c733..83d32d283 100644 --- a/features/testbot/distance_matrix.feature +++ b/features/testbot/distance_matrix.feature @@ -595,3 +595,75 @@ Feature: Basic Distance Matrix | 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 | \ No newline at end of file diff --git a/features/testbot/duration_matrix.feature b/features/testbot/duration_matrix.feature index c6977dfab..b3c65d364 100644 --- a/features/testbot/duration_matrix.feature +++ b/features/testbot/duration_matrix.feature @@ -510,3 +510,81 @@ 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 | + + 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 | \ No newline at end of file diff --git a/include/engine/api/table_api.hpp b/include/engine/api/table_api.hpp index 7f8cb7706..4667482e6 100644 --- a/include/engine/api/table_api.hpp +++ b/include/engine/api/table_api.hpp @@ -31,6 +31,15 @@ namespace api class TableAPI final : public BaseAPI { public: + struct TableCellRef + { + TableCellRef(const std::size_t &row, const std::size_t &column) : row{row}, column{column} + { + } + std::size_t row; + std::size_t column; + }; + TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters ¶meters_) : BaseAPI(facade_, parameters_), parameters(parameters_) { @@ -39,6 +48,7 @@ class TableAPI final : public BaseAPI virtual void MakeResponse(const std::pair, std::vector> &tables, const std::vector &phantoms, + const std::vector &estimated_cells, util::json::Object &response) const { auto number_of_sources = parameters.sources.size(); @@ -77,6 +87,11 @@ class TableAPI final : public BaseAPI MakeDistanceTable(tables.second, number_of_sources, number_of_destinations); } + if (parameters.fallback_speed > 0) + { + response.values["estimated_cells"] = MakeEstimatesTable(estimated_cells); + } + response.values["code"] = "Ok"; } @@ -163,6 +178,19 @@ class TableAPI final : public BaseAPI return json_table; } + virtual util::json::Array + MakeEstimatesTable(const std::vector &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; }; diff --git a/include/engine/api/table_parameters.hpp b/include/engine/api/table_parameters.hpp index 4f1a496bd..243d94142 100644 --- a/include/engine/api/table_parameters.hpp +++ b/include/engine/api/table_parameters.hpp @@ -59,6 +59,15 @@ struct TableParameters : public BaseParameters { std::vector sources; std::vector 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 + TableParameters(std::vector sources_, + std::vector destinations_, + const AnnotationsType annotations_, + double fallback_speed_, + FallbackCoordinateType fallback_coordinate_type_, + Args... args_) + : BaseParameters{std::forward(args_)...}, sources{std::move(sources_)}, + destinations{std::move(destinations_)}, fallback_speed{fallback_speed_}, + fallback_coordinate_type{fallback_coordinate_type_}, annotations{annotations_} + { + } + bool IsValid() const { if (!BaseParameters::IsValid()) @@ -117,6 +139,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; } }; diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index 27752e431..ba4aba6ce 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -1183,6 +1183,52 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo &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(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; } diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp index 66eee9448..bb731e8d3 100644 --- a/include/server/api/base_parameters_grammar.hpp +++ b/include/server/api/base_parameters_grammar.hpp @@ -178,6 +178,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar qi::rule base_rule; qi::rule query_rule; + qi::real_parser double_; + private: qi::rule bearings_rule; qi::rule radiuses_rule; @@ -195,7 +197,6 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar qi::rule base64_char; qi::rule polyline_chars; qi::rule unlimited_rule; - qi::real_parser double_; qi::symbols approach_type; }; diff --git a/include/server/api/table_parameter_grammar.hpp b/include/server/api/table_parameter_grammar.hpp index 5be793645..8b6d0ace6 100644 --- a/include/server/api/table_parameter_grammar.hpp +++ b/include/server/api/table_parameter_grammar.hpp @@ -48,10 +48,24 @@ struct TableParametersGrammar : public BaseParametersGrammar -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 &root_rule_) : BaseGrammar(root_rule_) @@ -73,13 +87,19 @@ struct TableParametersGrammar : public BaseParametersGrammar base_rule; private: + using json_policy = no_trailing_dot_policy; + qi::rule root_rule; qi::rule table_rule; qi::rule sources_rule; qi::rule destinations_rule; + qi::rule fallback_speed_rule; qi::rule size_t_; qi::symbols annotations; qi::rule annotations_list; + qi::symbols + fallback_coordinate_type; + qi::real_parser double_; }; } } diff --git a/src/engine/plugins/table.cpp b/src/engine/plugins/table.cpp index 3d89bc25a..41c3ebd5d 100644 --- a/src/engine/plugins/table.cpp +++ b/src/engine/plugins/table.cpp @@ -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" @@ -94,8 +95,47 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, return Error("NoTable", "No table found", result); } + std::vector 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}; - table_api.MakeResponse(result_tables_pair, snapped_phantoms, result); + table_api.MakeResponse(result_tables_pair, snapped_phantoms, estimated_pairs, result); return Status::Ok; } diff --git a/src/server/service/table_service.cpp b/src/server/service/table_service.cpp index 9a9ce0ab2..374ea2202 100644 --- a/src/server/service/table_service.cpp +++ b/src/server/service/table_service.cpp @@ -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 diff --git a/test/nodejs/table.js b/test/nodejs/table.js index e763eea86..c8f888438 100644 --- a/test/nodejs/table.js +++ b/test/nodejs/table.js @@ -234,7 +234,7 @@ tables.forEach(function(annotation) { }); test('table: ' + annotation + ' table in Monaco without motorways', function(assert) { - assert.plan(1); + assert.plan(2); var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'}); var options = { coordinates: two_test_coordinates, @@ -243,7 +243,24 @@ tables.forEach(function(annotation) { }; osrm.table(options, function(err, response) { 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); + }); + }); + }); diff --git a/unit_tests/server/parameters_parser.cpp b/unit_tests/server/parameters_parser.cpp index 4d3b8c53b..4667486a7 100644 --- a/unit_tests/server/parameters_parser.cpp +++ b/unit_tests/server/parameters_parser.cpp @@ -89,6 +89,8 @@ BOOST_AUTO_TEST_CASE(invalid_table_urls) BOOST_CHECK_EQUAL( testInvalidOptions("1,2;3,4?sources=all&destinations=all&annotations=bla"), 49UL); + BOOST_CHECK_EQUAL(testInvalidOptions("1,2;3,4?fallback_coordinate=asdf"), + 28UL); } BOOST_AUTO_TEST_CASE(valid_route_hint)