Skip to content
This repository has been archived by the owner on Oct 7, 2024. It is now read-only.

Add example of multiple geometries based on Directions route #1158

Merged
merged 1 commit into from
Sep 10, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import com.mapbox.mapboxandroiddemo.examples.dds.KotlinStyleCirclesCategoricallyActivity;
import com.mapbox.mapboxandroiddemo.examples.dds.LineGradientActivity;
import com.mapbox.mapboxandroiddemo.examples.dds.MultipleGeometriesActivity;
import com.mapbox.mapboxandroiddemo.examples.javaservices.MultipleGeometriesDirectionsRouteActivity;
import com.mapbox.mapboxandroiddemo.examples.dds.MultipleHeatmapStylingActivity;
import com.mapbox.mapboxandroiddemo.examples.dds.PolygonHolesActivity;
import com.mapbox.mapboxandroiddemo.examples.dds.PolygonSelectToggleActivity;
Expand Down Expand Up @@ -1060,6 +1061,15 @@ private void initializeModels() {
null,
R.string.activity_java_services_directions_gradient_url, false, BuildConfig.MIN_SDK_VERSION));

exampleItemModels.add(new ExampleItemModel(
R.id.nav_java_services,
R.string.activity_java_services_multiple_geometries_from_directions_route_title,
R.string.activity_java_services_multiple_geometries_from_directions_route_description,
new Intent(MainActivity.this, MultipleGeometriesDirectionsRouteActivity.class),
null,
R.string.activity_java_services_multiple_geometries_from_directions_route_url,
true, BuildConfig.MIN_SDK_VERSION));

exampleItemModels.add(new ExampleItemModel(
R.id.nav_snapshot_image_generator,
R.string.activity_image_generator_snapshot_notification_title,
Expand Down
7 changes: 7 additions & 0 deletions MapboxAndroidDemo/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapbox.mapboxandroiddemo.MainActivity" />
</activity>
<activity
android:name=".examples.javaservices.MultipleGeometriesDirectionsRouteActivity"
android:label="@string/activity_java_services_multiple_geometries_from_directions_route_title">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapbox.mapboxandroiddemo.MainActivity" />
</activity>
<activity
android:name=".examples.dds.DrawPolygonActivity"
android:label="@string/activity_dds_polygon_title">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
package com.mapbox.mapboxandroiddemo.examples.javaservices;

import android.graphics.Color;
import android.os.Bundle;
import android.widget.Toast;

import com.mapbox.api.directions.v5.DirectionsCriteria;
import com.mapbox.api.directions.v5.MapboxDirections;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.api.directions.v5.models.LegStep;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxandroiddemo.R;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import timber.log.Timber;

import static com.mapbox.core.constants.Constants.PRECISION_6;
import static com.mapbox.mapboxsdk.camera.CameraUpdateFactory.newLatLngBounds;
import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.layers.Property.CIRCLE_PITCH_ALIGNMENT_MAP;
import static com.mapbox.mapboxsdk.style.layers.Property.CIRCLE_PITCH_ALIGNMENT_VIEWPORT;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circlePitchAlignment;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineCap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;

/**
* Use the Mapbox Directions API to request and retrieve a Directions route. Show the route line and
* place a circle where each of the route's step maneuver locations are.
*/
public class MultipleGeometriesDirectionsRouteActivity extends AppCompatActivity
implements OnMapReadyCallback, MapboxMap.OnMapClickListener {

private static final String CIRCLE_GEOJSON_SOURCE_ID = "CIRCLE_GEOJSON_SOURCE_ID";
private static final String LINE_GEOJSON_SOURCE_ID = "LINE_GEOJSON_SOURCE_ID";
private static final String STEPS_CIRCLE_LAYER_ID = "steps-circle-layer";
private static final String STEPS_BACKGROUND_CIRCLE_LAYER_ID = "steps-background-circle-layer";
private static final String DIRECTIONS_ROUTE_LINE_LAYER_ID = "directions-line-layer";
private static final String SETTLEMENT_LABEL_LAYER_ID = "settlement-label";

// Adjust the following private static final variables to style this example's UI
private static final String LINE_COLOR = "#EE2E23";
private static final float LINE_WIDTH = 8f;
private static final float CIRCLE_RADIUS = 8f;
private static final float RADIUS_DIFFERENCE_BETWEEN_WAYPOINT_CIRCLES_AND_BACKGROUND_CIRCLES = 3f;
private static final int CIRCLE_COLOR = Color.WHITE;
private static final int BACKGROUND_CIRCLE_COLOR = Color.parseColor(LINE_COLOR);
private static final boolean ALIGN_CIRCLES_WITH_MAP = true;

private MapView mapView;
private MapboxMap mapboxMap;
private DirectionsRoute currentRoute;
private Point origin = Point.fromLngLat(-122.39648, 37.7914277);
private Point destination = Point.fromLngLat(-88.0430, 30.6944);

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Mapbox access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Mapbox.getInstance(this, getString(R.string.access_token));

// This contains the MapView in XML and needs to be called after the access token is configured.
setContentView(R.layout.activity_dds_multiple_geometries_from_directions_route);

mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}

@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(new Style.Builder().fromUri(Style.SATELLITE_STREETS)
.withSource(new GeoJsonSource(CIRCLE_GEOJSON_SOURCE_ID))
.withSource(new GeoJsonSource(LINE_GEOJSON_SOURCE_ID)), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
initLineLayerForDirectionsRoute(style);
initStepManeuverCircleLayer(style);
initStepManeuverBackgroundCircleLayer(style);
getRoute(origin, destination);
mapboxMap.addOnMapClickListener(MultipleGeometriesDirectionsRouteActivity.this);
Toast.makeText(MultipleGeometriesDirectionsRouteActivity.this,
getString(R.string.tap_on_map_to_change_destination), Toast.LENGTH_SHORT).show();
}
});
}

/**
* Create and style a LineLayer that will draw the Mapbox Directions API route line.
*
* @param loadedMapStyle the map's {@link Style} object
*/
private void initLineLayerForDirectionsRoute(@NonNull Style loadedMapStyle) {
LineLayer directionsRouteLineLayer = new LineLayer(DIRECTIONS_ROUTE_LINE_LAYER_ID, LINE_GEOJSON_SOURCE_ID);
directionsRouteLineLayer.setProperties(
lineColor(Color.parseColor(LINE_COLOR)),
lineCap(Property.LINE_CAP_ROUND),
lineWidth(LINE_WIDTH)
);

directionsRouteLineLayer.setFilter(eq(literal("$type"), literal("LineString")));

// Add the layer below the "settlement-label" layer (city name labels, etc.)
if (loadedMapStyle.getLayer(SETTLEMENT_LABEL_LAYER_ID) != null) {
loadedMapStyle.addLayerBelow(directionsRouteLineLayer, SETTLEMENT_LABEL_LAYER_ID);
} else {
loadedMapStyle.addLayer(directionsRouteLineLayer);
}
}

/**
* Create and style a CircleLayer that will place circles for each of the Mapbox Directions API
* route's step maneuver locations.
* @param loadedMapStyle the map's {@link Style} object
*/
private void initStepManeuverCircleLayer(@NonNull Style loadedMapStyle) {
CircleLayer individualCirclesLayer = new CircleLayer(STEPS_CIRCLE_LAYER_ID, CIRCLE_GEOJSON_SOURCE_ID);
individualCirclesLayer.setProperties(
circleColor(CIRCLE_COLOR),
circlePitchAlignment(ALIGN_CIRCLES_WITH_MAP ? CIRCLE_PITCH_ALIGNMENT_MAP : CIRCLE_PITCH_ALIGNMENT_VIEWPORT),
circleRadius(CIRCLE_RADIUS));
loadedMapStyle.addLayer(individualCirclesLayer);
}

/**
* Create and style a CircleLayer that will place circles beneath the STEPS_CIRCLE_LAYER_ID layer
* for each of the Mapbox Directions API route's step maneuver locations.
* @param loadedMapStyle the map's {@link Style} object
*/
private void initStepManeuverBackgroundCircleLayer(@NonNull Style loadedMapStyle) {
CircleLayer individualCirclesLayer = new CircleLayer(STEPS_BACKGROUND_CIRCLE_LAYER_ID, CIRCLE_GEOJSON_SOURCE_ID);
individualCirclesLayer.setProperties(
circleColor(BACKGROUND_CIRCLE_COLOR),
circlePitchAlignment(ALIGN_CIRCLES_WITH_MAP ? CIRCLE_PITCH_ALIGNMENT_MAP : CIRCLE_PITCH_ALIGNMENT_VIEWPORT),
circleRadius(CIRCLE_RADIUS + RADIUS_DIFFERENCE_BETWEEN_WAYPOINT_CIRCLES_AND_BACKGROUND_CIRCLES));
loadedMapStyle.addLayerBelow(individualCirclesLayer, STEPS_CIRCLE_LAYER_ID);
}

@Override
public boolean onMapClick(@NonNull LatLng point) {
destination = Point.fromLngLat(point.getLongitude(), point.getLatitude());
getRoute(origin, destination);
return true;
}

/**
* Make a request to the Mapbox Directions API. Once successful, pass the route to the
* route layer.
*
* @param origin the starting point of the route
* @param destination the desired finish point of the route
*/
private void getRoute(Point origin, Point destination) {
MapboxDirections directionsApiClient = MapboxDirections.builder()
.origin(origin)
.destination(destination)
.overview(DirectionsCriteria.OVERVIEW_FULL)
.profile(DirectionsCriteria.PROFILE_DRIVING)
.steps(true)
.accessToken(getString(R.string.access_token))
.build();

directionsApiClient.enqueueCall(new Callback<DirectionsResponse>() {
@Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
Timber.d("Response code: %s", response.code());
if (response.body() == null) {
Timber.e("Response body null. Try again later.");
Toast.makeText(MultipleGeometriesDirectionsRouteActivity.this,
getString(R.string.response_body_null), Toast.LENGTH_SHORT).show();
} else if (response.body().routes().size() < 1) {
Timber.e("No routes found");
Toast.makeText(MultipleGeometriesDirectionsRouteActivity.this,
getString(R.string.no_routes_found), Toast.LENGTH_SHORT).show();
} else {
// Get the directions route
if (response.body() != null) {
// Get the directions route
currentRoute = response.body().routes().get(0);
mapboxMap.getStyle(new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// Retrieve the sources from the map
GeoJsonSource circleLayerSource = style.getSourceAs(CIRCLE_GEOJSON_SOURCE_ID);
GeoJsonSource lineLayerSource = style.getSourceAs(LINE_GEOJSON_SOURCE_ID);
if (circleLayerSource != null && response.body() != null) {

List<Feature> featureList = new ArrayList<>();

// Use each step maneuver's location to create a Point Feature.
// The Feature is then added to the list.
if (currentRoute.legs().size() > 0) {
for (LegStep singleRouteLeg : currentRoute.legs().get(0).steps()) {
Point stepManeuverLocationPoint = singleRouteLeg.maneuver().location();
featureList.add(Feature.fromGeometry(stepManeuverLocationPoint));
}
} else {
Timber.d(getString(R.string.no_legs_toast));
}

// Update the CircleLayer's source with the Feature list.
circleLayerSource.setGeoJson(FeatureCollection.fromFeatures(featureList));

// Update the LineLayer's source with the Polyline route from the Directions API response.
if (lineLayerSource != null && currentRoute.geometry() != null) {
lineLayerSource.setGeoJson(Feature.fromGeometry(LineString.fromPolyline(
currentRoute.geometry(), PRECISION_6)));
}

// Ease the camera to fit to the Directions route.
easeCameraToShowEntireDirectionsRoute(new LatLng(origin.latitude(), origin.longitude()),
new LatLng(destination.latitude(), destination.longitude()));
}
}
});
}
}
}

@Override
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
Timber.e(throwable);
Toast.makeText(MultipleGeometriesDirectionsRouteActivity.this,
String.format("Error: %s", throwable.getMessage()),
Toast.LENGTH_SHORT).show();
langsmith marked this conversation as resolved.
Show resolved Hide resolved
}
});
}

private void easeCameraToShowEntireDirectionsRoute(LatLng origin, LatLng destination) {
mapboxMap.easeCamera(newLatLngBounds(new LatLngBounds.Builder()
.include(origin)
.include(destination)
.build(), 75), 2000);
}

// Add the mapView lifecycle to the activity's lifecycle methods
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}

@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}

@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}

@Override
public void onPause() {
super.onPause();
mapView.onPause();
}

@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}

@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnMapClickListener(this);
}
mapView.onDestroy();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
tools:context="com.mapbox.mapboxandroiddemo.examples.javaservices.MultipleGeometriesDirectionsRouteActivity">

<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
mapbox:mapbox_cameraTargetLat="43.621478"
mapbox:mapbox_cameraTargetLng="-105.409474"
mapbox:mapbox_cameraZoom=".8"/>
</FrameLayout>
6 changes: 6 additions & 0 deletions MapboxAndroidDemo/src/main/res/values/activity_strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,10 @@
<string name="route_call_failure">Directions API call failed. Try again later.</string>
<string name="tap_map_instruction_gradient_directions">Tap the map to change the route destination.</string>

<!-- Multiple geometries directions line-->
<string name="no_legs_toast">This directions route has no legs</string>
<string name="no_routes_found">No routes found</string>
<string name="response_body_null">Response body null. Try again later.</string>
<string name="tap_on_map_to_change_destination">Tap on map to change destination</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
<string name="activity_java_services_turf_physical_circle_description">Use Turf to generate a circle with a radius expressed in physical units (e.g. miles, kilometers, etc).</string>
<string name="activity_java_services_turf_line_distance_description">Use Turf to generate a circle with a radius expressed in physical units (e.g. miles, kilometers, etc).</string>
<string name="activity_java_services_directions_gradient_description">Apply a two-color gradient to a Directions API route line.</string>
<string name="activity_java_services_multiple_geometries_from_directions_route_description">Show multiple geometries based on a single Mapbox Directions API response.</string>
<string name="activity_plugins_traffic_plugin_description">Use the traffic plugin to display live car congestion data on top of a map.</string>
<string name="activity_plugins_building_plugin_description">Use the building plugin to easily display 3D building height</string>
<string name="activity_plugins_geojson_plugin_description">Easily retrieve GeoJSON data from a url, asset, or path</string>
Expand Down Expand Up @@ -139,4 +140,4 @@
<string name="activity_lab_spinning_icon_description">Use a ValueAnimator to adjust SymbolLayer icons\' rotation values and create a spinning effect.</string>
<string name="activity_china_simple_china_mapview_description">Show an accurate and government-approved China map in your app using the Mapbox Maps SDK.</string>

</resources>
</resources>
Loading