我正在尝试使用Haversine公式计算两个地理坐标之间的距离(以公里为单位)。

码:

Dim dbl_dLat As Double
Dim dbl_dLon As Double
Dim dbl_a As Double

dbl_P = WorksheetFunction.Pi / 180
dbl_dLat = dbl_P * (dbl_Latitude2 - dbl_Latitude1)
dbl_dLon = dbl_P * (dbl_Longitude2 - dbl_Longitude1)

dbl_a = Sin(dbl_dLat / 2) * Sin(dbl_dLat / 2) + Cos(dbl_Latitude1 * dbl_P) * Cos(dbl_Latitude2 * dbl_P) * Sin(dbl_dLon / 2) * Sin(dbl_dLon / 2)

dbl_Distance_KM = 6371 * 2 * WorksheetFunction.Atan2(Sqr(dbl_a), Sqr(1 - dbl_a))


我正在使用以下坐标进行测试:

dbl_Longitude1 = 55.629178
dbl_Longitude2 = 29.846686
dbl_Latitude1 = 37.659466
dbl_Latitude2 = 30.24441


并且代码返回20015.09,这显然是错误的。根据Yandex地图,它应该是642公里。

我哪里错了?经度和纬度格式是否错误?

最佳答案

据我所知,问题在于atan2()的参数顺序因语言而异。以下对我有用的*:

Option Explicit

Public Sub Distance()
    Dim dbl_Longitude1 As Double, dbl_Longitude2 As Double, dbl_Latitude1 As Double, dbl_Latitude2 As Double

    dbl_Longitude1 = 55.629178
    dbl_Longitude2 = 29.846686
    dbl_Latitude1 = 37.659466
    dbl_Latitude2 = 30.24441

    Dim dbl_dLat As Double
    Dim dbl_dLon As Double
    Dim dbl_a As Double
    Dim dbl_P As Double

    dbl_P = WorksheetFunction.Pi / 180
    dbl_dLat = dbl_P * (dbl_Latitude2 - dbl_Latitude1)      'to radians
    dbl_dLon = dbl_P * (dbl_Longitude2 - dbl_Longitude1)    'to radians

    dbl_a = Sin(dbl_dLat / 2) * Sin(dbl_dLat / 2) + _
            Cos(dbl_Latitude1 * dbl_P) * Cos(dbl_Latitude2 * dbl_P) * Sin(dbl_dLon / 2) * Sin(dbl_dLon / 2)

    Dim c As Double
    Dim dbl_Distance_KM As Double
    c = 2 * WorksheetFunction.Atan2(Sqr(1 - dbl_a), Sqr(dbl_a))  ' *** swapped arguments to Atan2
    dbl_Distance_KM = 6371 * c

    Debug.Print dbl_Distance_KM
End Sub


*输出:2507.26205401321,尽管gcmap.com表示答案为2512公里。这可能是一个精度问题---我认为它已经足够接近可以工作了。 (编辑它也可能是gcmap使用局部地球半径而不是平均半径;我不确定。)

说明

我发现了大正圆距离的Haversine公式的this description,这就是您要实现的。该页面上的JavaScript实现为c提供了以下计算:

var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));


在JavaScript中,atan2()采用参数yx。但是,在Excel VBA中,WorksheetFunction.Atan2采用参数xy。您的原始代码将Sqr(dbl_a)作为第一个参数传递,就像在JavaScript中一样。但是,Sqr(dbl_a)必须是Excel VBA中的第二个参数。

关于命名的评论

以@JohnColeman的观点为基础,有很多方法来命名变量。在这种情况下,我建议为单位而不是类型使用前缀:例如deg_Latitude1RadPerDeg = Pi/180rad_dLat = RadPerDeg * (deg_Latitude2 - deg_Latitude1)。我个人认为这有助于避免unit-conversion mishaps

关于excel - 计算坐标之间的距离(以公里为单位),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48008116/

10-11 17:54