Вычисление расстояния между двумя точками на поверхности Земли с использованием координат широты и долготы — обычная задача во многих приложениях. В этой статье блога мы рассмотрим различные методы расчета расстояния в C#, а также приведем примеры кода. Мы рассмотрим две популярные формулы: формулу Хаверсина и формулу Винсенти. Давайте погрузимся!
Метод 1: формула гаверсинуса
Формула гаверсинуса — это широко используемый метод расчета расстояния между двумя точками на сфере (например, на Земле) с использованием их координат широты и долготы. Вот пример реализации этого на C#:
public static double HaversineDistance(double lat1, double lon1, double lat2, double lon2)
{
const double radius = 6371; // Earth's radius in kilometers
var dLat = DegreesToRadians(lat2 - lat1);
var dLon = DegreesToRadians(lon2 - lon1);
var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
Math.Cos(DegreesToRadians(lat1)) * Math.Cos(DegreesToRadians(lat2)) *
Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
var distance = radius * c;
return distance;
}
public static double DegreesToRadians(double degrees)
{
return degrees * Math.PI / 180;
}
Метод 2: формула Винсенти
Формула Винсенти обеспечивает более точный расчет расстояния между двумя точками на эллипсоидальной модели Земли. Вот пример реализации этого на C#:
public static double VincentyDistance(double lat1, double lon1, double lat2, double lon2)
{
const double a = 6378137; // semi-major axis of the ellipsoid in meters
const double b = 6356752.314245; // semi-minor axis of the ellipsoid in meters
const double f = 1 / 298.257223563; // flattening of the ellipsoid
var L = DegreesToRadians(lon2 - lon1);
var U1 = Math.Atan((1 - f) * Math.Tan(DegreesToRadians(lat1)));
var U2 = Math.Atan((1 - f) * Math.Tan(DegreesToRadians(lat2)));
var sinU1 = Math.Sin(U1);
var cosU1 = Math.Cos(U1);
var sinU2 = Math.Sin(U2);
var cosU2 = Math.Cos(U2);
double lambda = L;
double lambdaP;
double iterLimit = 100;
do
{
var sinLambda = Math.Sin(lambda);
var cosLambda = Math.Cos(lambda);
var sinSigma = Math.Sqrt(
Math.Pow(cosU2 * sinLambda, 2) +
Math.Pow(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda, 2)
);
if (sinSigma == 0)
{
return 0; // coincident points
}
var cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
var sigma = Math.Atan2(sinSigma, cosSigma);
var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
var cosSqAlpha = 1 - Math.Pow(sinAlpha, 2);
var cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
lambdaP = lambda;
lambda = L + (1 - C) * f * sinAlpha *
(sigma + C * sinSigma *
(cos2SigmaM + C * cosSigma *
(-1 + 2 * Math.Pow(cos2SigmaM, 2))));
iterLimit--;
} while (Math.Abs(lambda - lambdaP) > 1e-12 && iterLimit > 0);
if (iterLimit == 0)
{
return double.NaN; // formula failed to converge
}
var uSq = cosSqAlpha * (Math.Pow(a, 2) - Math.Pow(b, 2)) / Math.Pow(b, 2);
var A = 1 + uSq / 16384 *
(4096 + uSq *8192 + uSq * (uSq * 16384 - 7680));
var B = uSq / 1024 *
(256 + uSq * (uSq * 16384 - 4096));
var deltaSigma = B * sinSigma *
(cos2SigmaM + B / 4 *
(cosSigma * (-1 + 2 * Math.Pow(cos2SigmaM, 2)) - B / 6 *
cos2SigmaM * (-3 + 4 * Math.Pow(sinSigma, 2)) *
(-3 + 4 * Math.Pow(cos2SigmaM, 2))));
var distance = b * A * (sigma - deltaSigma);
return distance;
}
В этой статье мы рассмотрели два популярных метода расчета расстояний с использованием координат широты и долготы в C#. Формула Хаверсина обеспечивает простое приближение, а формула Винсенти обеспечивает более высокую точность для эллипсоидальной модели Земли. В зависимости от ваших конкретных требований вы можете выбрать метод, который лучше всего соответствует вашим потребностям. Не стесняйтесь использовать предоставленные примеры кода в качестве отправной точки для собственных реализаций.
Не забудьте обработать проверку ввода, преобразование градусов в радианы и случаи ошибок в окончательной реализации. Приятного кодирования!