Подтвердить что ты не робот

Как этот расчет уровня масштабирования Google Maps работает?

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

Этот код используется, учитывая минимальную и максимальную долготу/широту (квадрат), которая содержит набор точек, определяет максимальный уровень масштабирования на Картах 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;
}
4b9b3361

Ответ 1

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

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

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

Из цифр мы находим, что уровень зума 8 соответствует расстоянию 276,89 км.

Ответ 2

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

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

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

Ответ 3

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

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

57.2958 равно 180/pi

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

Ответ 4

Мне нужно было обратное: учитывая определенный радиус при определенном уровне масштабирования (т.е. 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;
}

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

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

Ответ 5

После многих попыток я принял решение. Я предполагаю, что у вас есть отступ за пределами радиуса (например, если у вас радиус = 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) {
    val zoom = getCircleZoomValue(latitude, longitude, radius, googleMap!!.minZoomLevel, 
        googleMap!!.maxZoomLevel)
}

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

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

enter image description here

Ответ 6

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

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