30

方位を別のCLLocationに戻すために、CLLocationのカテゴリを作成しようとしています。

私は数式で何か間違ったことをしていると思います(結石は私の強いスーツではありません)。戻されたベアリングは常にオフです。

私はこの質問を見て、正解として受け入れられた変更とそれが参照するWebページを適用しようとしました。

2つのCLLocationCoordinate2D間の方位を計算する

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);
}
4

8 に答える 8

26

あなたのコードは私には問題ないようです。結石には何の問題もありません。結果がどれだけ離れているかは指定しませんが、ラジアン/度のコンバーターを次のように微調整してみてください。

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は(-180〜180度)の範囲の結果を返すため-M_PIM_PI次のコードのようなものを使用して、コンパス方位に変換することをお勧めします。

if(radiansBearing < 0.0)
    radiansBearing += 2*M_PI;
于 2010-10-13T19:17:04.490 に答える
8

これは、最初のカテゴリの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))
    }
}
于 2015-08-04T19:17:48.277 に答える
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;

}
于 2015-05-01T09:51:01.503 に答える
3

これは、Swift3およびSwift4で使用できるもう1つのCLLocation拡張機能です

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)
    }

}
于 2017-05-11T11:48:36.240 に答える
3

ワーキングスウィフト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)
于 2017-06-30T18:13:17.377 に答える
1

私はSwiftの余弦定理を使用しています。Haversineよりも高速に実行され、その結果は非常に似ています。遠距離での1メートルの変動。

余弦定理を使用する理由:

  • 高速実行(sqrt関数がないため)
  • 天文学をやらない限り、十分に正確です
  • バックグラウンドタスクに最適

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

}
于 2016-02-20T06:13:59.693 に答える
1

これをSwift5に実装しました。焦点は速度ではなく精度にありますが、リアルタイムnpで実行されます。

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メソッドは、原点、メートル単位の距離、度単位の方位を指定して、新しいポイントを正確にプロットします。

于 2020-04-23T15:36:35.003 に答える
0

あなたがグーグルマップを使用しているなら、方法GMSMapViewを使用するすぐに使える解決策があることを言及する価値があります:GMSGeometryHeading

GMSGeometryHeading(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D)

最短経路からへの最初の方位(北から時計回りに度)を返します。

于 2020-04-20T16:31:22.293 に答える