dispatchMain
dispatchMain

Reputation: 1617

Center coordinate of a set of CLLocationsCoordinate2D

Is there any way to get center coordinate of a set of CLLocationsCoordinate2D in iOS?

enter image description here

Upvotes: 8

Views: 10846

Answers (7)

Thanh-Nhon Nguyen
Thanh-Nhon Nguyen

Reputation: 3418

A small Array extension with no magic numbers like -200.0

extension Array where Element == CLLocationCoordinate2D {
    func center() -> CLLocationCoordinate2D {
        var maxLatitude: Double = -.greatestFiniteMagnitude
        var maxLongitude: Double = -.greatestFiniteMagnitude
        var minLatitude: Double = .greatestFiniteMagnitude
        var minLongitude: Double = .greatestFiniteMagnitude

        for location in self {
            maxLatitude = Swift.max(maxLatitude, location.latitude)
            maxLongitude = Swift.max(maxLongitude, location.longitude)
            minLatitude = Swift.min(minLatitude, location.latitude)
            minLongitude = Swift.min(minLongitude, location.longitude)
        }

        let centerLatitude = CLLocationDegrees((maxLatitude + minLatitude) * 0.5)
        let centerLongitude = CLLocationDegrees((maxLongitude + minLongitude) * 0.5)
        return .init(latitude: centerLatitude, longitude: centerLongitude)
    }
}

Upvotes: 1

Stremovskyy
Stremovskyy

Reputation: 502

And Swift 5 compatible extension

extension Array where Element == CLLocationCoordinate2D {
func center() -> CLLocationCoordinate2D {
    var maxLatitude: Double = -200;
    var maxLongitude: Double = -200;
    var minLatitude: Double = Double(MAXFLOAT);
    var minLongitude: Double = Double(MAXFLOAT);

    for location in self {
        if location.latitude < minLatitude {
            minLatitude = location.latitude;
        }

        if location.longitude < minLongitude {
            minLongitude = location.longitude;
        }

        if location.latitude > maxLatitude {
            maxLatitude = location.latitude;
        }

        if location.longitude > maxLongitude {
            maxLongitude = location.longitude;
        }
    }

    return CLLocationCoordinate2DMake(CLLocationDegrees((maxLatitude + minLatitude) * 0.5), CLLocationDegrees((maxLongitude + minLongitude) * 0.5));
}

}

Upvotes: 7

Adrian
Adrian

Reputation: 16715

You can also get both the center of an array of CLLocationCoordinate2Ds and a span.

extension MKCoordinateRegion {

  init(coordinates: [CLLocationCoordinate2D]) {
    var minLatitude: CLLocationDegrees = 90.0
    var maxLatitude: CLLocationDegrees = -90.0
    var minLongitude: CLLocationDegrees = 180.0
    var maxLongitude: CLLocationDegrees = -180.0

    for coordinate in coordinates {
      let lat = Double(coordinate.latitude)
      let long = Double(coordinate.longitude)
      if lat < minLatitude {
        minLatitude = lat
      }
      if long < minLongitude {
        minLongitude = long
      }
      if lat > maxLatitude {
        maxLatitude = lat
      }
      if long > maxLongitude {
        maxLongitude = long
      }
    }

    let span = MKCoordinateSpanMake(maxLatitude - minLatitude, maxLongitude - minLongitude)
    let center = CLLocationCoordinate2DMake((maxLatitude - span.latitudeDelta / 2), (maxLongitude - span.longitudeDelta / 2))
    self.init(center: center, span: span)
  }
}

Usage:

let region = MKCoordinateRegion(coordinates: coordinates)
region.center
region.span

Upvotes: 6

Fogmeister
Fogmeister

Reputation: 77631

Hmm... it depends how you define the centre of the points. Does it depend on the distribution etc...

An easy way to do it is as follows...

//find rect that encloses all coords

float maxLat = -200;
float maxLong = -200;
float minLat = MAXFLOAT;
float minLong = MAXFLOAT;

for (int i=0 ; i<[locations count] ; i++) {
    CLLocationCoordinate2D location = [locations objectAtIndex:i];

    if (location.latitude < minLat) {
        minLat = location.latitude;
    }

    if (location.longitude < minLong) {
        minLong = location.longitude;
    }

    if (location.latitude > maxLat) {
        maxLat = location.latitude;
    }

    if (location.longitude > maxLong) {
        maxLong = location.longitude;
    }
}

//Center point

CLLocationCoordinate2D center = CLLocationCoordinate2DMake((maxLat + minLat) * 0.5, (maxLong + minLong) * 0.5);

This will give the center of the rect covering all the points. However it does not take the spread into account.

i.e.

. = point
X = centre

.....               X                   .

EDIT

Corrected some of the maths.

Upvotes: 14

Aaron A.
Aaron A.

Reputation: 311

Fogmeisters answer will work but has 3 errors, which I have corrected below:

//find rect that encloses all coords

float maxLat = -200;
float maxLong = -200;
float minLat = MAXFLOAT;
float minLong = MAXFLOAT;

for (int i=0 ; i<[locations count] ; i++) {
CLLocationCoordinate2D location = [locations objectAtIndex:i];

    if (location.latitude < minLat) {
        minLat = location.latitude;
    }

    if (location.longitude < minLong) {
        minLong = location.longitude;
    }

    if (location.latitude > maxLat) {
        maxLat = location.latitude;
    }

    if (location.longitude > maxLong) { //Change to be greater than
        maxLong = location.longitude;
    }
}

//Center point
//The min's and max's should be ADDED not subtracted
CLLocationCoordinate2D center = CLLocationCoordinate2DMake((maxLat + minLat) * 0.5, (maxLong + minLong) * 0.5);

Upvotes: 1

Heavy_Bullets
Heavy_Bullets

Reputation: 508

I know it's really late but someone could read this and help himself Using Fogmeister answer you could create a MKCoordinateRegion

CLLocationDegrees minLat,minLng,maxLat,maxLng;
for(CLLocationCoordinate2D coordinate in coordinates) {
    minLat = MIN(minLat, coordinate.latitude);
    minLng = MIN(minLng, coordinate.longitude);

    maxLat = MAX(maxLat, coordinate.latitude);
    maxLng = MAX(maxLng, coordinate.longitude);
}

CLLocationCoordinate2D coordinateOrigin = CLLocationCoordinate2DMake(minLat, minLng);
CLLocationCoordinate2D coordinateMax = CLLocationCoordinate2DMake(maxLat, maxLng);

MKMapPoint upperLeft = MKMapPointForCoordinate(coordinateOrigin);
MKMapPoint lowerRight = MKMapPointForCoordinate(coordinateMax);

//Create the map rect
MKMapRect mapRect = MKMapRectMake(upperLeft.x,
                                  upperLeft.y,
                                  lowerRight.x - upperLeft.x,
                                  lowerRight.y - upperLeft.y);

//Create the region
MKCoordinateRegion region = MKCoordinateRegionForMapRect(mapRect);

//THIS HAS THE CENTER, it should include spread
CLLocationCoordinate2D centerCoordinate = region.center;

Greetings!!!

Upvotes: 5

Craig
Craig

Reputation: 8294

If you're looking for the average as the center then you sum up all the lats and longs into their own totals and then divide by the number of coordinates you have, pretty standard maths.

(Note this won't work if you coords span the date line)

Upvotes: 1

Related Questions