web-dev-qa-db-ja.com

2つのCLLocationCoordinate2D間の方位の計算

非常に「単純な」問題:2つのCLLocationCoordinate2Dがある場合、最初の方位から2番目の方位を(ラジアンとして)取得するにはどうすればよいですか?私はこれについて多くの調査と研究を行いました。一般的な問題と具体的には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.40334

公式が正しいことをダブルとトリプルで確認しました。上記の例のように、いくつかの値をスポットチェックしました。いくつかは正しい、いくつかは間違っています。私はさまざまなモジュロや戻り値の境界を試しましたが、運もありませんでした。

何か案は?コードに問題はありますか?多分私は数学関数がどのように機能するかについて何かを誤解しましたか?

38
James J

あなたの数学は正しいですが、次の例外があります:

  1. fLatfLontLat、およびtLonを適用する前にラジアンにsin( )またはcos()を使用します。 180.0で割り、PIを掛けます。

  2. tLngfLngの間のデルタをtLng-fLng、およびその逆ではありません。この違いは式に2回現れることに注意してください。

これらの変更により、倍精度演算と問題の値を含む1.18660677830947ラジアンを取得しています。

31
Oren Trutner

ここで、コードは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;
    }
}
52
megabri

スウィフト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)
    }
}
10
Sahil Kapoor