Define a reasonable zoom level for the accuracy of location data in Google Maps

I am trying to focus the Google map on the user's location, giving a reasonable level of zoom considering the accuracy of this location. Can someone describe how I can calculate it? What variables are involved, how do you achieve this?

+5
source share
3 answers

What you are looking for is a formula that calculates the zoom level based on location accuracy.

I managed to find this formula, which (in my tests) worked very well.

Formula

This can be simplified (or maybe not):

Simplified / Scarified formula

This scary thing is what you want.

EquatorLength is EquatorLength meters. While Meters/Pixel can be calculated by immersing the diameter of the circle of accuracy along the length of the device screen (in pixels).

Here is an example of a program that I used to test this formula:

 GoogleMap mMap; @Override protected void onStart() { super.onStart(); mMap = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap(); // Enable user location layer mMap.setMyLocationEnabled(true); mMap.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() { @Override public void onMyLocationChange(Location location) { // Location lat-lng LatLng loc = new LatLng(location.getLatitude(), location.getLongitude()); // Location accuracy diameter (in meters) float accuracy = location.getAccuracy() * 2; // Screen measurements DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); // Use min(width, height) (to properly fit the screen int screenSize = Math.min(metrics.widthPixels, metrics.heightPixels); // Equators length long equator = 40075004; // The meters per pixel required to show the whole area the user might be located in double requiredMpp = accuracy/screenSize; // Calculate the zoom level double zoomLevel = ((Math.log(equator / (256 * requiredMpp))) / Math.log(2)) + 1; Log.e(TAG, String.format("Accuracy: %f. Screen Width: %d, Height: %d", accuracy, metrics.widthPixels, metrics.heightPixels)); Log.e(TAG, String.format("Required M/Px: %f Zoom Level: %f Approx Zoom Level: %d", requiredMpp, zoomLevel, calculateZoomLevel(screenSize, accuracy))); // Center to user position mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(loc, (float) zoomLevel)); // Prevent the camera centering on the user again mMap.setOnMyLocationChangeListener(null); } }); } private int calculateZoomLevel(int screenWidth, float accuracy) { double equatorLength = 40075004; // in meters double metersPerPixel = equatorLength / 256; int zoomLevel = 1; while ((metersPerPixel * (double) screenWidth) > accuracy) { metersPerPixel /= 2; zoomLevel++; } return zoomLevel; } 

A few notes:

  • This answer is based on this and implements it to check the generated values.
  • Accuracy is the radius of the user's location, and according to the documents he can be up to 68% of the rights.

Any corrections are welcome.

+12
source

Thanks @Simas! I took your algorithm to make this extension for GMSMapView to calculate the perfect zoomLevel taking into account the accuracy of CLLocation.

I had to make adjustments to the consideration of devices with Retina displays, since each pixel is not quite the same as 1 dot on the screen:

 extension GMSMapView { func getIdealZoomLevel(usingLocation location:CLLocation)->Float { let retinaScale = Double(UIScreen.mainScreen().scale) let equatorLength : Double = 40075004 // in meters var metersPerPixel = equatorLength / 256 let accuracy = location.horizontalAccuracy // I used height because I'm on landscape, but moving forward I'll have to get the Min of the width and height. // I also took only 75% of the height to give it some margin let screenWidth : Double = Double( self.frame.size.height) * 0.75 var display = metersPerPixel * (screenWidth / retinaScale) var zoomLevel : Float = 0.0 while (display > accuracy) { metersPerPixel /= 2 display = metersPerPixel * (screenWidth / retinaScale) zoomLevel += 1 } return zoomLevel } } 

This is for the Swift project that I am working on, and right now, I can show a good proximity covering the radius inside this CLLocation.

Hope this helps.

0
source

If you are looking for something simple:

 var zoom = Math.min(20, Math.max(1, Math.log2(591657550/accuracy)-2)); 

-2 to get the desired zoom.

Check out this answer for the diagram of the corresponding increase with accuracy.

0
source

Source: https://habr.com/ru/post/1498400/


All Articles