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+ }
0 commit comments