计算给定轴承和距离的坐标

时间:2009-05-18 12:38:50

标签: algorithm gps coordinates bearing

我在实现此处描述的功能时遇到问题here

这是我的Java实现:

private static double[] pointRadialDistance(double lat1, double lon1, 
        double radianBearing, double radialDistance) {
     double lat = Math.asin(Math.sin(lat1)*Math.cos(radialDistance)+Math.cos(lat1)
             *Math.sin(radialDistance)*Math.cos(radianBearing));
     double lon;
     if(Math.cos(lat) == 0) {  // Endpoint a pole
        lon=lon1;      
     }
     else {
        lon = ((lon1-Math.asin(Math.sin(radianBearing)*Math.sin(radialDistance)/Math.cos(lat))
                +Math.PI) % (2*Math.PI)) - Math.PI;
     }
    return (new double[]{lat, lon});
}

我将度数轴承转换为弧度并在调用函数之前将距离(km)转换为弧度距离 - 这不是问题。

但是,当我输入坐标时,例如: lat = 49.25705; lon = -123.140259; 轴承225(西南),距离1km

我得到了这个: lat:-1.0085434360125864 lon:-3.7595299668539504

它显然不正确,谁能看到我做错了什么?

由于

6 个答案:

答案 0 :(得分:14)

似乎这些是您的代码中的问题:

  1. 在调用您的函数之前,您需要将lat1lon1转换为弧度。
  2. 您可能无法正确缩放radialDistance
  3. 测试浮点数是否相等是危险的。精确算术后相等的两个数字在浮点运算后可能不完全相等。因此,abs(x-y) < thresholdx == y更安全,可以测试两个浮点数xy是否相等。
  4. 我认为您希望将latlon从弧度转换为度数。
  5. 以下是我在Python中实现的代码:

    #!/usr/bin/env python
    
    from math import asin,cos,pi,sin
    
    rEarth = 6371.01 # Earth's average radius in km
    epsilon = 0.000001 # threshold for floating-point equality
    
    
    def deg2rad(angle):
        return angle*pi/180
    
    
    def rad2deg(angle):
        return angle*180/pi
    
    
    def pointRadialDistance(lat1, lon1, bearing, distance):
        """
        Return final coordinates (lat2,lon2) [in degrees] given initial coordinates
        (lat1,lon1) [in degrees] and a bearing [in degrees] and distance [in km]
        """
        rlat1 = deg2rad(lat1)
        rlon1 = deg2rad(lon1)
        rbearing = deg2rad(bearing)
        rdistance = distance / rEarth # normalize linear distance to radian angle
    
        rlat = asin( sin(rlat1) * cos(rdistance) + cos(rlat1) * sin(rdistance) * cos(rbearing) )
    
        if cos(rlat) == 0 or abs(cos(rlat)) < epsilon: # Endpoint a pole
            rlon=rlon1
        else:
            rlon = ( (rlon1 - asin( sin(rbearing)* sin(rdistance) / cos(rlat) ) + pi ) % (2*pi) ) - pi
    
        lat = rad2deg(rlat)
        lon = rad2deg(rlon)
        return (lat, lon)
    
    
    def main():
        print "lat1 \t lon1 \t\t bear \t dist \t\t lat2 \t\t lon2"
        testcases = []
        testcases.append((0,0,0,1))
        testcases.append((0,0,90,1))
        testcases.append((0,0,0,100))
        testcases.append((0,0,90,100))
        testcases.append((49.25705,-123.140259,225,1))
        testcases.append((49.25705,-123.140259,225,100))
        testcases.append((49.25705,-123.140259,225,1000))
        for lat1, lon1, bear, dist in testcases:
            (lat,lon) = pointRadialDistance(lat1,lon1,bear,dist)
            print "%6.2f \t %6.2f \t %4.1f \t %6.1f \t %6.2f \t %6.2f" % (lat1,lon1,bear,dist,lat,lon)
    
    
    if __name__ == "__main__":
        main()
    

    这是输出:

    lat1     lon1        bear    dist        lat2        lon2
      0.00     0.00       0.0       1.0        0.01        0.00
      0.00     0.00      90.0       1.0        0.00       -0.01
      0.00     0.00       0.0     100.0        0.90        0.00
      0.00     0.00      90.0     100.0        0.00       -0.90
     49.26   -123.14     225.0      1.0       49.25      -123.13
     49.26   -123.14     225.0    100.0       48.62      -122.18
     49.26   -123.14     225.0   1000.0       42.55      -114.51
    

答案 1 :(得分:3)

从根本上说,你的问题似乎是你将纬度,经度和方位作为度数而不是弧度。尝试确保你总是将弧度传递给你的函数,看看你得到了什么。

PS:请参阅herehere讨论的类似问题。

答案 2 :(得分:3)

我认为消息5中提供的算法存在问题。

它可以工作,但仅适用于纬度,因为符号会产生经度问题。

数据不言自明:

  

49.26 -123.14 225.0 1.0 49.25 -123.13

如果你从 -123.14°开始并进入西部,你应该在西部有一些东西。在这里,我们回到EAST(-123.13)!

该公式应包括某处:

  

degreeBearing =((360度轴承)%360)

在弧度转换之前。

答案 3 :(得分:0)

当我实施这个时,我产生的纬度是正确的,但经度是错误的。 例如起点:36.9460678N 9.434807E,轴承45.03334,距离15.0083313km 结果是37.0412865N 9.315302E 这比我的起点更向西,而不是向东。事实上它就好像轴承是315.03334度。

更多网络搜索引导我:http://www.movable-type.co.uk/scripts/latlong.html 经度代码如下所示(在C#中,所有内容均为弧度)

        if ((Math.Cos(rLat2) == 0) || (Math.Abs(Math.Cos(rLat2)) < EPSILON))
        {
            rLon2 = rLon1;
        }
        else
        {
            rLon2 = rLon1 + Math.Atan2(Math.Sin(rBearing) * Math.Sin(rDistance) * Math.Cos(rLat1), Math.Cos(rDistance) - Math.Sin(rLat1) * Math.Sin(rLat2));
        }

这对我来说似乎很好。希望它有用。

答案 4 :(得分:0)

感谢你的python代码 我尝试在我的用例中进行设置 在那里我试图在两个人之间找到一个点的纬度 距离第一个点一定距离,所以它与您的代码完全相似 我知道我的方位是动态计算的

startpoint(lat1)lon1 / lat1 = 55.625541,-21.142463

终点(lat2)lon2 / lat2 = 55.625792,-22.142248

我的结果应该是lon3 / lat3之间的两点 不幸的是我得到了lon3 / lat3 = 0.0267695450609,0.0223553243666

我认为这可能是拉特隆的差异但不是 当我添加或分享它时,它不是很好

任何建议都会非常棒 谢谢

这是我的实施

距离= 0.001 epsilon = 0.000001

动态计算轴承

y = math.sin(distance) * math.cos(lat2);
x = math.cos(lat1)*math.sin(lat2) - math.sin(lat1)*math.cos(lat2)*math.cos(distance);
bearing = math.atan2(y, x)

动态计算lat3 lon3

rlat1 = (lat1 * 180) / math.pi
rlon1 = (lon1 * 180) / math.pi
rbearing = (bearing * 180) / math.pi
rdistance = distance / R # normalize linear distance to radian angle

rlat = math.asin( math.sin(rlat1) * math.cos(rdistance) + math.cos(rlat1) * math.sin(rdistance) * math.cos(rbearing) )
if math.cos(rlat) == 0 or abs(math.cos(rlat)) < epsilon: # Endpoint a pole
      rlon=rlon1
else:
    rlon = ( (rlon1 + math.asin( math.sin(rbearing)* math.sin(rdistance) / math.cos(rlat) ) + math.pi ) % (2*math.pi) ) - math.pi

lat3 = (rlat * math.pi)/ 180
lon3 = (rlon * math.pi)/ 180

答案 5 :(得分:0)

一切都按预期工作,但问题是你的数学假定地球是一个球体,而实际上它近似于一个椭圆体。

快速浏览您喜爱的'Vincenty Formula'搜索引擎,希望证明它很有用。