質問

これは次のフォローアップです この質問.

私はこれに行き詰まっているようです。基本的に、標準度系の座標を参照するか、国際日付変更線に沿って南極から北への距離を測定し、次に日付のその点から東への距離を測定することによって、座標を参照するように相互に変換できる必要があります。ライン。これを行うために (より一般的な距離測定と同様に)、2 つの緯度/経度の点の間の距離を決定するメソッドと、緯度/経度の点、方位、距離を取得して結果を返す別のメソッドがあります。そのコースの終了時の緯度/経度のポイント。

私が定義した 2 つの静的メソッドは次のとおりです。

/* Takes two lon/lat pairs and returns the distance between them in kilometers.
*/
public static double distance (double lat1, double lon1, double lat2, double lon2) {
    double theta = toRadians(lon1-lon2);
    lat1 = toRadians(lat1);
    lon1 = toRadians(lon1);
    lat2 = toRadians(lat2);
    lon2 = toRadians(lon2);

    double dist = sin(lat1)*sin(lat2) + cos(lat1)*cos(lat2)*cos(theta);
    dist = toDegrees(acos(dist)) * 60 * 1.1515 * 1.609344 * 1000;

    return dist;
}

/* endOfCourse takes a lat/lon pair, a heading (in degrees clockwise from north), and a distance (in kilometers), and returns
 * the lat/lon pair that would be reached by traveling that distance in that direction from the given point.
 */
public static double[] endOfCourse (double lat1, double lon1, double tc, double dist) {
    double pi = Math.PI;
    lat1 = toRadians(lat1);
    lon1 = toRadians(lon1);
    tc = toRadians(tc);
    double dist_radians = toRadians(dist / (60 * 1.1515 * 1.609344 * 1000));
    double lat = asin(sin(lat1) * cos(dist_radians) + cos(lat1) * sin(dist_radians) * cos(tc));
    double dlon = atan2(sin(tc) * sin(dist_radians) * cos(lat1), cos(dist_radians) - sin(lat1) * sin(lat));
    double lon = ((lon1-dlon + pi) % (2*pi)) - pi;
    double[] endPoint = new double[2];
    endPoint[0] = lat; endPoint[1] = lon;
    return endPoint;
}

そして、これが私がそれをテストするために使用している関数です:

public static void main(String args[]) throws java.io.IOException, java.io.FileNotFoundException {
    double distNorth = distance(0.0, 0.0, 72.0, 0.0);
    double distEast = distance(72.0, 0.0, 72.0, 31.5);
    double lat1 = endOfCourse(0.0, 0.0, 0.0, distNorth)[0];
    double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[1];
    System.out.println("end at: " + lat1 + " / " + lon1);
    return;
}

「終了位置」の値は約 1 である必要があります。72.0 / 31.5。しかし、代わりに、約 1.25 / 0.021 が得られます。

どこかで単位を変換するのを忘れているか、何か愚かなことを見逃しているに違いないと思います...助けていただければ幸いです。

更新 1:

メートルを返す距離関数を(正しく)書いたのですが、コメントに誤ってキロメートルを書いてしまいました...もちろん、今日そのことに戻ったとき、私は混乱しました。とにかく、これで修正されました。endOfCourse メソッドの因数分解エラーも修正しました。また、そのメソッドでもラジアンから度に変換し直すのを忘れていたことに気付きました。ともかく:正しい緯度値 (71.99...) を取得しているように見えますが、経度値は大きく外れています (11.5 ではなく 3.54 が取得されます)。

更新 2:下記の通り、テストでタイプミスがありました。現在はコード内で修正されています。ただし、経度の数値はまだ間違っています。11.5 ではなく -11.34 が得られます。これらの行には何か問題があるはずだと思います:

double dlon = atan2(sin(tc) * sin(dist_radians) * cos(lat1), cos(dist_radians) - sin(lat1) * sin(lat));
double lon = ((lon1-dlon + pi) % (2*pi)) - pi;
役に立ちましたか?

解決

コードにマジックナンバーが含まれているという深刻なケースがあります。表現:

 (60 * 1.1515 * 1.609344 * 1000)

が2回出てきますが、あまり説明がありません。いくつかの助けを借りて:1.609344 は 1 マイルのキロ数です。60 は 1 度の分数です。1000 は 1 キロメートルのメートル数です。1.1515 は 1 海里の法定マイル数です (DanM さん、ありがとう)。1 海里は赤道における緯度 1 分の長さです。

回転楕円体の地球ではなく、球形の地球モデルを使用していると思いますか?代数は回転楕円体になるほど複雑ではありません。

最初の式 (緯度と経度の 2 つのペア間の変換) は奇数です。答えを整理するには、デルタラット (Δλ) とデルタロン (Δφ) の両方が必要です。さらに、ペア間の距離は次のようになります。

(60° N, 30° W), (60° N, 60° W)
(60° N, 60° W), (60° N, 90° W)

同じはずですが、コードが異なる答えを生成すると確信しています。

したがって、球面三角法の参考資料に戻って、何が間違っているかを確認する必要があると思います。(このテーマに関する本を見つけるには時間がかかります。どちらの箱に入っていたとしても開梱する必要があります。)

[...時間が経ちます...開梱完了...]

角度のある球面三角形が与えられた場合 , B, C 頂点と辺で ある, b, c それらの頂点の反対側 (つまり、側面) ある から BC, 、など)、コサインの公式は次のとおりです。

cos a = cos b . cos c + sin b . sin c . cos A

これを問題に適用すると、与えられた 2 つの点を次のように呼ぶことができます。 B そして C, で直角を持つ直球直角三角形を作成します。 .

最悪の状態のアスキーアート:

                  + C
                 /|
                / |
            a  /  | b
              /   |
             /    |
            /     |
         B +------+ A
              c

サイド c 経度の差に等しい。サイド b 緯度の差に等しい。角度 は 90° なので、cos = 0。したがって、私は次の方程式を信じます ある は:

cos a = cos Δλ . cos Δφ + sin Δλ . sin Δφ . cos 90°

a = arccos (cos Δλ . cos Δφ)

角度 ある ラジアン単位の値は、地球の半径を乗算して距離に変換されます。あるいは、与えられた ある 度 (および度の端数) で表すと、1 度は 60 海里となり、法定マイルは 60 * 1.1515 となり、1 度は 60 * 1.1515 * 1.609344 キロメートルとなります。距離をメートル単位で表示したい場合を除き、1000 という係数は必要ないと思います。

ポール・トンブリンはこう指摘する 航空公式集 v1.44 方程式のソースとして - そして実際に、位置の差が小さい場合のより数値的に安定したバージョンとともに存在します。

基本的な三角法の話に進むと、次のこともわかります。

cos (A - B) = cos A . cos B + sin A . sin B

これを私が示した式に 2 回適用すると、最終的には航空公式集の式になる可能性があります。

(私の参考資料: "天文学:原則と実践、第 4 版」 A・E・ロイとD・クラーク著(2003年)。私の本は 1977 年の初版、アダム ヒルガー、ISBN 0-85274-346-7 です。)


注意 (Google) 'define:"nautical mile"' をチェックしてください。現在では、定義上、海里は 1852 m (1.852 km) であるようです。乗数 1.1515 は、海里の古い定義である約 6080 フィートに対応します。使用する bc 10 段階で表すと、次のようになります。

(1852/(3*0.3048))/1760
1.1507794480

どの要素があなたにとって効果的かは、あなたの根拠が何であるかによって決まります。


2 番目の問題を第一原理から見ると、設定が少し異なり、「他の」球面三角方程式である正弦公式が必要になります。

sin A   sin B   sin C
----- = ----- = -----
sin a   sin b   sin c

前の図を調整すると、次のようになります。

                  + C
                 /|
                / |
            a  /  | b
           |  /   |
           |X/    |
           |/     |
         B +------+ A
              c

あなたには出発点が与えられます B, 、角度 バツ = 90° - B、長さ(角度) ある, 、角度 = 90°。あなたが求めているのは b (緯度のデルタ) と c (経度のデルタ)。

したがって、次のようになります。

sin a   sin b
----- = ----
sin A   sin B

または

        sin a . sin B
sin b = -------------
            sin A

または、A = 90°、sin A = 1、および sin B = sin (90° - X) = cos X であるため、次のようになります。

sin b = sin a . cos X

つまり、移動距離を角度に変換します ある, 、そのサインをとり、コース方向のコサインを掛けて、結果のアークサインをとります。

与えられた ある, b (計算しただけです)そして そして B, 、コサイン公式を適用して取得できます。 c. 。サイン公式を単純に再適用して次の値を得ることができないことに注意してください。 c という値を持っていないので、 C そして、私たちは球面三角法を使っているので、C = 90° - B という便利な規則はありません (球面三角形の角度の合計は 180° を超える可能性があります。すべての角度が 90° に等しい正三角形の球面三角形を考えてみましょう。これは完全に実現可能です)。


他のヒント

チェックアウト http://www.movable-type.co.uk/scripts/latlong.html

このサイトには、役立つさまざまな数式や Javascript コードが多数掲載されています。これを C# と SQL Server UDF の両方に正常に変換し、あらゆる場所で使用しています。

たとえば、JavaScript で距離を計算する場合は次のようになります。

var R = 6371; // km
var φ1 = lat1.toRadians();
var φ2 = lat2.toRadians();
var Δφ = (lat2-lat1).toRadians();
var Δλ = (lon2-lon1).toRadians();

var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
        Math.cos(φ1) * Math.cos(φ2) *
        Math.sin(Δλ/2) * Math.sin(Δλ/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

var d = R * c; 

楽しむ!

km とラジアンの間の変換が間違っています。海里は 1/60 度なので、1.15 と仮定すると…マイルから海里への換算は 1.6...kmから法定マイルへの換算は、

   nm = km /  (1.1515 * 1.609344);
   deg = nm / 60;
   rad = toRadians(deg);

言い換えれば、1000倍もずれていると思います。

更新された質問に関して:すべきではありません

double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[0];

なれ

double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[1];

他の回答や更新で言及されている実装エラーは別として、これらの式の大きな問題を理解しました。

大きな問題は次のとおりでした。距離法 (2 点間の距離を計算する) は大圏距離を計算していました。もちろん、これは理にかなっています。これが 2 点間の最短経路です。 しかし, 同じ平行線 (緯線) 上にある 2 点間の大圏距離は、赤道にいる場合を除き、緯線に沿って直接移動する場合の 2 点間の距離と同じではありません。

それで:機能は正しく動作しています。ただし、最初の質問で私が提案した代替座標系では、IDL に沿った北の距離のみを確認し、その後、結果として得られる緯度での緯線に沿って東の距離を確認する必要があります。そして、特定の緯線に沿った距離の計算は、大円に沿った距離の計算とはまったく異なります。

とにかく、それはあります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top