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
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ directions-fixtures:
curl "https://api.mapbox.com/directions/v5/mapbox/driving/-122.403561,37.777689;-122.405786,37.770369.json?access_token=$(MAPBOX_ACCESS_TOKEN)&steps=true&geometries=polyline&banner_instructions=true" \
-o services-directions/src/test/resources/directions_v5_banner_instructions.json

# Directions: route with approaches in request
curl "https://api.mapbox.com/directions/v5/mapbox/driving/13.4301,52.5109;13.432507621760521,52.501725088556014?approaches=unrestricted;curb&access_token=$(MAPBOX_ACCESS_TOKEN)" \
-o services-directions/src/test/resources/directions_v5_approaches.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
Expand All @@ -134,6 +138,10 @@ mapmatching-fixtures:
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)" \
-o services-matching/src/test/resources/mapmatching_v5_approaches.json


optimization-fixtures:
# request an optimized car trip with no additional options
Expand Down
21 changes: 21 additions & 0 deletions services-core/src/main/java/com/mapbox/core/utils/TextUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,25 @@ public static String formatDistributions(List<Integer[]> distributions) {
}
return TextUtils.join(";", distributionsFormatted);
}

/**
* Converts String array with approaches values
* to a string ready for API consumption.
* An approache could be unrestricted, curb or null.
*
* @param approaches a string representing approaches to each coordinate.
* @return a formatted string.
* @since 3.2.0
*/
public static String formatApproaches(String[] approaches) {
for (int i = 0; i < approaches.length; i++) {
if (approaches[i] == null) {
approaches[i] = "";
} else if (!approaches[i].equals("unrestricted")
&& !approaches[i].equals("curb") && !approaches[i].isEmpty()) {
return null;
}
}
return TextUtils.join(";", approaches);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,26 @@ public final class DirectionsCriteria {
*/
public static final String DESTINATION_LAST = "last";

/**
* The routes can approach waypoints from either side of the road. <p>
*
* Used in MapMatching and Directions API.
*
* @since 3.2.0
*/
public static final String APPROACH_UNRESTRICTED = "unrestricted";

/**
* 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 in which the returned route is located. <p>
*
* Used in MapMatching and Directions API.
*
* @since 3.2.0
*/
public static final String APPROACH_CURB = "curb";

private DirectionsCriteria() {
//not called
}
Expand Down Expand Up @@ -322,4 +342,18 @@ private DirectionsCriteria() {
})
public @interface DestinationCriteria {
}


/**
* Retention policy for the approaches parameter in the MapMatching and Directions API.
*
* @since 3.2.0
*/
@Retention(RetentionPolicy.SOURCE)
@StringDef( {
APPROACH_UNRESTRICTED,
APPROACH_CURB
})
public @interface ApproachesCriteria {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public interface DirectionsService {
* useful for navigation
* @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.
* @return the {@link DirectionsResponse} in a Call wrapper
* @since 1.0.0
*/
Expand All @@ -68,6 +69,7 @@ Call<DirectionsResponse> getCall(
@Query("voice_instructions") Boolean voiceInstructions,
@Query("banner_instructions") Boolean bannerInstructions,
@Query("voice_units") String voiceUnits,
@Query("exclude") String exclude
@Query("exclude") String exclude,
@Query("approaches") String approaches
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ protected Call<DirectionsResponse> initializeCall() {
voiceInstructions(),
bannerInstructions(),
voiceUnits(),
exclude());
exclude(),
approaches());
}

@Override
Expand Down Expand Up @@ -299,6 +300,9 @@ private static String formatCoordinates(List<Point> coordinates) {
@Nullable
abstract String exclude();

@Nullable
abstract String approaches();

/**
* 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 @@ -346,6 +350,7 @@ public abstract static class Builder {
private double[] radiuses;
private Point destination;
private Point origin;
private String[] approaches;

/**
* The username for the account that the directions engine runs on. In most cases, this should
Expand Down Expand Up @@ -678,6 +683,29 @@ public Builder radiuses(@FloatRange(from = 0) double... radiuses) {

abstract Builder coordinates(@NonNull List<Point> coordinates);


/**
* Indicates from which side of the road to approach a waypoint.
* Accepts unrestricted (default), curb or null.
* 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 in which the returned route is located.
* If provided, the list of approaches must be the same length as the list of waypoints.
*
* @param approaches null if you'd like the default approaches,
* else one of the options found in
* {@link com.mapbox.api.directions.v5.DirectionsCriteria.ApproachesCriteria}.
* @return this builder for chaining options together
* @since 3.2.0
*/
public Builder addApproaches(String... approaches) {
this.approaches = approaches;
return this;
}

abstract Builder approaches(@Nullable String approaches);

abstract MapboxDirections autoBuild();

/**
Expand All @@ -701,6 +729,18 @@ public MapboxDirections build() {
+ " directions API request.");
}

if (approaches != null) {
if (approaches.length != coordinates.size()) {
throw new ServicesException("Number of approach elements must match "
+ "number of coordinates provided.");
}
String formattedApproaches = TextUtils.formatApproaches(approaches);
if (formattedApproaches == null) {
throw new ServicesException("All approaches values must be one of curb, unrestricted");
}
approaches(formattedApproaches);
}

coordinates(coordinates);
bearing(TextUtils.formatBearing(bearings));
annotation(TextUtils.join(",", annotations));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,23 @@ public static Builder builder() {
@NonNull
public abstract String requestUuid();

/**
* Indicates from which side of the road to approach a waypoint.
* 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
* 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.
*
* @return a string representing approaches for each waypoint
* @since 3.2.0
*/

@Nullable
public abstract String approaches();

/**
* Gson type adapter for parsing Gson to this class.
*
Expand Down Expand Up @@ -456,7 +473,18 @@ public abstract Builder overview(
* @since 3.0.0
*/
@Nullable
public abstract Builder exclude(String exclude);
public abstract Builder exclude(@NonNull String exclude);

/**
* The same approaches the user originally made when the request was made.
*
* @param approaches unrestricted, curb or omitted (;)
* @return this builder for chaining options together
* @since 3.2.0
*/

@Nullable
public abstract Builder approaches(String approaches);

/**
* Builds a new instance of the {@link RouteOptions} object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@
import okhttp3.mockwebserver.RecordedRequest;
import retrofit2.Response;

import static com.mapbox.api.directions.v5.DirectionsCriteria.APPROACH_CURB;
import static com.mapbox.api.directions.v5.DirectionsCriteria.APPROACH_UNRESTRICTED;
import static com.mapbox.api.directions.v5.DirectionsCriteria.GEOMETRY_POLYLINE;
import static com.mapbox.api.directions.v5.DirectionsCriteria.PROFILE_DRIVING;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.startsWith;
import static org.hamcrest.junit.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
Expand All @@ -47,6 +50,7 @@ public class MapboxDirectionsTest extends TestUtils {
private static final String DIRECTIONS_V5_NO_ROUTE = "directions_v5_no_route.json";
private static final String DIRECTIONS_V5_MAX_SPEED_ANNOTATION = "directions_v5_max_speed_annotation.json";
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 MockWebServer server;
private HttpUrl mockUrl;
Expand All @@ -65,6 +69,8 @@ public MockResponse dispatch(RecordedRequest request) throws InterruptedExceptio
resource = DIRECTIONS_ROTARY_FIXTURE;
} else if (request.getPath().contains("annotations")) {
resource = DIRECTIONS_V5_ANNOTATIONS_FIXTURE;
} else if (request.getPath().contains("approaches")) {
resource = DIRECTIONS_V5_APPROACHES_REQUEST;
} else if (request.getPath().contains("-151.2302")) {
resource = DIRECTIONS_V5_NO_ROUTE;
} else if (request.getPath().contains("-122.403561,37.777689")) {
Expand Down Expand Up @@ -552,4 +558,64 @@ public void subBannerInstructionsFromJson() throws Exception {
assertNotNull(component.directions());
assertEquals(2, component.directions().size());
}

@Test
public void sanityApproachesInstructions() throws Exception {
MapboxDirections mapboxDirections = MapboxDirections.builder()
.origin(Point.fromLngLat(1.0, 1.0))
.addWaypoint(Point.fromLngLat(2.0, 2.0))
.addWaypoint(Point.fromLngLat(3.0, 3.0))
.destination(Point.fromLngLat(4.0, 4.0))
.addApproaches(APPROACH_UNRESTRICTED, null, "", APPROACH_CURB)
.baseUrl("https://foobar.com")
.accessToken(ACCESS_TOKEN)
.build();
assertNotNull(mapboxDirections);
assertTrue(mapboxDirections.cloneCall().request().url().toString()
.contains("approaches=unrestricted;;;curb"));
}
@Test
public void build_exceptionThrownWhenNumApproachesDoesNotMatchCoordinates() throws Exception {
thrown.expect(ServicesException.class);
thrown.expectMessage(
startsWith("Number of approach elements must match"));
MapboxDirections mapboxDirections = MapboxDirections.builder()
.origin(Point.fromLngLat(2.0, 2.0))
.destination(Point.fromLngLat(4.0, 4.0))
.addApproaches(APPROACH_UNRESTRICTED)
.baseUrl("https://foobar.com")
.accessToken(ACCESS_TOKEN)
.build();
}

@Test
public void build_exceptionThrownWhenInvalidApproaches() throws Exception {
thrown.expect(ServicesException.class);
thrown.expectMessage(
startsWith("All approaches values must be one of curb, unrestricted"));
MapboxDirections mapboxDirections = MapboxDirections.builder()
.origin(Point.fromLngLat(2.0, 2.0))
.destination(Point.fromLngLat(4.0, 4.0))
.addApproaches(APPROACH_UNRESTRICTED, "restricted")
.baseUrl("https://foobar.com")
.accessToken(ACCESS_TOKEN)
.build();
}

@Test
public void testApproaches() throws Exception {
MapboxDirections mapboxDirections = MapboxDirections.builder()
.profile(PROFILE_DRIVING)
.origin(Point.fromLngLat(13.4301,52.5109))
.destination(Point.fromLngLat(13.432508,52.501725))
.addApproaches(APPROACH_UNRESTRICTED, APPROACH_CURB)
.accessToken(ACCESS_TOKEN)
.baseUrl(mockUrl.toString())
.build();

mapboxDirections.setCallFactory(null);
Response<DirectionsResponse> response = mapboxDirections.executeCall();
assertEquals(200, response.code());
assertEquals("Ok", response.body().code());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"routes":[{"geometry":"y_o_Iac~pA|CjAtNfMfJmYbTdQ`EyN_BaB","legs":[{"summary":"","weight":476.5,"duration":329.3,"steps":[],"distance":1451.7}],"weight_name":"routability","weight":476.5,"duration":329.3,"distance":1451.7}],"waypoints":[{"name":"Andreasstraße","location":[13.430407,52.510853]},{"name":"Eisenbahnstraße","location":[13.432091,52.501882]}],"code":"Ok","uuid":"cjhtkxys0008646paxl5tdc20"}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public interface MapMatchingService {
* marked-up text for voice guidance along the route.
* @param voiceUnits voice units
* @param waypoints Which input coordinates should be treated as waypoints.
* @param approaches which side of the road to approach a waypoint.
* @return the MapMatchingResponse in a Call wrapper
* @since 2.0.0
*/
Expand All @@ -79,5 +80,6 @@ Call<MapMatchingResponse> getCall(
@Query("banner_instructions") Boolean bannerInstructions,
@Query("voice_instructions") Boolean voiceInstructions,
@Query("voice_units") String voiceUnits,
@Query("waypoints") String waypoints);
@Query("waypoints") String waypoints,
@Query("approaches") String approaches);
}
Loading