Given a set of latitude and longitude points, how can I calculate the latitude and longitude of the center point of that set (aka a point that would center a view on all poi
In the interest of possibly saving someone a minute or two, here is the solution that was used in Objective-C instead of python. This version takes an NSArray of NSValues that contain MKMapCoordinates, which was called for in my implementation:
#import <MapKit/MKGeometry.h>
+ (CLLocationCoordinate2D)centerCoordinateForCoordinates:(NSArray *)coordinateArray {
double x = 0;
double y = 0;
double z = 0;
for(NSValue *coordinateValue in coordinateArray) {
CLLocationCoordinate2D coordinate = [coordinateValue MKCoordinateValue];
double lat = GLKMathDegreesToRadians(coordinate.latitude);
double lon = GLKMathDegreesToRadians(coordinate.longitude);
x += cos(lat) * cos(lon);
y += cos(lat) * sin(lon);
z += sin(lat);
}
x = x / (double)coordinateArray.count;
y = y / (double)coordinateArray.count;
z = z / (double)coordinateArray.count;
double resultLon = atan2(y, x);
double resultHyp = sqrt(x * x + y * y);
double resultLat = atan2(z, resultHyp);
CLLocationCoordinate2D result = CLLocationCoordinate2DMake(GLKMathRadiansToDegrees(resultLat), GLKMathRadiansToDegrees(resultLon));
return result;
}
Here is the python Version for finding center point. The lat1 and lon1 are latitude and longitude lists. it will retuen the latitude and longitude of center point.
def GetCenterFromDegrees(lat1,lon1):
if (len(lat1) <= 0):
return false;
num_coords = len(lat1)
X = 0.0
Y = 0.0
Z = 0.0
for i in range (len(lat1)):
lat = lat1[i] * np.pi / 180
lon = lon1[i] * np.pi / 180
a = np.cos(lat) * np.cos(lon)
b = np.cos(lat) * np.sin(lon)
c = np.sin(lat);
X += a
Y += b
Z += c
X /= num_coords
Y /= num_coords
Z /= num_coords
lon = np.arctan2(Y, X)
hyp = np.sqrt(X * X + Y * Y)
lat = np.arctan2(Z, hyp)
newX = (lat * 180 / np.pi)
newY = (lon * 180 / np.pi)
return newX, newY
Dart Implementation for Flutter to find Center point for Multiple Latitude, Longitude.
import math package
import 'dart:math' as math;
Latitude and Longitude List
List<LatLng> latLongList = [LatLng(12.9824, 80.0603),LatLng(13.0569,80.2425,)];
LatLng getCenterLatLong(List<LatLng> latLongList) {
double pi = math.pi / 180;
double xpi = 180 / math.pi;
double x = 0, y = 0, z = 0;
if(latLongList.length==1)
{
return latLongList[0];
}
for (int i = 0; i < latLongList.length; i++) {
double latitude = latLongList[i].latitude * pi;
double longitude = latLongList[i].longitude * pi;
double c1 = math.cos(latitude);
x = x + c1 * math.cos(longitude);
y = y + c1 * math.sin(longitude);
z = z + math.sin(latitude);
}
int total = latLongList.length;
x = x / total;
y = y / total;
z = z / total;
double centralLongitude = math.atan2(y, x);
double centralSquareRoot = math.sqrt(x * x + y * y);
double centralLatitude = math.atan2(z, centralSquareRoot);
return LatLng(centralLatitude*xpi,centralLongitude*xpi);
}
Dart/Flutter Calculate the center point of multiple latitude/longitude coordinate pairs
Map<String, double> getLatLngCenter(List<List<double>> coords) {
const LATIDX = 0;
const LNGIDX = 1;
double sumX = 0;
double sumY = 0;
double sumZ = 0;
for (var i = 0; i < coords.length; i++) {
var lat = VectorMath.radians(coords[i][LATIDX]);
var lng = VectorMath.radians(coords[i][LNGIDX]);
// sum of cartesian coordinates
sumX += Math.cos(lat) * Math.cos(lng);
sumY += Math.cos(lat) * Math.sin(lng);
sumZ += Math.sin(lat);
}
var avgX = sumX / coords.length;
var avgY = sumY / coords.length;
var avgZ = sumZ / coords.length;
// convert average x, y, z coordinate to latitude and longtitude
var lng = Math.atan2(avgY, avgX);
var hyp = Math.sqrt(avgX * avgX + avgY * avgY);
var lat = Math.atan2(avgZ, hyp);
return {
"latitude": VectorMath.degrees(lat),
"longitude": VectorMath.degrees(lng)
};
}
Java Version if anyone needs it. Constants defined static to not calculate them twice.
/**************************************************************************************************************
* Center of geometry defined by coordinates
**************************************************************************************************************/
private static double pi = Math.PI / 180;
private static double xpi = 180 / Math.PI;
public static Coordinate center(Coordinate... arr) {
if (arr.length == 1) {
return arr[0];
}
double x = 0, y = 0, z = 0;
for (Coordinate c : arr) {
double latitude = c.lat() * pi, longitude = c.lon() * pi;
double cl = Math.cos(latitude);//save it as we need it twice
x += cl * Math.cos(longitude);
y += cl * Math.sin(longitude);
z += Math.sin(latitude);
}
int total = arr.length;
x = x / total;
y = y / total;
z = z / total;
double centralLongitude = Math.atan2(y, x);
double centralSquareRoot = Math.sqrt(x * x + y * y);
double centralLatitude = Math.atan2(z, centralSquareRoot);
return new Coordinate(centralLatitude * xpi, centralLongitude * xpi);
}
I used a formula that I got from www.geomidpoint.com and wrote the following C++ implementation. The array
and geocoords
are my own classes whose functionality should be self-explanatory.
/*
* midpoints calculated using formula from www.geomidpoint.com
*/
geocoords geocoords::calcmidpoint( array<geocoords>& points )
{
if( points.empty() ) return geocoords();
float cart_x = 0,
cart_y = 0,
cart_z = 0;
for( auto& point : points )
{
cart_x += cos( point.lat.rad() ) * cos( point.lon.rad() );
cart_y += cos( point.lat.rad() ) * sin( point.lon.rad() );
cart_z += sin( point.lat.rad() );
}
cart_x /= points.numelems();
cart_y /= points.numelems();
cart_z /= points.numelems();
geocoords mean;
mean.lat.rad( atan2( cart_z, sqrt( pow( cart_x, 2 ) + pow( cart_y, 2 ))));
mean.lon.rad( atan2( cart_y, cart_x ));
return mean;
}