Skip to content

Commit 381d492

Browse files
authored
Add waypoints parameter to viaroute API (#5345)
* Add silent waypoints to viaroute API.
1 parent e250c83 commit 381d492

File tree

13 files changed

+334
-28
lines changed

13 files changed

+334
-28
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# Unreleased
2+
- Changes from 5.21.0
3+
- Features:
4+
- ADDED: new waypoints parameter to the `route` plugin, enabling silent waypoints [#5345](https://github.com/Project-OSRM/osrm-backend/pull/5345)
25

36
# 5.21.0
47
- Changes from 5.20.0

docs/http.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ In addition to the [general options](#general-options) the following options are
195195
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
196196
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|
197197
|continue\_straight |`default` (default), `true`, `false` |Forces the route to keep going straight at waypoints constraining uturns there even if it would be faster. Default value depends on the profile. |
198+
|waypoints | `{index};{index};{index}...` |Treats input coordinates indicated by given indices as waypoints in returned Match object. Default is to treat all input coordinates as waypoints. |
198199

199200
\* Please note that even if alternative routes are requested, a result cannot be guaranteed.
200201

docs/nodejs/api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Returns the fastest route between two or more coordinates while visiting the way
5757
- `options.overview` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`)
5858
- `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.
5959
- `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`.
60+
- `options.waypoints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index.
6061
`null`/`true`/`false`
6162
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
6263

@@ -210,6 +211,7 @@ if they can not be matched successfully.
210211
- `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`.
211212
- `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`).
212213
- `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`).
214+
- `options.waypoints` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index.
213215
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
214216

215217
**Examples**

features/testbot/via.feature

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,53 @@ Feature: Via points
1818
| waypoints | route |
1919
| a,b,c | abc,abc,abc,abc |
2020

21+
Scenario: Simple via point with waypoints collapsing
22+
Given the node map
23+
"""
24+
a
25+
26+
b 1c d
27+
2
28+
29+
e
30+
"""
31+
32+
And the ways
33+
| nodes |
34+
| ace |
35+
| bcd |
36+
37+
Given the query options
38+
| waypoints | 0;2 |
39+
40+
When I route I should get
41+
| waypoints | route | turns |
42+
| b,1,e | bcd,ace,ace | depart,turn right,arrive |
43+
| b,2,e | bcd,ace,ace | depart,turn right,arrive |
44+
45+
Scenario: Simple via point with waypoints collapsing
46+
Given the node map
47+
"""
48+
a 2 b
49+
50+
c d
51+
1 3
52+
"""
53+
54+
And the ways
55+
| nodes |
56+
| ab |
57+
| bd |
58+
| cd |
59+
| ac |
60+
61+
Given the query options
62+
| waypoints | 0;2 |
63+
64+
When I route I should get
65+
| waypoints | route | turns |
66+
| 1,2,3 | cd,ac,ab,bd,cd | depart,new name right,new name right,new name right,arrive |
67+
2168
Scenario: Simple via point with core factor
2269
Given the contract extra arguments "--core 0.8"
2370
Given the node map

include/engine/api/match_parameters.hpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ struct MatchParameters : public RouteParameters
6363
RouteParameters::GeometriesType::Polyline,
6464
RouteParameters::OverviewType::Simplified,
6565
{}),
66-
gaps(GapsType::Split), tidy(false), waypoints()
66+
gaps(GapsType::Split), tidy(false)
6767
{
6868
}
6969

@@ -79,24 +79,19 @@ struct MatchParameters : public RouteParameters
7979
bool tidy_,
8080
std::vector<std::size_t> waypoints_,
8181
Args... args_)
82-
: RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)},
83-
gaps(gaps_), tidy(tidy_), waypoints{std::move(waypoints_)}
82+
: RouteParameters{std::forward<Args>(args_)..., waypoints_},
83+
timestamps{std::move(timestamps_)}, gaps(gaps_), tidy(tidy_)
8484
{
8585
}
8686

8787
std::vector<unsigned> timestamps;
8888
GapsType gaps;
8989
bool tidy;
90-
std::vector<std::size_t> waypoints;
9190

9291
bool IsValid() const
9392
{
94-
const auto valid_waypoints =
95-
std::all_of(waypoints.begin(), waypoints.end(), [this](const auto &w) {
96-
return w < coordinates.size();
97-
});
9893
return RouteParameters::IsValid() &&
99-
(timestamps.empty() || timestamps.size() == coordinates.size()) && valid_waypoints;
94+
(timestamps.empty() || timestamps.size() == coordinates.size());
10095
}
10196
};
10297
}

include/engine/api/route_api.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ class RouteAPI : public BaseAPI
4444
{
4545
}
4646

47-
void MakeResponse(const InternalManyRoutesResult &raw_routes,
48-
util::json::Object &response) const
47+
void
48+
MakeResponse(const InternalManyRoutesResult &raw_routes,
49+
const std::vector<PhantomNodes>
50+
&all_start_end_points, // all used coordinates, ignoring waypoints= parameter
51+
util::json::Object &response) const
4952
{
5053
BOOST_ASSERT(!raw_routes.routes.empty());
5154

@@ -62,8 +65,7 @@ class RouteAPI : public BaseAPI
6265
route.target_traversed_in_reverse));
6366
}
6467

65-
response.values["waypoints"] =
66-
BaseAPI::MakeWaypoints(raw_routes.routes[0].segment_end_coordinates);
68+
response.values["waypoints"] = BaseAPI::MakeWaypoints(all_start_end_points);
6769
response.values["routes"] = std::move(jsRoutes);
6870
response.values["code"] = "Ok";
6971
}

include/engine/api/route_parameters.hpp

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ struct RouteParameters : public BaseParameters
9898
annotations_type{AnnotationsType::None},
9999
geometries{geometries_},
100100
overview{overview_},
101-
continue_straight{continue_straight_}
101+
continue_straight{continue_straight_},
102+
waypoints()
102103
{
103104
}
104105

@@ -114,7 +115,9 @@ struct RouteParameters : public BaseParameters
114115
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
115116
number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_},
116117
annotations_type{annotations_ ? AnnotationsType::All : AnnotationsType::None},
117-
geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_}
118+
geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_},
119+
waypoints()
120+
118121
{
119122
}
120123

@@ -131,7 +134,43 @@ struct RouteParameters : public BaseParameters
131134
number_of_alternatives{alternatives_ ? 1u : 0u},
132135
annotations{annotations_ == AnnotationsType::None ? false : true},
133136
annotations_type{annotations_}, geometries{geometries_}, overview{overview_},
134-
continue_straight{continue_straight_}
137+
continue_straight{continue_straight_}, waypoints()
138+
{
139+
}
140+
141+
// RouteParameters constructor adding the `waypoints` parameter
142+
template <typename... Args>
143+
RouteParameters(const bool steps_,
144+
const bool alternatives_,
145+
const bool annotations_,
146+
const GeometriesType geometries_,
147+
const OverviewType overview_,
148+
const boost::optional<bool> continue_straight_,
149+
std::vector<std::size_t> waypoints_,
150+
const Args... args_)
151+
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
152+
number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_},
153+
annotations_type{annotations_ ? AnnotationsType::All : AnnotationsType::None},
154+
geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_},
155+
waypoints{waypoints_}
156+
{
157+
}
158+
159+
// RouteParameters constructor adding the `waypoints` parameter
160+
template <typename... Args>
161+
RouteParameters(const bool steps_,
162+
const bool alternatives_,
163+
const AnnotationsType annotations_,
164+
const GeometriesType geometries_,
165+
const OverviewType overview_,
166+
const boost::optional<bool> continue_straight_,
167+
std::vector<std::size_t> waypoints_,
168+
Args... args_)
169+
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
170+
number_of_alternatives{alternatives_ ? 1u : 0u},
171+
annotations{annotations_ == AnnotationsType::None ? false : true},
172+
annotations_type{annotations_}, geometries{geometries_}, overview{overview_},
173+
continue_straight{continue_straight_}, waypoints{waypoints_}
135174
{
136175
}
137176

@@ -144,12 +183,17 @@ struct RouteParameters : public BaseParameters
144183
GeometriesType geometries = GeometriesType::Polyline;
145184
OverviewType overview = OverviewType::Simplified;
146185
boost::optional<bool> continue_straight;
186+
std::vector<std::size_t> waypoints;
147187

148188
bool IsValid() const
149189
{
150190
const auto coordinates_ok = coordinates.size() >= 2;
151191
const auto base_params_ok = BaseParameters::IsValid();
152-
return coordinates_ok && base_params_ok;
192+
const auto valid_waypoints =
193+
std::all_of(waypoints.begin(), waypoints.end(), [this](const auto &w) {
194+
return w < coordinates.size();
195+
});
196+
return coordinates_ok && base_params_ok && valid_waypoints;
153197
}
154198
};
155199

@@ -173,8 +217,8 @@ inline RouteParameters::AnnotationsType operator|=(RouteParameters::AnnotationsT
173217
{
174218
return lhs = lhs | rhs;
175219
}
176-
}
177-
}
178-
}
220+
} // ns api
221+
} // ns engine
222+
} // ns osrm
179223

180224
#endif

include/nodejs/node_osrm_support.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,72 @@ argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
944944
}
945945
}
946946

947+
if (obj->Has(Nan::New("waypoints").ToLocalChecked()))
948+
{
949+
v8::Local<v8::Value> waypoints = obj->Get(Nan::New("waypoints").ToLocalChecked());
950+
if (waypoints.IsEmpty())
951+
return route_parameters_ptr();
952+
953+
// must be array
954+
if (!waypoints->IsArray())
955+
{
956+
Nan::ThrowError(
957+
"Waypoints must be an array of integers corresponding to the input coordinates.");
958+
return route_parameters_ptr();
959+
}
960+
961+
auto waypoints_array = v8::Local<v8::Array>::Cast(waypoints);
962+
// must have at least two elements
963+
if (waypoints_array->Length() < 2)
964+
{
965+
Nan::ThrowError("At least two waypoints must be provided");
966+
return route_parameters_ptr();
967+
}
968+
auto coords_size = params->coordinates.size();
969+
auto waypoints_array_size = waypoints_array->Length();
970+
971+
const auto first_index = Nan::To<std::uint32_t>(waypoints_array->Get(0)).FromJust();
972+
const auto last_index =
973+
Nan::To<std::uint32_t>(waypoints_array->Get(waypoints_array_size - 1)).FromJust();
974+
if (first_index != 0 || last_index != coords_size - 1)
975+
{
976+
Nan::ThrowError("First and last waypoints values must correspond to first and last "
977+
"coordinate indices");
978+
return route_parameters_ptr();
979+
}
980+
981+
for (uint32_t i = 0; i < waypoints_array_size; ++i)
982+
{
983+
v8::Local<v8::Value> waypoint_value = waypoints_array->Get(i);
984+
// all elements must be numbers
985+
if (!waypoint_value->IsNumber())
986+
{
987+
Nan::ThrowError("Waypoint values must be an array of integers");
988+
return route_parameters_ptr();
989+
}
990+
// check that the waypoint index corresponds with an inpute coordinate
991+
const auto index = Nan::To<std::uint32_t>(waypoint_value).FromJust();
992+
if (index >= coords_size)
993+
{
994+
Nan::ThrowError("Waypoints must correspond with the index of an input coordinate");
995+
return route_parameters_ptr();
996+
}
997+
params->waypoints.emplace_back(static_cast<unsigned>(waypoint_value->NumberValue()));
998+
}
999+
1000+
if (!params->waypoints.empty())
1001+
{
1002+
for (std::size_t i = 0; i < params->waypoints.size() - 1; i++)
1003+
{
1004+
if (params->waypoints[i] >= params->waypoints[i + 1])
1005+
{
1006+
Nan::ThrowError("Waypoints must be supplied in increasing order");
1007+
return route_parameters_ptr();
1008+
}
1009+
}
1010+
}
1011+
}
1012+
9471013
bool parsedSuccessfully = parseCommonParameters(obj, params);
9481014
if (!parsedSuccessfully)
9491015
{

include/server/api/match_parameter_grammar.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,12 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
4242
(qi::uint_ %
4343
';')[ph::bind(&engine::api::MatchParameters::timestamps, qi::_r1) = qi::_1];
4444

45-
waypoints_rule =
46-
qi::lit("waypoints=") >
47-
(size_t_ % ';')[ph::bind(&engine::api::MatchParameters::waypoints, qi::_r1) = qi::_1];
48-
4945
gaps_type.add("split", engine::api::MatchParameters::GapsType::Split)(
5046
"ignore", engine::api::MatchParameters::GapsType::Ignore);
5147

5248
root_rule =
5349
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
5450
-('?' > (timestamps_rule(qi::_r1) | BaseGrammar::base_rule(qi::_r1) |
55-
waypoints_rule(qi::_r1) |
5651
(qi::lit("gaps=") >
5752
gaps_type[ph::bind(&engine::api::MatchParameters::gaps, qi::_r1) = qi::_1]) |
5853
(qi::lit("tidy=") >
@@ -63,7 +58,6 @@ struct MatchParametersGrammar final : public RouteParametersGrammar<Iterator, Si
6358
private:
6459
qi::rule<Iterator, Signature> root_rule;
6560
qi::rule<Iterator, Signature> timestamps_rule;
66-
qi::rule<Iterator, Signature> waypoints_rule;
6761
qi::rule<Iterator, std::size_t()> size_t_;
6862

6963
qi::symbols<char, engine::api::MatchParameters::GapsType> gaps_type;

include/server/api/route_parameters_grammar.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
4848

4949
RouteParametersGrammar(qi::rule<Iterator, Signature> &root_rule_) : BaseGrammar(root_rule_)
5050
{
51+
#ifdef BOOST_HAS_LONG_LONG
52+
if (std::is_same<std::size_t, unsigned long long>::value)
53+
size_t_ = qi::ulong_long;
54+
else
55+
size_t_ = qi::ulong_;
56+
#else
57+
size_t_ = qi::ulong_;
58+
#endif
5159
using AnnotationsType = engine::api::RouteParameters::AnnotationsType;
5260

5361
const auto add_annotation = [](engine::api::RouteParameters &route_parameters,
@@ -70,8 +78,12 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
7078
"distance", AnnotationsType::Distance)("weight", AnnotationsType::Weight)(
7179
"datasources", AnnotationsType::Datasources)("speed", AnnotationsType::Speed);
7280

81+
waypoints_rule =
82+
qi::lit("waypoints=") >
83+
(size_t_ % ';')[ph::bind(&engine::api::RouteParameters::waypoints, qi::_r1) = qi::_1];
84+
7385
base_rule =
74-
BaseGrammar::base_rule(qi::_r1) |
86+
BaseGrammar::base_rule(qi::_r1) | waypoints_rule(qi::_r1) |
7587
(qi::lit("steps=") >
7688
qi::bool_[ph::bind(&engine::api::RouteParameters::steps, qi::_r1) = qi::_1]) |
7789
(qi::lit("geometries=") >
@@ -94,6 +106,8 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
94106
private:
95107
qi::rule<Iterator, Signature> root_rule;
96108
qi::rule<Iterator, Signature> route_rule;
109+
qi::rule<Iterator, Signature> waypoints_rule;
110+
qi::rule<Iterator, std::size_t()> size_t_;
97111

98112
qi::symbols<char, engine::api::RouteParameters::GeometriesType> geometries_type;
99113
qi::symbols<char, engine::api::RouteParameters::OverviewType> overview_type;

0 commit comments

Comments
 (0)