Trying to get the span size in meters for an iOS MKCoordinateSpan
Asked Answered
B

3

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...

Big answered 22/1, 2014 at 2:51 Comment(5)
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.Veach
By the way, the delta values are in degrees (just like the center coordinate).Veach
Are you 100% sure @Anna ? This is the current data I have for my test data (the free drive in the iOS Simulator). i.imgur.com/fVOWpJo.png Notice the LatitudeDelta is not a valid latitude value (+/-90) ....Big
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).Veach
Perhaps the documentation for MKCoordinateSpan explains it better: developer.apple.com/library/ios/documentation/MapKit/Reference/…Veach
P
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];
Prudenceprudent answered 22/1, 2014 at 6:10 Comment(4)
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).Big
Why the XXX_Delta * 0.5? and what value is a Delta, really? here's a screen shot of my values ... 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.Big
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.Prudenceprudent
@Prudenceprudent I added a followup question regarding your answer here, could you take a look here #40206711 ? Thanks!Bouncy
F
22

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)
Formidable answered 11/1, 2016 at 14:45 Comment(1)
I added a followup question regarding your answer here, could you take a look here #40206711 ? Thanks!Bouncy
N
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
    }
}
Navvy answered 10/9, 2021 at 0:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.