在Swift中计算两个CLLocation点之间的方位角

34

我正在尝试在纯Swift代码中计算两个CLLocation点之间的方位角。 我遇到了一些困难,并假设这是一个非常简单的函数。 Stack overflow似乎没有列出任何内容。

func d2r(degrees : Double) -> Double {
    return degrees * M_PI / 180.0
}

func RadiansToDegrees(radians : Double) -> Double {
    return radians * 180.0 / M_PI
}


func getBearing(fromLoc : CLLocation, toLoc : CLLocation) {

    let fLat = d2r(fromLoc.coordinate.latitude)
    let fLng = d2r(fromLoc.coordinate.longitude)
    let tLat = d2r(toLoc.coordinate.latitude)
    let tLng = d2r(toLoc.coordinate.longitude)

    var a = CGFloat(sin(fLng-tLng)*cos(tLat));
    var b = CGFloat(cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(fLng-tLng))

    return atan2(a,b)
}

我在调用atan2时遇到了一个关于lvalue cgfloat的错误...

2个回答

59

这里有一个Objective-C的解决方案

很容易将其转换为Swift:

func degreesToRadians(degrees: Double) -> Double { return degrees * .pi / 180.0 }
func radiansToDegrees(radians: Double) -> Double { return radians * 180.0 / .pi }

func getBearingBetweenTwoPoints1(point1 : CLLocation, point2 : CLLocation) -> Double {

    let lat1 = degreesToRadians(degrees: point1.coordinate.latitude)
    let lon1 = degreesToRadians(degrees: point1.coordinate.longitude)

    let lat2 = degreesToRadians(degrees: point2.coordinate.latitude)
    let lon2 = degreesToRadians(degrees: point2.coordinate.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(radians: radiansBearing)
}

结果类型为 Double ,因为所有位置坐标都是以此方式存储的(CLLocationDegreesDouble 的类型别名)。


为什么我们不能通过减去CLLocation对象上的课程值来计算它?但是即使我尝试这样做,想象一下用户从0度到359度的情况,那么如果实际变化角度是1度而不是359度怎么办?我该如何消除这种情况? - nr5
1
@Nil:课程值是设备当前移动的方向。这段代码涉及从一个给定点到另一个点的方向,与设备位置或移动无关。(因此,参数最好使用CLLocationCoordinate2D而不是CLLocation。我稍后会进行更新。) - Martin R
好的。但是您能帮我解决另一个问题吗,即0-359度的情况。 - nr5
1
@Nil:这与问答无关。但是您可以通过添加或减去360来将差异归一化为-180...+180范围内。 - Martin R
我同意。但是请考虑这两个数据点。在这种情况下,方位角只有约1度,这是您的逻辑正确找到的。但是请考虑一个环形交叉口,您需要走第三个出口。因此,您完成了270度的角度。但是您的答案将显示90度。我说得对吗? - nr5
显示剩余5条评论

6

这并不完全准确,但你可能正在寻找类似以下的内容:

func XXRadiansToDegrees(radians: Double) -> Double {
    return radians * 180.0 / M_PI
}

func getBearingBetweenTwoPoints(point1 : CLLocation, point2 : CLLocation) -> Double {
    // Returns a float with the angle between the two points
    let x = point1.coordinate.longitude - point2.coordinate.longitude
    let y = point1.coordinate.latitude - point2.coordinate.latitude

    return fmod(XXRadiansToDegrees(atan2(y, x)), 360.0) + 90.0
}

我从这篇NSHipster文章中借鉴了代码,该文章详细介绍了存在的问题。基本问题是它将坐标当作平面世界使用(但现实并非如此,对吧?)。Mattt的文章可以告诉你如何使用MKMapPoint而不是CLLocation来得到真正的方向。


1
为什么我们不能通过减去CLLocation对象上的课程值来计算这个?但是即使我尝试这样做,想象一下用户从0度到359度的情况,那么如果实际变化角度是1度而不是359度怎么办?我该如何消除这种情况? - nr5
@Guy Kogus。我正在尝试在地图上标记位置,但它不起作用。你能指导我如何实现吗? - Uma Madhavi
抱歉Uma,我自己从未使用过它,所以不确定我能提供多少帮助。 - Guy Kogus
@Nil,你在评论中提到的问题有解决方案了吗? - Abin Baby
你可能想使用“haversine”算法,它考虑到地球是一个球体。你会得到两个方位角,初始方位角和最终方位角(是的,它会改变)。对于短距离,初始方位角可以很好地工作。请参阅http://www.movable-type.co.uk/scripts/latlong.html进行优秀讨论。我用Java编写了它,现在将转换为Swift。 - Dave Hubbard
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接