Determining Midpoint Between 2 Coordinates

Mike D picture Mike D · May 12, 2012 · Viewed 10.4k times · Source

I am trying to determine the midpoint between two locations in an MKMapView. I am following the method outlined here (and here) and rewrote it in Objective-C, but the map is being centered somewhere northeast of Baffin Island, which is no where near the two points.

My method based on the java method linked above:

+(CLLocationCoordinate2D)findCenterPoint:(CLLocationCoordinate2D)_lo1 :(CLLocationCoordinate2D)_loc2 {
    CLLocationCoordinate2D center;

    double lon1 = _lo1.longitude * M_PI / 180;
    double lon2 = _loc2.longitude * M_PI / 100;

    double lat1 = _lo1.latitude * M_PI / 180;
    double lat2 = _loc2.latitude * M_PI / 100;

    double dLon = lon2 - lon1;

    double x = cos(lat2) * cos(dLon);
    double y = cos(lat2) * sin(dLon);

    double lat3 = atan2( sin(lat1) + sin(lat2), sqrt((cos(lat1) + x) * (cos(lat1) + x) + y * y) );
    double lon3 = lon1 + atan2(y, cos(lat1) + x);

    center.latitude  = lat3 * 180 / M_PI;
    center.longitude = lon3 * 180 / M_PI;

    return center;
}

The 2 parameters have the following data:

_loc1:
    latitude = 45.4959839
    longitude = -73.67826455

_loc2:
    latitude = 45.482889
    longitude = -73.57522299

The above are correctly place on the map (in and around Montreal). I am trying to center the map in the midpoint between the 2, yet my method return the following:

latitude = 65.29055
longitude = -82.55425

which somewhere in the arctic, when it should be around 500 miles south.

Answer

grandagile picture grandagile · May 21, 2015

In case someone need code in Swift, I have written library function in Swift to calculate the midpoint between MULTIPLE coordinates:

//        /** Degrees to Radian **/
class func degreeToRadian(angle:CLLocationDegrees) -> CGFloat {
    return (  (CGFloat(angle)) / 180.0 * CGFloat(M_PI)  )
}

//        /** Radians to Degrees **/
class func radianToDegree(radian:CGFloat) -> CLLocationDegrees {
    return CLLocationDegrees(  radian * CGFloat(180.0 / M_PI)  )
}

class func middlePointOfListMarkers(listCoords: [CLLocationCoordinate2D]) -> CLLocationCoordinate2D {

    var x = 0.0 as CGFloat
    var y = 0.0 as CGFloat
    var z = 0.0 as CGFloat

    for coordinate in listCoords{
        var lat:CGFloat = degreeToRadian(coordinate.latitude)
        var lon:CGFloat = degreeToRadian(coordinate.longitude)
        x = x + cos(lat) * cos(lon)
        y = y + cos(lat) * sin(lon)
        z = z + sin(lat)
    }

    x = x/CGFloat(listCoords.count)
    y = y/CGFloat(listCoords.count)
    z = z/CGFloat(listCoords.count)

    var resultLon: CGFloat = atan2(y, x)
    var resultHyp: CGFloat = sqrt(x*x+y*y)
    var resultLat:CGFloat = atan2(z, resultHyp)

    var newLat = radianToDegree(resultLat)
    var newLon = radianToDegree(resultLon)
    var result:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: newLat, longitude: newLon)

    return result

}

Detailed answer can be found here

Updated For Swift 5

func geographicMidpoint(betweenCoordinates coordinates: [CLLocationCoordinate2D]) -> CLLocationCoordinate2D {

    guard coordinates.count > 1 else {
        return coordinates.first ?? // return the only coordinate
            CLLocationCoordinate2D(latitude: 0, longitude: 0) // return null island if no coordinates were given
    }

    var x = Double(0)
    var y = Double(0)
    var z = Double(0)

    for coordinate in coordinates {
        let lat = coordinate.latitude.toRadians()
        let lon = coordinate.longitude.toRadians()
        x += cos(lat) * cos(lon)
        y += cos(lat) * sin(lon)
        z += sin(lat)
    }

    x /= Double(coordinates.count)
    y /= Double(coordinates.count)
    z /= Double(coordinates.count)

    let lon = atan2(y, x)
    let hyp = sqrt(x * x + y * y)
    let lat = atan2(z, hyp)

    return CLLocationCoordinate2D(latitude: lat.toDegrees(), longitude: lon.toDegrees())
}

}