Android:如何将地图视图的缩放级别设置为当前位置周围1公里半径?

时间:2011-05-14 14:50:21

标签: android google-maps zoom android-mapview

我想将地图视图设置为缩放到半径1公里,但无法弄清楚如何?

文档说缩放级别1会将地球赤道映射到256像素。那么如何计算我需要设置哪个缩放级别,以便地图视图显示半径为1KM的区域?

更新
在阅读了几篇博客文章后,我写了以下代码:

private int calculateZoomLevel() {
    double equatorLength = 6378140; // in meters
    double widthInPixels = screenWidth;
    double metersPerPixel = equatorLength / 256;
    int zoomLevel = 1;
    while ((metersPerPixel * widthInPixels) > 2000) {
        metersPerPixel /= 2;
        ++zoomLevel;
    }
    Log.i("ADNAN", "zoom level = "+zoomLevel);
    return zoomLevel;
}

我的想法是首先在缩放级别1中计算每像素米数,根据谷歌显示使用256像素的地球赤道。现在,每个后续缩放级别放大2级,因此每个缩放级别的每个像素的一半。我这样做,直到我有一个缩放级别,米/像素乘以屏幕宽度给我小于2000,即2公里。

但我不认为我得到的缩放级别显示的是2Km半径的地图。有人可以告诉我这里我做错了吗?

8 个答案:

答案 0 :(得分:46)

虽然这个答案是合乎逻辑的,但我发现它有效但结果不准确我不知道为什么但是我厌倦了这种方法而且这种技术更加准确。

1)在具有所需半径

的物体上做一个圆圈
Circle circle = mGoogleMap.addCircle(new CircleOptions().center(new LatLng(latitude, longitude)).radius(getRadiusInMeters()).strokeColor(Color.RED));           
        circle.setVisible(true);
        getZoomLevel(circle);

2)将该对象传递给此功能并设置缩放级别 这是a link

public int getZoomLevel(Circle circle) {
if (circle != null){
    double radius = circle.getRadius();
    double scale = radius / 500;
    zoomLevel =(int) (16 - Math.log(scale) / Math.log(2));
}
return zoomLevel;
}

答案 1 :(得分:33)

以下代码最终使用了。鉴于屏幕宽度以及在缩放级别1处地球的赤道长度为256像素并且每个后续缩放级别使表示地球赤道所需的像素数量加倍的事实,以下函数返回缩放级别,其中屏幕将显示区域宽2公里。

private int calculateZoomLevel(int screenWidth) {
    double equatorLength = 40075004; // in meters
    double widthInPixels = screenWidth;
    double metersPerPixel = equatorLength / 256;
    int zoomLevel = 1;
    while ((metersPerPixel * widthInPixels) > 2000) {
        metersPerPixel /= 2;
        ++zoomLevel;
    }
    Log.i("ADNAN", "zoom level = "+zoomLevel);
    return zoomLevel;
}

答案 2 :(得分:10)

我最终使用的是:

https://github.com/googlemaps/android-maps-utils

我从lib中提取了类,因此您不需要整个库。 您可以使用边界而不是设置缩放级别。结果是一样的。

准确显示1公里的代码:

animateToMeters(1000);

private void animateToMeters(int meters){
    int mapHeightInDP = 200;
    Resources r = getResources();
    int mapSideInPixels = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mapHeightInDP, r.getDisplayMetrics());

    LatLng point = new LatLng(0, 0);
    LatLngBounds latLngBounds = calculateBounds(point, meters);
    if(latLngBounds != null){
        cameraUpdate = CameraUpdateFactory.newLatLngBounds(latLngBounds, mapSideInPixels, mapSideInPixels, MARKER_BOUNDS);
        if(mMap != null)
            mMap.animateCamera(cameraUpdate); 
    }
}

private LatLngBounds calculateBounds(LatLng center, double radius) {
    return new LatLngBounds.Builder().
      include(SphericalUtil.computeOffset(center, radius, 0)).
      include(SphericalUtil.computeOffset(center, radius, 90)).
      include(SphericalUtil.computeOffset(center, radius, 180)).
      include(SphericalUtil.computeOffset(center, radius, 270)).build();
}

从lib中提取(略微更改)的类:

public class SphericalUtil {

    static final double EARTH_RADIUS = 6371009;

    /**
     * Returns hav() of distance from (lat1, lng1) to (lat2, lng2) on the unit sphere.
     */
    static double havDistance(double lat1, double lat2, double dLng) {
        return hav(lat1 - lat2) + hav(dLng) * cos(lat1) * cos(lat2);
    }

    /**
     * Returns haversine(angle-in-radians).
     * hav(x) == (1 - cos(x)) / 2 == sin(x / 2)^2.
     */
    static double hav(double x) {
        double sinHalf = sin(x * 0.5);
        return sinHalf * sinHalf;
    }

    /**
     * Computes inverse haversine. Has good numerical stability around 0.
     * arcHav(x) == acos(1 - 2 * x) == 2 * asin(sqrt(x)).
     * The argument must be in [0, 1], and the result is positive.
     */
    static double arcHav(double x) {
        return 2 * asin(sqrt(x));
    }

    private SphericalUtil() {}

    /**
     * Returns the heading from one LatLng to another LatLng. Headings are
     * expressed in degrees clockwise from North within the range [-180,180).
     * @return The heading in degrees clockwise from north.
     */
    public static double computeHeading(LatLng from, LatLng to) {
        // http://williams.best.vwh.net/avform.htm#Crs
        double fromLat = toRadians(from.latitude);
        double fromLng = toRadians(from.longitude);
        double toLat = toRadians(to.latitude);
        double toLng = toRadians(to.longitude);
        double dLng = toLng - fromLng;
        double heading = atan2(
                sin(dLng) * cos(toLat),
                cos(fromLat) * sin(toLat) - sin(fromLat) * cos(toLat) * cos(dLng));
        return wrap(toDegrees(heading), -180, 180);
    }

    /**
     * Returns the LatLng resulting from moving a distance from an origin
     * in the specified heading (expressed in degrees clockwise from north).
     * @param from     The LatLng from which to start.
     * @param distance The distance to travel.
     * @param heading  The heading in degrees clockwise from north.
     */
    public static LatLng computeOffset(LatLng from, double distance, double heading) {
        distance /= EARTH_RADIUS;
        heading = toRadians(heading);
        // http://williams.best.vwh.net/avform.htm#LL
        double fromLat = toRadians(from.latitude);
        double fromLng = toRadians(from.longitude);
        double cosDistance = cos(distance);
        double sinDistance = sin(distance);
        double sinFromLat = sin(fromLat);
        double cosFromLat = cos(fromLat);
        double sinLat = cosDistance * sinFromLat + sinDistance * cosFromLat * cos(heading);
        double dLng = atan2(
                sinDistance * cosFromLat * sin(heading),
                cosDistance - sinFromLat * sinLat);
        return new LatLng(toDegrees(asin(sinLat)), toDegrees(fromLng + dLng));
    }

    /**
     * Returns the location of origin when provided with a LatLng destination,
     * meters travelled and original heading. Headings are expressed in degrees
     * clockwise from North. This function returns null when no solution is
     * available.
     * @param to       The destination LatLng.
     * @param distance The distance travelled, in meters.
     * @param heading  The heading in degrees clockwise from north.
     */
    public static LatLng computeOffsetOrigin(LatLng to, double distance, double heading) {
        heading = toRadians(heading);
        distance /= EARTH_RADIUS;
        // http://lists.maptools.org/pipermail/proj/2008-October/003939.html
        double n1 = cos(distance);
        double n2 = sin(distance) * cos(heading);
        double n3 = sin(distance) * sin(heading);
        double n4 = sin(toRadians(to.latitude));
        // There are two solutions for b. b = n2 * n4 +/- sqrt(), one solution results
        // in the latitude outside the [-90, 90] range. We first try one solution and
        // back off to the other if we are outside that range.
        double n12 = n1 * n1;
        double discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4;
        if (discriminant < 0) {
            // No real solution which would make sense in LatLng-space.
            return null;
        }
        double b = n2 * n4 + sqrt(discriminant);
        b /= n1 * n1 + n2 * n2;
        double a = (n4 - n2 * b) / n1;
        double fromLatRadians = atan2(a, b);
        if (fromLatRadians < -PI / 2 || fromLatRadians > PI / 2) {
            b = n2 * n4 - sqrt(discriminant);
            b /= n1 * n1 + n2 * n2;
            fromLatRadians = atan2(a, b);
        }
        if (fromLatRadians < -PI / 2 || fromLatRadians > PI / 2) {
            // No solution which would make sense in LatLng-space.
            return null;
        }
        double fromLngRadians = toRadians(to.longitude) -
                atan2(n3, n1 * cos(fromLatRadians) - n2 * sin(fromLatRadians));
        return new LatLng(toDegrees(fromLatRadians), toDegrees(fromLngRadians));
    }

    /**
     * Returns the LatLng which lies the given fraction of the way between the
     * origin LatLng and the destination LatLng.
     * @param from     The LatLng from which to start.
     * @param to       The LatLng toward which to travel.
     * @param fraction A fraction of the distance to travel.
     * @return The interpolated LatLng.
     */
    public static LatLng interpolate(LatLng from, LatLng to, double fraction) {
        // http://en.wikipedia.org/wiki/Slerp
        double fromLat = toRadians(from.latitude);
        double fromLng = toRadians(from.longitude);
        double toLat = toRadians(to.latitude);
        double toLng = toRadians(to.longitude);
        double cosFromLat = cos(fromLat);
        double cosToLat = cos(toLat);

        // Computes Spherical interpolation coefficients.
        double angle = computeAngleBetween(from, to);
        double sinAngle = sin(angle);
        if (sinAngle < 1E-6) {
            return from;
        }
        double a = sin((1 - fraction) * angle) / sinAngle;
        double b = sin(fraction * angle) / sinAngle;

        // Converts from polar to vector and interpolate.
        double x = a * cosFromLat * cos(fromLng) + b * cosToLat * cos(toLng);
        double y = a * cosFromLat * sin(fromLng) + b * cosToLat * sin(toLng);
        double z = a * sin(fromLat) + b * sin(toLat);

        // Converts interpolated vector back to polar.
        double lat = atan2(z, sqrt(x * x + y * y));
        double lng = atan2(y, x);
        return new LatLng(toDegrees(lat), toDegrees(lng));
    }

    /**
     * Returns distance on the unit sphere; the arguments are in radians.
     */
    private static double distanceRadians(double lat1, double lng1, double lat2, double lng2) {
        return arcHav(havDistance(lat1, lat2, lng1 - lng2));
    }

    /**
     * Returns the angle between two LatLngs, in radians. This is the same as the distance
     * on the unit sphere.
     */
    static double computeAngleBetween(LatLng from, LatLng to) {
        return distanceRadians(toRadians(from.latitude), toRadians(from.longitude),
                               toRadians(to.latitude), toRadians(to.longitude));
    }

    /**
     * Returns the distance between two LatLngs, in meters.
     */
    public static double computeDistanceBetween(LatLng from, LatLng to) {
        return computeAngleBetween(from, to) * EARTH_RADIUS;
    }

    /**
     * Returns the length of the given path, in meters, on Earth.
     */
    public static double computeLength(List<LatLng> path) {
        if (path.size() < 2) {
            return 0;
        }
        double length = 0;
        LatLng prev = path.get(0);
        double prevLat = toRadians(prev.latitude);
        double prevLng = toRadians(prev.longitude);
        for (LatLng point : path) {
            double lat = toRadians(point.latitude);
            double lng = toRadians(point.longitude);
            length += distanceRadians(prevLat, prevLng, lat, lng);
            prevLat = lat;
            prevLng = lng;
        }
        return length * EARTH_RADIUS;
    }

    /**
     * Returns the area of a closed path on Earth.
     * @param path A closed path.
     * @return The path's area in square meters.
     */
    public static double computeArea(List<LatLng> path) {
        return abs(computeSignedArea(path));
    }

    /**
     * Returns the signed area of a closed path on Earth. The sign of the area may be used to
     * determine the orientation of the path.
     * "inside" is the surface that does not contain the South Pole.
     * @param path A closed path.
     * @return The loop's area in square meters.
     */
    public static double computeSignedArea(List<LatLng> path) {
        return computeSignedArea(path, EARTH_RADIUS);
    }

    /**
     * Returns the signed area of a closed path on a sphere of given radius.
     * The computed area uses the same units as the radius squared.
     * Used by SphericalUtilTest.
     */
    static double computeSignedArea(List<LatLng> path, double radius) {
        int size = path.size();
        if (size < 3) { return 0; }
        double total = 0;
        LatLng prev = path.get(size - 1);
        double prevTanLat = tan((PI / 2 - toRadians(prev.latitude)) / 2);
        double prevLng = toRadians(prev.longitude);
        // For each edge, accumulate the signed area of the triangle formed by the North Pole
        // and that edge ("polar triangle").
        for (LatLng point : path) {
            double tanLat = tan((PI / 2 - toRadians(point.latitude)) / 2);
            double lng = toRadians(point.longitude);
            total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng);
            prevTanLat = tanLat;
            prevLng = lng;
        }
        return total * (radius * radius);
    }

    /**
     * Returns the signed area of a triangle which has North Pole as a vertex.
     * Formula derived from "Area of a spherical triangle given two edges and the included angle"
     * as per "Spherical Trigonometry" by Todhunter, page 71, section 103, point 2.
     * See http://books.google.com/books?id=3uBHAAAAIAAJ&pg=PA71
     * The arguments named "tan" are tan((pi/2 - latitude)/2).
     */
    private static double polarTriangleArea(double tan1, double lng1, double tan2, double lng2) {
        double deltaLng = lng1 - lng2;
        double t = tan1 * tan2;
        return 2 * atan2(t * sin(deltaLng), 1 + t * cos(deltaLng));
    }

    /**
     * Wraps the given value into the inclusive-exclusive interval between min and max.
     * @param n   The value to wrap.
     * @param min The minimum.
     * @param max The maximum.
     */
    static double wrap(double n, double min, double max) {
        return (n >= min && n < max) ? n : (mod(n - min, max - min) + min);
    }

    /**
     * Returns the non-negative remainder of x / m.
     * @param x The operand.
     * @param m The modulus.
     */
    static double mod(double x, double m) {
        return ((x % m) + m) % m;
    }
}

答案 3 :(得分:9)

Google地图似乎与里程/像素紧密配合。在zoom = 13,1英里= 100像素。 2英里= 200像素。每个变焦杆增加或减少2倍。因此,在缩放14,1英里= 200像素和缩放12,1英里= 50像素。

答案 4 :(得分:6)

我已将已接受的答案转换为返回双倍值,因为Android Google地图库使用浮点缩放级别,并且还考虑了远离赤道的纬度。

public static double getZoomForMetersWide (
  final double desiredMeters,
  final double mapWidth,
  final double latitude )
{
  final double latitudinalAdjustment = Math.cos( Math.PI * latitude / 180.0 );

  final double arg = EQUATOR_LENGTH * mapWidth * latitudinalAdjustment / ( desiredMeters * 256.0 );

  return Math.log( arg ) / Math.log( 2.0 );
}

另外,为了获得Android上的最佳效果,请不要传递视图的实际像素数,而是按照设备的像素密度缩放尺寸。

DisplayMetrics metrics = getResources().getDisplayMetrics();
float mapWidth = mapView.getWidth() / metrics.scaledDensity;

希望这有助于某人。

答案 5 :(得分:4)

使用循环来计算缩放级别非常幼稚。 使用数学会好得多。

这里函数(返回类型:float)

public static double calcZoom(int visible_distance, int img_width)
{
    // visible_distance -> in meters
    // img_width -> in pixels

    visible_distance = Math.abs(visible_distance);
    double equator_length = 40075016; // in meters

    // for an immage of 256 pixel pixel
    double zoom256 = Math.log(equator_length/visible_distance)/Math.log(2);

    // adapt the zoom to the image size
    int x = (int) (Math.log(img_width/256)/Math.log(2));
    double zoom = zoom256 + x;

    return zoom;
}

示例电话:

public static void main(String[] args)
{
    // computes the zoom for 1km=1000m for an image having 256 width
    double zoom = MainClass.calcZoom(1000, 256);
    System.out.println("zoom: " + String.valueOf(zoom));
    return;
} 

计算缩放级别的数学公式为:

equator_length = 40075016
zoom_level = logE(equator_length/distance)/logE(2) + logE(img_width/256)/logE(2)
// The zoom_level computed here is a float number.

这就是所有人! : - )

注意:上面的解决方案作为已接受的答案仅适用于赤道旁边的缩放级别。 如果您想要一个适用于所有纬度的解决方案,则需要在要计算的缩放级别的相同纬度处使用并行长度。 calcZoom方法更改为

private double calcZoom(int visible_distance, int img_width, double atLatitude) {
    // visible_distance -> in meters
    // img_width -> in pixels

    double parallel_length = this.calcParallelLegth(atLatitude); // in meters

    // for an immage of 256 pixel pixel
    zoom256 = Math.log(parallel_length/visible_distance))/Math.log(2)

    // adapt the zoom to the image size
    x = (int) Math.log(img_width/256)/Math.log(2)
    zoom = zoom256 + x

    return zoom;
}

this.calcParallelLegth(atLatitude)atLatitude纬度处重新调整平行线的长度。

您可以使用某些库自己计算长度(最好使用Vincenty公式)。

可替换地

如果您没有这样的库(或者您没有搜索库,或者您只是想要一个有效的完整代码)在本答案的底部,您可以找到整个工作代码< / strong>,double calcParallelLegth(double atLatitude)的实现使用一个表(使用Vincenty公式计算),在所有纬度上具有平行长度,3%的公差。

注意:
如果您和您理解公式(或检查公式是否合适),您只需阅读以下内容

下面的公式解释:

以简单的方式使用它!

让我们将问题分成两部分。

第1部分 为256x256尺寸的图像计算缩放率

第2部分 适应不同尺寸图像的缩放

解决第1部分

图像大小为256x256。 缩放级别0显示整个赤道 每个后续的缩放级别让我看到之前的一半。

赤道长度为40,075,016米根据WGS-84 (*1)和 Vincenty公式(*2)

zoom=0 -> 40,075,016 / 1   = 40,075,016 meters visible         Note: 2^0=1
zoom=1 -> 40,075,016 / 2   = 20,037,508 meters visible         Note: 2^1=2
zoom=2 -> 40,075,016 / 4   = 10,018,754 meters visible         Note: 2^2=4
zoom=3 -> 40,075,016 / 8   =  5,009,377 meters visible         Note: 2^3=8
zoom=4 -> 40,075,016 / 16  =  2,504,688.5 meters visible       Note: 2^4=16
zoom=5 -> 40,075,016 / 2^5 =  1,252,344.25 meters visible      Note= 2^5=32
zoom=6 -> 40,075,016 / 2^6 =    636,172.125 meters visible     Note= 2^6=64
... 
zoom   -> equator_length / 2^zoom = visible_distance

如上所示,每个后续缩放级别让我看到之前的一半。

zoom 是想要的zoom_level visible_distance 是图像水平显示的距离。

如果你想要1km而不是你需要用 visible_distance = 1000 计算缩放

让我们找出缩放公式 数学就是这里的神奇之处(“无聊”神奇的东西)。

   equator_length / 2^zoom = visible_distance ->                            
-> equator_length / visible_distance = 2^zoom ->
-> log2(equator_length / visible_distance) = log2(2^zoom) ->        (*3)
-> log2(equator_length / visible_distance) = zoom*log2(2) ->        (*4)
-> log2(equator_length / visible_distance) = zoom*1 ->              (*5)
-> log2(equator_length / visible_distance) = zoom ->
-> logE(equator_length / visible_distance)/logE(2) = zoom ->          (*6)

256x256图像的缩放级别公式为:

zoom256 = logE(equator_length/visible_distance) / logE(2)

第1部分完成!!

解决第2部分

根据想要的图像尺寸调整缩放。

每次图像宽度加倍时,看到整个赤道需要的变焦增加一。

例:
在图像512x512中,查看整个赤道所需的变焦为1。 在图像1024x1024中,看到整个赤道所需的变焦是2。 在图像2048x2048中,看到整个赤道所需的变焦是3。

那说

width= 256 ->  256/256 = 1 ->   zoom=0 (needed to see the whole equator)
width= 512 ->  512/256 = 2   -> zoom=1 (needed to see the whole equator)
width=1024 -> 1024/256 = 4   -> zoom=2 (needed to see the whole equator)
width=2048 -> 2048/256 = 8   -> zoom=3 (needed to see the whole equator)
width=4096 -> 4096/256 = 2^4 -> zoom=4 (needed to see the whole equator)
width=4096 -> 4096/256 = 2^5 -> zoom=5 (needed to see the whole equator)

...  宽度 - &gt; width / 256 = 2 ^ x - &gt; zoom = x(需要看整个赤道)

这意味着(zoom_level是

- with an   512x512    image, the zoom needed is zoom256+1
- with an  1024x1024   image, the zoom needed is zoom256+2
- with an  2048x2048   image, the zoom needed is zoom256+3
...
- with an WIDTHxHEIGHT image, the zoom needed is zoom256+x

需要 x 来调整缩放所需的图像大小。

所以,这是来自

的提取物x的问题
width/256 = 2^x

我们这样做

width/256 = 2^x ->
-> log2(width/256) = log2(2^x) ->            (*3)
-> log2(width/256) = x * log2(2) ->          (*4)
-> log2(width/256) = x * 1 ->                (*5)
-> log2(width/256) = x -> 
-> logE(width/256) / logE(2) = x ->          (*6)

现在我们有 x 公式。

WIDTHxHEIGHT图像的缩放级别公式为:

zoom = zoom256 + x

所以,如果你想在512x512图像中看到1km而不是

zoom256 = logE(40075016/1000) / logE(2) = 15.29041547592718
x = logE(512/256) / logE(2) = 1
zoom = zoom256 + z = 15.29041547592718 + 1 = 16.29041547592718

如果必须是整数

zoom = floor(zoom) = 16

完成!

(*3) expr1=expr2 <-> log(expr1)=log(expr2)
(*4) logN(a^b) = b * logN(a)
(*5) logN(N) = 1
(*6) logN(expr) = log(expr)/log(N)
(*7) log(a/b) = log(a) - log(b)

以下是计算每个纬度ed图像宽度的缩放级别的完整代码。

class MainClass
{
    public static int getParallelLength(double atLatitude)
    {

        int FR_LAT = 0; // from latitude
        int TO_LAT = 1; // to latidude
        int PA_LEN = 2; // parallel length in meters)
        int PC_ERR = 3; // percentage error

        //  fr_lat| to_lat            |  par_len| perc_err
        double tbl[][] = {
            { 0.00, 12.656250000000000, 40075016, 2.410},
            {12.66, 17.402343750000000, 39107539, 2.180},
            {17.40, 22.148437500000000, 38252117, 2.910},
            {22.15, 25.708007812500000, 37135495, 2.700},
            {25.71, 28.377685546875000, 36130924, 2.330},
            {28.38, 31.047363281250000, 35285940, 2.610},
            {31.05, 33.717041015625000, 34364413, 2.890},
            {33.72, 35.719299316406250, 33368262, 2.380},
            {35.72, 37.721557617187500, 32573423, 2.560},
            {37.72, 39.723815917968750, 31738714, 2.750},
            {39.72, 41.726074218750000, 30865121, 2.950},
            {41.73, 43.227767944335938, 29953681, 2.360},
            {43.23, 44.729461669921875, 29245913, 2.480},
            {44.73, 46.231155395507812, 28517939, 2.620},
            {46.23, 47.732849121093750, 27770248, 2.760},
            {47.73, 49.234542846679688, 27003344, 2.900},
            {49.23, 50.360813140869141, 26217745, 2.290},
            {50.36, 51.487083435058594, 25616595, 2.380},
            {51.49, 52.613353729248047, 25005457, 2.480},
            {52.61, 53.739624023437500, 24384564, 2.580},
            {53.74, 54.865894317626953, 23754152, 2.690},
            {54.87, 55.992164611816406, 23114464, 2.800},
            {55.99, 57.118434906005859, 22465745, 2.920},
            {57.12, 57.963137626647949, 21808245, 2.280},
            {57.96, 58.807840347290039, 21309508, 2.360},
            {58.81, 59.652543067932129, 20806081, 2.440},
            {59.65, 60.497245788574219, 20298074, 2.520},
            {60.50, 61.341948509216309, 19785597, 2.610},
            {61.34, 62.186651229858398, 19268762, 2.700},
            {62.19, 63.031353950500488, 18747680, 2.800},
            {63.03, 63.876056671142578, 18222465, 2.900},
            {63.88, 64.509583711624146, 17693232, 2.250},
            {64.51, 65.143110752105713, 17293739, 2.320},
            {65.14, 65.776637792587280, 16892100, 2.390},
            {65.78, 66.410164833068848, 16488364, 2.460},
            {66.41, 67.043691873550415, 16082582, 2.530},
            {67.04, 67.677218914031982, 15674801, 2.610},
            {67.68, 68.310745954513550, 15265074, 2.690},
            {68.31, 68.944272994995117, 14853450, 2.780},
            {68.94, 69.577800035476685, 14439980, 2.870},
            {69.58, 70.211327075958252, 14024715, 2.970},
            {70.21, 70.686472356319427, 13607707, 2.300},
            {70.69, 71.161617636680603, 13293838, 2.360},
            {71.16, 71.636762917041779, 12979039, 2.430},
            {71.64, 72.111908197402954, 12663331, 2.500},
            {72.11, 72.587053477764130, 12346738, 2.570},
            {72.59, 73.062198758125305, 12029281, 2.640},
            {73.06, 73.537344038486481, 11710981, 2.720},
            {73.54, 74.012489318847656, 11391862, 2.800},
            {74.01, 74.487634599208832, 11071946, 2.890},
            {74.49, 74.962779879570007, 10751254, 2.980},
            {74.96, 75.319138839840889, 10429810, 2.310},
            {75.32, 75.675497800111771, 10188246, 2.370},
            {75.68, 76.031856760382652,  9946280, 2.430},
            {76.03, 76.388215720653534,  9703923, 2.500},
            {76.39, 76.744574680924416,  9461183, 2.560},
            {76.74, 77.100933641195297,  9218071, 2.640},
            {77.10, 77.457292601466179,  8974595, 2.710},
            {77.46, 77.813651561737061,  8730766, 2.790},
            {77.81, 78.170010522007942,  8486593, 2.880},
            {78.17, 78.526369482278824,  8242085, 2.970},
            {78.53, 78.793638702481985,  7997252, 2.290},
            {78.79, 79.060907922685146,  7813420, 2.350},
            {79.06, 79.328177142888308,  7629414, 2.410},
            {79.33, 79.595446363091469,  7445240, 2.470},
            {79.60, 79.862715583294630,  7260900, 2.540},
            {79.86, 80.129984803497791,  7076399, 2.600},
            {80.13, 80.397254023700953,  6891742, 2.680},
            {80.40, 80.664523243904114,  6706931, 2.750},
            {80.66, 80.931792464107275,  6521972, 2.830},
            {80.93, 81.199061684310436,  6336868, 2.920},
            {81.20, 81.399513599462807,  6151624, 2.250},
            {81.40, 81.599965514615178,  6012600, 2.310},
            {81.60, 81.800417429767549,  5873502, 2.360},
            {81.80, 82.000869344919920,  5734331, 2.420},
            {82.00, 82.201321260072291,  5595088, 2.480},
            {82.20, 82.401773175224662,  5455775, 2.550},
            {82.40, 82.602225090377033,  5316394, 2.620},
            {82.60, 82.802677005529404,  5176947, 2.690},
            {82.80, 83.003128920681775,  5037435, 2.770},
            {83.00, 83.203580835834146,  4897860, 2.850},
            {83.20, 83.404032750986516,  4758224, 2.930},
            {83.40, 83.554371687350795,  4618528, 2.260},
            {83.55, 83.704710623715073,  4513719, 2.320},
            {83.70, 83.855049560079351,  4408878, 2.370},
            {83.86, 84.005388496443629,  4304006, 2.430},
            {84.01, 84.155727432807907,  4199104, 2.490},
            {84.16, 84.306066369172186,  4094172, 2.560},
            {84.31, 84.456405305536464,  3989211, 2.630},
            {84.46, 84.606744241900742,  3884223, 2.700},
            {84.61, 84.757083178265020,  3779207, 2.770},
            {84.76, 84.907422114629298,  3674165, 2.850},
            {84.91, 85.057761050993577,  3569096, 2.940},
            {85.06, 85.170515253266785,  3464003, 2.270},
            {85.17, 85.283269455539994,  3385167, 2.320},
            {85.28, 85.396023657813203,  3306318, 2.380},
            {85.40, 85.508777860086411,  3227456, 2.440},
            {85.51, 85.621532062359620,  3148581, 2.500},
            {85.62, 85.734286264632829,  3069693, 2.570},
            {85.73, 85.847040466906037,  2990793, 2.630},
            {85.85, 85.959794669179246,  2911882, 2.710},
            {85.96, 86.072548871452454,  2832959, 2.780},
            {86.07, 86.185303073725663,  2754025, 2.860},
            {86.19, 86.298057275998872,  2675080, 2.950},
            {86.30, 86.382622927703778,  2596124, 2.280},
            {86.38, 86.467188579408685,  2536901, 2.330},
            {86.47, 86.551754231113591,  2477672, 2.390},
            {86.55, 86.636319882818498,  2418437, 2.440},
            {86.64, 86.720885534523404,  2359197, 2.510},
            {86.72, 86.805451186228311,  2299952, 2.570},
            {86.81, 86.890016837933217,  2240701, 2.640},
            {86.89, 86.974582489638124,  2181446, 2.710},
            {86.97, 87.059148141343030,  2122186, 2.790},
            {87.06, 87.143713793047937,  2062921, 2.870},
            {87.14, 87.228279444752843,  2003652, 2.950},
            {87.23, 87.291703683531523,  1944378, 2.280},
            {87.29, 87.355127922310203,  1899919, 2.340},
            {87.36, 87.418552161088883,  1855459, 2.390},
            {87.42, 87.481976399867563,  1810996, 2.450},
            {87.48, 87.545400638646242,  1766531, 2.510},
            {87.55, 87.608824877424922,  1722063, 2.580},
            {87.61, 87.672249116203602,  1677594, 2.650},
            {87.67, 87.735673354982282,  1633122, 2.720},
            {87.74, 87.799097593760962,  1588648, 2.790},
            {87.80, 87.862521832539642,  1544172, 2.880},
            {87.86, 87.925946071318322,  1499695, 2.960},
            {87.93, 87.973514250402332,  1455215, 2.290},
            {87.97, 88.021082429486341,  1421854, 2.340},
            {88.02, 88.068650608570351,  1388493, 2.400},
            {88.07, 88.116218787654361,  1355130, 2.460},
            {88.12, 88.163786966738371,  1321766, 2.520},
            {88.16, 88.211355145822381,  1288401, 2.580},
            {88.21, 88.258923324906391,  1255036, 2.650},
            {88.26, 88.306491503990401,  1221669, 2.730},
            {88.31, 88.354059683074411,  1188302, 2.800},
            {88.35, 88.401627862158421,  1154934, 2.880},
            {88.40, 88.449196041242431,  1121565, 2.970},
            {88.45, 88.484872175555438,  1088195, 2.290},
            {88.48, 88.520548309868445,  1063167, 2.350},
            {88.52, 88.556224444181453,  1038139, 2.410},
            {88.56, 88.591900578494460,  1013110, 2.470},
            {88.59, 88.627576712807468,   988081, 2.530},
            {88.63, 88.663252847120475,   963052, 2.590},
            {88.66, 88.698928981433482,   938022, 2.660},
            {88.70, 88.734605115746490,   912992, 2.740},
            {88.73, 88.770281250059497,   887961, 2.810},
            {88.77, 88.805957384372505,   862930, 2.900},
            {88.81, 88.841633518685512,   837899, 2.980},
            {88.84, 88.868390619420268,   812867, 2.300},
            {88.87, 88.895147720155023,   794093, 2.360},
            {88.90, 88.921904820889779,   775319, 2.420},
            {88.92, 88.948661921624534,   756545, 2.480},
            {88.95, 88.975419022359290,   737771, 2.540},
            {88.98, 89.002176123094046,   718996, 2.610},
            {89.00, 89.028933223828801,   700221, 2.680},
            {89.03, 89.055690324563557,   681446, 2.750},
            {89.06, 89.082447425298312,   662671, 2.830},
            {89.08, 89.109204526033068,   643896, 2.910},
            {89.11, 89.129272351584135,   625121, 2.250},
            {89.13, 89.149340177135201,   611039, 2.300},
            {89.15, 89.169408002686268,   596957, 2.350},
            {89.17, 89.189475828237335,   582876, 2.410},
            {89.19, 89.209543653788401,   568794, 2.470},
            {89.21, 89.229611479339468,   554712, 2.530},
            {89.23, 89.249679304890535,   540630, 2.600},
            {89.25, 89.269747130441601,   526548, 2.670},
            {89.27, 89.289814955992668,   512466, 2.740},
            {89.29, 89.309882781543735,   498384, 2.820},
            {89.31, 89.329950607094801,   484302, 2.900},
            {89.33, 89.350018432645868,   470219, 2.990},
            {89.35, 89.365069301809172,   456137, 2.310},
            {89.37, 89.380120170972475,   445575, 2.370},
            {89.38, 89.395171040135779,   435013, 2.420},
            {89.40, 89.410221909299082,   424451, 2.480},
            {89.41, 89.425272778462386,   413889, 2.550},
            {89.43, 89.440323647625689,   403328, 2.610},
            {89.44, 89.455374516788993,   392766, 2.680},
            {89.46, 89.470425385952296,   382204, 2.760},
            {89.47, 89.485476255115600,   371642, 2.840},
            {89.49, 89.500527124278904,   361080, 2.920},
            {89.50, 89.511815276151381,   350518, 2.260},
            {89.51, 89.523103428023859,   342596, 2.310},
            {89.52, 89.534391579896337,   334674, 2.360},
            {89.53, 89.545679731768814,   326753, 2.420},
            {89.55, 89.556967883641292,   318831, 2.480},
            {89.56, 89.568256035513770,   310910, 2.540},
            {89.57, 89.579544187386247,   302988, 2.610},
            {89.58, 89.590832339258725,   295066, 2.680},
            {89.59, 89.602120491131203,   287145, 2.750},
            {89.60, 89.613408643003680,   279223, 2.830},
            {89.61, 89.624696794876158,   271301, 2.910},
            {89.62, 89.633162908780520,   263380, 2.250},
            {89.63, 89.641629022684882,   257438, 2.300},
            {89.64, 89.650095136589243,   251497, 2.360},
            {89.65, 89.658561250493605,   245556, 2.410},
            {89.66, 89.667027364397967,   239615, 2.470},
            {89.67, 89.675493478302329,   233673, 2.540},
            {89.68, 89.683959592206691,   227732, 2.600},
            {89.68, 89.692425706111052,   221791, 2.670},
            {89.69, 89.700891820015414,   215849, 2.750},
            {89.70, 89.709357933919776,   209908, 2.830},
            {89.71, 89.717824047824138,   203967, 2.910},
            {89.72, 89.724173633252406,   198026, 2.250},
            {89.72, 89.730523218680673,   193570, 2.300},
            {89.73, 89.736872804108941,   189114, 2.350},
            {89.74, 89.743222389537209,   184658, 2.410},
            {89.74, 89.749571974965477,   180202, 2.470},
            {89.75, 89.755921560393745,   175746, 2.530},
            {89.76, 89.762271145822012,   171290, 2.600},
            {89.76, 89.768620731250280,   166834, 2.670},
            {89.77, 89.774970316678548,   162378, 2.740},
            {89.77, 89.781319902106816,   157922, 2.820},
            {89.78, 89.787669487535084,   153466, 2.900},
            {89.79, 89.794019072963351,   149010, 2.990},
            {89.79, 89.798781262034552,   144554, 2.310},
            {89.80, 89.803543451105753,   141212, 2.360},
            {89.80, 89.808305640176954,   137869, 2.420},
            {89.81, 89.813067829248155,   134527, 2.480},
            {89.81, 89.817830018319356,   131185, 2.540},
            {89.82, 89.822592207390556,   127843, 2.610},
            {89.82, 89.827354396461757,   124501, 2.680},
            {89.83, 89.832116585532958,   121159, 2.750},
            {89.83, 89.836878774604159,   117817, 2.830},
            {89.84, 89.841640963675360,   114475, 2.910},
            {89.84, 89.845212605478764,   111133, 2.250},
            {89.85, 89.848784247282168,   108627, 2.300},
            {89.85, 89.852355889085572,   106120, 2.360},
            {89.85, 89.855927530888977,   103614, 2.410},
            {89.86, 89.859499172692381,   101107, 2.470},
            {89.86, 89.863070814495785,    98601, 2.540},
            {89.86, 89.866642456299189,    96094, 2.600},
            {89.87, 89.870214098102593,    93588, 2.670},
            {89.87, 89.873785739905998,    91081, 2.750},
            {89.87, 89.877357381709402,    88575, 2.830},
            {89.88, 89.880929023512806,    86068, 2.910},
            {89.88, 89.883607754865352,    83562, 2.240},
            {89.88, 89.886286486217898,    81682, 2.300},
            {89.89, 89.888965217570444,    79802, 2.350},
            {89.89, 89.891643948922990,    77922, 2.410},
            {89.89, 89.894322680275536,    76042, 2.470},
            {89.89, 89.897001411628082,    74162, 2.530},
            {89.90, 89.899680142980628,    72282, 2.600},
            {89.90, 89.902358874333174,    70402, 2.660},
            {89.90, 89.905037605685720,    68523, 2.740},
            {89.91, 89.907716337038266,    66643, 2.820},
            {89.91, 89.910395068390812,    64763, 2.900},
            {89.91, 89.913073799743358,    62883, 2.980},
            {89.91, 89.915082848257768,    61003, 2.310},
            {89.92, 89.917091896772178,    59593, 2.360},
            {89.92, 89.919100945286587,    58183, 2.420},
            {89.92, 89.921109993800997,    56773, 2.480},
            {89.92, 89.923119042315406,    55363, 2.540},
            {89.92, 89.925128090829816,    53953, 2.610},
            {89.93, 89.927137139344225,    52543, 2.680},
            {89.93, 89.929146187858635,    51134, 2.750},
            {89.93, 89.931155236373044,    49724, 2.830},
            {89.93, 89.933164284887454,    48314, 2.910},
            {89.93, 89.934671071273257,    46904, 2.250},
            {89.93, 89.936177857659061,    45846, 2.300},
            {89.94, 89.937684644044865,    44789, 2.360},
            {89.94, 89.939191430430668,    43731, 2.410},
            {89.94, 89.940698216816472,    42674, 2.470},
            {89.94, 89.942205003202275,    41617, 2.540},
            {89.94, 89.943711789588079,    40559, 2.600},
            {89.94, 89.945218575973882,    39502, 2.670},
            {89.95, 89.946725362359686,    38444, 2.740},
            {89.95, 89.948232148745490,    37387, 2.820},
            {89.95, 89.949738935131293,    36329, 2.900}
        };

        for(int r=0; r < tbl.length; r++)
        {
            double fromLat = tbl[r][FR_LAT];
            double toLat = tbl[r][TO_LAT];
            double atLat = atLatitude;

            if(fromLat <= atLat && atLat < toLat)
            {
                double parallelLength = tbl[r][PA_LEN];
                return (int)parallelLength;
            } 
        }

        return 0;
    }

    public static double calcZoom(int visible_distance, int img_width, double atLat)
    {
        // visible_distance -> in meters
        // img_width -> in pixels
        // atLat -> the latitude you want the zoom level

        visible_distance = Math.abs(visible_distance);
        double parallel_length = MainClass.getParallelLength(atLat); // in meters

        // for an immage of 256 pixel pixel
        double zoom256 = Math.log(parallel_length/visible_distance)/Math.log(2);

        // adapt the zoom to the image size
        int x = (int) (Math.log(img_width/256)/Math.log(2));
        double zoom = zoom256 + x;

        return zoom;
    }

    public static void main(String[] args)
    {
        int len;
        double zoom;

        // equator length
        len = MainClass.getParallelLength(0);
        System.out.println("parallel length at 0: " + String.valueOf(len));

        // legth parallel at latitude 89.9 (near the north pole)
        len = MainClass.getParallelLength(89.9);
        System.out.println("parallel length at 89.9: " + String.valueOf(len));

        // the zoom level needed to see 100km=100000m in a img having 
        // width 256 at equator latitude
        zoom = MainClass.calcZoom(100000, 256, 0);
        System.out.println("zoom (100km, width:256, lat:0): " + String.valueOf(zoom));

        // the zoom level needed to see 100km=100000m in a img having 
        // width 512 at equator latitude
        zoom = MainClass.calcZoom(100000, 512, 0);
        System.out.println("zoom (100km, width:512, lat:0): " + String.valueOf(zoom));

        // the zoom level needed to see 100km=100000m in a img having 
        // width 256 at latitude 60
        zoom = MainClass.calcZoom(100000, 256, 60);
        System.out.println("zoom (100km, width:256, lat:60): " + String.valueOf(zoom));

        return;
    }
}

答案 6 :(得分:1)

最终的工作解决方案:

public static void getZoomForMetersWide(GoogleMap googleMap, int mapViewWidth, LatLng latLngPoint, int desiredMeters) {
        DisplayMetrics metrics = App.getAppCtx().getResources().getDisplayMetrics();
        float mapWidth = mapViewWidth / metrics.density;

        final int EQUATOR_LENGTH = 40075004;
        final int TIME_ANIMATION_MILIS = 1500;
        final double latitudinalAdjustment = Math.cos(Math.PI * latLngPoint.latitude / 180.0);
        final double arg = EQUATOR_LENGTH * mapWidth * latitudinalAdjustment / (desiredMeters * 256.0);
        double valToZoom = Math.log(arg) / Math.log(2.0);

        googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLngPoint, Float.valueOf(String.valueOf(valToZoom))), TIME_ANIMATION_MILIS , null);
    }

p.s。使用@sho答案和@Lionel Briand评论

答案 7 :(得分:0)

我确信有很多方法可以找到它我使用这种技术来计算缩放级别

 mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
        private float currentZoom = -1;
        @Override
        public void onCameraChange(CameraPosition position) {
            if (position.zoom != currentZoom){
                currentZoom = position.zoom;  // here you get zoom level
                Toast.makeText(this, "Zoom Value is : "+currentZoom, Toast.LENGTH_SHORT).show();
            }
        }
    });