Skip to content

Commit

Permalink
Add non-stopover Waypoint support.
Browse files Browse the repository at this point in the history
  • Loading branch information
apjanke committed Jul 7, 2018
1 parent fa0ccd9 commit e42752f
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 20 deletions.
122 changes: 102 additions & 20 deletions src/main/java/com/google/maps/DirectionsApiRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.google.maps;

import static com.google.maps.internal.StringJoin.join;
import static java.util.Objects.requireNonNull;

import com.google.maps.model.DirectionsResult;
import com.google.maps.model.LatLng;
Expand All @@ -35,7 +36,7 @@ public DirectionsApiRequest(GeoApiContext context) {
}

protected boolean optimizeWaypoints;
protected String[] waypoints;
protected Waypoint[] waypoints;

@Override
protected void validateRequest() {
Expand All @@ -58,8 +59,8 @@ protected void validateRequest() {

/**
* The address or textual latitude/longitude value from which you wish to calculate directions. If
* you pass an address as a string, the Directions service will geocode the string and convert it
* to a latitude/longitude coordinate to calculate directions. If you pass coordinates, ensure
* you pass an address as a location, the Directions service will geocode the location and convert
* it to a latitude/longitude coordinate to calculate directions. If you pass coordinates, ensure
* that no space exists between the latitude and longitude values.
*
* @param origin The starting location for the Directions request.
Expand All @@ -71,8 +72,8 @@ public DirectionsApiRequest origin(String origin) {

/**
* The address or textual latitude/longitude value from which you wish to calculate directions. If
* you pass an address as a string, the Directions service will geocode the string and convert it
* to a latitude/longitude coordinate to calculate directions. If you pass coordinates, ensure
* you pass an address as a location, the Directions service will geocode the location and convert
* it to a latitude/longitude coordinate to calculate directions. If you pass coordinates, ensure
* that no space exists between the latitude and longitude values.
*
* @param destination The ending location for the Directions request.
Expand Down Expand Up @@ -166,9 +167,9 @@ public DirectionsApiRequest departureTime(ReadableInstant time) {
}

/**
* Specifies a list of waypoints. Waypoints alter a route by routing it through the specified
* Specifies a list of waypoints. Waypoints alter a route by routing it through the specified *
* location(s). A waypoint is specified as either a latitude/longitude coordinate or as an address
* which will be geocoded. Waypoints are only supported for driving, walking and bicycling
* * which will be geocoded. Waypoints are only supported for driving, walking and bicycling *
* directions.
*
* <p>For more information on waypoints, see <a
Expand All @@ -178,33 +179,52 @@ public DirectionsApiRequest departureTime(ReadableInstant time) {
* @param waypoints The waypoints to add to this directions request.
* @return Returns this {@code DirectionsApiRequest} for call chaining.
*/
public DirectionsApiRequest waypoints(String... waypoints) {
this.waypoints = waypoints;
public DirectionsApiRequest waypoints(Waypoint... waypoints) {
if (waypoints == null || waypoints.length == 0) {
this.waypoints = new Waypoint[0];
param("waypoints", "");
return this;
} else if (waypoints.length == 1) {
return param("waypoints", waypoints[0]);
} else {
return param("waypoints", (optimizeWaypoints ? "optimize:true|" : "") + join('|', waypoints));
this.waypoints = waypoints;
String[] waypointStrs = new String[waypoints.length];
for (int i = 0; i < waypoints.length; i++) {
waypointStrs[i] = waypoints[i].toString();
}
param("waypoints", (optimizeWaypoints ? "optimize:true|" : "") + join('|', waypointStrs));
return this;
}
}

/**
* Specifies the list of waypoints as String addresses.
*
* <p>See {@link #waypoints(Waypoint...)}.
*
* @param waypoints The waypoints to add to this directions request.
* @return Returns this {@code DirectionsApiRequest} for call chaining.
*/
public DirectionsApiRequest waypoints(String... waypoints) {
Waypoint[] objWaypoints = new Waypoint[waypoints.length];
for (int i = 0; i < waypoints.length; i++) {
objWaypoints[i] = new Waypoint(waypoints[i]);
}
return waypoints(objWaypoints);
}

/**
* The list of waypoints as latitude/longitude locations.
*
* <p>See {@link #waypoints(Waypoint...)}.
*
* @param waypoints The waypoints to add to this directions request.
* @return Returns this {@code DirectionsApiRequest} for call chaining.
*/
public DirectionsApiRequest waypoints(LatLng... waypoints) {
if (waypoints == null) {
return this;
Waypoint[] objWaypoints = new Waypoint[waypoints.length];
for (int i = 0; i < waypoints.length; i++) {
objWaypoints[i] = new Waypoint(waypoints[i]);
}
int length = waypoints.length;
String[] waypointStrings = new String[length];
for (int i = 0; i < length; i++) {
waypointStrings[i] = waypoints[i].toString();
}
return waypoints(waypointStrings);
return waypoints(objWaypoints);
}

/**
Expand Down Expand Up @@ -271,4 +291,66 @@ public DirectionsApiRequest transitRoutingPreference(TransitRoutingPreference pr
public DirectionsApiRequest trafficModel(TrafficModel trafficModel) {
return param("traffic_model", trafficModel);
}

public static class Waypoint {
/** The location of this waypoint, expressed as an API-recognized location. */
private String location;
/** Whether this waypoint is a stopover waypoint. */
private boolean isStopover;

/**
* Constructs a stopover Waypoint using a String address.
*
* @param location Any address or location recognized by the Google Maps API.
*/
public Waypoint(String location) {
this(location, true);
}

/**
* Constructs a Waypoint using a String address.
*
* @param location Any address or location recognized by the Google Maps API.
* @param isStopover Whether this waypoint is a stopover waypoint.
*/
public Waypoint(String location, boolean isStopover) {
requireNonNull(location, "address may not be null");
this.location = location;
this.isStopover = isStopover;
}

/**
* Constructs a stopover Waypoint using a Latlng location.
*
* @param location The LatLng coordinates of this waypoint.
*/
public Waypoint(LatLng location) {
this(location, true);
}

/**
* Constructs a Waypoint using a LatLng location.
*
* @param location The LatLng coordinates of this waypoint.
* @param isStopover Whether this waypoint is a stopover waypoint.
*/
public Waypoint(LatLng location, boolean isStopover) {
requireNonNull(location, "location may not be null");
this.location = location.toString();
this.isStopover = isStopover;
}

/**
* Gets the String representation of this Waypoint, as an API request parameter fragment.
*
* @return The HTTP parameter fragment representing this waypoint.
*/
public String toString() {
if (isStopover) {
return location;
} else {
return "via:" + location;
}
}
}
}
49 changes: 49 additions & 0 deletions src/test/java/com/google/maps/DirectionsApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,30 @@ public void testBostonToConcordViaCharlestownAndLexington() throws Exception {
}
}

/**
* Boston to Concord, via Charlestown and Lexington, using non-stopover waypoints.
*
* <p>{@code
* http://maps.googleapis.com/maps/api/directions/json?origin=Boston,MA&destination=Concord,MA&waypoints=via:Charlestown,MA|via:Lexington,MA}
*/
@Test
public void testBostonToConcordViaCharlestownAndLexingtonNonStopover() throws Exception {
try (LocalTestServerContext sc =
new LocalTestServerContext("{\"routes\": [{}],\"status\": \"OK\"}")) {
DirectionsApi.newRequest(sc.context)
.origin("Boston,MA")
.destination("Concord,MA")
.waypoints(
new DirectionsApiRequest.Waypoint("Charlestown,MA", false),
new DirectionsApiRequest.Waypoint("Lexington,MA", false))
.await();

sc.assertParamValue("Boston,MA", "origin");
sc.assertParamValue("Concord,MA", "destination");
sc.assertParamValue("via:Charlestown,MA|via:Lexington,MA", "waypoints");
}
}

/**
* Boston to Concord, via Charlestown and Lexington, but using exact latitude and longitude
* coordinates for the waypoints.
Expand All @@ -249,6 +273,31 @@ public void testBostonToConcordViaCharlestownAndLexingtonLatLng() throws Excepti
}
}

/**
* Boston to Concord, via Charlestown and Lexington, but using exact latitude and longitude
* coordinates for the waypoints, using non-stopover waypoints.
*
* <p>{@code
* http://maps.googleapis.com/maps/api/directions/json?origin=Boston,MA&destination=Concord,MA&waypoints=via:42.379322,-71.063384|via:42.444303,-71.229087}
*/
@Test
public void testBostonToConcordViaCharlestownAndLexingtonLatLngNonStopoever() throws Exception {
try (LocalTestServerContext sc =
new LocalTestServerContext("{\"routes\": [{}],\"status\": \"OK\"}")) {
DirectionsApi.newRequest(sc.context)
.origin("Boston,MA")
.destination("Concord,MA")
.waypoints(
new DirectionsApiRequest.Waypoint(new LatLng(42.379322, -71.063384), false),
new DirectionsApiRequest.Waypoint(new LatLng(42.444303, -71.229087), false))
.await();

sc.assertParamValue("Boston,MA", "origin");
sc.assertParamValue("Concord,MA", "destination");
sc.assertParamValue("via:42.37932200,-71.06338400|via:42.44430300,-71.22908700", "waypoints");
}
}

/**
* Toledo to Madrid, in Spain. This showcases region biasing results.
*
Expand Down

0 comments on commit e42752f

Please sign in to comment.