Как работает расчет уровня масштабирования в Картах Google? - PullRequest
11 голосов
/ 09 мая 2011

Я знаю, что такое вход и выход, но я просто не уверен, как и почему он работает.

Этот код используется, учитывая минимальную и максимальную долготу / широту (квадрат)который содержит набор точек, определите максимальный уровень масштабирования на Картах Google, в котором будут отображаться все эти точки.Первоначальный автор ушел, поэтому я не уверен, что некоторые из этих чисел даже для (то есть 6371 и 8).Считай это загадкой = D

int mapdisplay = 322; //min of height and width of element which contains the map
double dist = (6371 * Math.acos(Math.sin(min_lat / 57.2958) * Math.sin(max_lat / 57.2958) + 
            (Math.cos(min_lat / 57.2958) * Math.cos(max_lat / 57.2958) * Math.cos((max_lon / 57.2958) - (min_lon / 57.2958)))));

double zoom = Math.floor(8 - Math.log(1.6446 * dist / Math.sqrt(2 * (mapdisplay * mapdisplay))) / Math.log (2));

if(numPoints == 1 || ((min_lat == max_lat)&&(min_lon == max_lon))){
    zoom = 11;
}

Ответы [ 6 ]

11 голосов
/ 31 октября 2012

Я использую простую формулу ниже:

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;
}

Вы также можете заменить круг на определенный радиус.

11 голосов
/ 09 мая 2011

Некоторые цифры можно легко объяснить

И снова уровень масштабирования удваивает размер с каждым шагом, т.е. увеличивает уровень масштабирования в два раза по сравнению с размером на экране.

zoom = 8 - log(factor * dist) / log(2) = 8 - log_2(factor * dist)
=> dist = 2^(8-zoom) / factor

Из чисел мы видим, что восьмой уровень масштабирования соответствует расстоянию 276,89 км.

2 голосов
/ 09 мая 2011

Эта страница чрезвычайно полезна для объяснения всего этого (расстояние между двумя широтными парами и т. Д.).

6371 - приблизительный радиус Земли в километрах.

57,2958 - также 180 / pi

, также посмотрите эти расчеты проекции Меркатора для преобразования между широтой и долготой и XY: http://wiki.openstreetmap.org/wiki/Mercator

0 голосов
/ 05 июня 2019

После многих попыток я принял решение. Я предполагаю, что у вас есть отступ за пределами радиуса (например, если у вас радиус = 10000 м, то это будет 2500 м влево и вправо). Также вы должны иметь точность в метрах. Вы можете установить подходящий зум с рекурсией (бинарный поиск). Если вы измените moveCamera на animateCamera, вы получите интересную анимацию поиска. Чем больше радиус, тем более точное значение увеличения вы получите.

private fun getCircleZoomValue(latitude: Double, longitude: Double, radius: Double,
                               minZoom: Float, maxZoom: Float): Float {
    val position = LatLng(latitude, longitude)
    val currZoom = (minZoom + maxZoom) / 2
    val camera = CameraUpdateFactory.newLatLngZoom(position, currZoom)
    googleMap!!.moveCamera(camera)
    val results = FloatArray(1)
    val topLeft = googleMap!!.projection.visibleRegion.farLeft
    val topRight = googleMap!!.projection.visibleRegion.farRight
    Location.distanceBetween(topLeft.latitude, topLeft.longitude, topRight.latitude,
        topRight.longitude, results)
    // Difference between visible width in meters and 2.5 * radius.
    val delta = results[0] - 2.5 * radius
    val accuracy = 10 // 10 meters.
    return when {
        delta < -accuracy -> getCircleZoomValue(latitude, longitude, radius, minZoom,
            currZoom)
        delta > accuracy -> getCircleZoomValue(latitude, longitude, radius, currZoom,
            maxZoom)
        else -> currZoom
    }
}

Использование:

if (googleMap != null) {
    zoomCircle(latitude, longitude, radius, googleMap!!.minZoomLevel,
        googleMap!!.maxZoomLevel)
}

Вы должны вызывать этот метод не ранее, чем внутри первого события googleMap?.setOnCameraIdleListener, см. animateCamera работает, а moveCamera не работает для GoogleMap - Android . Если вы назовете его сразу после onMapReady, у вас будет неправильное расстояние, потому что карта не будет рисоваться сама в это время.

Внимание! Уровень масштабирования зависит от местоположения (широта). Таким образом, круг будет иметь разные размеры с одинаковым уровнем масштабирования в зависимости от расстояния от экватора (см. Определение разумного уровня масштабирования для Карт Google с учетом точности определения местоположения ).

enter image description here

0 голосов
/ 14 февраля 2017

Мне нужно было наоборот: учитывая определенный радиус при определенном уровне масштабирования (т.е. 40 метров при уровне масштабирования 15), мне были нужны радиусы при других уровнях масштабирования, которые отображали на карте тот же размер круга (графически).Чтобы сделать это:

// after retrieving the googleMap from either getMap() or getMapAsync()...

// we want a circle with r=40 meters at zoom level 15
double base = 40 / zoomToDistFactor(15);

final Circle circle = googleMap.addCircle(new CircleOptions()
        .center(center)
        .radius(40)
        .fillColor(Color.LTGRAY)
);

googleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
    @Override
    public void onCameraMove() {
        CameraPosition cameraPosition = googleMap.getCameraPosition();
        LatLng center = cameraPosition.target;
        float z2 = cameraPosition.zoom;
        double newR = base * zoomToDistFactor(z2);
        circle.setRadius(newR);
    }
});

// ...

private double zoomToDistFactor(double z) {
    return Math.pow(2,8-z) / 1.6446;
}

Я полагаю, я бы добавил это сюда, чтобы сэкономить кому-либо еще усилия, чтобы получить это преобразование.Камера-осветлитель сделала движение по кругу очень прерывистым.Я закончил тем, что поместил вид в центр вмещающего MapView, который просто нарисовал маленький круг.

0 голосов
/ 09 августа 2016

Я думаю, он получает эту функцию:

 function calculateZoom(WidthPixel,Ratio,Lat,Length){
    // from a segment Length (km), 
    // with size ratio of the of the segment expected on a map (70%),
    // with a map widthpixel size (100px), and a latitude (45°) we can ge the best Zoom
    // earth radius : 6,378,137m, earth is a perfect ball; perimeter at the equator = 40,075,016.7 m
    // the full world on googlemap is available in a box of 256 px; It has a ratio of 156543.03392 (px/m)
    // for Z = 0; 
    // pixel scale at the Lat_level is ( 156543,03392 * cos ( PI * (Lat/180) ))
    // map scale increase at the rate of square root of Z
    //
    Length = Length *1000;                     //Length is in Km
    var k = WidthPixel * 156543.03392 * Math.cos(Lat * Math.PI / 180);        //k = perimeter of the world at the Lat_level, for Z=0 
    var myZoom = Math.round( Math.log( (Ratio * k)/(Length*100) )/Math.LN2 );
    myZoom =  myZoom -1;                   // z start from 0 instead of 1
    //console.log("calculateZoom: width "+WidthPixel+" Ratio "+Ratio+" Lat "+Lat+" length "+Length+" (m) calculated zoom "+ myZoom);

    // not used but it could be usefull for some: Part of the world size a the Lat 
    MapDim = k /Math.pow(2,myZoom);
    //console.log("calculateZoom: size of the map at the Lat: "+MapDim + " meters.");
    //console.log("calculateZoom: world perimeter at the Lat: " +k+ " meters.");
return(myZoom);
}
...