Skip to content

Commit 796f12d

Browse files
authored
Support waypoints per route (#1503)
1 parent 8afd9fa commit 796f12d

13 files changed

Lines changed: 225 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
Mapbox welcomes participation and contributions from everyone.
44

55
### main
6+
- Added `RouteOptions#waypointsPerRoute()` and `RouteOption.Builders#waypointsPerRoute()` methods. [#1503](https://github.com/mapbox/mapbox-java/pull/1503)
7+
- Added `DirectionsRoute#waypoints` and deprecated `DirectionsResponse#waypoints`. [#1503](https://github.com/mapbox/mapbox-java/pull/1503)
68

79
### v6.9.0-beta.1 - October 21, 2022
810
- Added `getUnrecognizedJsonProperties()` method to `DirectionsRefreshJsonObject` so that unrecognized properties can be received from refresh response. [#1500](https://github.com/mapbox/mapbox-java/pull/1500)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.mapbox.samples;
2+
3+
import com.mapbox.api.directions.v5.DirectionsCriteria;
4+
import com.mapbox.api.directions.v5.MapboxDirections;
5+
import com.mapbox.api.directions.v5.models.DirectionsResponse;
6+
import com.mapbox.api.directions.v5.models.RouteOptions;
7+
import com.mapbox.geojson.Point;
8+
import com.mapbox.sample.BuildConfig;
9+
import retrofit2.Response;
10+
11+
import java.io.IOException;
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
15+
/**
16+
* Shows how to make a directions request using `waypoints_per_route=true` and access the waypoints from the response.
17+
*/
18+
public class BasicDirectionsWaypointsPerRoute {
19+
20+
public static void main(String[] args) throws IOException {
21+
simpleMapboxDirectionsWithWaypointsPerRouteRequest();
22+
}
23+
24+
private static void simpleMapboxDirectionsWithWaypointsPerRouteRequest() throws IOException {
25+
MapboxDirections.Builder builder = MapboxDirections.builder();
26+
27+
// 1. Pass in all the required information to get a simple directions route.
28+
List<Point> coordinates = new ArrayList<>();
29+
coordinates.add(Point.fromLngLat(-95.6332, 29.7890));
30+
coordinates.add(Point.fromLngLat(-95.3591, 29.7576));
31+
RouteOptions routeOptions = RouteOptions.builder()
32+
.profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC)
33+
.geometries(DirectionsCriteria.GEOMETRY_POLYLINE6)
34+
.coordinatesList(coordinates)
35+
.waypointsPerRoute(true)
36+
.alternatives(true)
37+
.build();
38+
builder.routeOptions(routeOptions);
39+
builder.accessToken(BuildConfig.MAPBOX_ACCESS_TOKEN);
40+
41+
// 2. That's it! Now execute the command and get the response.
42+
Response<DirectionsResponse> response = builder.build().executeCall();
43+
44+
// 3. Log information from the response
45+
System.out.printf("%nCheck that the GET response is successful %b", response.isSuccessful());
46+
System.out.printf("%nFirst route's waypoints: %s", response.body().routes().get(0).waypoints());
47+
System.out.printf("%nSecond route's waypoints: %s", response.body().routes().get(1).waypoints());
48+
System.out.printf("%nRoot waypoints: %s", response.body().waypoints());
49+
}
50+
}

services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/DirectionsResponse.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,16 @@ public static Builder builder() {
6666
* List of {@link DirectionsWaypoint} objects. Each {@code waypoint} is an input coordinate
6767
* snapped to the road and path network. The {@code waypoint} appear in the list in the order of
6868
* the input coordinates.
69+
* @deprecated the waypoints are returned in the root of the response only if
70+
* {@link RouteOptions#waypointsPerRoute()} is false. Otherwise they are returned in
71+
* {@link DirectionsRoute#waypoints()}. You can continue to use this and it will work as-is.
72+
* However, it's recommended to use the new approach to distinguish waypoints between routes
73+
* (for example, this is necessary when asking for an EV-optimized route with alternatives).
6974
*
7075
* @return list of {@link DirectionsWaypoint} objects ordered from start of route till the end
7176
* @since 1.0.0
7277
*/
78+
@Deprecated
7379
@Nullable
7480
public abstract List<DirectionsWaypoint> waypoints();
7581

@@ -263,12 +269,18 @@ public abstract static class Builder extends DirectionsJsonObject.Builder<Builde
263269
* List of {@link DirectionsWaypoint} objects. Each {@code waypoint} is an input coordinate
264270
* snapped to the road and path network. The {@code waypoint} appear in the list in the order of
265271
* the input coordinates.
272+
* @deprecated the waypoints are returned in the root of the response only if
273+
* {@link RouteOptions#waypointsPerRoute()} is false. Otherwise they are returned in
274+
* {@link DirectionsRoute#waypoints()}. You can continue to use this and it will work as-is.
275+
* However, it's recommended to use the new approach to distinguish waypoints between routes
276+
* (for example, this is necessary when asking for an EV-optimized route with alternatives).
266277
*
267278
* @param waypoints list of {@link DirectionsWaypoint} objects ordered from start of route till
268279
* the end
269280
* @return this builder for chaining options together
270281
* @since 3.0.0
271282
*/
283+
@Deprecated
272284
public abstract Builder waypoints(@Nullable List<DirectionsWaypoint> waypoints);
273285

274286
/**

services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/DirectionsRoute.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,19 @@ public static Builder builder() {
110110
@Nullable
111111
public abstract List<RouteLeg> legs();
112112

113+
/**
114+
* List of {@link DirectionsWaypoint} objects. Each {@code waypoint} is an input coordinate
115+
* snapped to the road and path network. The {@code waypoint} appear in the list in the order of
116+
* the input coordinates.
117+
* Waypoints are returned in the {@link DirectionsRoute} object only when
118+
* {@link RouteOptions#waypointsPerRoute()} is set to true. Otherwise they are returned
119+
* in the root: {@link DirectionsResponse#waypoints()}.
120+
*
121+
* @return list of {@link DirectionsWaypoint} objects ordered from start of route till the end
122+
*/
123+
@Nullable
124+
public abstract List<DirectionsWaypoint> waypoints();
125+
113126
/**
114127
* Holds onto the parameter information used when making the directions request. Useful for
115128
* re-requesting a directions route using the same information previously used.
@@ -301,6 +314,21 @@ public abstract static class Builder extends DirectionsJsonObject.Builder<Builde
301314
@NonNull
302315
public abstract Builder legs(@Nullable List<RouteLeg> legs);
303316

317+
/**
318+
* List of {@link DirectionsWaypoint} objects. Each {@code waypoint} is an input coordinate
319+
* snapped to the road and path network. The {@code waypoint} appear in the list in the order of
320+
* the input coordinates.
321+
* Waypoints are returned in the {@link DirectionsRoute} object only when
322+
* {@link RouteOptions#waypointsPerRoute()} is set to true. Otherwise they are returned
323+
* in the root: {@link DirectionsResponse#waypoints()}.
324+
*
325+
* @param waypoints list of {@link DirectionsWaypoint} objects ordered from start of route
326+
* till the end
327+
* @return this builder for chaining options together
328+
*/
329+
@NonNull
330+
public abstract Builder waypoints(@Nullable List<DirectionsWaypoint> waypoints);
331+
304332
/**
305333
* Holds onto the parameter information used when making the directions request.
306334
*

services-directions-models/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,18 @@ public List<Point> waypointTargetsList() {
688688
return ParseUtils.parseToPoints(waypointTargets());
689689
}
690690

691+
/**
692+
* If true, the waypoints array is returned within the route object, else its returned
693+
* at the root of the response body. Defaults to false if unspecified.
694+
* Setting `waypoints_per_route` to true is necessary when asking for an EV-optimized
695+
* route with alternatives, since each alternative route may produce separate
696+
* sets of waypoints (charging stations).
697+
* @return boolean representing the waypoints_per_route value
698+
*/
699+
@SerializedName("waypoints_per_route")
700+
@Nullable
701+
public abstract Boolean waypointsPerRoute();
702+
691703
/**
692704
* A scale from -1 to 1, where -1 biases the route against alleys
693705
* and 1 biases the route toward alleys. If null, default is 0, which is neutral.
@@ -1031,6 +1043,7 @@ public URL toUrl(@NonNull String accessToken) {
10311043
appendQueryParameter(sb, "max_width", maxWidth());
10321044
appendQueryParameter(sb, "max_weight", maxWeight());
10331045
appendQueryParameter(sb, "compute_toll_cost", computeTollCost());
1046+
appendQueryParameter(sb, "waypoints_per_route", waypointsPerRoute());
10341047
appendQueryParameter(sb, "metadata", metadata());
10351048

10361049
Map<String, SerializableJsonElement> unrecognized = unrecognized();
@@ -2031,6 +2044,19 @@ public Builder snappingIncludeStaticClosuresList(
20312044
@SuppressWarnings("checkstyle:javadocmethod")
20322045
public abstract Builder computeTollCost(@Nullable Boolean computeTollCost);
20332046

2047+
/**
2048+
* If true, the waypoints array is returned within the route object, else its returned
2049+
* at the root of the response body. Defaults to false if unspecified.
2050+
* Setting `waypoints_per_route` to true is necessary when asking for an EV-optimized
2051+
* route with alternatives, since each alternative route may produce separate
2052+
* sets of waypoints (charging stations).
2053+
*
2054+
* @param waypointsPerRoute boolean representing the `waypoints_per_route` value
2055+
* @return this builder
2056+
*/
2057+
@NonNull
2058+
public abstract Builder waypointsPerRoute(@Nullable Boolean waypointsPerRoute);
2059+
20342060
/**
20352061
* Whether the response should contain metadata holding versioning information.
20362062
* <p>

services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/DirectionsRouteTest.java

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
import java.io.IOException;
1111
import java.util.ArrayList;
12+
import java.util.Arrays;
13+
import java.util.List;
14+
1215
import org.hamcrest.junit.ExpectedException;
1316
import org.junit.Rule;
1417
import org.junit.Test;
@@ -130,9 +133,7 @@ public void directionsRoute_hasTollCosts() throws IOException {
130133
String uuid = "123";
131134
DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid);
132135

133-
DirectionsRoute newRoute = route.toBuilder().routeIndex("0").build();
134-
135-
assertEquals(2, newRoute.tollCosts().size());
136+
assertEquals(2, route.tollCosts().size());
136137
}
137138

138139
@Test
@@ -148,8 +149,72 @@ public void directionsRoute_noTollCosts() throws IOException {
148149
String uuid = "123";
149150
DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid);
150151

151-
DirectionsRoute newRoute = route.toBuilder().routeIndex("0").build();
152+
assertNull(route.tollCosts());
153+
}
154+
155+
@Test
156+
public void directionsRoute_hasWaypoints() throws IOException {
157+
String json = loadJsonFixture("directions_v5_with_waypoints.json");
158+
RouteOptions options = RouteOptions.builder()
159+
.profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC)
160+
.coordinatesList(new ArrayList<Point>() {{
161+
add(Point.fromLngLat(1.0, 1.0));
162+
add(Point.fromLngLat(2.0, 2.0));
163+
}})
164+
.waypointsPerRoute(true)
165+
.build();
166+
String uuid = "123";
167+
DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid);
168+
169+
assertEquals(2, route.waypoints().size());
170+
}
171+
172+
@Test
173+
public void directionsRouteBuilder_hasWaypoints() {
174+
List<DirectionsWaypoint> waypoints = Arrays.asList(
175+
DirectionsWaypoint.builder()
176+
.name("name1")
177+
.rawLocation(new double[] { 5.6, 7.8 })
178+
.build(),
179+
DirectionsWaypoint.builder()
180+
.name("name2")
181+
.rawLocation(new double[] { 1.2, 3.4 })
182+
.build()
183+
);
184+
DirectionsRoute route = DirectionsRoute.builder()
185+
.duration(12.12)
186+
.distance(34.34)
187+
.waypoints(waypoints)
188+
.build();
189+
190+
assertEquals(waypoints, route.waypoints());
191+
}
192+
193+
194+
@Test
195+
public void directionsRoute_noWaypoints() throws IOException {
196+
String json = loadJsonFixture("directions_v5-with-closure_precision_6.json");
197+
RouteOptions options = RouteOptions.builder()
198+
.profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC)
199+
.coordinatesList(new ArrayList<Point>() {{
200+
add(Point.fromLngLat(1.0, 1.0));
201+
add(Point.fromLngLat(2.0, 2.0));
202+
}})
203+
.waypointsPerRoute(true)
204+
.build();
205+
String uuid = "123";
206+
DirectionsRoute route = DirectionsRoute.fromJson(json, options, uuid);
207+
208+
assertNull(route.waypoints());
209+
}
210+
211+
@Test
212+
public void directionsRouteBuilder_noWaypoints() {
213+
DirectionsRoute route = DirectionsRoute.builder()
214+
.duration(12.12)
215+
.distance(34.34)
216+
.build();
152217

153-
assertNull(newRoute.tollCosts());
218+
assertNull(route.waypoints());
154219
}
155220
}

services-directions-models/src/test/java/com/mapbox/api/directions/v5/models/RouteOptionsTest.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class RouteOptionsTest extends TestUtils {
3737
*/
3838
private static final String ROUTE_OPTIONS_JSON = "route_options_v5.json";
3939
private static final String ROUTE_OPTIONS_URL =
40-
"https://api.mapbox.com/directions/v5/mapbox/driving/-122.4003312,37.7736941;-122.4187529,37.7689715;-122.4255172,37.7775835?access_token=pk.token&geometries=polyline6&alternatives=false&overview=full&radiuses=%3Bunlimited%3B5.1&steps=true&avoid_maneuver_radius=200.0&bearings=0%2C90%3B90%2C0%3B&layers=-42%3B%3B0&continue_straight=false&annotations=congestion%2Cdistance%2Cduration&language=ru&roundabout_exits=false&voice_instructions=true&banner_instructions=true&voice_units=metric&exclude=toll%2Cferry%2Cpoint%2811.0+-22.0%29&include=hot%2Chov2&approaches=%3Bcurb%3B&waypoints=0%3B1%3B2&waypoint_names=%3BSerangoon+Garden+Market+%26+Food+Centre%3BFunky+%26nAmE*&waypoint_targets=%3B12.2%2C21.2%3B&enable_refresh=true&walking_speed=5.11&walkway_bias=-0.2&alley_bias=0.75&snapping_include_closures=%3Bfalse%3Btrue&snapping_include_static_closures=true%3B%3Bfalse&arrive_by=2021-01-01%27T%2701%3A01&depart_at=2021-02-02%27T%2702%3A02&max_height=1.5&max_width=1.4&max_weight=2.9&compute_toll_cost=true&metadata=true";
40+
"https://api.mapbox.com/directions/v5/mapbox/driving/-122.4003312,37.7736941;-122.4187529,37.7689715;-122.4255172,37.7775835?access_token=pk.token&geometries=polyline6&alternatives=false&overview=full&radiuses=%3Bunlimited%3B5.1&steps=true&avoid_maneuver_radius=200.0&bearings=0%2C90%3B90%2C0%3B&layers=-42%3B%3B0&continue_straight=false&annotations=congestion%2Cdistance%2Cduration&language=ru&roundabout_exits=false&voice_instructions=true&banner_instructions=true&voice_units=metric&exclude=toll%2Cferry%2Cpoint%2811.0+-22.0%29&include=hot%2Chov2&approaches=%3Bcurb%3B&waypoints=0%3B1%3B2&waypoint_names=%3BSerangoon+Garden+Market+%26+Food+Centre%3BFunky+%26nAmE*&waypoint_targets=%3B12.2%2C21.2%3B&enable_refresh=true&walking_speed=5.11&walkway_bias=-0.2&alley_bias=0.75&snapping_include_closures=%3Bfalse%3Btrue&snapping_include_static_closures=true%3B%3Bfalse&arrive_by=2021-01-01%27T%2701%3A01&depart_at=2021-02-02%27T%2702%3A02&max_height=1.5&max_width=1.4&max_weight=2.9&compute_toll_cost=true&waypoints_per_route=true&metadata=true";
4141
private static final String ACCESS_TOKEN = "pk.token";
4242

4343
private final String optionsJson = loadJsonFixture(ROUTE_OPTIONS_JSON);
@@ -349,13 +349,27 @@ public void computeTollCostIsValid_fromJson() {
349349
assertEquals(true, options.computeTollCost());
350350
}
351351

352+
@Test
353+
public void waypointsPerRouteAreValid_fromJson() {
354+
RouteOptions routeOptions = RouteOptions.fromJson(optionsJson);
355+
356+
assertEquals(true, routeOptions.waypointsPerRoute());
357+
}
358+
352359
@Test
353360
public void defaultTollCost() {
354361
RouteOptions options = defaultRouteOptions();
355362

356363
assertNull(options.computeTollCost());
357364
}
358365

366+
@Test
367+
public void defaultWaypointsPerRoute() {
368+
RouteOptions options = defaultRouteOptions();
369+
370+
assertNull(options.waypointsPerRoute());
371+
}
372+
359373
@Test
360374
public void routeOptions_toJson() {
361375
RouteOptions options = routeOptions();
@@ -1046,6 +1060,7 @@ private RouteOptions routeOptions() {
10461060
.enableRefresh(true)
10471061
.metadata(true)
10481062
.computeTollCost(true)
1063+
.waypointsPerRoute(true)
10491064
.build();
10501065
}
10511066

@@ -1152,6 +1167,7 @@ private RouteOptions routeOptionsList() {
11521167
.enableRefresh(true)
11531168
.metadata(true)
11541169
.computeTollCost(true)
1170+
.waypointsPerRoute(true)
11551171
.build();
11561172
}
11571173
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"weight_typical":49.666,"duration_typical":36.767,"weight_name":"auto","weight":49.666,"duration":36.767,"distance":265.56,"waypoints":[{"name":"Köpenicker Straße","location":[13.426579,52.508068]},{"name":"Engeldamm","location":[13.427292,52.506902]}],"legs":[{"admins":[{"iso_3166_1_alpha3":"USA","iso_3166_1":"US"}],"closures":[{"geometry_index_end":21,"geometry_index_start":13}],"incidents":[{"id":"12887387251066566","type":"road_closure","description":"Washington Blvd: road closed from Kobbe Ave to Lincoln Blvd","long_description":"Road closed due to Slow Streets Program on Washington Blvd both ways from Kobbe Ave to Lincoln Blvd.","creation_time":"2021-03-29T20:25:39Z","start_time":"2020-07-02T15:26:14Z","end_time":"2021-06-14T22:59:00Z","impact":"low","sub_type":"CONSTRUCTION","alertc_codes":[401,703],"lanes_blocked":[],"closed":true,"congestion":{"value":101},"geometry_index_start":13,"geometry_index_end":19}],"annotation":{"congestion":["low","low","low","low","low","low","low","low","low","low","low","low","low","unknown","severe","severe","severe","severe","severe","severe","severe"],"distance":[8.5,28.8,10.6,8.3,8,8.1,8.9,8,10.9,27.4,8.3,2.4,7,5.9,5.7,6.4,12.7,17.1,18.6,19.4,34.9]},"weight_typical":49.666,"duration_typical":36.767,"weight":49.666,"duration":36.767,"steps":[{"intersections":[{"entry":[true],"bearings":[198],"duration":3.749,"mapbox_streets_v8":{"class":"secondary"},"is_urban":false,"admin_index":0,"out":0,"weight":3.562,"geometry_index":0,"location":[-122.477426,37.801498]},{"entry":[false,true],"in":0,"bearings":[19,204],"duration":5.282,"turn_weight":0.5,"turn_duration":0.01,"mapbox_streets_v8":{"class":"secondary"},"is_urban":false,"admin_index":0,"out":1,"weight":5.508,"geometry_index":3,"location":[-122.477599,37.801089]},{"entry":[false,true],"in":0,"bearings":[29,213],"duration":6.3,"turn_weight":0.5,"mapbox_streets_v8":{"class":"secondary"},"is_urban":false,"admin_index":0,"out":1,"weight":6.485,"geometry_index":8,"location":[-122.477809,37.800758]},{"bearings":[33,210],"entry":[false,true],"in":0,"turn_weight":2,"lanes":[{"indications":["left","straight"],"valid_indication":"left","valid":true,"active":true}],"turn_duration":0.021,"mapbox_streets_v8":{"class":"secondary"},"is_urban":false,"admin_index":0,"out":1,"geometry_index":12,"location":[-122.478115,37.800389]}],"maneuver":{"type":"depart","instruction":"Drive south on Lincoln Boulevard.","bearing_after":198,"bearing_before":0,"location":[-122.477426,37.801498]},"name":"Lincoln Boulevard","weight_typical":18.409,"duration_typical":16.252,"duration":16.252,"distance":144.905,"driving_side":"right","weight":18.409,"mode":"driving","geometry":"s`fbgAbvlrhFpCz@jNjErDpAhCfA`CjA`CpAjC~AzB|AdDbCvK|I|BdBd@ZjBnA"},{"intersections":[{"bearings":[30,161],"entry":[false,true],"in":0,"turn_weight":12.5,"lanes":[{"indications":["left","straight"],"valid_indication":"left","valid":true,"active":true}],"turn_duration":0.772,"mapbox_streets_v8":{"class":"tertiary"},"is_urban":false,"admin_index":0,"out":1,"geometry_index":13,"location":[-122.478155,37.800335]}],"maneuver":{"type":"turn","instruction":"Turn left onto Washington Boulevard.","modifier":"left","bearing_after":161,"bearing_before":210,"location":[-122.478155,37.800335]},"name":"Washington Boulevard","weight_typical":31.256,"duration_typical":20.516,"duration":20.516,"distance":120.655,"driving_side":"right","weight":31.256,"mode":"driving","geometry":"}wcbgAtcnrhFlAyA~Ai@pBUbFLpHShIcArIcBhQ}G"},{"intersections":[{"bearings":[339],"entry":[true],"in":0,"admin_index":0,"geometry_index":21,"location":[-122.477848,37.799296]}],"maneuver":{"type":"arrive","instruction":"You have arrived at your destination.","bearing_after":0,"bearing_before":159,"location":[-122.477848,37.799296]},"name":"Washington Boulevard","weight_typical":0,"duration_typical":0,"duration":0,"distance":0,"driving_side":"right","weight":0,"mode":"driving","geometry":"_wabgAnpmrhF??"}],"distance":265.56,"summary":"Lincoln Boulevard, Washington Boulevard"}],"geometry":"s`fbgAbvlrhFpCz@jNjErDpAhCfA`CjA`CpAjC~AzB|AdDbCvK|I|BdBd@ZjBnAlAyA~Ai@pBUbFLpHShIcArIcBhQ}G"}

services-directions-models/src/test/resources/route_options_v5.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@
3636
"max_weight": 2.9,
3737
"enable_refresh": true,
3838
"metadata": true,
39+
"waypoints_per_route": true,
3940
"compute_toll_cost": true
4041
}

0 commit comments

Comments
 (0)