I'm attempting to use MapSnapshotter (a part of the Mapbox Maps SDK for Android) to generate a screenshot of a Mapbox map instance, including a single line annotation that I've added to the map.
I seem to be able to generate a static map bitmap as expected, however the image does not contain my line annotation.
Is there a way of having the line appear in the bitmap that MapSnapshotter generates, or is MapSnapshotter limited to capturing map screenshots sans annotations?
I'm using the example code provided in one of Mapbox's repositories for the moment. The only alterations that I've made are to add a new layer and source to the Mapbox map style such that it is displayed on the interactive Mapbox map.
In order to have any symbols/geometries visible on the snapshot taken with the MapSnapshotter, the desired layers would have to be added directly to the style. Alternatively, you can draw on top of the image like in this example, which adds a marker to a snapshot.
Another way is to render a normal, interactive map and take a picture of it with MapboxMap#snapshot.
Please tell how to add the desired layer directly to the style according above answer?
I added my custom symbol layer to mapbox style, but snapshot does not make bitmap with symbols.
FeatureCollection featureCollection = FeatureCollection.fromJson(geoJson);
Source source = new GeoJsonSource("my.data.source", featureCollection);
mapboxMap.addSource(source);
SymbolLayer myLayer = new SymbolLayer("my.layer.id", "my.source.id");
myLayer.withProperties(PropertyFactory.iconImage("my.image"));
mapboxMap.addLayer(myLayer);
// ...
MapSnapshotter.Options snapShotOptions = new MapSnapshotter.Options(500, 500);
snapShotOptions.withRegion(mapboxMap.getProjection()
.getVisibleRegion().latLngBounds);
snapShotOptions.withStyle(mapboxMap.getStyle().getUrl());
MapSnapshotter mapSnapshotter = new MapSnapshotter(this, snapShotOptions);
Thank you.
Related
I have a webservice that returns GeoJson polygons (timezones) and I'm trying to draw them in a layer over the map object using GeoJsonLayer
I already tested the GeoJson file in geojson.io and it looks fine (image at the bottom) but when I add it to the map its not being filled and some extra lines appear down south, it looks like its not closing the poly properly, this is the code I'm using to load the file (I have it locally in raw folder at the moment)
val layer = GeoJsonLayer(mGoogleMap, R.raw.sample_timezones_response, requireContext())
layer.addLayerToMap()
val polygonStyle = GeoJsonPolygonStyle()
polygonStyle.fillColor = resources.getColor(R.color.color_main_green_200, null)
polygonStyle.zIndex = 10000f
layer.features.forEach { it1 ->
it1.polygonStyle = polygonStyle
}
This is the json file I'm trying with.
EDIT: the original json file was not followinf the right-hand rule, I fixed it with python lib: geojson-rewind, this is the fixed version that passes the test in https://geojsonlint.com/
I tried also updating to the latest version of the library (18.0.2) and updating the renderer to the newer one but it displays in the same way.
This is how it looks on android:
This is how its supose to look, same json file in geojson.io:
When validating the geojson, I get the error:
Line 1: Polygons and MultiPolygons should follow the right-hand rule
https://www.rfc-editor.org/rfc/rfc7946#section-3.1.6
A linear ring MUST follow the right-hand rule with respect to the
area it bounds, i.e., exterior rings are counterclockwise, and
holes are clockwise.
I'm trying to develop an offline navigation app for Trekking.
The app shows to the user a list of nearby track/routes where he can go.
Examples:
-Walking to Etna Vulcan
-Walking in the wood.
I've several KML files provided to me by local guides, each one for a different track.
So, if i choose "Walking to Etna Vulcan", I will have a Map with the track that I've to follow to go the Etna Vulcan, with some markers of interesting point (Examples: Refuges, Monuments). This data is actually ready, in KML format.
So:
The user chooses the track from the list that I provide, then the phone shows the track on the map(from kml or equivalent) with the current user position.
I'm doing it with MapBox sdk (but i'm open to alternatives).
Actually, I've successfully downloaded an offline map of the zone (Sicily), but i'm note sure how to write my kml on the map.
I also imported a kml in Mapbox Studio, but i don't know how to download a MapBox Studio Map into my application.
Thank you for your time!
If Mapbox seems like a good alternative then you just need to study their Android SDK to see if and how drawing markers and coordinate tracks are supported.
For the tracks see https://www.mapbox.com/android-sdk/geojson/
The relevant (to you) part is right at the end of their example code:
LatLng[] pointsArray = points.toArray(new LatLng[points.size()]);
// Draw Points on MapView
mapboxMap.addPolyline(new PolylineOptions()
.add(pointsArray)
.color(Color.parseColor("#3bb2d0"))
.width(2));
Here they have the coordinate points in the points ArrayList. They have been extracted from GeoJSON data, but you would just need to extract the coordinate points from the KML data and then draw the track based on that example.
For markers see https://www.mapbox.com/android-sdk/marker/
They have this example code:
mapboxMap.addMarker(new MarkerOptions()
.position(new LatLng(48.13863, 11.57603))
.title("Hello World!")
.snippet("Welcome to my marker."));
For a marker with a custom icon see https://www.mapbox.com/android-sdk/custom-marker-icon/
They have this example code:
// Create an Icon object for the marker to use
IconFactory iconFactory = IconFactory.getInstance(MainActivity.this);
Drawable iconDrawable = ContextCompat.getDrawable(MainActivity.this, drawable.ic_directions_boat_black_18dp);
Icon icon = iconFactory.fromDrawable(iconDrawable);
// Add the custom icon marker to the map
mapboxMap.addMarker(new MarkerOptions()
.position(new LatLng(-33.8500000, 18.4158234))
.title("Cape Town Harbour")
.icon(icon));
So you would just use a regular Android Drawable for the custom icon.
Looks quite convenient. I haven't used the Mapbox SDK myself.
I want to create a map from some opengl code that I wrote :
In order to do that I though about taking a screen shot of the upperview of the gl screen.
Yet I cant seem to find how to do that...
any suggestions?
Similar problem has been solved in OSG example code here.
First you need to set your view such that you are looking at center from the TOP VIEW.
osg::Vec3 center = scene->getBound().center();
double radius = scene->getBound().radius();
view->getCamera()->setViewMatrixAsLookAt( center - lookDir*(radius*3.0), center, up );
view->getCamera()->setProjectionMatrixAsPerspective(
30.0f, static_cast<double>(width)/static_cast<double>(height), 1.0f, 10000.0f );
Then, you need to use some OS specific API to do similar to logic below:
osgViewer::ScreenCaptureHandler* scrn = new osgViewer::ScreenCaptureHandler();
osgViewer::ScreenCaptureHandler::WriteToFile* captureOper = new osgViewer::ScreenCaptureHandler::WriteToFile(tmpStr.m_szBuffer, "png");
scrn->setCaptureOperation(captureOper);
scrn->captureNextFrame(*_viewer);
_viewer->frame();
Of course if you are not using OSG then you need to find equivalent APIs (of library you are using) to achieve the same task.
I use MapBox Android SDK 0.7.2 to get tiles from MapBox web service:
WebSourceTileLayer webSourceTileLayer = new WebSourceTileLayer("MapBox", "http://api.tiles.mapbox.com/v4/examples.map-zr0njcqy/-73.99,40.70,13/256x256.png?access_token=<my key>");
webSourceTileLayer.setName("MapBox")
.setAttribution("© MapBox © OpenStreetMap")
.setMinimumZoomLevel(1)
.setMaximumZoomLevel(18);
mapView.setTileSource(webSourceTileLayer);
mapView.setZoom(12);
mapView.setCenter(mapView.getTileProvider().getCenterCoordinate());
so I get back a 256x256 png format tile. But the tile repeats in the screen while I suppose it should be one tile in the screen. Any suggestion is appreciated.
Are you looking to just download the one tile from the Mapbox Web Service API? If so using a regular Android HTTP client (ex: URLConnnection class) to download it and then paint it on the Canvas would serve this better. TileLayers like WebSourceTileLayer are meant to download many different tiles and display them on the MapView as described.
I have written a radar weather app using osmdroid for map tiles, and manually overlaying NOAA ridge radar data. Everything Is working great except that the radar images are unprojected, while the openstreetmap tiles are in transverse Mercator projection. The weather lies within the bounds it should but the data is distorted.
I see three ways to fix this (in order of preference) but am having trouble with all three:
1) find a source of radar data already projected in mercator - hours of Googling later, I've found nothing
2) programmatically reproject the images right after I download them. Does anyone know a good API for this?
3) project them on the fly, perhaps with openlayers.im reading that can openlayers reproject,but can it be used over top of an osmdroid mapview?
Any ideas? Thanks for any help
Mike
GDAL is the way to go. There is no official Android build that I know of however some people have been successful in getting it running on Android. For example, Nutiteq has a build in the libs folder of their AdvancedMap3D sample project. Put the contents of both armeabi folders in your project's lib folder and you should be able to access the GDAL packages.
Then take a look at the GDAL in Java page. Look at the gdalinfo.java sample to get a feel for how to load and examine the parts of a GDAL dataset. To reproject your dataset, you will do something along the lines of:
SpatialReference sr = new SpatialReference();
sr.ImportFromProj4("+proj=merc +datum=WGS84");
String result[] = new String[1];
sr.ExportToPrettyWkt(result, 1);
String oldProjection = mDataset.getProjection();
String newProjection = result[0];
Dataset newDataset = gdal.AutoCreateWarpedVRT(mDataset, oldProjection, newProjection, gdalconst.GRA_NearestNeighbour, 0.0);
Dataset savedDataset = mDriver.CreateCopy(outpath, newDataset, 0, new String[] { "COMPRESS=LZW", "PREDICTOR=2" }, null, null);
newDataset.delete();
savedDataset.delete();
You may need to make a few adjustments, but that should get you most of the way there.