Skip to content

Commit 14ebdf6

Browse files
author
Cameron Mace
authored
adds a snap to route activity to testapp (mapbox#286)
1 parent 6d56821 commit 14ebdf6

7 files changed

Lines changed: 424 additions & 0 deletions

File tree

mapbox/app/src/main/AndroidManifest.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@
169169
android:name="android.support.PARENT_ACTIVITY"
170170
android:value=".MainActivity"/>
171171
</activity>
172+
<activity
173+
android:name=".nav.SnapToRouteActivity"
174+
android:label="@string/title_snap_to_route">
175+
<meta-data
176+
android:name="android.support.PARENT_ACTIVITY"
177+
android:value=".MainActivity"/>
178+
</activity>
172179

173180
<!--
174181
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
@@ -27,6 +27,7 @@
2727
import com.mapbox.services.android.testapp.icons.MakiIconsActivity;
2828
import com.mapbox.services.android.testapp.location.LocationEngineActivity;
2929
import com.mapbox.services.android.testapp.nav.OffRouteDetectionActivity;
30+
import com.mapbox.services.android.testapp.nav.SnapToRouteActivity;
3031
import com.mapbox.services.android.testapp.staticimage.StaticImageActivity;
3132
import com.mapbox.services.android.testapp.turf.TurfBearingActivity;
3233
import com.mapbox.services.android.testapp.turf.TurfDestinationActivity;
@@ -156,6 +157,11 @@ protected void onCreate(Bundle savedInstanceState) {
156157
getString(R.string.title_connectivity),
157158
getString(R.string.description_connectivity),
158159
ConnectivityActivity.class
160+
),
161+
new SampleItem(
162+
getString(R.string.title_snap_to_route),
163+
getString(R.string.description_snap_to_route),
164+
SnapToRouteActivity.class
159165
)
160166
));
161167

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
package com.mapbox.services.android.testapp.nav;
2+
3+
import android.graphics.Color;
4+
import android.os.Bundle;
5+
import android.support.annotation.NonNull;
6+
import android.support.design.widget.FloatingActionButton;
7+
import android.support.v7.app.AppCompatActivity;
8+
import android.util.Log;
9+
import android.view.View;
10+
import android.widget.Toast;
11+
12+
import com.mapbox.mapboxsdk.MapboxAccountManager;
13+
import com.mapbox.mapboxsdk.annotations.Marker;
14+
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
15+
import com.mapbox.mapboxsdk.annotations.Polyline;
16+
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
17+
import com.mapbox.mapboxsdk.geometry.LatLng;
18+
import com.mapbox.mapboxsdk.maps.MapView;
19+
import com.mapbox.mapboxsdk.maps.MapboxMap;
20+
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
21+
import com.mapbox.services.Constants;
22+
import com.mapbox.services.android.testapp.R;
23+
import com.mapbox.services.api.ServicesException;
24+
import com.mapbox.services.api.directions.v5.DirectionsCriteria;
25+
import com.mapbox.services.api.directions.v5.MapboxDirections;
26+
import com.mapbox.services.api.directions.v5.models.DirectionsResponse;
27+
import com.mapbox.services.api.directions.v5.models.DirectionsRoute;
28+
import com.mapbox.services.api.navigation.v5.RouteUtils;
29+
import com.mapbox.services.api.utils.turf.TurfException;
30+
import com.mapbox.services.api.utils.turf.TurfMisc;
31+
import com.mapbox.services.commons.geojson.LineString;
32+
import com.mapbox.services.commons.geojson.Point;
33+
import com.mapbox.services.commons.models.Position;
34+
import com.mapbox.services.commons.utils.PolylineUtils;
35+
36+
import java.util.ArrayList;
37+
import java.util.List;
38+
39+
import retrofit2.Call;
40+
import retrofit2.Callback;
41+
import retrofit2.Response;
42+
43+
44+
public class SnapToRouteActivity extends AppCompatActivity implements OnMapReadyCallback, MapboxMap.OnMapClickListener {
45+
46+
private static final String TAG = "SnapToRouteActivity";
47+
private static final Position origin = Position.fromCoordinates(-95.75188, 29.78533);
48+
private static final Position destination = Position.fromCoordinates(-95.71892, 29.77516);
49+
50+
private MapView mapView;
51+
private MapboxMap mapboxMap;
52+
private DirectionsRoute currentRoute;
53+
54+
private Marker userLocation;
55+
private Marker snappedLocation;
56+
private int stepCount = 0;
57+
private Polyline stepPolyline;
58+
private Polyline distancePolyline;
59+
private Polyline distanceRoutePolyline;
60+
61+
@Override
62+
protected void onCreate(Bundle savedInstanceState) {
63+
super.onCreate(savedInstanceState);
64+
setContentView(R.layout.activity_snap_to_route);
65+
66+
FloatingActionButton forwardStepFab = (FloatingActionButton) findViewById(R.id.fab_forward_a_step);
67+
FloatingActionButton backStepFab = (FloatingActionButton) findViewById(R.id.fab_back_a_step);
68+
69+
backStepFab.setOnClickListener(new View.OnClickListener() {
70+
@Override
71+
public void onClick(View view) {
72+
if (currentRoute == null || mapboxMap == null) {
73+
return;
74+
}
75+
76+
if (stepCount <= 0) {
77+
Toast.makeText(SnapToRouteActivity.this, "On first step already", Toast.LENGTH_SHORT).show();
78+
return;
79+
}
80+
81+
stepCount--;
82+
83+
drawStepPolyline();
84+
}
85+
});
86+
87+
forwardStepFab.setOnClickListener(new View.OnClickListener() {
88+
@Override
89+
public void onClick(View view) {
90+
if (currentRoute == null || mapboxMap == null) {
91+
return;
92+
}
93+
94+
if (currentRoute.getLegs().get(0).getSteps().size() - 1 <= stepCount) {
95+
Toast.makeText(SnapToRouteActivity.this, "On last step already", Toast.LENGTH_SHORT).show();
96+
return;
97+
}
98+
99+
stepCount++;
100+
101+
drawStepPolyline();
102+
}
103+
});
104+
105+
mapView = (MapView) findViewById(R.id.mapview);
106+
mapView.onCreate(savedInstanceState);
107+
mapView.getMapAsync(this);
108+
}
109+
110+
@Override
111+
public void onMapClick(@NonNull LatLng point) {
112+
if (userLocation != null) {
113+
mapboxMap.removeMarker(userLocation);
114+
}
115+
if (snappedLocation != null) {
116+
mapboxMap.removeMarker(snappedLocation);
117+
}
118+
119+
userLocation = mapboxMap.addMarker(new MarkerOptions()
120+
.position(point)
121+
);
122+
123+
RouteUtils routeUtils = new RouteUtils();
124+
Position snappedPosition = null;
125+
126+
try {
127+
snappedPosition = routeUtils.getSnapToRoute(
128+
Position.fromCoordinates(point.getLongitude(), point.getLatitude()),
129+
currentRoute.getLegs().get(0),
130+
stepCount
131+
);
132+
} catch (ServicesException | TurfException exception) {
133+
exception.printStackTrace();
134+
Log.e(TAG, "snap to route util: " + exception.getMessage());
135+
}
136+
137+
if (snappedPosition == null) {
138+
Log.i(TAG, "snapPosition is null");
139+
return;
140+
}
141+
142+
snappedLocation = mapboxMap.addMarker(new MarkerOptions()
143+
.position(new LatLng(snappedPosition.getLatitude(), snappedPosition.getLongitude()))
144+
);
145+
146+
drawDistanceRoutePolyline(snappedPosition);
147+
148+
149+
// Decode the geometry and draw the route from current position to start of next step.
150+
List<Position> coords = PolylineUtils.decode(currentRoute.getLegs().get(0).getSteps().get(stepCount).getGeometry(),
151+
Constants.OSRM_PRECISION_V5);
152+
153+
// remove old line
154+
if (distancePolyline != null) {
155+
mapboxMap.removePolyline(distancePolyline);
156+
}
157+
158+
try {
159+
LineString slicedLine = TurfMisc.lineSlice(
160+
Point.fromCoordinates(snappedPosition),
161+
Point.fromCoordinates(coords.get(coords.size() - 1)),
162+
LineString.fromCoordinates(coords)
163+
);
164+
165+
List<Position> linePositions = slicedLine.getCoordinates();
166+
List<LatLng> lineLatLng = new ArrayList<>();
167+
for (Position pos : linePositions) {
168+
lineLatLng.add(new LatLng(pos.getLatitude(), pos.getLongitude()));
169+
}
170+
171+
distancePolyline = mapboxMap.addPolyline(new PolylineOptions()
172+
.addAll(lineLatLng)
173+
.color(Color.parseColor("#f1f075"))
174+
.width(5f)
175+
);
176+
} catch (TurfException turfException) {
177+
turfException.printStackTrace();
178+
}
179+
}
180+
181+
@Override
182+
public void onMapReady(MapboxMap mapboxMap) {
183+
SnapToRouteActivity.this.mapboxMap = mapboxMap;
184+
mapboxMap.setOnMapClickListener(this);
185+
186+
try {
187+
getRoute(origin, destination);
188+
} catch (ServicesException servicesException) {
189+
servicesException.printStackTrace();
190+
}
191+
}
192+
193+
private void drawDistanceRoutePolyline(Position snappedPosition) {
194+
// Decode the geometry and draw the route from current position to end of route
195+
List<Position> routeCoords = PolylineUtils.decode(currentRoute.getGeometry(), Constants.OSRM_PRECISION_V5);
196+
197+
// remove old line
198+
if (distanceRoutePolyline != null) {
199+
mapboxMap.removePolyline(distanceRoutePolyline);
200+
}
201+
202+
try {
203+
LineString slicedRouteLine = TurfMisc.lineSlice(
204+
Point.fromCoordinates(snappedPosition),
205+
Point.fromCoordinates(routeCoords.get(routeCoords.size() - 1)),
206+
LineString.fromCoordinates(routeCoords)
207+
);
208+
209+
List<Position> linePositions = slicedRouteLine.getCoordinates();
210+
List<LatLng> lineLatLng = new ArrayList<>();
211+
for (Position pos : linePositions) {
212+
lineLatLng.add(new LatLng(pos.getLatitude(), pos.getLongitude()));
213+
}
214+
215+
distanceRoutePolyline = mapboxMap.addPolyline(new PolylineOptions()
216+
.addAll(lineLatLng)
217+
.color(Color.parseColor("#3887be"))
218+
.width(5f)
219+
);
220+
} catch (TurfException turfException) {
221+
turfException.printStackTrace();
222+
}
223+
}
224+
225+
private void getRoute(Position origin, Position destination) throws ServicesException {
226+
227+
MapboxDirections client = new MapboxDirections.Builder()
228+
.setOrigin(origin)
229+
.setDestination(destination)
230+
.setOverview(DirectionsCriteria.OVERVIEW_FULL)
231+
.setSteps(true)
232+
.setProfile(DirectionsCriteria.PROFILE_DRIVING)
233+
.setAccessToken(MapboxAccountManager.getInstance().getAccessToken())
234+
.build();
235+
236+
Log.i(TAG, "Request: " + client.cloneCall().request());
237+
238+
client.enqueueCall(new Callback<DirectionsResponse>() {
239+
@Override
240+
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
241+
// You can get the generic HTTP info about the response
242+
Log.d(TAG, "Response code: " + response.code());
243+
if (response.body() == null) {
244+
Log.e(TAG, "No routes found, make sure you set the right user and access token.");
245+
return;
246+
} else if (response.body().getRoutes().size() < 1) {
247+
Log.e(TAG, "No routes found");
248+
return;
249+
}
250+
251+
// Print some info about the route
252+
currentRoute = response.body().getRoutes().get(0);
253+
Log.d(TAG, "Distance: " + currentRoute.getDistance());
254+
Toast.makeText(
255+
SnapToRouteActivity.this,
256+
"Route is " + currentRoute.getDistance() + " meters long.",
257+
Toast.LENGTH_SHORT).show();
258+
259+
// Draw the route on the map
260+
drawRoute(currentRoute);
261+
}
262+
263+
@Override
264+
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
265+
Log.e(TAG, "Error: " + throwable.getMessage());
266+
Toast.makeText(SnapToRouteActivity.this, "Error: " + throwable.getMessage(), Toast.LENGTH_SHORT).show();
267+
}
268+
});
269+
}
270+
271+
private void drawRoute(DirectionsRoute route) {
272+
// Convert LineString coordinates into LatLng[]
273+
LineString lineString = LineString.fromPolyline(route.getGeometry(), Constants.OSRM_PRECISION_V5);
274+
List<Position> coordinates = lineString.getCoordinates();
275+
LatLng[] points = new LatLng[coordinates.size()];
276+
for (int i = 0; i < coordinates.size(); i++) {
277+
points[i] = new LatLng(
278+
coordinates.get(i).getLatitude(),
279+
coordinates.get(i).getLongitude());
280+
}
281+
282+
// Draw Points on MapView
283+
mapboxMap.addPolyline(new PolylineOptions()
284+
.add(points)
285+
.color(Color.parseColor("#009688"))
286+
.width(5));
287+
}
288+
289+
private void drawStepPolyline() {
290+
LineString lineString = LineString.fromPolyline(
291+
currentRoute.getLegs().get(0).getSteps().get(stepCount).getGeometry(),
292+
Constants.OSRM_PRECISION_V5
293+
);
294+
295+
List<Position> coordinates = lineString.getCoordinates();
296+
297+
List<LatLng> points = new ArrayList<>();
298+
for (int i = 0; i < coordinates.size(); i++) {
299+
points.add(
300+
new LatLng(coordinates.get(i).getLatitude(), coordinates.get(i).getLongitude())
301+
);
302+
}
303+
304+
if (stepPolyline != null) {
305+
mapboxMap.removePolyline(stepPolyline);
306+
}
307+
308+
stepPolyline = mapboxMap.addPolyline(new PolylineOptions()
309+
.addAll(points)
310+
.color(Color.parseColor("#e55e5e"))
311+
.width(5));
312+
}
313+
314+
@Override
315+
public void onResume() {
316+
super.onResume();
317+
mapView.onResume();
318+
}
319+
320+
@Override
321+
public void onPause() {
322+
super.onPause();
323+
mapView.onPause();
324+
}
325+
326+
@Override
327+
public void onLowMemory() {
328+
super.onLowMemory();
329+
mapView.onLowMemory();
330+
}
331+
332+
@Override
333+
protected void onDestroy() {
334+
super.onDestroy();
335+
mapView.onDestroy();
336+
}
337+
338+
@Override
339+
protected void onSaveInstanceState(Bundle outState) {
340+
super.onSaveInstanceState(outState);
341+
mapView.onSaveInstanceState(outState);
342+
}
343+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24.0"
5+
android:viewportHeight="24.0">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/>
9+
</vector>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24.0"
5+
android:viewportHeight="24.0">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
9+
</vector>

0 commit comments

Comments
 (0)