【问题标题】:Calculating bearing between two CLLocationCoordinate2Ds计算两个 CLLocationCoordinate2D 之间的方位
【发布时间】:2011-04-18 02:00:27
【问题描述】:

非常“简单”的问题:给定两个 CLLocationCoordinate2D,我怎样才能得到从第一个到第二个的方位(以弧度表示)?我对此做了很多研究和研究,包括一般问题和Objective-C/Cocoa Touch/iOS。

这是我的实现:

- (float) getHeadingForDirectionFromCoordinate:(CLLocationCoordinate2D)fromLoc toCoordinate:(CLLocationCoordinate2D)toLoc
{
    float fLat = fromLoc.latitude;
    float fLng = fromLoc.longitude;
    float tLat = toLoc.latitude;
    float tLng = toLoc.longitude;

    return atan2(sin(fLng-tLng)*cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(fLng-tLng));         
}

但是,此方法不会为我返回一致的结果。如果方位接近正北或正南,似乎没问题,但是,任何其他方向似乎返回不一致的数据,例如:

从 50.405018、8.437500

至 51.339802、12.403340

我的方法返回:5.918441 弧度

应该是 1.18660576 弧度

(见http://www.movable-type.co.uk/scripts/latlong.htmlhttp://www.movable-type.co.uk/scripts/latlong-map.html?lat1=50.405018&long1=8.437500&lat2=51.339802&long2=12.403340

我已经两次和三次检查公式是否正确。我还抽查了上面示例中的一堆值,有些是正确的,有些是错误的。我玩过各种模数或返回值的边界,也没有运气。

有什么想法吗?我的代码有问题吗?也许我误解了数学函数的工作原理?

【问题讨论】:

    标签: ios objective-c coordinates core-location


    【解决方案1】:

    这里是使用 Oren Trutner 和我自己建议的更改修改的代码:

    #define degreesToRadians(x) (M_PI * x / 180.0)
    #define radiansToDegrees(x) (x * 180.0 / M_PI)
    
    - (float)getHeadingForDirectionFromCoordinate:(CLLocationCoordinate2D)fromLoc toCoordinate:(CLLocationCoordinate2D)toLoc
    {
        float fLat = degreesToRadians(fromLoc.latitude);
        float fLng = degreesToRadians(fromLoc.longitude);
        float tLat = degreesToRadians(toLoc.latitude);
        float tLng = degreesToRadians(toLoc.longitude);
    
        float degree = radiansToDegrees(atan2(sin(tLng-fLng)*cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng)));
    
        if (degree >= 0) {
            return degree;
        } else {
            return 360+degree;
        }
    }
    

    【讨论】:

    • 这些不应该是双精度而不是浮点数..?
    • 最后的if语句是干什么用的?角度怎么会小于0?另外else语句的意义何在,为什么角度会超过360??
    • 记得只在新旧位置不一样的时候计算这个/改变汽车图片旋转。否则,相同位置之间的旋转为0,汽车图标将保持原地旋转。
    • cos(tLat) 被调用两次,可以提取到预先计算的变量中。
    【解决方案2】:

    你的数学是正确的,但有以下例外:

    1. 确保在应用前将 fLatfLontLattLon 转换为弧度任何 sin()cos() 给他们。除以 180.0 并乘以 PI。

    2. tLngfLng 之间的差值输入为 tLng-fLng,而不是相反。请注意,这种差异在表达式中出现了两次。

    通过这些更改,我得到 1.18660677830947 弧度,具有双精度数学和问题中的值。

    【讨论】:

    • 我最初的反应是“将纬度/经度转换为弧度?这是什么疯狂的方式?”然后我真的试了一下,效果很好。
    • 好点。地理纬度和经度中度数的使用是如此根深蒂固,以至于很容易忘记它们描述了地球球体几何形状中的角度。大多数现代语言中的三角函数都需要弧度,从而强制转换。
    • 你能解释一下2吗?如果 fLng 更大怎么办?
    • 如果 fLng>tLng 比 tLng-fLng 为负数。这没关系!在这种情况下,算术仍然可以正常工作——事实上,负值对于结果的正确性至关重要。
    【解决方案3】:

    斯威夫特 3:

    extension CLLocationCoordinate2D {
        func bearing(to point: CLLocationCoordinate2D) -> Double {
            func degreesToRadians(_ degrees: Double) -> Double { return degrees * Double.pi / 180.0 }
            func radiansToDegrees(_ radians: Double) -> Double { return radians * 180.0 / Double.pi }
    
            let lat1 = degreesToRadians(latitude)
            let lon1 = degreesToRadians(longitude)
    
            let lat2 = degreesToRadians(point.latitude);
            let lon2 = degreesToRadians(point.longitude);
    
            let dLon = lon2 - lon1;
    
            let y = sin(dLon) * cos(lat2);
            let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
            let radiansBearing = atan2(y, x);
    
            return radiansToDegrees(radiansBearing)
        }
    }
    

    【讨论】:

    • 谢谢你。又是一个小疑问。我的地图视图在更新位置时动画,例如建筑物和其他图标闪烁。
    • 是的,我以类似的方式做过,但对我不起作用
    • 我绘制了 3 个点,其中 2 个正确,1 个相反。如何纠正这个问题?
    【解决方案4】:

    您可以使用我的代码。它适用于我的项目,其中微控制器使用 GPS 获取数据。

    #define d2r ((22/7.0)/180.0)
    #define r2d (180.0/(22/7.0))
    
    double get_heading1(double lat1, double long1, double lat2, double long2)  
    {
        double diff_lat, diff_long;
        double degree;
    
        diff_long =(double) (((long2*1000000)-(long1*1000000))/1000000) * d2r;
        diff_lat = (double) (((lat2*1000000)-(lat1*1000000))/1000000) * d2r;     
    
        degree = r2d     (atan2(sin(diff_long)*cos(d2r*lat2),cos(d2r*lat1)*sin(d2r*lat2)-sin(d2r*lat1)*cos(d2r*lat2)    *cos(diff_long)));
    
        if (degree >= 0) {
            return degree;
        } else {
            return 360+degree;
        }                                                                 
    }
    

    【讨论】:

    • 为什么是22/7 而不是更精确的M_PI?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 2023-01-24
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    相关资源
    最近更新 更多