Skip to content

Commit 66d9087

Browse files
author
Cameron Mace
authored
Optimized Trips (#437)
* added optimized trips api * adds test for optimized trips API * fixed up some javadoc * fixed fixture filepath * added testapp activity * fixed makefile * removed empty lines
1 parent d1a263f commit 66d9087

16 files changed

Lines changed: 17875 additions & 10 deletions

File tree

Makefile

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,7 @@ mapmatching-fixtures:
116116
curl "https://api.mapbox.com/matching/v5/mapbox/driving/$(MAP_MATCHING_COORDINATES)?geometries=polyline&access_token=$(MAPBOX_ACCESS_TOKEN)" \
117117
-o mapbox/libjava-services/src/test/fixtures/mapmatching_v5_polyline.json
118118

119-
distance-fixtures:
120-
# Retrieve a duration matrix
121-
curl -X POST --header "Content-Type:application/json" -d @mapbox/libjava-services/src/test/fixtures/distance_coordinates.json \
122-
"https://api.mapbox.com/distances/v1/mapbox/driving?access_token=$(MAPBOX_ACCESS_TOKEN)" \
123-
-o mapbox/libjava-services/src/test/fixtures/distance_v1.json
119+
optimized-trips-fixtures:
120+
# request an optimized car trip with no additional options
121+
curl "https://api.mapbox.com/optimized-trips/v1/mapbox/driving/-122.42,37.78;-122.45,37.91;-122.48,37.73?access_token=$(MAPBOX_ACCESS_TOKEN)" \
122+
-o mapbox/libjava-services/src/test/fixtures/optimized_trip.json

mapbox/app/src/main/AndroidManifest.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@
134134
android:name="android.support.PARENT_ACTIVITY"
135135
android:value=".MainActivity"/>
136136
</activity>
137+
<activity
138+
android:name=".optimizedtrip.OptimizedTripActivity"
139+
android:label="@string/title_optimized_trip">
140+
<meta-data
141+
android:name="android.support.PARENT_ACTIVITY"
142+
android:value=".MainActivity"/>
143+
</activity>
137144

138145
<!--
139146
Service to asynchronously fetch a location address using a Geocoder. Setting the

mapbox/app/src/main/java/com/mapbox/services/android/testapp/MainActivity.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import com.mapbox.services.android.testapp.geocoding.GeocodingServiceActivity;
2222
import com.mapbox.services.android.testapp.geocoding.GeocodingWidgetActivity;
2323
import com.mapbox.services.android.testapp.location.LocationEngineActivity;
24+
import com.mapbox.services.android.testapp.optimizedtrip.OptimizedTripActivity;
25+
2426
import com.mapbox.services.android.testapp.staticimage.StaticImageActivity;
2527
import com.mapbox.services.android.testapp.turf.TurfBearingActivity;
2628
import com.mapbox.services.android.testapp.turf.TurfDestinationActivity;
@@ -53,6 +55,10 @@ protected void onCreate(Bundle savedInstanceState) {
5355
setContentView(R.layout.activity_main);
5456

5557
final List<SampleItem> samples = new ArrayList<>(Arrays.asList(
58+
new SampleItem(
59+
getString(R.string.title_optimized_trip),
60+
getString(R.string.description_optimized_trip),
61+
OptimizedTripActivity.class),
5662
new SampleItem(
5763
getString(R.string.title_location),
5864
getString(R.string.description_location),
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package com.mapbox.services.android.testapp.optimizedtrip;
2+
3+
import android.animation.ValueAnimator;
4+
import android.graphics.Color;
5+
import android.os.Bundle;
6+
import android.support.v7.app.AppCompatActivity;
7+
8+
import com.mapbox.mapboxsdk.Mapbox;
9+
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
10+
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
11+
import com.mapbox.mapboxsdk.geometry.LatLng;
12+
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
13+
import com.mapbox.mapboxsdk.maps.MapView;
14+
import com.mapbox.mapboxsdk.maps.MapboxMap;
15+
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
16+
import com.mapbox.mapboxsdk.style.layers.LineLayer;
17+
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
18+
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
19+
import com.mapbox.services.Constants;
20+
import com.mapbox.services.android.testapp.R;
21+
import com.mapbox.services.api.directions.v5.DirectionsCriteria;
22+
import com.mapbox.services.api.optimizedtrips.v1.MapboxOptimizedTrips;
23+
import com.mapbox.services.api.optimizedtrips.v1.models.OptimizedTripsResponse;
24+
import com.mapbox.services.api.utils.turf.TurfConstants;
25+
import com.mapbox.services.api.utils.turf.TurfMeasurement;
26+
import com.mapbox.services.api.utils.turf.TurfMisc;
27+
import com.mapbox.services.commons.geojson.Feature;
28+
import com.mapbox.services.commons.geojson.FeatureCollection;
29+
import com.mapbox.services.commons.geojson.LineString;
30+
import com.mapbox.services.commons.geojson.Point;
31+
import com.mapbox.services.commons.models.Position;
32+
33+
import java.util.ArrayList;
34+
import java.util.List;
35+
36+
import retrofit2.Call;
37+
import retrofit2.Callback;
38+
import retrofit2.Response;
39+
import timber.log.Timber;
40+
41+
public class OptimizedTripActivity extends AppCompatActivity implements OnMapReadyCallback {
42+
43+
private static final String LINE_SOURCE = "line-source";
44+
private static final String LINE_LAYER = "line-layer";
45+
46+
private MapView mapView;
47+
private MapboxMap mapboxMap;
48+
private List<MarkerOptions> tripStops;
49+
private ValueAnimator valueAnimator;
50+
51+
@Override
52+
protected void onCreate(Bundle savedInstanceState) {
53+
super.onCreate(savedInstanceState);
54+
setContentView(R.layout.activity_optimized_trip);
55+
56+
tripStops = new ArrayList<>();
57+
tripStops.add(new MarkerOptions().position(new LatLng(40.74302, -73.99322)));
58+
tripStops.add(new MarkerOptions().position(new LatLng(40.74451, -73.97920)));
59+
tripStops.add(new MarkerOptions().position(new LatLng(40.75979, -73.99179)));
60+
tripStops.add(new MarkerOptions().position(new LatLng(40.76369, -73.97144)));
61+
tripStops.add(new MarkerOptions().position(new LatLng(40.75906, -73.98812)));
62+
63+
mapView = (MapView) findViewById(R.id.mapView);
64+
mapView.onCreate(savedInstanceState);
65+
mapView.getMapAsync(this);
66+
67+
}
68+
69+
@Override
70+
public void onMapReady(MapboxMap mapboxMap) {
71+
this.mapboxMap = mapboxMap;
72+
mapboxMap.addMarkers(tripStops);
73+
74+
MapboxOptimizedTrips.Builder builder = new MapboxOptimizedTrips.Builder()
75+
.setAccessToken(Mapbox.getAccessToken())
76+
.setProfile(DirectionsCriteria.PROFILE_DRIVING)
77+
// .setRoundTrip(false)
78+
.setSource(DirectionsCriteria.SOURCE_FIRST)
79+
// .setDestination(DirectionsCriteria.SOURCE_LAST)
80+
.setOverview(DirectionsCriteria.OVERVIEW_FULL);
81+
82+
List<Position> coords = new ArrayList<>();
83+
LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
84+
for (MarkerOptions markerOptions : tripStops) {
85+
coords.add(Position.fromCoordinates(
86+
markerOptions.getPosition().getLongitude(),
87+
markerOptions.getPosition().getLatitude())
88+
);
89+
90+
boundsBuilder.include(markerOptions.getPosition());
91+
}
92+
93+
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), 150));
94+
95+
MapboxOptimizedTrips client = builder.setCoordinates(coords).build();
96+
client.enqueueCall(new Callback<OptimizedTripsResponse>() {
97+
@Override
98+
public void onResponse(Call<OptimizedTripsResponse> call, Response<OptimizedTripsResponse> response) {
99+
Timber.v("Call Url: %s", call.request().url().toString());
100+
101+
drawLine(response.body().getTrips().get(0).getGeometry());
102+
}
103+
104+
@Override
105+
public void onFailure(Call<OptimizedTripsResponse> call, Throwable throwable) {
106+
Timber.e("Calling optimize trips failed: ", throwable);
107+
}
108+
});
109+
}
110+
111+
private void drawLine(String geometry) {
112+
113+
LineString linestring = LineString.fromPolyline(geometry, Constants.PRECISION_6);
114+
FeatureCollection featureCollection
115+
= FeatureCollection.fromFeatures(new Feature[] {Feature.fromGeometry(linestring)});
116+
117+
GeoJsonSource source = new GeoJsonSource(LINE_SOURCE, featureCollection);
118+
mapboxMap.addSource(source);
119+
120+
LineLayer layer = new LineLayer(LINE_LAYER, LINE_SOURCE).withProperties(
121+
PropertyFactory.lineWidth(5f),
122+
PropertyFactory.lineColor(Color.parseColor("#009DF9"))
123+
);
124+
125+
mapboxMap.addLayerBelow(layer, "poi-parks-scalerank2");
126+
127+
startAnimation(
128+
Position.fromCoordinates(
129+
tripStops.get(0).getPosition().getLongitude(),
130+
tripStops.get(0).getPosition().getLatitude()),
131+
linestring);
132+
133+
}
134+
135+
private void startAnimation(final Position startPosition, final LineString route) {
136+
137+
final double routeDistance = TurfMeasurement.lineDistance(route, TurfConstants.UNIT_METERS);
138+
139+
valueAnimator = ValueAnimator.ofFloat(0, 1);
140+
valueAnimator.setDuration(30000);
141+
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
142+
@Override
143+
public void onAnimationUpdate(ValueAnimator animation) {
144+
Point currentPoint = TurfMeasurement.along(
145+
route,
146+
routeDistance * (double) animation.getAnimatedFraction(),
147+
TurfConstants.UNIT_METERS
148+
);
149+
LineString newLine = TurfMisc.lineSlice(Point.fromCoordinates(startPosition), currentPoint, route);
150+
151+
GeoJsonSource source = mapboxMap.getSourceAs(LINE_SOURCE);
152+
if (source != null) {
153+
FeatureCollection newRouteFeature
154+
= FeatureCollection.fromFeatures(new Feature[] {Feature.fromGeometry(newLine)});
155+
source.setGeoJson(newRouteFeature);
156+
157+
}
158+
}
159+
});
160+
valueAnimator.start();
161+
}
162+
163+
@Override
164+
public void onResume() {
165+
super.onResume();
166+
mapView.onResume();
167+
}
168+
169+
@Override
170+
protected void onStart() {
171+
super.onStart();
172+
mapView.onStart();
173+
}
174+
175+
@Override
176+
protected void onStop() {
177+
super.onStop();
178+
mapView.onStop();
179+
if (valueAnimator != null) {
180+
valueAnimator.removeAllUpdateListeners();
181+
}
182+
}
183+
184+
@Override
185+
public void onPause() {
186+
super.onPause();
187+
mapView.onPause();
188+
}
189+
190+
@Override
191+
public void onLowMemory() {
192+
super.onLowMemory();
193+
mapView.onLowMemory();
194+
}
195+
196+
@Override
197+
protected void onDestroy() {
198+
super.onDestroy();
199+
mapView.onDestroy();
200+
}
201+
202+
@Override
203+
protected void onSaveInstanceState(Bundle outState) {
204+
super.onSaveInstanceState(outState);
205+
mapView.onSaveInstanceState(outState);
206+
}
207+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<RelativeLayout
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
5+
xmlns:tools="http://schemas.android.com/tools"
6+
android:layout_width="match_parent"
7+
android:layout_height="match_parent"
8+
tools:context=".optimizedtrip.OptimizedTripActivity">
9+
10+
<com.mapbox.mapboxsdk.maps.MapView
11+
android:id="@+id/mapView"
12+
android:layout_width="match_parent"
13+
android:layout_height="match_parent"
14+
mapbox:mapbox_styleUrl="@string/mapbox_style_light"/>
15+
16+
</RelativeLayout>

mapbox/app/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
<string name="description_turf_inside">Use Turf to determine if something is within a polygon.</string>
6060
<string name="description_turf_midpoint">Use Turf to get a midpoint.</string>
6161
<string name="description_connectivity">Keep track of the connectivity status.</string>
62+
<string name="title_optimized_trip">Optimized Trip</string>
63+
<string name="description_optimized_trip">Use the optimized trip API to solve the traveling salesperson problem</string>
64+
6265

6366
<string-array name="turf_calculation_items">
6467
<item>Select calculation</item>

mapbox/libjava-services/src/main/java/com/mapbox/services/api/directions/v5/DirectionsCriteria.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ public class DirectionsCriteria {
117117
*/
118118
public static final String RESPONSE_OK = "Ok";
119119

120+
public static final String SOURCE_FIRST = "first";
121+
public static final String SOURCE_ANY = "any";
122+
public static final String SOURCE_LAST = "last";
123+
124+
120125
/**
121126
* There was no route found for the given query.
122127
*

mapbox/libjava-services/src/main/java/com/mapbox/services/api/directions/v5/DirectionsService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public interface DirectionsService {
3232
* the angle of approach
3333
* @param continueStraight Define whether the route should continue straight even if the route
3434
* will be slower. @return A retrofit Call object
35-
* @param annotations An annotations object that contains additional details about each line segment along the
35+
* @param annotations An annotations object that contains additional details about each line segment along the
3636
* route geometry. Each entry in an annotations field corresponds to a coordinate along the
3737
* route geometry.
3838
* @since 1.0.0

mapbox/libjava-services/src/main/java/com/mapbox/services/api/directions/v5/MapboxDirections.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ public Builder() {
161161
this.geometries = DirectionsCriteria.GEOMETRY_POLYLINE6;
162162
}
163163

164+
/*
165+
* Setters
166+
*/
167+
164168
/**
165169
* The SDK currently only supports {@code Polyline} geometry (not GeoJSON) to simplify the response. You do have
166170
* the option on whether the precision is 5 or 6 using either {@link DirectionsCriteria#GEOMETRY_POLYLINE} or
@@ -175,10 +179,6 @@ public T setGeometry(String geometries) {
175179
return (T) this;
176180
}
177181

178-
/*
179-
* Setters
180-
*/
181-
182182
/**
183183
* @param user User string
184184
* @return Builder

0 commit comments

Comments
 (0)