mapbox-navigation-android icon indicating copy to clipboard operation
mapbox-navigation-android copied to clipboard

Point list will not accept location coordinates to create linestring to draw a trailing line

Open AaronConvery opened this issue 3 years ago • 2 comments

Android API: Mapbox Navigation SDK version:

Steps to trigger behavior

  1. Get user coordinates using Location.getLatitude/getLongitude
  2. Add these to Point list
  3. Create Linestring from pointlist

Expected behavior

To intake user coordinates anytime they move and draw a trailing line behind the puck

Actual behavior

The app crashes when the coordinates are trying to be added into the Point list, if this line of code is uncommented the app runs but no line is drawn

I believe it is partly due to looking for location history and not actively calling for location updates but I dont see anywhere how to add location updates into the point list to create the linestring

See below my main activity

private MapView mapView; private static final int PERMISSION_LOCATION = 1000; public MapboxMap mapboxMap; ArrayList<Point> pointList = new ArrayList<Point>(); private PermissionsManager permissionsManager; private static final String TAG = "SimplifyLineActivity"; private List<Point> routeCoordinates; private LatLng locationHistory; public LocationManager locationManager;

@SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent(@NonNull Style loadedMapStyle) {
    // Check if permissions are enabled and if not request
    if (PermissionsManager.areLocationPermissionsGranted(this)) {

        // Get an instance of the LocationComponent.
        LocationComponent locationComponent = mapboxMap.getLocationComponent();

        // Activate the LocationComponent
        locationComponent.activateLocationComponent(
                LocationComponentActivationOptions.builder(this, loadedMapStyle).build());

        // Enable the LocationComponent so that it's actually visible on the map
        locationComponent.setLocationComponentEnabled(true);

        // Set the LocationComponent's camera mode
        locationComponent.setCameraMode(CameraMode.TRACKING);

        // Set the LocationComponent's render mode
        locationComponent.setRenderMode(RenderMode.NORMAL);
    } else {
        permissionsManager = new PermissionsManager(this);
        permissionsManager.requestLocationPermissions(this);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
    Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show();
}

@Override
public void onPermissionResult(boolean granted) {
    if (granted) {
        mapboxMap.getStyle(new Style.OnStyleLoaded() {
            @Override
            public void onStyleLoaded(@NonNull Style style) {
                enableLocationComponent(style);
            }
        });
    } else {
        Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show();
        finish();
    }
}

@Override
public void onLocationChanged(Location location) {

    location.getLongitude();
    location.getLatitude();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Mapbox.getInstance(this, "pk.eyJ1IjoiYWFyb25jb252ZXJ5IiwiYSI6ImNsN2l6ZHptMTB0YnYzcHBid2hrY2Q5cXUifQ.vMh6oO3R5sWWPPxklfrHRA");

    setContentView(R.layout.activity_main);


    // Create supportMapFragment
    SupportMapFragment mapFragment;
    if (savedInstanceState == null) {

        // Create fragment
        final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Build a Mapbox map
        MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null);
        options.camera(new CameraPosition.Builder()
                .target(new LatLng(38.899895, -77.03401))
                .zoom(18)
                .tilt(45)
                .build());


        // Create map fragment
        mapFragment = SupportMapFragment.newInstance(options);

        // Add map fragment to parent container
        transaction.add(R.id.location_frag_container, mapFragment, "com.mapbox.map");
        transaction.commit();
    } else {
        mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag("com.mapbox.map");
    }

    if (mapFragment != null) {
        mapFragment.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(@NonNull MapboxMap mapboxMap) {
                LocationComponentActivity.this.mapboxMap = mapboxMap;
                mapboxMap.setStyle(Style.OUTDOORS, new Style.OnStyleLoaded() {
                    @Override
                    public void onStyleLoaded(@NonNull Style style) {
                        enableLocationComponent(style);

                        List<Point> routeCoordinates = new ArrayList<>();

                        routeCoordinates.add(Point.fromLngLat(locationHistory.getLongitude(), locationHistory.getLatitude()));

                        LineString lineString = LineString.fromLngLats(routeCoordinates);

                        // Create the LineString from the list of coordinates and then make a GeoJSON
                        // FeatureCollection so we can add the line to our map as a layer.
                        style.addSource(new GeoJsonSource("line-source",
                                FeatureCollection.fromFeatures(new Feature[]{Feature.fromGeometry(lineString)

                                })));

                        // The layer properties for our line. This is where we make the line dotted, set the
                        // color, etc.
                        style.addLayer(new LineLayer("linelayer", "line-source").withProperties(
                                PropertyFactory.lineDasharray(new Float[]{0.01f, 2f}),
                                PropertyFactory.lineCap(Property.LINE_CAP_ROUND),
                                PropertyFactory.lineJoin(Property.LINE_JOIN_ROUND),
                                PropertyFactory.lineWidth(5f),
                                PropertyFactory.lineColor(Color.parseColor("#e55e5e"))
                        ));
                    }
                });
            }
        });
    }
}

@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {

}

}

AaronConvery avatar Sep 09 '22 07:09 AaronConvery

Convert the Point collection to a collection of Feature objects, then use that to create the FeatureCollection. I suggest doing something like (verbose for clarity):

Point pointA = Point.fromLngLat(longitudeA, latitudeA);
Point pointB = Point.fromLngLat(longitudeB, latitudeB);

Feature featureA = Feature.fromGeometry(pointA);
Feature featureB = Feature.fromGeometry(pointB);

List<Feature> featureList = new ArrayList();
featureList.add(featureA);
featureList.add(featureB);

FeatureCollection fc = FeatureCollection.fromFeatures(featureList);

BTW be careful about posting your Mapbox token into a public ticket. If that's your token rather than one of the public demonstration tokens then I suggest changing it.

cafesilencio avatar Sep 09 '22 18:09 cafesilencio

Hi thanks for the reply @cafesilencio

I tried implementing your suggestion and this did stop my app from crashing but it still does not produce a trailing line from the feature collection when the user moves and location therefore changes

Perhaps the issue is with how I am getting the location? But I can use the same process to produce accurate coordinates so that seems unlikely

See below my updated main activity with your suggestion

public class LocationComponentActivity extends AppCompatActivity implements OnMapReadyCallback, PermissionsListener, LocationListener, IBaseGpsListener {

public MapboxMap mapboxMap;
private PermissionsManager permissionsManager;
List<Feature> featureList = new ArrayList();

@SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent(@NonNull Style loadedMapStyle) {
    // Check if permissions are enabled and if not request
    if (PermissionsManager.areLocationPermissionsGranted(this)) {

        // Get an instance of the LocationComponent.
        LocationComponent locationComponent = mapboxMap.getLocationComponent();

        // Activate the LocationComponent
        locationComponent.activateLocationComponent(
                LocationComponentActivationOptions.builder(this, loadedMapStyle).build());

        // Enable the LocationComponent so that it's actually visible on the map
        locationComponent.setLocationComponentEnabled(true);

        // Set the LocationComponent's camera mode
        locationComponent.setCameraMode(CameraMode.TRACKING);

        // Set the LocationComponent's render mode
        locationComponent.setRenderMode(RenderMode.NORMAL);

        locationComponent.getLastKnownLocation();

    } else {
        permissionsManager = new PermissionsManager(this);
        permissionsManager.requestLocationPermissions(this);
    }


}

@SuppressLint("MissingPermission")
private void showLocation() {
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    // check if gps is enabled
    if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
        // Start locating
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, this);
    } else {
        // enable GPS
        Toast.makeText(this, "Enable GPS!", Toast.LENGTH_SHORT).show();
        startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
    }

}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
    Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show();
}

@Override
public void onPermissionResult(boolean granted) {
    if (granted) {
        mapboxMap.getStyle(new Style.OnStyleLoaded() {
            @Override
            public void onStyleLoaded(@NonNull Style style) {
                enableLocationComponent(style);
            }
        });
    } else {
        Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show();
        finish();
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Mapbox.getInstance(this, "pk.eyJ1IjoiYWFyb25jb252ZXJ5IiwiYSI6ImNsN2l6ZHptMTB0YnYzcHBid2hrY2Q5cXUifQ.vMh6oO3R5sWWPPxklfrHRA");

    setContentView(R.layout.activity_main);

    // Create supportMapFragment
    SupportMapFragment mapFragment;
    if (savedInstanceState == null) {

        // Create fragment
        final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Build a Mapbox map
        MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null);
        options.camera(new CameraPosition.Builder()
                .target(new LatLng(38.899895, -77.03401))
                .zoom(18)
                .tilt(45)
                .build());


        // Create map fragment
        mapFragment = SupportMapFragment.newInstance(options);

        // Add map fragment to parent container
        transaction.add(R.id.location_frag_container, mapFragment, "com.mapbox.map");
        transaction.commit();
    } else {
        mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag("com.mapbox.map");
    }

    if (mapFragment != null) {
        mapFragment.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(@NonNull MapboxMap mapboxMap ) {
                LocationComponentActivity.this.mapboxMap = mapboxMap;
                mapboxMap.setStyle(Style.OUTDOORS, new Style.OnStyleLoaded() {
                    @Override
                    public void onStyleLoaded(@NonNull Style style) {
                        enableLocationComponent(style);

                        FeatureCollection fc = FeatureCollection.fromFeatures(featureList);


                        // FeatureCollection so we can add the line to our map as a layer.
                        style.addSource(new GeoJsonSource("line-source", fc ));

                        // The layer properties for our line. This is where we make the line dotted, set the
                        // color, etc.
                        style.addLayer(new LineLayer("linelayer", "line-source").withProperties(
                                PropertyFactory.lineDasharray(new Float[]{0.01f, 2f}),
                                PropertyFactory.lineCap(Property.LINE_CAP_ROUND),
                                PropertyFactory.lineJoin(Property.LINE_JOIN_ROUND),
                                PropertyFactory.lineWidth(5f),
                                PropertyFactory.lineColor(Color.parseColor("#e55e5e"))
                        ));
                    }
                });
            }
        });
    }
}

@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {


}

@Override
public void onLocationChanged(@NonNull Location location) {

    Point pointA = Point.fromLngLat(location.getLatitude(), location.getLatitude());
    Point pointB = Point.fromLngLat(location.getLongitude(), location.getLongitude());

    Feature featureA = Feature.fromGeometry(pointA);
    Feature featureB = Feature.fromGeometry(pointB);

    featureList.add(featureA);
    featureList.add(featureB);

}

@Override
public void onProviderDisabled(String provider) {

}

@Override
public void onProviderEnabled(String provider) {

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

@Override
public void onGpsStatusChanged(int event) {

}

}

AaronConvery avatar Sep 12 '22 11:09 AaronConvery