How to update existing line layer in MapBox - android

Here is mapBox sample to draw a line geometry.
private void onStyleLoaded(Style style) {
initRouteCoordinates();
style.addSource(new GeoJsonSource("line-source",
FeatureCollection.fromFeatures(new Feature[]{
Feature.fromGeometry(LineString.fromLngLats(routeCoordinates))})));
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"))));
Point point = routeCoordinates.get(0);
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(point.latitude(), point.longitude()), 17));
}
I need to add more points and update the line. As you can see in the example line geometry is given to the source layer at the construction time. I couldn't find any api to add a point to the current line later.
Should I remove this line and redraw a new one ? Isn't there a better approach ?

You can add the "line-source" source and corresponding "lineLayer" layer once, and set the data contained by the source each time you want to add more points to update the line. Namely, each time you want to update the data rendered by the LineLayer:
Add the newly acquired coordinate to your existing GeoJSON source, stored in a variable called data. (I'd recommend storing new GeoJsonSource("line-source", ... in a data variable rather than creating it inline within the call to style#addSource, so that you can access it later to update).
Execute style.getSourceAs("line-source").setGeoJson(data).
Alternatively, you could use geoJsonSource.setGeoJson(Feature.fromGeometry(LineString.fromLngLats(updatedRouteCoordinates))) rather than setGeoJson(data), which might be more convenient depending on your use case.
You can modify the implementation according to your specific needs, but the general idea is that you only need to update the existing source's data, and not its corresponding layer, each time you want to update the line. This concept is described in the modify properties documentation for the Mapbox Maps SDK for Android. To quote the documentation:
sources and layers aren't immutable so they can be modified anytime during the map render

Related

Switch GeoJsonSource data in MapBox

I want to replace the data behind an existing source. This is trivial in javascript:
map.getSource('trace').setData(data);
See https://docs.mapbox.com/mapbox-gl-js/example/live-update-feature/
That method does not exist in Android. Once I have set a value, I can't replace it (nothing changes if I do):
GeoJsonSource mySource;
mySource.setGeoJson("some json data");
To delete and readd the source, I'd have to remove the layer using the source first: https://github.com/mapbox/mapbox-gl-native/issues/12526
Since I'm getting a fully functioning Style object from the server, removing, recreating and readding the layer/source at the correct position is tedious to say the least.
Above code actually works, but to reset my layer I used:
mySource.setGeoJson("");
Setting the source to empty String breaks something. Afterwards the GeoJson can not be set to something meaningful again. So to reset data, I'll have to use the visibility attribute of a layer. Replacing meaningful GeoJson with meaningful GeoJson works just fine.
The setGeoJson methods work correctly with any valid Geometry to add data (e.g. Point, MultiPoint).
Then, to clear or initialize the source without "breaking" the layer you can use:
mySource.setGeoJson(FeatureCollection.fromFeatures(new ArrayList<Feature>()));

How to filter markers in Mapbox Sdk

I'm creating an Android app using MapBox. I've already set up a simple map functionality with markers sourced from .json file. Next step is filtering the markers on the map, just like in this gl-js example here:
https://docs.mapbox.com/mapbox-gl-js/example/filter-markers/
I can't find any sdk examples anywhere, and since this is my first app I really can't figure it out on my own. Any help will be appreciated.
You can check out this example https://docs.mapbox.com/android/maps/examples/multiple-expressions-temperature-change/ that features two layers that fetch a min or max temperature from the data source and display it.
The filtering part is done here:
// Only display Maximum Temperature in this layer
maxTempLayer.setFilter(eq(get("element"), literal("All-Time Maximum Temperature")));
loadedMapStyle.addLayer(maxTempLayer);
Filters accept expressions as arguments, and here Expression.eq is used to compare "element" from the GeoJSON data source (referenced with the Expression.get) with the "All-Time Maximum Temperature" value. If it resolves to true, the feature is going to be displayed, otherwise, it's going to be hidden.

Android: OpenGL ES: associating information with drawn objects

I have a fairly basic question that I cannot for the life of me find the answer to online (most definitely due to not really knowing what I am looking for).
Suppose I have multiple (for the most part static) objects that are stored inside one VBO and drawn to the screen. Each object will have images and text/external data associated with it. I need to be able to navigate this "map" of objects and on-tap, access the corresponding information.
My question is, what is the best practice when it comes to storing this corresponding data and linking it to its respective drawing? I figured you create a "parallel" array of custom objects that each references its drawing and holds all the data... Although it seems quite elementary and thought there might be a better way. Considering also that there will potentially be thousands of these objects on the "map".
You can Use model class and put all common data intro one entity than use extends. You can use yours custom object who will consider whole VBO or opengles program data. About identity make ID for each elementary object or "draws".
-I understand your problematic. In opengl/es procedural programming is actually on scene.
Remember you are still in android envelopment you can use any java/android methodology.
-When you say "tap" did you mean click? If you so than see "Raycast" thema.
-This is interest file . It is JS not android but you can use same logic methods to make your object based app.
https://github.com/zlatnaspirala/visualjs/blob/master/project/project_instance_webgl2/lib/matrix-world.js
You can see lines like this :
App.scene[squareObject.name] = squareObject;
I have a global object App.scene . I put here all object buffer data. It is a key access but works like array.
I wanna say your idea about arrays is good. But not in parallel order. Procedural part works with no problem you need draw function for each element entity.
Look at draw methods :
https://github.com/zlatnaspirala/visualjs/blob/master/project/project_instance_webgl2/lib/matrix-draws.js
For example one of my draw entity is App.operation.draws.cube function.
I use this method to draw any cube but each cube is uniq object with uniq data inside.

Add a layer of paths on whole map

I use here-map sdk. I have db file with 16500 ! paths (coordinates of a point). I need to draw all paths on the map, when user activate function "show additional paths". But i think, if i try to fetch big number of path and add all poplilynes object on here map, it will take a huge amount of time.
Help to find the optimal solution.
I would filter your data based on the visible viewport and disable this functionality where it doesn't make much sense (continental or globe level).
So, let's assume you app shows the map on zoomlevel 16 or 17 (district level), you can retrieve the viewport as GeoBoundingBox from the Map instance (e.g. via mapView.getMap()) with getBoundingBox().
The GeoBoundingBox makes it easy for you now to check for collisions with your own objects, since it has several "contains()" methods.
So everything that collides with your viewport should be shown, everything else is ignored.
You can update whenever the map viewport changes with either listening for OnTransformListener in the Map class or register for the MapGesture events (get MapGesture via getMapGesture() and listen for zooming events via addOnGestureListener())
If the amount of data for filtering is still too big, you can also think about preparing your data for more efficient filtering, like partitioning (region based would be my first idea) so only a subset of your data needs to be filtered.
It seems that Custom Location Extension (https://developer.here.com/platform-extensions/documentation/custom-location/topics/what-is.html) can help with this case.
In short, it allows you to upload a custom data to the HERE backend and query it later.

SkMaps Remove SKPolylines

Currently I am removing SKPolylines by tracking their setIdentifier(int) numbers when I create them, and then when I delete them I apply a new polyline to the map with the same identifier that is transparent. I have two issues with this:
I assume there should be a way to do mapView.removePolyline(int identifier); or mapView.removeAllPolylines();
I also assume there should be a way to do mapView.getAllPolylines() that returns a List<SKPolyine> because that is possible with POI's and annotations. At the very least mapView.getNumPolylines(); that returns the number of polylines so that I can delete them all with my original method, without having to track how many I have put down.
My question is: Am I missing either functionality described in 1/2? If those functionalities do not exist then is there a better way than my current method?

Categories

Resources