How to find latitudeDelta & longitudeDelta of the visible map area

I am trying to calculate the  latitudeDelta & longitudeDelta of visible map area on the phone screen. The two method used were:

   spanLat = map.visibleMapRect.size.width / 111000;
   spanLon = map.visibleMapRect.size.height / (111000 * cos(centreLat*3.14159/180));

And

   MKMapRect mRect = map.visibleMapRect;

   MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect));
   MKMapPoint westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect));
   
   MKMapPoint northMapPoint = MKMapPointMake(MKMapRectGetMinY(mRect), MKMapRectGetMidX(mRect));
   MKMapPoint southMapPoint = MKMapPointMake(MKMapRectGetMaxY(mRect), MKMapRectGetMidX(mRect));
   
   CLLocationDistance wLength = MKMetersBetweenMapPoints(eastMapPoint, westMapPoint);
   CLLocationDistance hLength = MKMetersBetweenMapPoints(northMapPoint, southMapPoint);
   
  spanLat = wLength / 111000;
  spanLon = hLength / (111000 * cos(centreLat*3.14159/180));

Neither gives me right  latitudeDelta & longitudeDelta of the visible area.

Are you sure this is correct ?

   MKMapPoint northMapPoint = MKMapPointMake(MKMapRectGetMinY(mRect), MKMapRectGetMidX(mRect));
   MKMapPoint southMapPoint = MKMapPointMake(MKMapRectGetMaxY(mRect), MKMapRectGetMidX(mRect));

Shouldn't it be

   MKMapPoint northMapPoint = MKMapPointMake(MKMapRectGetMidX(mRect), MKMapRectGetMaxY(mRect));
   MKMapPoint southMapPoint = MKMapPointMake(MKMapRectGetMidX(mRect), MKMapRectGetMinY(mRect));
  • What do you get ?
  • What did you expect ?

I cannot find how centerLat is defined.

I found a few other issues.

  • It depends when you call this code

Doc of setRegion(_:animated:) indicates:

When setting a new region, the map may adjust the value in the region parameter so that it fits the visible area of the map precisely. This adjustment is normal and is done to ensure that the value in the region property always reflects the visible portion of the map. However, it does mean that if you get the value of that property right after calling this method, the returned value may not match the value you set. (You can use the regionThatFits(_:) method to determine the region that will actually be set by the map.)

So I had to call when mapView.setRegion animation was completed (or remove the animation by setting parameter to false.

  • Looks like you have defined some wrong coordinates:
   MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect)); // east should be maxX
   MKMapPoint westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect)); // west should be minX
   
   MKMapPoint northMapPoint = MKMapPointMake(MKMapRectGetMinY(mRect), MKMapRectGetMidX(mRect)); // north should be MKMapRectGetMidX, MKMapRectGetMaxY
   MKMapPoint southMapPoint = MKMapPointMake(MKMapRectGetMaxY(mRect), MKMapRectGetMidX(mRect)); // south should be MKMapRectGetMidX, MKMapRectGetMinY
   
   CLLocationDistance wLength = MKMetersBetweenMapPoints(eastMapPoint, westMapPoint);
   CLLocationDistance hLength = MKMetersBetweenMapPoints(northMapPoint, southMapPoint);

  spanLat = wLength / 111000;  // that is spanLon
  spanLon = hLength / (111000 * cos(centreLat*3.14159/180));  // that is spanLat

With those different changes, it apparently works fine.

Here is my Swift code:

private extension MKMapView {
    func mapSpan() -> (DeltaLat: Double, deltaLong: Double) {
        
        let mRect = self.visibleMapRect

        let westMapPoint = MKMapPoint(x: mRect.minX, y: mRect.midY)
        let eastMapPoint = MKMapPoint(x: mRect.maxX, y: mRect.midY)
         
        let northMapPoint = MKMapPoint(x: mRect.midX, y: mRect.maxY)//(x: mRect.minY, y: mRect.midX)
        let southMapPoint = MKMapPoint(x: mRect.midX, y: mRect.minY)//(x: mRect.maxY, y: mRect.midX)
         
        let wLength = westMapPoint.distance(to: eastMapPoint)
        let hLength = southMapPoint.distance(to: northMapPoint)

        let spanLat = hLength / 111000
        let centreLat = (northMapPoint.coordinate.latitude + southMapPoint.coordinate.latitude) / 2
        let spanLon = wLength / (111000 * cos(centreLat * .pi/180))
        
        return (spanLat, spanLon)
    }
}

I call as:

        mapView.setRegion(region, animated: false)   // need to set animation to false
        print(mapView.mapSpan())  

Or call from different thread after delay:

        mapView.setRegion(region, animated: true)   
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
            print(self.mapView.mapSpan()) 
        }
How to find latitudeDelta & longitudeDelta of the visible map area
 
 
Q