我编写了一个MS Access VBA函数来计算轴承和距离的新纬度/经度坐标。然而,它返回错误的结果,我不明白为什么。我在https://www.movable-type.co.uk/scripts/latlong.html上使用了公式但是当我在该页面上对计算器进行测试时,它会给出错误的结果。例如,NewLatLong(0, 0, 500, "K", 45)
给出的纬度为5.54656612024095E-02,经度为0.转换为度数后,纬度是正确的,与页面上的计算器进行比较,但为什么经度会回归零? NewLatLong的参数是以度为单位的原始纬度和经度,距离,距离单位(K =公里)和从北以顺时针方向承载的度数。
MS Access不具备所需的所有三角函数。我提供了新的。这些已经过单独测试,看起来功能正确。
我看不出我的代码有什么问题。谁能帮忙。
Public Function NewLatLong(latD As Double, longD As Double, distance As Double, unit As String, bearingD As Double) As Double()
Dim latlong(2) As Double
Dim latR As Double, bearingR As Double
latR = Radians(latD)
bearingR = Radians(bearingD)
Dim cosAngDistance As Double, sinAngDistance As Double
cosAngDistance = Cos(distance / EarthRadius(unit))
sinAngDistance = Sin(distance / EarthRadius(unit))
latlong(0) = ArcSine(Sin(latR) * cosAngDistance + Cos(latR) * sinAngDistance * Cos(bearingR))
latlong(1) = (Radians(longD) + ArcTan2(Sin(bearingR) * sinAngDistance * Cos(latR), cosAngDistance - Sin(latR) * Sin(latlong(0))) + 540) Mod 360 - 180
NewLatLong = latlong
Debug.Print latlong(0) & " " & latlong(1)
End Function
Public Function EarthRadius(unit As String) As Double
If (unit = "M") Then
EarthRadius = 3963
ElseIf (unit = "K") Then
EarthRadius = 6371
Else
EarthRadius = 3443.753
End If
End Function
Public Function Pi() As Double
Pi = 4 * Atn(1)
End Function
Public Function ArcCosine(value As Double) As Double
ArcCosine = Atn(-value / Sqr(-value * value + 1)) + 2 * Atn(1)
End Function
Public Function ArcSine(value As Double) As Double
ArcSine = Atn(value / Sqr(-value * value + 1))
End Function
Public Function ArcTan2(y As Double, x As Double) As Double
If x > 0 Then
ArcTan2 = Atn(y / x)
ElseIf x < 0 Then
ArcTan2 = Sgn(y) * (Pi() - Atn(Abs(y / x)))
ElseIf y = 0 Then
ArcTan2 = 0
Else
ArcTan2 = Sgn(y) * Pi() / 2
End If
End Function
Public Function Radians(degrees As Double) As Double
Radians = degrees * Pi() / 180
End Function
好消息和坏消息。好消息是你的代码几乎完美无缺,坏消息是Mod运算符总是返回一个整数而不管它的参数类型(为什么是微软!?为什么!?)。
而不是latlong(1) = (Radians(longD) + ArcTan2(Sin(bearingR) * sinAngDistance * Cos(latR), cosAngDistance - Sin(latR) * Sin(latlong(0))) + 540) Mod 360 - 180
,使用下面的代码来找到经度
Dim tempLong As Double
tempLong = Radians(longD) + ArcTan2(Sin(bearingR) * sinAngDistance * Cos(latR), cosAngDistance - Sin(latR) * Sin(latlong(0)))
' set longitude if calculated value less than 1
If tempLong < 1 Then
latlong(1) = tempLong
' if greater than 1, add decimal part back to modulus result
Else
Dim decLong As Double
decLong = tempLong
While decLong > 1
decLong = decLong - 1
Wend
latlong(1) = ((tempLong + 540) Mod 360 - 180) + decLong
End If
我添加了自己的mod函数,可以正常使用双精度函数。
Public Function ModDouble(dividend As Double, divisor As Double) As Double
Dim x As Double
x = Int(dividend / divisor)
ModDouble = dividend - (x * divisor)
End Function
这使得原始代码工作正常,使用
latlong(1) = ModDouble(radians(longD) + ArcTan2(Sin(bearingR) * sinAngDistance * Cos(latR), cosAngDistance - Sin(latR) * Sin(latlong(0))) + 540, 360) - 180
但我要将BankBuilder的答案标记为正确,因为他基本上发现了错误,这是我永远不会发现的。