2

次のメソッドを書くのに助けが必要です:

def get_new_location(current_location, target_location, distance_travelled):
    ...
    ...
    return new_location

すべての場所は (緯度、経度)

地球が楕円体であるという事実を考慮した、地球にはさまざまなモデル (WGS-84、GRS-80 など) があることを認識しています。私の目的では、完全な球体で十分であると仮定すると、このレベルの精度は必要ありません。

アップデート

いくつかの回答を考慮して、質問を微調整しています。

benjismithは、地球上のポイント間に複数の最短経路があるため、私の質問に答えることができないと主張しています。彼は投票という形で多くの支持を持っているので、私は同意しないので、私が理解できない何かがあると思います.

球上の任意の 2 つの位置の間の中点は円弧です。

これは、2 つの点が完全に正反対の場合に当てはまることを認めます。これは、両方の点が球の表面にとどまっている間、互いにこれ以上離れることはできないことを意味します。この場合、両方の点を結ぶ等距離の経路は無数にあります。ただし、これは特殊なケースであり、ルールではありません。他のすべてのケースでは、大多数のケースでは、単一の最短パスがあります。

説明すると、2 点を通過する紐を持って強く引っ張った場合、紐が落ち着く経路は 1 つだけではないでしょうか (既に説明したエッジ ケースを除く)。

さて、質問をする前に、2 点と方​​位の間の距離を取得することは問題ではありませんでした。

私が尋ねるべきだったのは、次のことが有効かどうかだと思います。

def get_new_location(current_location, target_location, percent_traveled):
    new_location.lon = (1-percent_traveled)*current_location.lon+percent_traveled*target_location.lon
    new_location.lat = (1-percent_traveled)*current_location.lat+percent_traveled*target_location.lat
    return new_location

もし私がこの道をたどるとしたら、私は大圏、菱形線をたどることになるでしょうか?それとも完全に外れてしまうのでしょうか? (Drew Hall の回答のおかげで、これらの用語を知っています。)

4

4 に答える 4

3

BenjiSmith が言ったように、地球上の任意の A と B を接続する経路は潜在的にいくつかありますが、最も人気のある (断然!) 2 つの経路は、「大円」と「菱形」経路です。

大円は最短距離を示します (2 点と地球の中心から平面を作成し、その平面で円弧をたどることにより)。

菱形線は一定の方位を維持し、使いやすさのためにある程度の距離 (高緯度では極端になる可能性があります) を交換します。つまり、船や飛行機では目的の方向を指し示し、目的地に到着するまで進みます (大円の場合、方向は連続的に変化します)。中緯度では、距離のペナルティはそれほど厳しくありません。

どちらのパス タイプにも、対蹠点 (球上で互いに反対側にある点) を処理する際の極とあいまいさを含む不連続性があることに注意してください。


大円を作成するには、ポイントを 3D デカルト座標に変換する必要があります (この手順は省きますが、球状の地球では簡単なことであり、WGS-84 の偏球地球モデルでは反復的に見つけられます)。

地球の中心から始点を指す単位ベクトルを a とし ます

地球の中心から端点を指す単位ベクトルを b とします

rを地球の半径とします

(与えられた) 移動距離を d とする。

単位ベクトルabの外積をとることにより、GC 平面に垂直な単位ベクトルを作成します。つまり、n = axb とします。

(与えられた) 移動距離は、ベクトル *r***a** をnの周りで角度thetaだけ掃引することによって形成される弧の長さです。完全な大円の円周が 2 * pi * rであることを思い出して、シータ= d / rを見つけます。

したがって、新しい位置に対応するデカルト ポイントは、*r***a** をnの周りでシータラジアンだけ回転させることによって検出されます。そのデカルト ポイントを緯度/経度に変換して完了です。

ここでは菱形線の計算を導出しませんが、メルカトル図法には菱形線が直線であるという性質があることを述べておきます。メルカトル図法を使用して菱形線を簡単に作成できますが、パスを短い直線セグメントに分割できるように、ある程度の許容誤差を定義する必要があります。

幸運を!

于 2008-11-12T05:53:19.307 に答える
2

これを行うサンプルコードを次に示します。このアルゴリズムはすべてのケースで機能し、常に 2 つの場所の間の最短の大圏経路に従います。数学は基本的に Drew Hall の回答と同じですが、percent_traveled を使用し、地球の半径を無視しています。

簡単にするために、このコードでは緯度と経度がラジアンで格納されていることを前提としています。

def get_new_location(current_location, target_location, percent_traveled):
# convert locations into cartiesian co-ordinates current_vector = location_to_vector(current_location) target_vector = location_to_vector(target_location) # compute the angle between current_vector and target_vector complete_angle = acos(vector_dot_product(current_vector, target_vector)) # determine the current partial angle, based on percent_traveled partial_angle = percent_traveled*complete_angle # compute a temporary vector to simplify calculation temporary_vector = vector_cross_product(current_vector, target_vector) temporary_vector = vector_cross_product(current_vector, temporary_vector) # calculate new_vector scalar_one = cos(partial_angle) scalar_two = -sin(partial_angle)/sin(complete_angle) vector_one = vector_multiply_by_scalar(scalar_one, current_vector) vector_two = vector_multiply_by_scalar(scalar_two, temporary_vector) new_vector = vector_sum(vector_one, vector_two) # convert new_vector back into latitude & longitude and return new_location = vector_to_location(new_vector) return new_location
緯度と経度からデカルト座標に変換する関数:
def location_to_vector(location)
    vector.x = cos(location.lat)*sin(location.lon)
    vector.y = sin(location.lat)
    vector.z = cos(location.lat)*cos(location.lon)
    return vector
デカルト座標から緯度と経度に変換する関数:
def vector_to_location(vector)
    location.lat = asin(vector.y)
    if (vector.z == 0):
        if (vector.x < 0):
            location.lon = -pi/2
        else:
            location.lon = pi/2
    else:
        if (vector.z < 0):
            if (vector.x < 0):
                location.lon = atan(vector.x/vector.z) - pi
            else:
                location.lon = pi - atan(-vector.x/vector.z)
        else:
            if (vector.x < 0):
                location.lon = -atan(-vector.x/vector.z)
            else:
                location.lon = atan(vector.x/vector.z)
    return location
2 つのベクトルの内積を計算する関数:
def vector_dot_product(A, B):
    dot_product = A.x*B.x + A.y*B.y + A.z*B.z
    return dot_product
2 つのベクトルの外積を計算する関数:
def vector_cross_product(A, B):
    cross_product.x = A.y*B.z - A.z*B.y
    cross_product.y = A.z*B.x - A.x*B.z
    cross_product.z = A.x*B.y - A.y*B.x
    return cross_product
ベクトルをスカラーで乗算する関数:
def vector_multiply_by_scalar(scalar, vector)
    scaled_vector.x = scalar*vector.x
    scaled_vector.y = scalar*vector.y
    scaled_vector.z = scalar*vector.z
    return scaled_vector
2 つのベクトルの和を計算する関数:
def vector_sum(A, B)
    sum.x = A.x + B.x
    sum.y = A.y + B.y
    sum.z = A.z + B.z
    return sum

于 2008-11-14T16:35:48.283 に答える
2

更新された質問について:

あなたがしているように見えるのは、緯度/経度座標の線形補間です。これは有効なパスですが、大円でも菱形でもありません。実際、子午線は緯度が増加するにつれて (少なくとも北半球では) 収束するため、緯度/経度の意味で滑らかな補間を行うと、地上で奇妙に加速する経路になります。

デカルト座標で補間を記述している場合、少なくとも正しい平面で移動しますが、パスは地球の表面を横切ります (つまり、円弧ではなく、大円の弦になります)。

于 2008-11-12T20:42:39.683 に答える
-1

更新されたサンプル コードが常に正しいパスをたどるとは限りません。

簡単な例として、太平洋の真ん中にある赤道上の次の 2 つのポイントを考えてみましょう。

  • 現在の場所: 緯度 = 0、経度 = -179
  • target_location: 緯度 = 0、経度 = 179

これら 2 つのポイントは非常に接近しています (経度で 2 度しか離れていません) が、percent_traveled が 0.5 の場合、new_location は次のようになります: lat = 0, lon = 0、これは地球の反対側のポイントです。

編集:悪化します

北半球の次の 2 点について考えてみましょう。

  • current_location: 緯度 = 80、経度 = 0
  • target_location: 緯度 = 80、経度 = 180

これら 2 点間の大円経路は北極を直接通過しますが、new_location は地球上を移動、赤道と平行のままになります。

于 2008-11-12T23:17:22.367 に答える