16

When I need to make an MKCoordinateRegion, I do the following:

var region = MKCoordinateRegion
               .FromDistance(coordinate, RegionSizeInMeters, RegionSizeInMeters);

very simple - works perfectly.

Now I wish to store the value of the current region span. When i look at the region.Span value, it’s an MKCoordinateSpan which has two properties:

public double LatitudeDelta;
public double LongitudeDelta;

How can I convert the LatitudeDelta value into a latitudinalMeters please? (So then I can recreate my region (later on) using the above method...

Pure.Krome
  • 84,693
  • 113
  • 396
  • 647
  • 1
    If you store the span, you _could_ call the plain MKCoordinateRegionMake which takes a center and a span instead of trying to convert the span to meters. Alternatively, why not just store the _meters_ instead of the span in which case no conversion is necessary and you can use MKCoordinateRegionMakeWithDistance. –  Jan 22 '14 at 12:51
  • By the way, the delta values are in degrees (just like the center coordinate). –  Jan 22 '14 at 12:57
  • Are you 100% sure @Anna ? This is the current data I have for my test data (the free drive in the iOS Simulator). http://i.imgur.com/fVOWpJo.png Notice the LatitudeDelta is not a valid latitude value (+/-90) .... – Pure.Krome Jan 22 '14 at 13:25
  • Yes, I'm sorry I wasn't clear. What I mean is it is a value in degree units (but it is not an absolute coordinate). It's a _delta_ in degrees so that means a distance. A latitudeDelta of 117 means a distance of 117 degrees in height (eg. from +40 to -77). However, since it is in degree units just like the coordinate, you can add/subtract delta values as-is to the coordinate values (you'd still have to adjust if the total went over the limit). –  Jan 22 '14 at 14:45
  • Perhaps the documentation for MKCoordinateSpan explains it better: https://developer.apple.com/library/ios/documentation/MapKit/Reference/MapKitDataTypesReference/Reference/reference.html#//apple_ref/doc/uid/TP40009734-CH1-SW29 –  Jan 22 '14 at 14:48

3 Answers3

38

As I can see you already have the region of the map. It doesn't only contain the lat & long deltas but also the center point of the region. You can calculate the distances in meters as illustrated in the picture:

enter image description here

1: Get the region span (how big the region is in lat/long degrees)

MKCoordinateSpan span = region.span;

2: Get the region center (lat/long coordinates)

CLLocationCoordinate2D center = region.center;

3: Create two locations (loc1 & loc2, north - south) based on the center location and calculate the distance inbetween (in meters)

//get latitude in meters
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:(center.latitude - span.latitudeDelta * 0.5) longitude:center.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:(center.latitude + span.latitudeDelta * 0.5) longitude:center.longitude];
int metersLatitude = [loc1 distanceFromLocation:loc2];

4: Create two locations (loc3 & loc4, west - east) based on the center location and calculate the distance inbetween (in meters)

//get longitude in meters
CLLocation *loc3 = [[CLLocation alloc] initWithLatitude:center.latitude longitude:(center.longitude - span.longitudeDelta * 0.5)];
CLLocation *loc4 = [[CLLocation alloc] initWithLatitude:center.latitude longitude:(center.longitude + span.longitudeDelta * 0.5)];
int metersLongitude = [loc3 distanceFromLocation:loc4];
Tomas Jablonskis
  • 4,246
  • 4
  • 22
  • 40
Hannes
  • 3,752
  • 2
  • 37
  • 47
  • This looks like it might fix my problem. Can u explain what is going on? what this delta thing is? why the 0.5 etc? (I love knowing why things, not just answers and then moving on). – Pure.Krome Jan 22 '14 at 06:26
  • Why the XXX_Delta * 0.5? and what value is a Delta, really? here's a screen shot of my values ... http://i.imgur.com/fVOWpJo.png ... I thought it might have been a valid lat/long coord .. but it's not? Also, when I try your code, the map region is slightly larger than the current one so it's not getting an exact copy. This in effect, means every time i move, i'm zooming out slowly until i can't, anymore. – Pure.Krome Jan 22 '14 at 13:28
  • the deltas are the "width" (long > north to south) and "height" (lat > west to east) of the region. i subtract/add `delta * 0.5` to the center coordinate in order to get the 4 coordinates (loc1 > west, loc2 > east, loc3 > north, loc4 > south). There will always be a little discrepancy since the conversion from degrees to meters is always a little bit lossy (due to the earth's curvature). You could also store the center coordinate and lat/long deltas to recreate the region. – Hannes Jan 22 '14 at 22:02
  • @Hannes I added a followup question regarding your answer here, could you take a look here https://stackoverflow.com/questions/40206211/how-can-i-center-my-map-on-the-annotation-view-only-when-it-is-close-to-the-edge ? Thanks! – user3766930 Oct 26 '16 at 16:17
20

Swift implementation for Hanne's solution:

    let span = mapView.region.span
    let center = mapView.region.center
    
    let loc1 = CLLocation(latitude: center.latitude - span.latitudeDelta * 0.5, longitude: center.longitude)
    let loc2 = CLLocation(latitude: center.latitude + span.latitudeDelta * 0.5, longitude: center.longitude)
    let loc3 = CLLocation(latitude: center.latitude, longitude: center.longitude - span.longitudeDelta * 0.5)
    let loc4 = CLLocation(latitude: center.latitude, longitude: center.longitude + span.longitudeDelta * 0.5)
    
    let metersInLatitude = loc1.distanceFromLocation(loc2)
    let metersInLongitude = loc3.distanceFromLocation(loc4)

EDIT:

For Swift 5 distanceFromLocation(_:) has been renamed to distance(from:) meaning that the two last lines now read

   let metersInLatitude = loc1.distance(from: loc2)
   let metersInLongitude = loc3.distance(from: loc4)
Fredrik
  • 971
  • 8
  • 23
Stephen Silber
  • 263
  • 3
  • 10
  • I added a followup question regarding your answer here, could you take a look here https://stackoverflow.com/questions/40206211/how-can-i-center-my-map-on-the-annotation-view-only-when-it-is-close-to-the-edge ? Thanks! – user3766930 Oct 26 '16 at 16:18
5

Based on the above, here's a useful extension I use in my mapping projects:

extension MKCoordinateRegion {
    public var radius: CLLocationDistance {
        let loc1 = CLLocation(latitude: center.latitude - span.latitudeDelta * 0.5, longitude: center.longitude)
        let loc2 = CLLocation(latitude: center.latitude + span.latitudeDelta * 0.5, longitude: center.longitude)
        let loc3 = CLLocation(latitude: center.latitude, longitude: center.longitude - span.longitudeDelta * 0.5)
        let loc4 = CLLocation(latitude: center.latitude, longitude: center.longitude + span.longitudeDelta * 0.5)
    
        let metersInLatitude = loc1.distance(from: loc2)
        let metersInLongitude = loc3.distance(from: loc4)
        let radius = max(metersInLatitude, metersInLongitude) / 2.0
        return radius
    }
}
Sherwin Zadeh
  • 1,339
  • 15
  • 17