How does this Google Maps zoom level calculation work?

匿名 (未验证) 提交于 2019-12-03 01:29:01

问题:

I know what the input and outputs are, but I'm just not sure how or why it works.

This code is being used to, given a min and max longitude/latitude (a square) that contains a set of points, determine the maximum zoom level on Google Maps that will still display all of those points. The original author is gone, so I'm not sure what some of these numbers are even for (i.e. 6371 and 8). Consider it a puzzle =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; } 

回答1:

Some numbers can be explained easily

And again the zoom level doubles the size with each step, i.e. increase the zoomlevel by one halfs the size on the screen.

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

From the numbers we find that zoom level eight corresponds to a distance of 276.89km.



回答2:

I use a simple formula below:

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

You can also replace circle with its specific radius.



回答3:

This page is extremely helpful for explaining all this stuff (distance between two lat-lng pairs, etc).

6371 is the approximate radius of the earth in kilometers.

57.2958 is 180/pi

also, check out these Mercator projection calculations for converting between latitude-longitude and X-Y: http://wiki.openstreetmap.org/wiki/Mercator



回答4:

I think he gets this function:

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


回答5:

I needed the opposite: given a particular radius at a certain zoom level (i.e., 40 meters at zoom level 15), I needed the radii at other zoom levels that showed the same circle size (graphically) in the map. To do this:

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

I figure I'd put it here to save anyone else the effort to get this conversion.

As a side note, moving the circle around like this in a cameramovelistener made the circle motion very choppy. I ended up putting a view in the center of the enclosing MapView that simply drew a small circle.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!