Compare commits

...

5 Commits

Author SHA1 Message Date
Daniel Patterson
1d435266aa
Fix typo. 2019-02-02 22:25:05 -08:00
Daniel Patterson
9b414a17e8
Build tags with semver metadata. 2019-02-02 22:19:15 -08:00
Daniel Patterson
54a8a8c494
Update version for custom build. 2019-02-02 22:15:41 -08:00
Daniel Patterson
469c3331e4
Fix formatting. 2019-02-02 22:15:16 -08:00
Daniel Patterson
2aa9e2859a
Prototype configurable snapping. 2019-02-02 22:12:05 -08:00
12 changed files with 151 additions and 36 deletions

View File

@ -14,7 +14,7 @@ branches:
only: only:
- master - master
# enable building tags # enable building tags
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/ - /^v\d+\.\d+(\.\d+)?(\+[^-]+)?(-\S*)?$/
cache: cache:
npm: true npm: true

View File

@ -35,3 +35,23 @@ Feature: Car - Allowed start/end modes
| from | to | route | modes | | from | to | route | modes |
| 1 | 2 | ab,ab | driving,driving | | 1 | 2 | ab,ab | driving,driving |
| 2 | 1 | ab,ab | driving,driving | | 2 | 1 | ab,ab | driving,driving |
Scenario: Car - URL override of non-startpoints
Given the node map
"""
a 1 b c 2 d
"""
Given the query options
| snapping | any |
And the ways
| nodes | highway | access |
| ab | service | private |
| bc | primary | |
| cd | service | private |
When I route I should get
| from | to | route |
| 1 | 2 | ab,bc,cd |
| 2 | 1 | cd,bc,ab |

View File

@ -78,6 +78,11 @@ struct RouteParameters : public BaseParameters
Speed = 0x20, Speed = 0x20,
All = Duration | Nodes | Distance | Weight | Datasources | Speed All = Duration | Nodes | Distance | Weight | Datasources | Speed
}; };
enum class SnappingType
{
Default,
Any
};
RouteParameters() = default; RouteParameters() = default;
@ -147,12 +152,13 @@ struct RouteParameters : public BaseParameters
const OverviewType overview_, const OverviewType overview_,
const boost::optional<bool> continue_straight_, const boost::optional<bool> continue_straight_,
std::vector<std::size_t> waypoints_, std::vector<std::size_t> waypoints_,
const SnappingType snapping_,
const Args... args_) const Args... args_)
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_}, : BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_}, number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_},
annotations_type{annotations_ ? AnnotationsType::All : AnnotationsType::None}, annotations_type{annotations_ ? AnnotationsType::All : AnnotationsType::None},
geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_}, geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_},
waypoints{waypoints_} waypoints{waypoints_}, snapping{snapping_}
{ {
} }
@ -165,12 +171,13 @@ struct RouteParameters : public BaseParameters
const OverviewType overview_, const OverviewType overview_,
const boost::optional<bool> continue_straight_, const boost::optional<bool> continue_straight_,
std::vector<std::size_t> waypoints_, std::vector<std::size_t> waypoints_,
const SnappingType snapping_,
Args... args_) Args... args_)
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_}, : BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
number_of_alternatives{alternatives_ ? 1u : 0u}, number_of_alternatives{alternatives_ ? 1u : 0u},
annotations{annotations_ == AnnotationsType::None ? false : true}, annotations{annotations_ == AnnotationsType::None ? false : true},
annotations_type{annotations_}, geometries{geometries_}, overview{overview_}, annotations_type{annotations_}, geometries{geometries_}, overview{overview_},
continue_straight{continue_straight_}, waypoints{waypoints_} continue_straight{continue_straight_}, waypoints{waypoints_}, snapping{snapping_}
{ {
} }
@ -184,6 +191,7 @@ struct RouteParameters : public BaseParameters
OverviewType overview = OverviewType::Simplified; OverviewType overview = OverviewType::Simplified;
boost::optional<bool> continue_straight; boost::optional<bool> continue_straight;
std::vector<std::size_t> waypoints; std::vector<std::size_t> waypoints;
SnappingType snapping = SnappingType::Default;
bool IsValid() const bool IsValid() const
{ {

View File

@ -389,23 +389,25 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, approach); input_coordinate, approach, use_all_edges);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, approach); input_coordinate, max_distance, approach, use_all_edges);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
@ -413,24 +415,26 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, bearing, bearing_range, approach); input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const override final const Approach approach,
const bool use_all_edges) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, bearing, bearing_range, approach); input_coordinate, bearing, bearing_range, approach, use_all_edges);
} }
std::uint32_t GetCheckSum() const override final { return m_check_sum; } std::uint32_t GetCheckSum() const override final { return m_check_sum; }

View File

@ -161,22 +161,26 @@ class BaseDataFacade
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges) const = 0;
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const = 0; const Approach approach,
const bool use_all_edges = false) const = 0;
virtual bool HasLaneData(const EdgeID id) const = 0; virtual bool HasLaneData(const EdgeID id) const = 0;
virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0; virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0;

View File

@ -205,18 +205,23 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate, &has_big_component, &has_small_component]( [this,
const CandidateSegment &segment) { approach,
&input_coordinate,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment = auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); (!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment); auto use_directions = std::make_pair(use_segment, use_segment);
const auto valid_edges = HasValidEdge(segment); const auto valid_edges = HasValidEdge(segment, use_all_edges);
const auto admissible_segments = CheckSegmentExclude(segment); const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, admissible_segments); use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(use_directions, valid_edges); use_directions = boolPairAnd(use_directions, valid_edges);
@ -251,19 +256,24 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
// a second phantom node is return that is the nearest coordinate in a big component. // a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
auto results = rtree.Nearest( auto results = rtree.Nearest(
input_coordinate, input_coordinate,
[this, approach, &input_coordinate, &has_big_component, &has_small_component]( [this,
const CandidateSegment &segment) { approach,
&input_coordinate,
&has_big_component,
&has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment = auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); (!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment); auto use_directions = std::make_pair(use_segment, use_segment);
const auto valid_edges = HasValidEdge(segment); const auto valid_edges = HasValidEdge(segment, use_all_edges);
const auto admissible_segments = CheckSegmentExclude(segment); const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, admissible_segments); use_directions = boolPairAnd(use_directions, admissible_segments);
use_directions = boolPairAnd(use_directions, valid_edges); use_directions = boolPairAnd(use_directions, valid_edges);
@ -298,7 +308,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
@ -310,12 +321,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
bearing, bearing,
bearing_range, bearing_range,
&has_big_component, &has_big_component,
&has_small_component](const CandidateSegment &segment) { &has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment = auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); (!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment); auto use_directions = std::make_pair(use_segment, use_segment);
const auto admissible_segments = CheckSegmentExclude(segment); const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, HasValidEdge(segment)); use_directions = boolPairAnd(use_directions, HasValidEdge(segment, use_all_edges));
if (use_segment) if (use_segment)
{ {
@ -356,7 +368,8 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach) const const Approach approach,
const bool use_all_edges) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
@ -368,12 +381,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
bearing, bearing,
bearing_range, bearing_range,
&has_big_component, &has_big_component,
&has_small_component](const CandidateSegment &segment) { &has_small_component,
&use_all_edges](const CandidateSegment &segment) {
auto use_segment = auto use_segment =
(!has_small_component || (!has_big_component && !IsTinyComponent(segment))); (!has_small_component || (!has_big_component && !IsTinyComponent(segment)));
auto use_directions = std::make_pair(use_segment, use_segment); auto use_directions = std::make_pair(use_segment, use_segment);
const auto admissible_segments = CheckSegmentExclude(segment); const auto admissible_segments = CheckSegmentExclude(segment);
use_directions = boolPairAnd(use_directions, HasValidEdge(segment)); use_directions = boolPairAnd(use_directions, HasValidEdge(segment, use_all_edges));
if (use_segment) if (use_segment)
{ {

View File

@ -262,7 +262,8 @@ class BasePlugin
} }
std::vector<PhantomNodePair> GetPhantomNodes(const datafacade::BaseDataFacade &facade, std::vector<PhantomNodePair> GetPhantomNodes(const datafacade::BaseDataFacade &facade,
const api::BaseParameters &parameters) const const api::BaseParameters &parameters,
const bool use_all_edges = false) const
{ {
std::vector<PhantomNodePair> phantom_node_pairs(parameters.coordinates.size()); std::vector<PhantomNodePair> phantom_node_pairs(parameters.coordinates.size());
@ -296,7 +297,8 @@ class BasePlugin
*parameters.radiuses[i], *parameters.radiuses[i],
parameters.bearings[i]->bearing, parameters.bearings[i]->bearing,
parameters.bearings[i]->range, parameters.bearings[i]->range,
approach); approach,
use_all_edges);
} }
else else
{ {
@ -305,7 +307,8 @@ class BasePlugin
parameters.coordinates[i], parameters.coordinates[i],
parameters.bearings[i]->bearing, parameters.bearings[i]->bearing,
parameters.bearings[i]->range, parameters.bearings[i]->range,
approach); approach,
use_all_edges);
} }
} }
else else
@ -314,13 +317,16 @@ class BasePlugin
{ {
phantom_node_pairs[i] = phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent( facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], *parameters.radiuses[i], approach); parameters.coordinates[i],
*parameters.radiuses[i],
approach,
use_all_edges);
} }
else else
{ {
phantom_node_pairs[i] = phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent( facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], approach); parameters.coordinates[i], approach, use_all_edges);
} }
} }

View File

@ -1010,6 +1010,35 @@ argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
} }
} }
if (obj->Has(Nan::New("snapping").ToLocalChecked()))
{
v8::Local<v8::Value> snapping = obj->Get(Nan::New("snapping").ToLocalChecked());
if (snapping.IsEmpty())
return route_parameters_ptr();
if (!snapping->IsString())
{
Nan::ThrowError("Snapping must be a string: [default, any]");
return route_parameters_ptr();
}
const Nan::Utf8String snapping_utf8str(snapping);
std::string snapping_str{*snapping_utf8str, *snapping_utf8str + snapping_utf8str.length()};
if (snapping_str == "default")
{
params->snapping = osrm::RouteParameters::SnappingType::Default;
}
else if (snapping_str == "any")
{
params->snapping = osrm::RouteParameters::SnappingType::Any;
}
else
{
Nan::ThrowError("'snapping' param must be one of [default, any]");
return route_parameters_ptr();
}
}
bool parsedSuccessfully = parseCommonParameters(obj, params); bool parsedSuccessfully = parseCommonParameters(obj, params);
if (!parsedSuccessfully) if (!parsedSuccessfully)
{ {

View File

@ -82,6 +82,9 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
qi::lit("waypoints=") > qi::lit("waypoints=") >
(size_t_ % ';')[ph::bind(&engine::api::RouteParameters::waypoints, qi::_r1) = qi::_1]; (size_t_ % ';')[ph::bind(&engine::api::RouteParameters::waypoints, qi::_r1) = qi::_1];
snapping_type.add("default", engine::api::RouteParameters::SnappingType::Default)(
"any", engine::api::RouteParameters::SnappingType::Any);
base_rule = base_rule =
BaseGrammar::base_rule(qi::_r1) | waypoints_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) | waypoints_rule(qi::_r1) |
(qi::lit("steps=") > (qi::lit("steps=") >
@ -91,6 +94,8 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
qi::_1]) | qi::_1]) |
(qi::lit("overview=") > (qi::lit("overview=") >
overview_type[ph::bind(&engine::api::RouteParameters::overview, qi::_r1) = qi::_1]) | overview_type[ph::bind(&engine::api::RouteParameters::overview, qi::_r1) = qi::_1]) |
(qi::lit("snapping=") >
snapping_type[ph::bind(&engine::api::RouteParameters::snapping, qi::_r1) = qi::_1]) |
(qi::lit("annotations=") > (qi::lit("annotations=") >
(qi::lit("true")[ph::bind(add_annotation, qi::_r1, AnnotationsType::All)] | (qi::lit("true")[ph::bind(add_annotation, qi::_r1, AnnotationsType::All)] |
qi::lit("false")[ph::bind(add_annotation, qi::_r1, AnnotationsType::None)] | qi::lit("false")[ph::bind(add_annotation, qi::_r1, AnnotationsType::None)] |
@ -112,6 +117,7 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
qi::symbols<char, engine::api::RouteParameters::GeometriesType> geometries_type; qi::symbols<char, engine::api::RouteParameters::GeometriesType> geometries_type;
qi::symbols<char, engine::api::RouteParameters::OverviewType> overview_type; qi::symbols<char, engine::api::RouteParameters::OverviewType> overview_type;
qi::symbols<char, engine::api::RouteParameters::AnnotationsType> annotations_type; qi::symbols<char, engine::api::RouteParameters::AnnotationsType> annotations_type;
qi::symbols<char, engine::api::RouteParameters::SnappingType> snapping_type;
}; };
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "osrm", "name": "osrm",
"version": "5.22.0-latest.1", "version": "5.22.0+customsnapping.3",
"private": false, "private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": { "dependencies": {

View File

@ -87,7 +87,10 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
return Status::Error; return Status::Error;
const auto &facade = algorithms.GetFacade(); const auto &facade = algorithms.GetFacade();
auto phantom_node_pairs = GetPhantomNodes(facade, route_parameters); auto phantom_node_pairs =
GetPhantomNodes(facade,
route_parameters,
(route_parameters.snapping == api::RouteParameters::SnappingType::Any));
if (phantom_node_pairs.size() != route_parameters.coordinates.size()) if (phantom_node_pairs.size() != route_parameters.coordinates.size())
{ {
return Error("NoSegment", return Error("NoSegment",

View File

@ -690,3 +690,24 @@ test('route: throws on invalid waypoints values, waypoints must be an array of i
assert.throws(function () { osrm.route(options, function (err, response) { console.error(`response: ${response}`); console.error(`error: ${err}`); }); }, assert.throws(function () { osrm.route(options, function (err, response) { console.error(`response: ${response}`); console.error(`error: ${err}`); }); },
/Waypoints must be supplied in increasing order/); /Waypoints must be supplied in increasing order/);
}); });
test('route: throws on invalid snapping values', function (assert) {
assert.plan(1);
var osrm = new OSRM(monaco_path);
var options = {
steps: true,
coordinates: three_test_coordinates.concat(three_test_coordinates),
snapping: "zing"
};
assert.throws(function () { osrm.route(options, function (err, response) { console.error(`response: ${response}`); console.error(`error: ${err}`); }); },
/'snapping' param must be one of \[default, any\]/);
});
test('route: snapping parameter passed through OK', function(assert) {
assert.plan(2);
var osrm = new OSRM(monaco_path);
osrm.route({snapping: "any", coordinates: [[7.448205209414596,43.754001097311544],[7.447122039202185,43.75306156811368]]}, function(err, route) {
assert.ifError(err);
assert.equal(Math.round(route.routes[0].distance * 10), 1314); // Round it to nearest 0.1m to eliminate floating point comparison error
});
});