Я рассчитываю расстояние между двумя географическими координатами. Я тестирую свое приложение против 3-4 других приложений. Когда я рассчитываю расстояние, я обычно получаю в среднем 3,3 мили для своих расчетов, тогда как другие приложения получают 3,5 мили. Это большая разница для вычислений, которые я пытаюсь выполнить. Есть ли какие-нибудь хорошие библиотеки классов для расчета расстояния? Я рассчитываю это так на C #:
public static double Calculate(double sLatitude,double sLongitude, double eLatitude,
double eLongitude)
{
var radiansOverDegrees = (Math.PI / 180.0);
var sLatitudeRadians = sLatitude * radiansOverDegrees;
var sLongitudeRadians = sLongitude * radiansOverDegrees;
var eLatitudeRadians = eLatitude * radiansOverDegrees;
var eLongitudeRadians = eLongitude * radiansOverDegrees;
var dLongitude = eLongitudeRadians - sLongitudeRadians;
var dLatitude = eLatitudeRadians - sLatitudeRadians;
var result1 = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) +
Math.Cos(sLatitudeRadians) * Math.Cos(eLatitudeRadians) *
Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);
// Using 3956 as the number of miles around the earth
var result2 = 3956.0 * 2.0 *
Math.Atan2(Math.Sqrt(result1), Math.Sqrt(1.0 - result1));
return result2;
}
Что я делаю не так? Следует ли мне сначала рассчитать его в км, а затем преобразовать в мили?
c#
windows-phone-7
geocoding
latitude-longitude
Джейсон Н. Гейлорд
источник
источник
Ответы:
У класса GeoCoordinate (.NET Framework 4 и выше) уже есть
GetDistanceTo
метод.var sCoord = new GeoCoordinate(sLatitude, sLongitude); var eCoord = new GeoCoordinate(eLatitude, eLongitude); return sCoord.GetDistanceTo(eCoord);
Расстояние в метрах.
Вам нужно сослаться на System.Device.
источник
GetDistance - лучшее решение , но во многих случаях мы не можем использовать этот метод (например, универсальное приложение)
Псевдокод алгоритма вычисления расстояния между координатами:
public static double DistanceTo(double lat1, double lon1, double lat2, double lon2, char unit = 'K') { double rlat1 = Math.PI*lat1/180; double rlat2 = Math.PI*lat2/180; double theta = lon1 - lon2; double rtheta = Math.PI*theta/180; double dist = Math.Sin(rlat1)*Math.Sin(rlat2) + Math.Cos(rlat1)* Math.Cos(rlat2)*Math.Cos(rtheta); dist = Math.Acos(dist); dist = dist*180/Math.PI; dist = dist*60*1.1515; switch (unit) { case 'K': //Kilometers -> default return dist*1.609344; case 'N': //Nautical Miles return dist*0.8684; case 'M': //Miles return dist; } return dist; }
Реальная реализация C # , в которой используются методы расширения
Применение:
var distance = new Coordinates(48.672309, 15.695585) .DistanceTo( new Coordinates(48.237867, 16.389477), UnitOfLength.Kilometers );
Реализация:
public class Coordinates { public double Latitude { get; private set; } public double Longitude { get; private set; } public Coordinates(double latitude, double longitude) { Latitude = latitude; Longitude = longitude; } } public static class CoordinatesDistanceExtensions { public static double DistanceTo(this Coordinates baseCoordinates, Coordinates targetCoordinates) { return DistanceTo(baseCoordinates, targetCoordinates, UnitOfLength.Kilometers); } public static double DistanceTo(this Coordinates baseCoordinates, Coordinates targetCoordinates, UnitOfLength unitOfLength) { var baseRad = Math.PI * baseCoordinates.Latitude / 180; var targetRad = Math.PI * targetCoordinates.Latitude/ 180; var theta = baseCoordinates.Longitude - targetCoordinates.Longitude; var thetaRad = Math.PI * theta / 180; double dist = Math.Sin(baseRad) * Math.Sin(targetRad) + Math.Cos(baseRad) * Math.Cos(targetRad) * Math.Cos(thetaRad); dist = Math.Acos(dist); dist = dist * 180 / Math.PI; dist = dist * 60 * 1.1515; return unitOfLength.ConvertFromMiles(dist); } } public class UnitOfLength { public static UnitOfLength Kilometers = new UnitOfLength(1.609344); public static UnitOfLength NauticalMiles = new UnitOfLength(0.8684); public static UnitOfLength Miles = new UnitOfLength(1); private readonly double _fromMilesFactor; private UnitOfLength(double fromMilesFactor) { _fromMilesFactor = fromMilesFactor; } public double ConvertFromMiles(double input) { return input*_fromMilesFactor; } }
источник
И вот, для тех, кто все еще не удовлетворен, исходный код из
GeoCoordinate
класса .NET-Frameworks , преобразованный в автономный метод:public double GetDistance(double longitude, double latitude, double otherLongitude, double otherLatitude) { var d1 = latitude * (Math.PI / 180.0); var num1 = longitude * (Math.PI / 180.0); var d2 = otherLatitude * (Math.PI / 180.0); var num2 = otherLongitude * (Math.PI / 180.0) - num1; var d3 = Math.Pow(Math.Sin((d2 - d1) / 2.0), 2.0) + Math.Cos(d1) * Math.Cos(d2) * Math.Pow(Math.Sin(num2 / 2.0), 2.0); return 6376500.0 * (2.0 * Math.Atan2(Math.Sqrt(d3), Math.Sqrt(1.0 - d3))); }
источник
double oneDegree = Math.PI / 180.0;
?Вот версия JavaScript, ребята и девчонки
function distanceTo(lat1, lon1, lat2, lon2, unit) { var rlat1 = Math.PI * lat1/180 var rlat2 = Math.PI * lat2/180 var rlon1 = Math.PI * lon1/180 var rlon2 = Math.PI * lon2/180 var theta = lon1-lon2 var rtheta = Math.PI * theta/180 var dist = Math.sin(rlat1) * Math.sin(rlat2) + Math.cos(rlat1) * Math.cos(rlat2) * Math.cos(rtheta); dist = Math.acos(dist) dist = dist * 180/Math.PI dist = dist * 60 * 1.1515 if (unit=="K") { dist = dist * 1.609344 } if (unit=="N") { dist = dist * 0.8684 } return dist }
источник
Для тех, кто использует Xamarin и не имеет доступа к классу GeoCoordinate, вы можете вместо этого использовать класс Android Location:
public static double GetDistanceBetweenCoordinates (double lat1, double lng1, double lat2, double lng2) { var coords1 = new Location (""); coords1.Latitude = lat1; coords1.Longitude = lng1; var coords2 = new Location (""); coords2.Latitude = lat2; coords2.Longitude = lng2; return coords1.DistanceTo (coords2); }
источник
Вы можете использовать эту функцию:
Источник: https://www.geodatasource.com/developers/c-sharp
private double distance(double lat1, double lon1, double lat2, double lon2, char unit) { if ((lat1 == lat2) && (lon1 == lon2)) { return 0; } else { double theta = lon1 - lon2; double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta)); dist = Math.Acos(dist); dist = rad2deg(dist); dist = dist * 60 * 1.1515; if (unit == 'K') { dist = dist * 1.609344; } else if (unit == 'N') { dist = dist * 0.8684; } return (dist); } } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //:: This function converts decimal degrees to radians ::: //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: private double deg2rad(double deg) { return (deg * Math.PI / 180.0); } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //:: This function converts radians to decimal degrees ::: //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: private double rad2deg(double rad) { return (rad / Math.PI * 180.0); } Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "M")); Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "K")); Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "N"));
источник
Для этих платформ есть библиотека GeoCoordinate :
Установка выполняется через NuGet:
Применение
GeoCoordinate pin1 = new GeoCoordinate(lat, lng); GeoCoordinate pin2 = new GeoCoordinate(lat, lng); double distanceBetween = pin1.GetDistanceTo(pin2);
Расстояние между двумя координатами в метрах .
источник
На основе функции Эллиота Вуда, и если кого-то интересует функция C, эта работает ...
#define SIM_Degree_to_Radian(x) ((float)x * 0.017453292F) #define SIM_PI_VALUE (3.14159265359) float GPS_Distance(float lat1, float lon1, float lat2, float lon2) { float theta; float dist; theta = lon1 - lon2; lat1 = SIM_Degree_to_Radian(lat1); lat2 = SIM_Degree_to_Radian(lat2); theta = SIM_Degree_to_Radian(theta); dist = (sin(lat1) * sin(lat2)) + (cos(lat1) * cos(lat2) * cos(theta)); dist = acos(dist); // dist = dist * 180.0 / SIM_PI_VALUE; // dist = dist * 60.0 * 1.1515; // /* Convert to km */ // dist = dist * 1.609344; dist *= 6370.693486F; return (dist); }
Вы можете изменить его на двойной . Возвращает значение в км.
источник
Расчет расстояния между точками широты и долготы ...
double Lat1 = Convert.ToDouble(latitude); double Long1 = Convert.ToDouble(longitude); double Lat2 = 30.678; double Long2 = 45.786; double circumference = 40000.0; // Earth's circumference at the equator in km double distance = 0.0; double latitude1Rad = DegreesToRadians(Lat1); double latititude2Rad = DegreesToRadians(Lat2); double longitude1Rad = DegreesToRadians(Long1); double longitude2Rad = DegreesToRadians(Long2); double logitudeDiff = Math.Abs(longitude1Rad - longitude2Rad); if (logitudeDiff > Math.PI) { logitudeDiff = 2.0 * Math.PI - logitudeDiff; } double angleCalculation = Math.Acos( Math.Sin(latititude2Rad) * Math.Sin(latitude1Rad) + Math.Cos(latititude2Rad) * Math.Cos(latitude1Rad) * Math.Cos(logitudeDiff)); distance = circumference * angleCalculation / (2.0 * Math.PI); return distance;
источник
Это старый вопрос, тем не менее, ответы меня не удовлетворили с точки зрения производительности и оптимизации.
Вот мой оптимизированный вариант C # (расстояние в км, без переменных и избыточных вычислений, очень близко к математическому выражению Haversine Formular https://en.wikipedia.org/wiki/Haversine_formula ).
На основе: https://rosettacode.org/wiki/Haversine_formula#C.23
public static class Haversine { public static double Calculate(double lat1, double lon1, double lat2, double lon2) { double rad(double angle) => angle * 0.017453292519943295769236907684886127d; // = angle * Math.Pi / 180.0d double havf(double diff) => Math.Pow(Math.Sin(rad(diff) / 2d), 2); // = sin²(diff / 2) return 12745.6 * Math.Asin(Math.Sqrt(havf(lat2 - lat1) + Math.Cos(rad(lat1)) * Math.Cos(rad(lat2)) * havf(lon2 - lon1))); // earth radius 6.372,8km x 2 = 12745.6 } }
источник
Попробуй это:
public double getDistance(GeoCoordinate p1, GeoCoordinate p2) { double d = p1.Latitude * 0.017453292519943295; double num3 = p1.Longitude * 0.017453292519943295; double num4 = p2.Latitude * 0.017453292519943295; double num5 = p2.Longitude * 0.017453292519943295; double num6 = num5 - num3; double num7 = num4 - d; double num8 = Math.Pow(Math.Sin(num7 / 2.0), 2.0) + ((Math.Cos(d) * Math.Cos(num4)) * Math.Pow(Math.Sin(num6 / 2.0), 2.0)); double num9 = 2.0 * Math.Atan2(Math.Sqrt(num8), Math.Sqrt(1.0 - num8)); return (6376500.0 * num9); }
источник
Вы можете использовать
System.device.Location
:System.device.Location.GeoCoordinate gc = new System.device.Location.GeoCoordinate(){ Latitude = yourLatitudePt1, Longitude = yourLongitudePt1 }; System.device.Location.GeoCoordinate gc2 = new System.device.Location.GeoCoordinate(){ Latitude = yourLatitudePt2, Longitude = yourLongitudePt2 }; Double distance = gc2.getDistanceTo(gc);
удачи
источник
Когда вычислительная мощность ЦП / математики ограничена:
Бывают случаи (например, в моей работе), когда вычислительная мощность недостаточна (например, нет процессора с плавающей запятой, работа с небольшими микроконтроллерами), когда некоторые триггерные функции могут занимать непомерное количество процессорного времени (например, 3000+ тактовых циклов), поэтому, когда я требуется только приближение, особенно если ЦП не должен быть связан в течение длительного времени, я использую это, чтобы минимизировать накладные расходы ЦП:
/**------------------------------------------------------------------------ * \brief Great Circle distance approximation in km over short distances. * * Can be off by as much as 10%. * * approx_distance_in_mi = sqrt(x * x + y * y) * * where x = 69.1 * (lat2 - lat1) * and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3) *//*----------------------------------------------------------------------*/ double ApproximateDisatanceBetweenTwoLatLonsInKm( double lat1, double lon1, double lat2, double lon2 ) { double ldRadians, ldCosR, x, y; ldRadians = (lat1 / 57.3) * 0.017453292519943295769236907684886; ldCosR = cos(ldRadians); x = 69.1 * (lat2 - lat1); y = 69.1 * (lon2 - lon1) * ldCosR; return sqrt(x * x + y * y) * 1.609344; /* Converts mi to km. */ }
Кредит идет на https://github.com/kristianmandrup/geo_vectors/blob/master/Distance%20calc%20notes.txt .
источник