我正在计算两个地理坐标之间的距离。我正在针对 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;
}
我可能做错了什么?我应该先以公里计算,然后再转换为英里吗?
GeoCoordinate 类(.NET Framework 4 和更高版本)已经有 GetDistanceTo
方法。
var sCoord = new GeoCoordinate(sLatitude, sLongitude);
var eCoord = new GeoCoordinate(eLatitude, eLongitude);
return sCoord.GetDistanceTo(eCoord);
距离以米为单位。
您需要引用 System.Device。
GetDistance 是最好的解决方案,但是在很多情况下我们不能使用这个方法(例如 Universal App)
计算坐标之间距离的算法伪代码: public static double DistanceTo(double lat1, double lon1, double lat2, double lon2, char unit = 'K') { double rlat1 = Math.PI*lat1/180;双 rlat2 = Math.PI*lat2/180;双 theta = lon1 - lon2;双 rtheta = Math.PI*theta/180;双距离 = Math.Sin(rlat1)*Math.Sin(rlat2) + Math.Cos(rlat1)* Math.Cos(rlat2)*Math.Cos(rtheta); dist = Math.Acos(dist); dist = dist*180/Math.PI;距离=距离*60*1.1515; switch (unit) { case 'K': //公里 -> 默认返回 dist*1.609344; case 'N': //海里返回 dist*0.8684; case 'M': //里程返回 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;私人套装; } 公共双经度 { 得到;私人套装; } 公共坐标(双纬度,双经度){纬度=纬度;经度=经度; } } 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;双距离 = Math.Sin(baseRad) * Math.Sin(targetRad) + Math.Cos(baseRad) * Math.Cos(targetRad) * Math.Cos(thetaRad); dist = Math.Acos(dist); dist = dist * 180 / Math.PI;距离 = 距离 * 60 * 1.1515;返回 unitOfLength.ConvertFromMiles(dist); } } 公共类 UnitOfLength { 公共静态 UnitOfLength 公里 = 新 UnitOfLength(1.609344);公共静态 UnitOfLength NauticalMiles = new UnitOfLength(0.8684);公共静态单位长度英里=新单位长度(1);私有只读双 _fromMilesFactor;私人 UnitOfLength(双 fromMilesFactor){ _fromMilesFactor = fromMilesFactor; } public double ConvertFromMiles(double input) { return input*_fromMilesFactor; } }
在这里,对于那些仍然不满意的人(比如我),来自 .NET-Frameworks GeoCoordinate
类的原始代码被重构为一个独立的方法:
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
}
rlon1
和 `rlon2' 做什么?
对于那些使用 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);
}
这些平台有这个库 GeoCoordinate:
单核细胞增多症
.NET 4.5
.NET 核心
视窗电话 8.x
通用 Windows 平台
Xamarin iOS
Xamarin Android
安装是通过 NuGet 完成的:
PM> Install-Package GeoCoordinate
用法
GeoCoordinate pin1 = new GeoCoordinate(lat, lng);
GeoCoordinate pin2 = new GeoCoordinate(lat, lng);
double distanceBetween = pin1.GetDistanceTo(pin2);
两个坐标之间的距离,以米为单位。
这是一个老问题,但是关于性能和优化的答案并没有让我满意。
这是我优化的 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
}
}
https://i.stack.imgur.com/d9Twv.png
您可以使用此功能:
来源: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"));
基于 Elliot Wood 的函数,如果有人对 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;
当 CPU/数学计算能力有限时:
有时(例如在我的工作中)计算能力稀缺(例如,没有浮点处理器,使用小型微控制器),其中一些三角函数可能会占用过多的 CPU 时间(例如 3000 多个时钟周期),所以当我只需要一个近似值,特别是如果 CPU 不能长时间占用,我使用它来最小化 CPU 开销:
/**------------------------------------------------------------------------
* \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。
尝试这个:
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);
祝你好运