我正在尝试为CLLocation编写一个类别,以将轴承返回到另一个CLLocation。
我相信我对这个公式做错了(计算不是我的强项)。返回的轴承总是关闭。
我一直在看这个问题并尝试应用被接受为正确答案的更改及其引用的网页:
Calculating bearing between two CLLocationCoordinate2Ds
http://www.movable-type.co.uk/scripts/latlong.html
感谢您的任何指示。我尝试将其他问题的反馈结合起来,但我仍然没有得到什么。
由于
这是我的类别 -
----- CLLocation + Bearing.h
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
@interface CLLocation (Bearing)
-(double) bearingToLocation:(CLLocation *) destinationLocation;
-(NSString *) compassOrdinalToLocation:(CLLocation *) nwEndPoint;
@end
--------- + CLLocation Bearing.m
#import "CLLocation+Bearing.h"
double DegreesToRadians(double degrees) {return degrees * M_PI / 180;};
double RadiansToDegrees(double radians) {return radians * 180/M_PI;};
@implementation CLLocation (Bearing)
-(double) bearingToLocation:(CLLocation *) destinationLocation {
double lat1 = DegreesToRadians(self.coordinate.latitude);
double lon1 = DegreesToRadians(self.coordinate.longitude);
double lat2 = DegreesToRadians(destinationLocation.coordinate.latitude);
double lon2 = DegreesToRadians(destinationLocation.coordinate.longitude);
double dLon = lon2 - lon1;
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
double radiansBearing = atan2(y, x);
return RadiansToDegrees(radiansBearing);
}
答案 0 :(得分:25)
你的代码对我来说似乎没问题。该计算没有错。您没有指定结果的距离,但您可以尝试将您的弧度/度数转换器调整为:
double DegreesToRadians(double degrees) {return degrees * M_PI / 180.0;};
double RadiansToDegrees(double radians) {return radians * 180.0/M_PI;};
如果您获得负面方位,请将2*M_PI
添加到radiansBearing中的最终结果(如果转换为度数后再添加360)。 atan2返回范围-M_PI
到M_PI
(-180到180度)的结果,因此您可能希望将其转换为罗盘方位,使用类似下面的代码
if(radiansBearing < 0.0)
radiansBearing += 2*M_PI;
答案 1 :(得分:6)
这是一个开头的类别Swift的移植:
import Foundation
import CoreLocation
public extension CLLocation{
func DegreesToRadians(_ degrees: Double ) -> Double {
return degrees * M_PI / 180
}
func RadiansToDegrees(_ radians: Double) -> Double {
return radians * 180 / M_PI
}
func bearingToLocationRadian(_ destinationLocation:CLLocation) -> Double {
let lat1 = DegreesToRadians(self.coordinate.latitude)
let lon1 = DegreesToRadians(self.coordinate.longitude)
let lat2 = DegreesToRadians(destinationLocation.coordinate.latitude);
let lon2 = DegreesToRadians(destinationLocation.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 radiansBearing
}
func bearingToLocationDegrees(destinationLocation:CLLocation) -> Double{
return RadiansToDegrees(bearingToLocationRadian(destinationLocation))
}
}
答案 2 :(得分:4)
这是另一种实现
public func bearingBetweenTwoPoints(#lat1 : Double, #lon1 : Double, #lat2 : Double, #lon2: Double) -> Double {
func DegreesToRadians (value:Double) -> Double {
return value * M_PI / 180.0
}
func RadiansToDegrees (value:Double) -> Double {
return value * 180.0 / M_PI
}
let y = sin(lon2-lon1) * cos(lat2)
let x = (cos(lat1) * sin(lat2)) - (sin(lat1) * cos(lat2) * cos(lat2-lon1))
let degrees = RadiansToDegrees(atan2(y,x))
let ret = (degrees + 360) % 360
return ret;
}
答案 3 :(得分:2)
这是另一个 CLLocation 扩展,可用于 Swift 3 和 Swift 4
public extension CLLocation {
func degreesToRadians(degrees: Double) -> Double {
return degrees * .pi / 180.0
}
func radiansToDegrees(radians: Double) -> Double {
return radians * 180.0 / .pi
}
func getBearingBetweenTwoPoints(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)
}
}
答案 4 :(得分:1)
我在Swift中使用Cosines法则。它的运行速度比Haversine快,其结果非常相似。远距离变化1米。
为什么我使用余弦定律:
func calculateDistance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> Double {
let π = M_PI
let degToRad: Double = π/180
let earthRadius: Double = 6372797.560856
// Law of Cosines formula
// d = r . arc cos (sin A sin B + cos A cos B cos(B - A) )
let A = from.latitude * degToRad
let B = to.latitude * degToRad
let A = from.longitude * degToRad
let B = to.longitude * degToRad
let angularDistance = acos(sin(A) * sin(B) + cos(A) * cos(B) * cos(B - A) )
let distance = earthRadius * angularDistance
return distance
}
答案 5 :(得分:1)
使用Swift 3和4
尝试了这么多版本,这个版本最终给出了正确的值!
extension CLLocation {
func getRadiansFrom(degrees: Double ) -> Double {
return degrees * .pi / 180
}
func getDegreesFrom(radians: Double) -> Double {
return radians * 180 / .pi
}
func bearingRadianTo(location: CLLocation) -> Double {
let lat1 = self.getRadiansFrom(degrees: self.coordinate.latitude)
let lon1 = self.getRadiansFrom(degrees: self.coordinate.longitude)
let lat2 = self.getRadiansFrom(degrees: location.coordinate.latitude)
let lon2 = self.getRadiansFrom(degrees: location.coordinate.longitude)
let dLon = lon2 - lon1
let y = sin(dLon) * cos(lat2)
let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon)
var radiansBearing = atan2(y, x)
if radiansBearing < 0.0 {
radiansBearing += 2 * .pi
}
return radiansBearing
}
func bearingDegreesTo(location: CLLocation) -> Double {
return self.getDegreesFrom(radians: self.bearingRadianTo(location: location))
}
}
用法:
let degrees = location1.bearingDegreesTo(location: location2)
答案 6 :(得分:0)
值得一提的是,如果您使用的是Google地图GMSMapView
,那么可以使用GMSGeometryHeading
method的即用型解决方案:
GMSGeometryHeading(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D)
从处返回初始航向(北向顺时针方向) 到达的最短路径。
答案 7 :(得分:0)
在 Swift 5 中实现。重点在于准确性,而不是速度,而是实时运行。
let earthRadius: Double = 6372456.7
let degToRad: Double = .pi / 180.0
let radToDeg: Double = 180.0 / .pi
func calcOffset(_ coord0: CLLocationCoordinate2D,
_ coord1: CLLocationCoordinate2D) -> (Double, Double) {
let lat0: Double = coord0.latitude * degToRad
let lat1: Double = coord1.latitude * degToRad
let lon0: Double = coord0.longitude * degToRad
let lon1: Double = coord1.longitude * degToRad
let dLat: Double = lat1 - lat0
let dLon: Double = lon1 - lon0
let y: Double = cos(lat1) * sin(dLon)
let x: Double = cos(lat0) * sin(lat1) - sin(lat0) * cos(lat1) * cos(dLon)
let t: Double = atan2(y, x)
let bearing: Double = t * radToDeg
let a: Double = pow(sin(dLat * 0.5), 2.0) + cos(lat0) * cos(lat1) * pow(sin(dLon * 0.5), 2.0)
let c: Double = 2.0 * atan2(sqrt(a), sqrt(1.0 - a));
let distance: Double = c * earthRadius
return (distance, bearing)
}
func translateCoord(_ coord: CLLocationCoordinate2D,
_ distance: Double,
_ bearing: Double) -> CLLocationCoordinate2D {
let d: Double = distance / earthRadius
let t: Double = bearing * degToRad
let lat0: Double = coord.latitude * degToRad
let lon0: Double = coord.longitude * degToRad
let lat1: Double = asin(sin(lat0) * cos(d) + cos(lat0) * sin(d) * cos(t))
let lon1: Double = lon0 + atan2(sin(t) * sin(d) * cos(lat0), cos(d) - sin(lat0) * sin(lat1))
let lat: Double = lat1 * radToDeg
let lon: Double = lon1 * radToDeg
let c: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: lat,
longitude: lon)
return c
}
我发现Haversine相对于CLLocation的distance
方法确定了距离,但是没有为CL提供现成的轴承。因此,我没有将其用于轴承。通过我尝试过的所有数学运算,可以得出最准确的测量结果。 translateCoord
方法还将在给定原点,以米为单位的距离和以度为单位的方位的情况下精确绘制新点。