Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -136,31 +136,35 @@ directions-fixtures:

# Directions: includes waypoint_names
curl "https://api.mapbox.com/directions/v5/mapbox/cycling/-122.42,37.78;-77.03,38.91?steps=true&voice_instructions=true&banner_instructions=true&voice_units=imperial&waypoint_names=Home;Work&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-directions/src/test/resources/directions_v5_waypoint_names.json
-o services-directions/src/test/resources/directions_v5_waypoint_names.json

# Directions: includes waypoint_targets
curl "https://api.mapbox.com/directions/v5/mapbox/driving-traffic/-6.80904429026134,62.00015328799685;-6.800065040588378,62.00012400993553?waypoint_targets=;-6.799936294555664,61.99987216574813&steps=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-directions/src/test/resources/directions_v5_waypoint_targets.json

mapmatching-fixtures:
curl "https://api.mapbox.com/matching/v5/mapbox/driving/$(MAP_MATCHING_COORDINATES)?geometries=polyline&language=sv&steps=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/map_matching_v5_polyline.json

# Unmatchable MapMatching request
curl "https://api.mapbox.com/matching/v5/mapbox/driving/0,-40;0,-20?access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/mapmatching_nosegment_v5_polyline.json
curl "https://api.mapbox.com/matching/v5/mapbox/driving/0,-40;0,-20?access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/mapmatching_nosegment_v5_polyline.json

# MapMatching request with approaches
curl "https://api.mapbox.com/matching/v5/mapbox/driving/-117.1728265285492,32.71204416018209;-117.17334151268004,32.71254065549407?approaches=unrestricted;curb&access_token=$(MAPBOX_ACCESS_TOKEN)" \
curl "https://api.mapbox.com/matching/v5/mapbox/driving/-117.1728265285492,32.71204416018209;-117.17334151268004,32.71254065549407?approaches=unrestricted;curb&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/mapmatching_v5_approaches.json

# MapMatching request with waypoint_names:
curl "https://api.mapbox.com/matching/v5/mapbox/driving/2.344003915786743,48.85805170891599;2.346750497817993,48.85727523615161;2.348681688308716,48.85936462637049;2.349550724029541,48.86084691113991;2.349550724029541,48.8608892614883;2.349625825881958,48.86102337068847;2.34982967376709,48.86125629633996?steps=true&tidy=true&waypoints=0;6&waypoint_names=Home;Work&banner_instructions=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/mapmatching_v5_waypoint_names.json
curl "https://api.mapbox.com/matching/v5/mapbox/driving/2.344003915786743,48.85805170891599;2.346750497817993,48.85727523615161;2.348681688308716,48.85936462637049;2.349550724029541,48.86084691113991;2.349550724029541,48.8608892614883;2.349625825881958,48.86102337068847;2.34982967376709,48.86125629633996?steps=true&tidy=true&waypoints=0;6&waypoint_names=Home;Work&banner_instructions=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/mapmatching_v5_waypoint_names.json

# MapMatching with valid voiceLanguage
curl "https://api.mapbox.com/matching/v5/mapbox/driving/$(MAP_MATCHING_COORDINATES)?steps=true&overview=full&geometries=polyline6&roundabout_exits=true&voice_instructions=true&language=en&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/map_matching_v5_voice_language.json
curl "https://api.mapbox.com/matching/v5/mapbox/driving/$(MAP_MATCHING_COORDINATES)?steps=true&overview=full&geometries=polyline6&roundabout_exits=true&voice_instructions=true&language=en&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/map_matching_v5_voice_language.json

# MapMatching with invalid voiceLanguage
curl "https://api.mapbox.com/matching/v5/mapbox/driving/$(MAP_MATCHING_COORDINATES)?steps=true&overview=full&geometries=polyline6&roundabout_exits=true&voice_instructions=true&language=he&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/map_matching_v5_invalid_voice_language.json
curl "https://api.mapbox.com/matching/v5/mapbox/driving/$(MAP_MATCHING_COORDINATES)?steps=true&overview=full&geometries=polyline6&roundabout_exits=true&voice_instructions=true&language=he&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-matching/src/test/resources/map_matching_v5_invalid_voice_language.json

optimization-fixtures:
# request an optimized car trip with no additional options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public interface DirectionsService {
* @param voiceUnits voice units
* @param exclude exclude tolls, motorways or more along your route
* @param approaches which side of the road to approach a waypoint
* @param waypointNames custom names for waypoints used for the arrival instruction.
* @param waypointNames custom names for waypoints used for the arrival instruction
* @param waypointTargets list of coordinate pairs for drop-off locations
* @return the {@link DirectionsResponse} in a Call wrapper
* @since 1.0.0
*/
Expand All @@ -72,6 +73,7 @@ Call<DirectionsResponse> getCall(
@Query("voice_units") String voiceUnits,
@Query("exclude") String exclude,
@Query("approaches") String approaches,
@Query("waypoint_names") String waypointNames
@Query("waypoint_names") String waypointNames,
@Query("waypoint_targets") String waypointTargets
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ protected Call<DirectionsResponse> initializeCall() {
voiceUnits(),
exclude(),
approaches(),
waypointNames());
waypointNames(),
waypointTargets());
}

@Override
Expand Down Expand Up @@ -206,6 +207,7 @@ private List<DirectionsRoute> generateRouteOptions(Response<DirectionsResponse>
.profile(profile())
.coordinates(coordinates())
.waypointNames(waypointNames())
.waypointTargets(waypointTargets())
.continueStraight(continueStraight())
.annotations(annotation())
.approaches(approaches())
Expand All @@ -232,14 +234,38 @@ private List<DirectionsRoute> generateRouteOptions(Response<DirectionsResponse>
}

private static String formatCoordinates(List<Point> coordinates) {
List<String> coordinatesFormatted = new ArrayList<>();
String[] coordinatesFormatted = new String[coordinates.size()];
int index = 0;
for (Point point : coordinates) {
coordinatesFormatted.add(String.format(Locale.US, "%s,%s",
coordinatesFormatted[index++] = String.format(Locale.US, "%s,%s",
TextUtils.formatCoordinate(point.longitude()),
TextUtils.formatCoordinate(point.latitude())));
TextUtils.formatCoordinate(point.latitude()));
}

return TextUtils.join(";", coordinatesFormatted.toArray());
return TextUtils.join(";", coordinatesFormatted);
}

/**
* Converts array of Points with waypoint_targets values
* to a string ready for API consumption.
*
* @param waypointTargets a string representing approaches to each coordinate.
* @return a formatted string.
* @since 4.3.0
*/
private static String formatWaypointTargets(Point[] waypointTargets) {
String[] coordinatesFormatted = new String[waypointTargets.length];
int index = 0;
for (Point target : waypointTargets) {
if (target == null) {
coordinatesFormatted[index++] = "";
} else {
coordinatesFormatted[index++] = String.format(Locale.US, "%s,%s",
TextUtils.formatCoordinate(target.longitude()),
TextUtils.formatCoordinate(target.latitude()));
}
}
return TextUtils.join(";", coordinatesFormatted);
}

@NonNull
Expand Down Expand Up @@ -309,6 +335,9 @@ private static String formatCoordinates(List<Point> coordinates) {
@Nullable
abstract String waypointNames();

@Nullable
abstract String waypointTargets();

/**
* Build a new {@link MapboxDirections} object with the initial values set for
* {@link #baseUrl()}, {@link #profile()}, {@link #user()}, and {@link #geometries()}.
Expand Down Expand Up @@ -358,6 +387,7 @@ public abstract static class Builder {
private Point origin;
private String[] approaches;
private String[] waypointNames;
private Point[] waypointTargets;

/**
* The username for the account that the directions engine runs on. In most cases, this should
Expand Down Expand Up @@ -713,7 +743,7 @@ public Builder addApproaches(String... approaches) {
* Custom names for waypoints used for the arrival instruction,
* each separated by ; . Values can be any string and total number of all characters cannot
* exceed 500. If provided, the list of waypointNames must be the same length as the list of
* coordinates, but you can skip a coordinate and show its position with the ; separator.
* coordinates, but you can skip a coordinate and show its position with the ; separator.
* @param waypointNames Custom names for waypoints used for the arrival instruction.
* @return this builder for chaining options together
* @since 3.3.0
Expand All @@ -725,6 +755,23 @@ public Builder addWaypointNames(@Nullable String... waypointNames) {

abstract Builder waypointNames(@Nullable String waypointNames);

/**
* A list of coordinate points used to specify drop-off locations
* that are distinct from the locations specified in coordinates.
* The number of waypoint targets must be the same as the number of coordinates,
* but you can skip a coordinate with a null value.
* Must be used with steps=true.
* @param waypointTargets list of coordinate points for drop-off locations
* @return this builder for chaining options together
* @since 4.3.0
*/
public Builder addWaypointTargets(@Nullable Point... waypointTargets) {
this.waypointTargets = waypointTargets;
return this;
}

abstract Builder waypointTargets(@Nullable String waypointTargets);

abstract MapboxDirections autoBuild();

/**
Expand Down Expand Up @@ -757,6 +804,15 @@ public MapboxDirections build() {
waypointNames(waypointNamesStr);
}

if (waypointTargets != null) {
if (waypointTargets.length != coordinates.size()) {
throw new ServicesException("Number of waypoint targets must match "
+ " the number of waypoints provided.");
}

waypointTargets(formatWaypointTargets(waypointTargets));
}

if (approaches != null) {
if (approaches.length != coordinates.size()) {
throw new ServicesException("Number of approach elements must match "
Expand All @@ -783,4 +839,5 @@ public MapboxDirections build() {
return directions;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,10 @@ public static Builder builder() {
* Accepts unrestricted (default) or curb . If set to unrestricted ,
* the route can approach waypoints from either side of the road.
* If set to curb, the route will be returned so that on arrival,
* the waypoint will be found on the side that corresponds with the driving_side of the region
* the waypoint will be found on the side that corresponds with the driving_side of the region
* in which the returned route is located.
* If provided, the list of approaches must be the same length as the list of waypoints.
* However, you can skip a coordinate and show its position in the list with the ; separator.
* However, you can skip a coordinate and show its position in the list with the ; separator.
*
* @return a string representing approaches for each waypoint
* @since 3.2.0
Expand All @@ -271,7 +271,7 @@ public static Builder builder() {
* Custom names for waypoints used for the arrival instruction in banners and voice instructions,
* each separated by ; . Values can be any string and total number of all characters cannot
* exceed 500. If provided, the list of waypoint_names must be the same length as the list of
* coordinates, but you can skip a coordinate and show its position with the ; separator.
* coordinates, but you can skip a coordinate and show its position with the ; separator.
* @return a string representing names for each waypoint
* @since 3.3.0
*/
Expand All @@ -280,6 +280,22 @@ public static Builder builder() {
public abstract String waypointNames();


/**
* A semicolon-separated list of coordinate pairs used to specify drop-off
* locations that are distinct from the locations specified in coordinates.
* If this parameter is provided, the Directions API will compute the side of the street,
* left or right, for each target based on the waypoint_targets and the driving direction.
* The maneuver.modifier, banner and voice instructions will be updated with the computed
* side of street. The number of waypoint targets must be the same as the number of coordinates,
* but you can skip a coordinate pair and show its position in the list with the ; separator.
* Must be used with steps=true.
* @return a string representing coordinate pairs for drop-off locations
* @since 4.3.0
*/
@SerializedName("waypoint_targets")
@Nullable
public abstract String waypointTargets();

/**
* Gson type adapter for parsing Gson to this class.
*
Expand Down Expand Up @@ -526,7 +542,7 @@ public abstract Builder overview(
public abstract Builder approaches(String approaches);

/**
* The same approaches the user originally made when the request was made.
* The same waypoint names the user originally made when the request was made.
*
* @param waypointNames unrestricted, curb or omitted (;)
* @return this builder for chaining options together
Expand All @@ -536,6 +552,17 @@ public abstract Builder overview(
@Nullable
public abstract Builder waypointNames(@Nullable String waypointNames);

/**
* The same waypoint targets the user originally made when the request was made.
*
* @param waypointTargets list of coordinate pairs for drop-off locations (;)
* @return this builder for chaining options together
* @since 4.3.0
*/

@Nullable
public abstract Builder waypointTargets(@Nullable String waypointTargets);

/**
* Builds a new instance of the {@link RouteOptions} object.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.api.directions.v5.models.LegAnnotation;
import com.mapbox.api.directions.v5.models.RouteOptions;
import com.mapbox.api.directions.v5.models.StepManeuver;
import com.mapbox.core.TestUtils;
import com.mapbox.core.exceptions.ServicesException;
import com.mapbox.geojson.Point;
Expand Down Expand Up @@ -37,6 +38,7 @@
import static com.mapbox.api.directions.v5.DirectionsCriteria.GEOMETRY_POLYLINE;
import static com.mapbox.api.directions.v5.DirectionsCriteria.PROFILE_CYCLING;
import static com.mapbox.api.directions.v5.DirectionsCriteria.PROFILE_DRIVING;
import static com.mapbox.api.directions.v5.DirectionsCriteria.PROFILE_DRIVING_TRAFFIC;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.startsWith;
import static org.hamcrest.junit.MatcherAssert.assertThat;
Expand All @@ -56,6 +58,7 @@ public class MapboxDirectionsTest extends TestUtils {
private static final String DIRECTIONS_V5_BANNER_INSTRUCTIONS = "directions_v5_banner_instructions.json";
private static final String DIRECTIONS_V5_APPROACHES_REQUEST = "directions_v5_approaches.json";
private static final String DIRECTIONS_V5_WAYPOINT_NAMES_FIXTURE = "directions_v5_waypoint_names.json";
private static final String DIRECTIONS_V5_WAYPOINT_TARGETS_FIXTURE = "directions_v5_waypoint_targets.json";

private MockWebServer server;
private HttpUrl mockUrl;
Expand All @@ -76,6 +79,8 @@ public MockResponse dispatch(RecordedRequest request) throws InterruptedExceptio
resource = DIRECTIONS_V5_ANNOTATIONS_FIXTURE;
} else if (request.getPath().contains("waypoint_names")) {
resource = DIRECTIONS_V5_WAYPOINT_NAMES_FIXTURE;
} else if (request.getPath().contains("waypoint_targets")) {
resource = DIRECTIONS_V5_WAYPOINT_TARGETS_FIXTURE;
}else if (request.getPath().contains("approaches")) {
resource = DIRECTIONS_V5_APPROACHES_REQUEST;
} else if (request.getPath().contains("-151.2302")) {
Expand Down Expand Up @@ -701,4 +706,28 @@ public void testWithWaypointNames() throws Exception {
assertEquals("Ok", response.body().code());
}

@Test
public void testWithWaypointTargets() throws Exception {

MapboxDirections mapboxDirections = MapboxDirections.builder()
.profile(PROFILE_DRIVING_TRAFFIC)
.origin(Point.fromLngLat(-6.80904429026134,62.00015328799685))
.destination(Point.fromLngLat(-6.800065040588378,62.00012400993553))
.steps(true)
.addWaypointTargets(null, Point.fromLngLat(-6.799936294555664,61.99987216574813))
.accessToken(ACCESS_TOKEN)
.baseUrl(mockUrl.toString())
.build();

assertNotNull(mapboxDirections);
assertNotNull(mapboxDirections.cloneCall().request().url().queryParameter("waypoint_targets"));

Response<DirectionsResponse> response = mapboxDirections.executeCall();
assertEquals(200, response.code());
assertEquals("Ok", response.body().code());
assertEquals("left",
response.body().routes().get(0).legs().get(0).steps().get(0).maneuver().modifier());

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"routes":[{"geometry":"mklyJf{ph@g@aHh@m@LeBD_BDuNAqC_@_R","legs":[{"summary":"Velbastaðarvegur, Gamli Velbastaðvegur","weight":74.2,"duration":65.3,"steps":[{"intersections":[{"out":0,"entry":[true],"bearings":[74],"location":[-6.808995,62.000073]}],"driving_side":"right","geometry":"mklyJf{ph@g@aH","mode":"driving","maneuver":{"bearing_after":74,"bearing_before":0,"location":[-6.808995,62.000073],"modifier":"left","type":"depart","instruction":"Head east on Velbastaðarvegur"},"weight":15.2,"duration":6.6,"name":"Velbastaðarvegur","distance":78.4},{"intersections":[{"out":1,"in":2,"entry":[true,true,false],"bearings":[75,150,255],"location":[-6.807551,62.000267]},{"out":0,"in":2,"entry":[true,true,false],"bearings":[90,195,270],"location":[-6.806054,61.999953]},{"out":0,"in":2,"entry":[true,true,false],"bearings":[90,180,270],"location":[-6.804462,61.999935]},{"out":0,"in":2,"entry":[true,true,false],"bearings":[90,180,270],"location":[-6.802712,61.999962]}],"driving_side":"right","geometry":"ullyJdrph@VUPWBY@KF_AD_B@w@?{@@eB?{A?_A@[?cBAqCCw@?SGiDIwCG_EAQ","mode":"driving","maneuver":{"bearing_after":156,"bearing_before":73,"location":[-6.807551,62.000267],"modifier":"right","type":"turn","instruction":"Turn right onto Gamli Velbastaðvegur"},"weight":58.99999999999999,"duration":58.7,"name":"Gamli Velbastaðvegur","distance":408.1},{"intersections":[{"in":0,"entry":[true],"bearings":[257],"location":[-6.800053,62.000099]}],"driving_side":"right","geometry":"sklyJhcoh@","mode":"driving","maneuver":{"bearing_after":0,"bearing_before":77,"location":[-6.800053,62.000099],"type":"arrive","modifier":"right","instruction":"You have arrived at your destination, on the right"},"weight":0,"duration":0,"name":"Gamli Velbastaðvegur","distance":0}],"distance":486.6}],"weight_name":"routability","weight":74.2,"duration":65.3,"distance":486.6}],"waypoints":[{"name":"Velbastaðarvegur","location":[-6.808995,62.000073]},{"name":"Gamli Velbastaðvegur","location":[-6.800053,62.000099]}],"code":"Ok","uuid":"cjpois8j900098anrxqn5kdc5"}