Is there another way for add geoJSON polygon to map using mapbox sdk 9.0 stable on android?
I have the following but not sure if it's correct:
GeoJsonSource source = new GeoJsonSource("geojson", geoJsonString);
mapboxMap.addSource(source);
mapboxMap.addLayer(new LineLayer("geojson", "geojson"));
This example from the Mapbox documentation shows how to add a GeoJSON polygon to your map with the Mapbox Maps SDK for Android. The relevant code is in the onMapReady callback, extracted below (I omitted the code related to adding a click listener, since that is not relevant for your question);
#Override
public void onStyleLoaded(#NonNull Style style) {
// Add the GeoJSON as a source to the map.
addGeoJsonSourceToMap(style);
// Create FillLayer with GeoJSON source and add the FillLayer to the map.
if (style != null) {
style.addLayer(new FillLayer(geoJsonLayerId, geoJsonSourceId)
.withProperties(fillOpacity(0.5f)));
}
}
The addGeoJsonSourceToMap helper method in this example loads the GeoJSON from an external URI, but in your case the first two lines of your provided code snippet would replace the addGeoJsonSourceToMap(style); call.
A FillLayer is used rather than a LineLayer since, per the linked API reference documentation:
FillLayer:
A filled polygon with an optional stroked border.
LineLayer:
A stroked line.
1. Try adding the Source:
// WARDS – 2020 – SOURCE
// url = 'https://opendata.arcgis.com/datasets/845bbfdb73944694b3b81c5636be46b5_0.geojson';
map.addSource(
'ward-source', {
type: 'geojson',
data: 'Wards.geojson'
}
);
2. and the Layers:
// WARDS FILL
map.addLayer({
'id': 'wards-fill',
'type': 'fill',
'source': 'wards-source',
'layout': {},
'paint': {
'fill-color': '#627BC1',
'fill-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
1,
0.5
]
}
});
Related
I want to use the world map in Unity and have been looking at the API of various map services. I need to show a screenshot (a static map with markers) on the screen, and move to the full map view to navigate it after clicking on it.
MapBox managed to display the map with the selected coordinates and add test markers, but that's all I can do with a query like this: https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/url-https%3A%2F%2Fwww.mapbox.com%2Fimg%2Frocket.png(-76.9,38.9)/-76.9,38.9,15/1000x1000?access_token=pk.eyJ1IjoiZGVuZGVhZCIsImEiOiJja2F1dha4egixnnfhmnvtc2u0y3bua2ntin0.GGOyhgN_fEqtPpPc5n6OLg because this request returns a jpg image.
They also have a plugin for Unity, but it's only used in 3d projects and does not allow me to configure the display in 2d.
In MapBox, the mapping I need is implemented using JavaScript for Web and Java for Android. On Android I can do what I need. I can connect to the API on Android, but will I be able to use it in Unity later?
It's the same with Google maps.
Actually, the question is, did someone work with map services in Unity? And how can this be implemented correctly?
I don't know if this is still relevant, but I used Mapbox in Unity (the Mapbox plugin) to create a AR Soundscape by "registering" GameObjects to coordinates and moving them in real-time when the map is moved.
Your problem sounds an awful lot like the one I solved with that.
Basically you provide the Lat/Lon values for your objects and convert them to Unity world space coordinates using the AbstractMap.GeoToWorldPosition() function.
I used a raycast to actually pull that off in-engine, which is quite convenient.
//Edit:
Unity is quite capable of handling 2D projects. You just have to configure it properly and build your project around it.
The following is the class that I use to handle all positioning-related calculations. Maybe it's of some help to you.
namespace TehMightyPotato.Positioning
{
[Serializable]
public class GeoPosition
{
[Tooltip(
"Update frequency of position polling. Update every n-th frame. 1 is every frame, 60 is every 60th frame.")]
[Range(1, 60)]
public int positionUpdateFrequency = 1;
[Tooltip("Should the object have a specified altitude?")]
public bool useYOffset = false;
[Tooltip("If useMeterConversion is activated the yOffsets unit is meters, otherwise its unity units.")]
public bool useMeterConversion = false;
[Tooltip("The actual y position of the object in m or unity units depending on useMeterConversion.")]
public float yOffset = 0;
[Tooltip("X is LAT, Y is LON")]public Vector2d geoVector;
[HideInInspector] public float worldRelativeScale;
// Apply the result of this function to your gameobjects transform.position on every frame to keep them on this position.
public Vector3 GetUnityWorldSpaceCoordinates(AbstractMap map)
{
UpdateWorldRelativeScale(map);
var worldSpaceCoordinates = map.GeoToWorldPosition(geoVector, false);
if (useYOffset)
{
worldSpaceCoordinates.y = yOffset;
}
return worldSpaceCoordinates;
}
public void UpdateWorldRelativeScale(AbstractMap map)
{
worldRelativeScale = map.WorldRelativeScale;
}
public void SetGeoVectorFromRaycast(Vector3 position, AbstractMap map, LayerMask layerMask)
{
var ray = new Ray(position, Vector3.down);
if (Physics.Raycast(ray, out var hitInfo, Mathf.Infinity, layerMask))
{
geoVector = map.WorldToGeoPosition(hitInfo.point);
}
else
{
throw new NullReferenceException("Raycast did not hit the map. Did you turn on map preview?");
}
}
public void SetYOffsetFromRaycast(AbstractMap map, Vector3 position, LayerMask layerMask)
{
UpdateWorldRelativeScale(map);
// using raycast because of possible y-non-zero maps/ terrain etc.
var ray = new Ray(position, Vector3.down);
if (Physics.Raycast(ray, out var hitInfo, Mathf.Infinity, layerMask))
{
var worldSpaceDistance = Vector3.Distance(position, hitInfo.point);
if (useMeterConversion)
{
yOffset = worldSpaceDistance * worldRelativeScale;
}
else
{
yOffset = worldSpaceDistance;
}
}
else
{
throw new NullReferenceException("Could not find map below. Is map preview turned on?");
}
}
}
}
I'm trying to display a custom vector layer on a map using Mapbox in my Android application. Using the latest mapbox version.
When I include the layer the following way :
//DOES NOT WORK
binding.mapView.getMapAsync(mapboxMap -> {
map = mapboxMap;
VectorSource source = new VectorSource("source-id", new TileSet("2.1.0", baseUrl + "/{z}/{x}/{y}.mvt"));
mapboxMap.addSource(source);
LineLayer layer = new LineLayer("zones-outline", "source-id");
layer.setSourceLayer("zones");
layer.setProperties(
PropertyFactory.lineWidth(2f),
PropertyFactory.lineColor(getResources().getColor(R.color.md_blue_500))
);
mapboxMap.addLayer(layer);
})
It show nothing (no log in android nor in my server, it is like the layer is not even known to mapbox).
But if I put the addsource and addlayer code in a runnable, lets say with a 100 milliseconds delay, it does show my layers properly. Obviously this looks like its related to some kind of concurrency or "order of initialization", and the delay works, but it is not a nice and proper solution (I imagine on old device it could take more than 100 ms to load the map, maybe it wont work).
//WORKS
binding.mapView.getMapAsync(mapboxMap -> {
final Handler handler = new Handler();
handler.postDelayed(() -> {
map = mapboxMap;
VectorSource source = new VectorSource("source-id", new TileSet("2.1.0", baseUrl + "/{z}/{x}/{y}.mvt"));
mapboxMap.addSource(source);
LineLayer layer = new LineLayer("zones-outline", "source-id");
layer.setSourceLayer("zones");
layer.setProperties(
PropertyFactory.lineWidth(2f),
PropertyFactory.lineColor(getResources().getColor(R.color.md_blue_500))
);
mapboxMap.addLayer(layer);
}, 100)
})
Is there another method / callback where I should put this initialization ? How to be sure my layers will be drawn ?
The problem came from the fact that I was setting, also in the onMapReady callback, a new style url (loaded dynamically depending on the content displayed).
I move the mapView.setStyleUrl(mapboxStyle) before the map initialization :
mapView.setStyleUrl(mapboxStyle);
binding.contestMapView.onCreate(savedInstanceState);
binding.contestMapView.getMapAsync(mapboxMap -> {
// vector source and layer initialization
});
I want to display downloaded layers on the map. The map which I am using is also an offline Esri map. The problem is that when I am adding layers on the map using myMap.OperationalLayers.Add();. I am getting an Exception i.e Object already owned.
Code:
if (featureLayerDict.Any())
{
// Remove the previously applied layers
if (myMap.OperationalLayers != null)
{
myMap.OperationalLayers.Clear();
}
// Select the LayerIds, which are based on if Parent Layer is selected
var selectedMapLayerIds = mapLayers.Select(l => l.ID).ToList();
foreach (var dictItem in featureLayerDict)
{
try
{
// Add the layer to maps operational layer only if its parent layer is selected and if its present in the userlayers
if (userLayers.Contains(dictItem.Key) && selectedMapLayerIds.Contains(dictItem.Key))
{
myMap.OperationalLayers.Add(dictItem.Value);
}
}
catch (Exception ex)
{
continue;
}
}
}
A FeatureLayer can only be owned by one map at the same time.
So after close the first map, you have to make null the references to their layers or just do:
myMap.OperationalLayers.Clear();
at the beginning of the method that adds the layers to the map.
I'm using this library to show a kml markers in a map in Android Maps V2.
I´m trying to get the lat and lon from a kml layer to do zoom directly to a placemark after add it to a map.
I tried to do this:
layer = new KmlLayer(mMap,R.raw.ruta, this );
layer.addLayerToMap();
for (KmlPlacemark act : layer.getPlacemarks()){
System.out.println("hi");//not iterate
}
but it doesn´t enter in the loop I read this kml-feature but don't work as is
You will have to read the 1st container of the KML-layer before attempting to read information about the placemarks:
KmlContainer = layer.getContainers().iterator().next();
if (kmlContainer == null) return;
for (KmlPlacemarks placemark : kmlContainer.getPlacemarks()) {
// Do the placemark magic here!
}
I have an Android application and I'm trying to populate a Google Map with a route, this route is store on a JSON array this way:
JSONArray.getString("points") = ["-33.45591917507404, -70.59198361376951","-33.453484420618416, -70.61635952929686"]
So in this case I have
Point A=(-33.49088437162095, -70.64043194102163) and
Point B=(-33.49423964397045, -70.63992768572683)
And my route or path is A-----B
I'm new to Android and I was wondering how to get this to work. Also, in this case my route is A-----B, but it can also be A----B----C----D. I can have any number of points on the path.
One thing you can try is the Google Maps Polyline object: https://developers.google.com/maps/documentation/javascript/reference#Polyline You specify to setPath() an ordered list of the points (either an Array of LatLng or an MVCArray or LatLng), you want to connect together on the map, and Google Maps will make a polyline for you to your specifications.
// path = Array of LatLng or MVCArray of LatLng
routeLine = new Polyline();
routeLine.setPath(JSONArray);
In your case, passing JSONArray into setPath should work OK.
If you want to get fancy and incorporate directions, you need to use the Google Directions API. https://developers.google.com/maps/documentation/javascript/directions
// All waypoints must be stopovers for the Directions service to optimize their route.
// start & end are of type String or LatLng, waypts is an array of String or LatLng
request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: [type Boolean],
travelMode: [type TravelMode]
};
// go on and actually perform the request
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
// if successful, this will run
}
});
Once you finish constructing your object, you should be able to display it by running setMap(map:Map), such as
routeLine.setMap(map)