The prime meridian is the line of 0° longitude, the starting point for measuring distance both east and west around the Earth. The prime meridian is arbitrary, meaning it could be chosen to be anywhere.
There are two options for averaging coordinates. The first involves math skills and can be done manually. The second is an automatic feature available on some GPS receivers. If you are fortunate enough to have a GPS receiver with a feature that will average for you, then by all means find out how to use it!
Thanks! Here is a C# version of OP's solutions using degrees. It utilises the System.Device.Location.GeoCoordinate class
public static GeoCoordinate GetCentralGeoCoordinate(
IList<GeoCoordinate> geoCoordinates)
{
if (geoCoordinates.Count == 1)
{
return geoCoordinates.Single();
}
double x = 0;
double y = 0;
double z = 0;
foreach (var geoCoordinate in geoCoordinates)
{
var latitude = geoCoordinate.Latitude * Math.PI / 180;
var longitude = geoCoordinate.Longitude * Math.PI / 180;
x += Math.Cos(latitude) * Math.Cos(longitude);
y += Math.Cos(latitude) * Math.Sin(longitude);
z += Math.Sin(latitude);
}
var total = geoCoordinates.Count;
x = x / total;
y = y / total;
z = z / total;
var centralLongitude = Math.Atan2(y, x);
var centralSquareRoot = Math.Sqrt(x * x + y * y);
var centralLatitude = Math.Atan2(z, centralSquareRoot);
return new GeoCoordinate(centralLatitude * 180 / Math.PI, centralLongitude * 180 / Math.PI);
}
The simple approach of just averaging them has weird edge cases with angles when they wrap from 359' back to 0'.
A much earlier question on SO asked about finding the average of a set of compass angles.
An expansion of the approach recommended there for spherical coordinates would be:
I found this post very useful so here is the solution in PHP. I've been using this successfully and just wanted to save another dev some time.
/**
* Get a center latitude,longitude from an array of like geopoints
*
* @param array data 2 dimensional array of latitudes and longitudes
* For Example:
* $data = array
* (
* 0 = > array(45.849382, 76.322333),
* 1 = > array(45.843543, 75.324143),
* 2 = > array(45.765744, 76.543223),
* 3 = > array(45.784234, 74.542335)
* );
*/
function GetCenterFromDegrees($data)
{
if (!is_array($data)) return FALSE;
$num_coords = count($data);
$X = 0.0;
$Y = 0.0;
$Z = 0.0;
foreach ($data as $coord)
{
$lat = $coord[0] * pi() / 180;
$lon = $coord[1] * pi() / 180;
$a = cos($lat) * cos($lon);
$b = cos($lat) * sin($lon);
$c = sin($lat);
$X += $a;
$Y += $b;
$Z += $c;
}
$X /= $num_coords;
$Y /= $num_coords;
$Z /= $num_coords;
$lon = atan2($Y, $X);
$hyp = sqrt($X * $X + $Y * $Y);
$lat = atan2($Z, $hyp);
return array($lat * 180 / pi(), $lon * 180 / pi());
}
Very useful post! I've implemented this in JavaScript, hereby my code. I've used this successfully.
function rad2degr(rad) { return rad * 180 / Math.PI; }
function degr2rad(degr) { return degr * Math.PI / 180; }
/**
* @param latLngInDeg array of arrays with latitude and longtitude
* pairs in degrees. e.g. [[latitude1, longtitude1], [latitude2
* [longtitude2] ...]
*
* @return array with the center latitude longtitude pairs in
* degrees.
*/
function getLatLngCenter(latLngInDegr) {
var LATIDX = 0;
var LNGIDX = 1;
var sumX = 0;
var sumY = 0;
var sumZ = 0;
for (var i=0; i<latLngInDegr.length; i++) {
var lat = degr2rad(latLngInDegr[i][LATIDX]);
var lng = degr2rad(latLngInDegr[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 / latLngInDegr.length;
var avgY = sumY / latLngInDegr.length;
var avgZ = sumZ / latLngInDegr.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 ([rad2degr(lat), rad2degr(lng)]);
}
Javascript version of the original function
/**
* Get a center latitude,longitude from an array of like geopoints
*
* @param array data 2 dimensional array of latitudes and longitudes
* For Example:
* $data = array
* (
* 0 = > array(45.849382, 76.322333),
* 1 = > array(45.843543, 75.324143),
* 2 = > array(45.765744, 76.543223),
* 3 = > array(45.784234, 74.542335)
* );
*/
function GetCenterFromDegrees(data)
{
if (!(data.length > 0)){
return false;
}
var num_coords = data.length;
var X = 0.0;
var Y = 0.0;
var Z = 0.0;
for(i = 0; i < data.length; i++){
var lat = data[i][0] * Math.PI / 180;
var lon = data[i][1] * Math.PI / 180;
var a = Math.cos(lat) * Math.cos(lon);
var b = Math.cos(lat) * Math.sin(lon);
var c = Math.sin(lat);
X += a;
Y += b;
Z += c;
}
X /= num_coords;
Y /= num_coords;
Z /= num_coords;
var lon = Math.atan2(Y, X);
var hyp = Math.sqrt(X * X + Y * Y);
var lat = Math.atan2(Z, hyp);
var newX = (lat * 180 / Math.PI);
var newY = (lon * 180 / Math.PI);
return new Array(newX, newY);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With