Specific range of map in android by using mapView - android

how to show the mapBox map view in specific range in android just like i need to show only Asia pacific in mapView only ,not display full world in mapView android?

You can manually set the zoom level of the map (radius is the radius of the map in meter):
double radius = 500.0;
Circle circle = map.addCircle(new CircleOptions().center(latLng).radius(radius).strokeColor(Color.RED));
circle.setVisible(false);
int zoomLevel = getZoomLevel(circle);
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoomLevel));
private int getZoomLevel(Circle circle) {
int zoomLevel = 15;
if (circle != null) {
double radius = circle.getRadius();
double scale = radius / 500;
zoomLevel = (int) (16 - Math.log(scale) / Math.log(2));
}
return zoomLevel;
}

Related

Shrink LatLngBounds by 5%

Alright so after reading Antonio's comment, I am with this in my code. Now regardless of what I submit as my percentage it still thinks my object is outside the bounding box.
My Position is the marker passed in.
LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
LatLngBounds newBounds = reduceBy(bounds, 0.05d);
if(newBounds.contains(myPosition.getPosition())) {
//If the item is within the the bounds of the screen
} else{
//If the marker is off screen
zoomLevel -= 1;}
}
return zoomLevel;
}
public LatLngBounds reduceBy(LatLngBounds bounds, double percentage) {
double distance = SphericalUtil.computeDistanceBetween(bounds.northeast, bounds.southwest);
double reduced = distance * percentage;
double headingNESW = SphericalUtil.computeHeading(bounds.northeast, bounds.southwest);
LatLng newNE = SphericalUtil.computeOffset(bounds.northeast, reduced/2d, headingNESW);
double headingSWNE = SphericalUtil.computeHeading(bounds.southwest, bounds.northeast);
LatLng newSW = SphericalUtil.computeOffset(bounds.southwest, reduced/2d, headingSWNE);
return LatLngBounds.builder().include(newNE).include(newSW).build();
}
}
I have all the zoom levels set but sometimes I run into spots such as this where it is still in bounds except the marker is off screen. I want to have a slightly smaller bounding box to detect this and then zoom out one level on only these situations.
You can use SphericalUtil class from the Google Maps API Utility Library to make the calculations:
public LatLngBounds reduceBy(LatLngBounds bounds, double percentage) {
double distance = SphericalUtil.computeDistanceBetween(bounds.northeast, bounds.southwest);
double reduced = distance * percentage;
double headingNESW = SphericalUtil.computeHeading(bounds.northeast, bounds.southwest);
LatLng newNE = SphericalUtil.computeOffset(bounds.northeast, reduced/2d, headingNESW);
double headingSWNE = SphericalUtil.computeHeading(bounds.southwest, bounds.northeast);
LatLng newSW = SphericalUtil.computeOffset(bounds.southwest, reduced/2d, headingSWNE);
return LatLngBounds.builder().include(newNE).include(newSW).build();
}
To reduce your bounds by a 5% (diagonal) you can do:
LatLngBounds newBounds = reduceBy(bounds, 0.05d);
Depending on your requirements for precision, you might want to just use simple interpolation like here:
public LatLngBounds reduceBounds(LatLngBounds bounds, double percentage) {
double north = bounds.northeast.latitude;
double south = bounds.southwest.latitude;
double east = bounds.northeast.longitude;
double west = bounds.southwest.longitude;
double lowerFactor = percentage / 2 / 100;
double upperFactor = (100 - percentage / 2) / 100;
return new LatLngBounds(new LatLng(south + (north - south) * lowerFactor, west + (east - west) * lowerFactor),
new LatLng(south + (north - south) * upperFactor, west + (east - west) * upperFactor));
}
This is very simple Math using +-*/ and doesn't cost a lot of performance.
To reduce your bounds dimensions by 10% you do:
LatLngBounds newBounds = reduceBounds(bounds, 10);
Add error checking and border case handling as needed

Calculate Zoom Level for Google Map for two LatLong values

I am using com.google.android.gms.maps.GoogleMap in SherlockFragmentActivity.
XML code is this :
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="fill_parent"
android:layout_height="150dip" />
int zoomLevel = ? // How I can calculate the zoom level for two diffrent latlong values
as android map v3 need to tell zoom level as int
map.setZoom(zoomLevel);
I have start and destination values as com.google.android.gms.maps.model.LatLng
LatLng start , end;
I am adding a pligon like GoogleLocation.addPolyLineOnGMap(mMap, startPoint, endPoint, startMarker, endMarker)
My problem is how I can calculate zoom level for Google map so it can show both marker appropriately on map.
Use LatLngBounds.Builder add all the bounds in it and build it, Then create the CameraUpdate object and pass the bounds in it updatefactory with padding. Use this CameraUpdate object to animate the map camera.
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (Marker m : markers) {
builder.include(m.getPosition());
}
LatLngBounds bounds = builder.build();
int padding = ((width * 10) / 100); // offset from edges of the map
// in pixels
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds,
padding);
mMap.animateCamera(cu);
For me, i need to calculate the zoom for initial map setup by GoogleMapOptions, so using LatLngBounds.Builder
would not work and not optimized. This is how I calculate the zoom based on a city's northeast and southwest coordinates
It's referencing here and this answer, you can simply put the code below to your helper class:
final static int GLOBE_WIDTH = 256; // a constant in Google's map projection
final static int ZOOM_MAX = 21;
public static int getBoundsZoomLevel(LatLng northeast,LatLng southwest,
int width, int height) {
double latFraction = (latRad(northeast.latitude) - latRad(southwest.latitude)) / Math.PI;
double lngDiff = northeast.longitude - southwest.longitude;
double lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
double latZoom = zoom(height, GLOBE_WIDTH, latFraction);
double lngZoom = zoom(width, GLOBE_WIDTH, lngFraction);
double zoom = Math.min(Math.min(latZoom, lngZoom),ZOOM_MAX);
return (int)(zoom);
}
private static double latRad(double lat) {
double sin = Math.sin(lat * Math.PI / 180);
double radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
}
private static double zoom(double mapPx, double worldPx, double fraction) {
final double LN2 = .693147180559945309417;
return (Math.log(mapPx / worldPx / fraction) / LN2);
}
Creating LatLng simply by new LatLng(lat-double, lng-double)
width and height is the map layout size in pixels
in Android:
LatLngBounds group = new LatLngBounds.Builder()
.include(tokio) // LatLgn object1
.include(sydney) // LatLgn object2
.build();
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(group, 100)); // Set Padding and that's all!

Is it possible to set dimensions to a groundOverlay that is independent of the map zoom level?

I have a GroundOverlay on my GoogleMap and I want that its dimensions to not change when I zoom in/out on map. Exact like default map markers that always keep their dimensions. I have tried with both forms of the GroundOverlay.setDimensions() but the image is still resize on zoom. Here is my code:
Bitmap btm = BitmapFactory.decodeResource(getResources(), R.drawable.map_arrow);
BitmapDescriptor arrow = BitmapDescriptorFactory.fromBitmap(btm);
float w = btm.getWidth();
float h = btm.getHeight();
if (groundOverlay != null) groundOverlay.remove();
groundOverlay = mMap.addGroundOverlay(new GroundOverlayOptions()
.image(arrow).position(meLoc, w,h).bearing(bearAngle));
groundOverlay.setDimensions(1000);
you have your width and heigth of overlay and placed it on the map according to your zoom level. It seems good for that zoom level. Right? Now you can calculate radius and get meters of your map screen. Because map background overlay width and height values are meters. We have to go with meter not zoom level or anything else. Maybe someone can find a better solution but I have tried too many ways, and end up with this solution and it worked very well.
float zoomLevel=mMap.getCameraPosition().zoom;
//calculate meters*********************
myBounds = mMap.getProjection().getVisibleRegion().latLngBounds;
myCenter= mMap.getCameraPosition().target;
if (myCenter.latitude==0 || myCenter.longitude==0) {
myCenter=new LatLng(myLocation.getLatitude(),myLocation.getLongitude());
}
LatLng ne = myBounds.northeast;
// r = radius of the earth in statute miles
double r = 3963.0;
// Convert lat or lng from decimal degrees into radians (divide by 57.2958)
double lat1 = myCenter.latitude / 57.2958;
double lon1 = myCenter.longitude / 57.2958;
final double lat2 = ne.latitude / 57.2958;
final double lon2 = ne.longitude / 57.2958;
// distance = circle radius from center to Northeast corner of bounds
double dis = r * Math.acos(Math.sin(lat1) * Math.sin(lat2) +
Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1));
//1 Meter = 0.000621371192237334 Miles
double meters_calc=dis/0.000621371192237334;
float factor=1;
if (zoomLevel==15) { // my default zoom level yours can be different
metersoverlay=meters_calc; // global variable metersoverlay set
}
else { // if my zoom level change then I have to calculate dimension scale factor
factor=(float) (meters_calc/metersoverlay);
}
//******************************* now we are ready to set dimension of background overlay
float dimensions=1000*factor;
loadingGroundOverlayBg.setDimensions(dimensions);
I hope it works for all of you :)
I had the same issue. If you want to place an image, you can use the default markers provided by Google maps API. You can set a custom image as the marker icon, which will remain the same size.
private final List<BitmapDescriptor> mImages = new ArrayList<BitmapDescriptor>();
mImages.add(BitmapDescriptorFactory.fromResource(R.drawable.YOUR_IMAGE));
Marker marker = map.addMarker(new MarkerOptions().icon(mImages.get(0)));
This example shows how to set the icon of the marker, from an element of an image list. Hope it helps.

Android Maps API v2: Zoom in on current location and marker

I have a map included in an application. I need the map to zoom in on the a marker and the users location but keep the marker centered. The zoom in works perfectly, but of course doesn't center the marker on the map.
#Override
public void onLocationChanged(Location location) {
if (mListener != null) {
mListener.onLocationChanged(location);
LatLngBounds bounds = new LatLngBounds.Builder()
.include(new LatLng(location.getLatitude(),location.getLongitude()))
.include((new LatLng(52.3563, 4.8790)))
.build();
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 35));
}
}
What is the best way to keep both within the bounds but keep the marker centered? I can't seem to find a solution in the official documentation.
There are two functions I would call, one for centering the marker and an other one to zoom on the map until your current location is still visible.
My solution for zooming to a point with a 15 zoom level:
myMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLngToCenter, 1));
zooming until all markers are still visible (change code to fit the marker and your position instead):
public void fitZoomAndPositionToMapByMarkers() {
int minLat = Integer.MAX_VALUE;
int maxLat = Integer.MIN_VALUE;
int minLon = Integer.MAX_VALUE;
int maxLon = Integer.MIN_VALUE;
List<MyMapMarker> markersShownOnMap = getMarkersToShow();
for (MyMapMarker item : markersShownOnMap) {
int lat = (int) (item.getLatitude() * 1E6);
int lon = (int) (item.getLongitude() * 1E6);
maxLat = Math.max(lat, maxLat);
minLat = Math.min(lat, minLat);
maxLon = Math.max(lon, maxLon);
minLon = Math.min(lon, minLon);
}
double latitudeToGo = (maxLat + minLat) / 1E6 / 2;
double longitudeToGo = (maxLon + minLon) / 1E6 / 2;
LatLng toCenter = new LatLng(latitudeToGo, longitudeToGo);
centerCameraToProperPosition(toCenter);
LatLng southWestLatLon = new LatLng(minLat / 1E6, minLon / 1E6);
LatLng northEastLatLon = new LatLng(maxLat / 1E6, maxLon / 1E6);
zoomInUntilAllMarkersAreStillVisible(southWestLatLon, northEastLatLon);
}
Hope this helps!
private void zoomInUntilAllMarkersAreStillVisible(final LatLng southWestLatLon, final LatLng northEastLatLon) {
myMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition arg0) {
myMap.moveCamera(CameraUpdateFactory.newLatLngBounds(new LatLngBounds(southWestLatLon, northEastLatLon), 50));
myMap.setOnCameraChangeListener(null);
}
});
}
Hello i have found a nice and easy way using LatLngbounds:
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(new LatLngBounds(latlngSW, latlngNE, 50));
this function will use the most SW point and the most NE point to create a rectangle to center the view with 50 padding, but u need to check first which one of the points should be given as first or second parameter, here is my code:
public void centerMap(LatLng latLng){
if(fenceMarker != null){
LatLngBounds center;
LatLng fence = fenceMarker.getPosition();
if(fence.latitude < latLng.latitude || fence.longitude < latLng.longitude)
center = new LatLngBounds(fenceMarker.getPosition(), latLng);
else{
center = new LatLngBounds(latLng, fenceMarker.getPosition());
}
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(center, 50));
}
}
The 2 points are my position latLng and the marker I have for the GeoFence, fenceMarker.
I call this function centerMap(latLng) from the onLocationChanged():
#Override
public void onLocationChanged(Location location) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
centerMap(latLng);
}
Setting Boundaries -
An overload of the method, newLatLngBounds(boundary, width, height, padding) allows you to specify a width and height in pixels for a rectangle, with the intention that these correspond to the dimensions of the map. The rectangle is positioned such that its center is the same as that of the map's view (so that if the dimensions specified are the same as those of the map's view, then the rectangle coincides with the map's view). The returned CameraUpdate will move the camera such that the specified LatLngBounds are centered on screen within the given rectangle at the greatest possible zoom level, taking into account the padding required.
Reference- https://developers.google.com/maps/documentation/android/views#target_location

How to find zoom level based on circle draw on map

I am drawing the circle on map with specifying the radius and it'll draw the circle successfully. But when I change the size of circle using seekbar I need to feet the circle in screen and zoom the map of that level, I have not idea about this, need your guideline thank you.
We can also get the zoom level for map from the drawn circle
Circle circle = googleMap.addCircle(circleOptions);
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
circleOptions.getCenter(), getZoomLevel(circle)
// Methode for zoomlevel
public int getZoomLevel(Circle circle) {
int zoomLevel = 11;
if (circle != null) {
double radius = circle.getRadius() + circle.getRadius() / 2;
double scale = radius / 500;
zoomLevel = (int) (16 - Math.log(scale) / Math.log(2));
}
return zoomLevel;
}
build.gradle:
dependencies {
compile 'com.google.maps.android:android-maps-utils:0.4+'
}
public static LatLngBounds getLatLngBoundsFromCircle(Circle circle){
if(circle != null){
return new LatLngBounds.Builder()
.include(SphericalUtil.computeOffset(circle.getCenter(), circle.getRadius() * Math.sqrt(2), 45))
.include(SphericalUtil.computeOffset(circle.getCenter(), circle.getRadius() * Math.sqrt(2), 225))
.build();
}
return null;
}
map.animateCamera( CameraUpdateFactory
.newLatLngBounds(MapUtils.getLatLngBoundsFromCircle(mapCircle),20) );
After long time I found the solution from somewhere.
here is the method which was giving me the min lat/lng and max lat/lng.
Based on this I have getting the latspan and longspan.
public void boundingCoordinates(double distance, double radius) {
if (radius < 0d || distance < 0d)
throw new IllegalArgumentException();
// angular distance in radians on a great circle
double radDist = distance / radius;
double radLat = Math.toRadians(gp.getLatitudeE6()/1e6); // here is your single point latitude gp.getLatitude
double radLon = Math.toRadians(gp.getLongitudeE6()/1e6); // here is your single point longitude gp.getlongitude
double minLat = radLat - radDist;
double maxLat = radLat + radDist;
double minLon, maxLon;
if (minLat > MIN_LAT && maxLat < MAX_LAT) {
double deltaLon = Math.asin(Math.sin(radDist) /Math.cos(radLat));
minLon = radLon - deltaLon;
if (minLon < MIN_LON)
minLon += 2d * Math.PI;
maxLon = radLon + deltaLon;
if (maxLon > MAX_LON)
maxLon -= 2d * Math.PI;
} else {
// a pole is within the distance
minLat = Math.max(minLat, MIN_LAT);
maxLat = Math.min(maxLat, MAX_LAT);
minLon = MIN_LON;
maxLon = MAX_LON;
}
minLat = Math.toDegrees(minLat);
minLon = Math.toDegrees(minLon);
maxLat = Math.toDegrees(maxLat);
maxLon = Math.toDegrees(maxLon);
minGeo = new GeoPoint((int)(minLat*1e6),(int)(minLon*1e6));
maxGeo = new GeoPoint((int)(maxLat*1e6),(int)(maxLon*1e6));
}
now you pass the distance in any unit as per that you have to pass the radius of earth for example if you pass 2 km then the radius of earth is in km say 6370.997.
you can try it, its cool thing
In my code I am adding a transparent circle around a marker which has dynamic radius and zooming the map camera so it fit to screen.
it is working 100% fine in my project.
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setOnMarkerClickListener(this);
MapsInitializer.initialize(Objects.requireNonNull(getContext()));
// Add a marker on Property location
LatLng propertyLatlng = new LatLng(getLatitude(), getLongitude());
// draw transparent blue circle around marker
try {
CircleOptions circleOptions = new CircleOptions()
.center(propertyLatlng)
.radius(Double.parseDouble(radius) / 0.00062137)
.strokeColor(BLUE_TRANSPARENT)
.strokeWidth(0)
.fillColor(BLUE_TRANSPARENT);
Circle circle = mMap.addCircle(circleOptions);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
circleOptions.getCenter(), getZoomLevel(circle)));
} catch (Exception e) {
AppLogger.logError(TAG, e.getMessage());
}
}
/**
* #param circle : circle
* #return : return zoom level according to circle radius
*/
public float getZoomLevel(Circle circle) {
int zoomLevel = 11;
if (circle != null) {
double radius = circle.getRadius() + circle.getRadius() / 2;
double scale = radius / 500;
zoomLevel = (int) (16 - Math.log(scale) / Math.log(2));
}
return zoomLevel+.4f;
}
double getZoomLevel() {
double zoomLevel = 0.0;
double newRadius = radiusOfCircle + radiusOfCircle / 2;
double scale = newRadius / 500;
zoomLevel = (6 - log(scale) / log(2));
return zoomLevel;
}
This worked for me
Thanks to #Anand Tiwari

Categories

Resources