8

I am trying to figure out a way of determining the zoom level of a Map before I call map.fitBounds(), and I cannot seem to find a way.

In the API v2 there was a method GMap.getBoundsZoomLevel(bounds:GLatLngBounds), but I can't find an equivalent in the API v3 documentation.

Is there a non-Google algorythm for determining what a zoom level will be beforehand?

Alex Lein
  • 384
  • 3
  • 14
  • There isn't an equivalent that is part of the standard library. What are you trying to achieve? You no longer have to pass a zoom level to `setCenter`. The v3 version of `setCenter` takes only 1 parameter, a `google.maps.LatLng`. – Sean Mickey May 16 '12 at 14:32
  • 1
    http://stackoverflow.com/questions/6048975/google-maps-v3-how-to-calculate-the-zoom-level-for-a-given-bounds – Nick Clark May 16 '12 at 14:37

1 Answers1

15

Nick is right, this discussion outlines a workable method: Google Maps V3 - How to calculate the zoom level for a given bounds

However, it is in Javascript. For those needing to do this with Android GMaps v3, the following is a translation:

private static final double LN2 = 0.6931471805599453;
private static final int WORLD_PX_HEIGHT = 256;
private static final int WORLD_PX_WIDTH = 256;
private static final int ZOOM_MAX = 21;

public int getBoundsZoomLevel(LatLngBounds bounds, int mapWidthPx, int mapHeightPx){

    LatLng ne = bounds.northeast;
    LatLng sw = bounds.southwest;

    double latFraction = (latRad(ne.latitude) - latRad(sw.latitude)) / Math.PI;

    double lngDiff = ne.longitude - sw.longitude;
    double lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;

    double latZoom = zoom(mapHeightPx, WORLD_PX_HEIGHT, latFraction);
    double lngZoom = zoom(mapWidthPx, WORLD_PX_WIDTH, lngFraction);

    int result = Math.min((int)latZoom, (int)lngZoom);
    return Math.min(result, ZOOM_MAX);
}

private 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 double zoom(int mapPx, int worldPx, double fraction) {
    return Math.floor(Math.log(mapPx / worldPx / fraction) / LN2);
}
Community
  • 1
  • 1
Elroid
  • 476
  • 4
  • 12
  • 1
    Google API doc (https://developers.google.com/android/reference/com/google/android/gms/maps/model/CameraPosition.Builder) says "whole world is approximately 256dp wide" - Note: "dp", not "px". So, the excellent calculations above should be converted into "dp" (e.g. via the display metrics, "scaled density"). I used: double latZoom = zoom(mapHeightPx, WORLD_DP_HEIGHT * mDisplayMetrics.scaledDensity, latFraction); double lngZoom = zoom(mapWidthPx, WORLD_DP_WIDTH * mDisplayMetrics.scaledDensity, lngFraction); – Paul Smith Racing Nov 28 '16 at 23:00
  • Besides the `WORLD_PX_HEIGHT * density` thing, I also needed to remove the `Math.floor` on `zoom` function, make it return `float` and set the `int result` as `float result`, otherwise I had bigger paddings then when using the bounds directly with deltas. Of course that all affected calls must change and don't forget that `getBoundsZoomLevel` also must return `float`. – Cristiano Santos May 08 '18 at 09:26