it is about android and google maps v2. I want to set max zoom level with bounds.
Here is the method I'm using :
gMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, width, height, padding));
I've found this link which gave me a possible workaround
Setting max zoom level in google maps android api v2
Here is the workaraound found
gMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition position) {
if (position.zoom > DEFAULT_ZOOM)
gMap.animateCamera(CameraUpdateFactory.zoomTo(DEFAULT_ZOOM));
}
});
But this solution zoom in until the zoom level defined by first animateCamera and then zoom out until DEFAULT_ZOOM if (DEFAULT_ZOOM < position.zoom). In this case, there is two animateCamera
How to avoid that ? And make only one animateCamera
Thx in advance
Ok, for now, my only solution is related here https://stackoverflow.com/a/19343818/1646479
Here is the workaround:
private LatLngBounds adjustBoundsForMaxZoomLevel(LatLngBounds bounds) {
LatLng sw = bounds.southwest;
LatLng ne = bounds.northeast;
double deltaLat = Math.abs(sw.latitude - ne.latitude);
double deltaLon = Math.abs(sw.longitude - ne.longitude);
final double zoomN = 0.005; // minimum zoom coefficient
if (deltaLat < zoomN) {
sw = new LatLng(sw.latitude - (zoomN - deltaLat / 2), sw.longitude);
ne = new LatLng(ne.latitude + (zoomN - deltaLat / 2), ne.longitude);
bounds = new LatLngBounds(sw, ne);
}
else if (deltaLon < zoomN) {
sw = new LatLng(sw.latitude, sw.longitude - (zoomN - deltaLon / 2));
ne = new LatLng(ne.latitude, ne.longitude + (zoomN - deltaLon / 2));
bounds = new LatLngBounds(sw, ne);
}
return bounds;
}
but I'm looking for a solution to translate android zoom level (16 in my case) to zoomN.
Related
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
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;
}
with my standard setup of Google Map API v2 it seems to be allowed to scroll outside the existing map data. There is actually a limit for scrolling, but it seems to be quite a bit outside the actual map bounds.
Is there an easy way of fixing this?
In my project, I use function which is called from onCameraChange. It moves the camera back to inside the allowed area of the map.
// First set the bounds
private static final LatLng NORTHEAST = new LatLng("LAT HERE", "LNG HERE");
private static final LatLng SOUTHWEST = new LatLng("LAT HERE", "LNG HERE");
private static final LatLngBounds BOUNDS = new LatLngBounds(SOUTHWEST, NORTHEAST);
The method looks like this:
if (BOUNDS.contains(googleMap.getCameraPosition().target)) {
return;
}
double x = googleMap.getCameraPosition().target.longitude;
double y = googleMap.getCameraPosition().target.latitude;
double maxX = BOUNDS.northeast.longitude;
double maxY = BOUNDS.northeast.latitude;
double minX = BOUNDS.southwest.longitude;
double minY = BOUNDS.southwest.latitude;
if (x < minX) {
x = minX;
}
if (x > maxX) {
x = maxX;
}
if (y < minY) {
y = minY;
}
if (y > maxY) {
y = maxY;
}
googleMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(y, x)));
I hope this is what you are looking for.
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!
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