我使用 dot42 制作了一个示例项目,并将此 C# 代码放入库中:
var gcd = GetGreatCircleDistanceKm(52.0, -1.90, 21.0, 39.0); // returns NaN should be ~4915
public double GetGreatCircleDistanceKm(double startLat, double startLong, double endLat, double endLong)
{
var earthRadius = Constants.EarthRadiusKm;
var φ1 = DegreesToRadians(startLat);
var φ2 = DegreesToRadians(endLat);
var Δφ = DegreesToRadians(endLat - startLat);
var Δλ = DegreesToRadians(endLong - startLong);
var a = Math.Sin(Δφ / 2) * Math.Sin(Δφ / 2) + Math.Cos(φ1) * Math.Cos(φ2) * Math.Sin(Δλ / 2) * Math.Sin(Δλ / 2);
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
return earthRadius * c;
}
public static double DegreesToRadians(double angle)
{
return Math.PI * angle / 180.0;
}
然而,问题是c
总是返回NaN
,因此函数返回NaN
。同样的方法在普通的 .net 项目中也能正常工作。
我尝试了同一个haversine
公式的许多版本,认为我可能打错了一些东西,但不,全部返回NaN
。
公式来源:http ://www.movable-type.co.uk/scripts/latlong.html
解决方案是(奇怪地)这样做:
var a1 = Δφ/2;
var a = Math.Sin(a1) * Math.Sin(a1) + Math.Cos(φ1) * Math.Cos(φ2) * Math.Sin(Δλ / 2) * Math.Sin(Δλ / 2);
不知道它是如何工作的,但它确实有效。请如果有人可以阐明。
完全固定版本:
/// <summary>
/// Gets the shortest possible distance between two points on earth
/// </summary>
/// <param name="startLat"></param>
/// <param name="startLong"></param>
/// <param name="endLat"></param>
/// <param name="endLong"></param>
/// <returns></returns>
public double GetGreatCircleDistanceKm(double startLat, double startLong, double endLat, double endLong)
{
var startLatRad = DegreesToRadians(startLat);
var endLatRad = DegreesToRadians(endLat);
var latDiffRad = DegreesToRadians(endLat - startLat);
var longDiffRad = DegreesToRadians(endLong - startLong);
var halfLatDiff = latDiffRad/2;
var a = Math.Sin(halfLatDiff) * Math.Sin(halfLatDiff) + Math.Cos(startLatRad) * Math.Cos(endLatRad) * Math.Sin(longDiffRad / 2) * Math.Sin(longDiffRad / 2);
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
return Constants.EarthRadiusKm * c;
}