0

Googleでこれを検索すると多くの結果が得られると思いましたが、ほとんどの場合、ここのstackoverflowのように、質問は非常に具体的で、Googleマップ、一部のGIS、または楕円形の現実世界が含まれます。

私の場合、

  • lat、long、およびalt値を持つオブジェクトがあります。ここで、latおよびlongは度単位の浮動小数点数であり、altは10進値としての浮動小数点数であり、球の中心からの距離を表します。したがって、分はありません(10°30'は10.5です)。
  • オブジェクトは、x、y、zの3つの軸すべてで移動します。ここで、移動は現在の位置を基準にしています。
  • 新しい緯度、経度、代替値を計算する必要があります

あまり考えずに、最初は次のように実装しました。

altにzの動きを追加し、仮想球の円周を計算して、単位(メートル)あたりの度数を取得しました。それで私は最初に新しい緯度を計算し、その後ずっと新しい緯度を計算しました。次々と値を計算するのは間違っていることは知っていましたが、私の「オブジェクトワールド」でのすべての計算が同じ方法で行われる限り、全体的な動作は問題ありません。オブジェクトが球全体を回るとき、長い値は変わらない、球の周りを半分回るのはx軸とy軸で異なる(x軸:-180〜180、y-)などのことを考えました。軸-90から90)とそのようなものとそれは働いた。

しかし、その後、赤道でメートルあたりの度数を計算したことや、他の緯度の値を考慮していないことに気付きました。その時点で、私は物事がもっと複​​雑であることに気づき、ウェブを検索し始めました。しかし、自分のニーズに合うアルゴリズムは見つかりませんでした。これは以前にも何度も行われたことがあると確信しているので、誰かが以前にこのトピックを扱ったことがあり、素晴らしい実装を教えてくれる場合に備えて、ここで質問しています:)。

私が見つけたのはこれです:

  • 緯度/経度をメルカトル図法に変換するアルゴリズム
  • 2つの緯度/経度の値のペアからの距離を計算するための半正矢関数
  • 他の目的のための他の処方者

それは私を助けませんでした。

私が最も助けたのはこれでした:別の緯度/経度ポイントからメートルの距離を持つ緯度と経度を計算します

しかし、私はまだそれを完全には理解していなかったと思います。

  • ラジアンのコースは何ですか?(私にはxとyの動きがあることに関して)
  • 外挿法は、高度/地球の半径を考慮していませんか?

誰かがこれを手伝ってくれるといいですね!

(補足:私はこれをErlangで実装していますが、それは問題ではありません。どんな種類のアルゴリズムでも役に立ちます)


アップデート

上記の機能と以下の回答の機能を実装しました。テスト時に間違った値を取得しました。これは、実装を間違えたか、間違ったテストデータを計算したことが原因である可能性があります。どれどれ:

実装1:

% My own implementation that only works on the equator so far. Simple calculations as mentioned above.

テスト(赤道上)OK。

実装2:

% @doc calculates new lat+long+alt values for old values + movement vector
% https://stackoverflow.com/questions/5857523/calculate-latitude-and-longitude-having-meters-distance-from-another-latitude-lo
calc_position2(LastCurrLat, LastCurrLong, LastCurrAlt, MoveX, MoveY, MoveZ) ->
    % first the new altitude
    NewCurrAlt = LastCurrAlt + MoveZ,

    % original algorithm: http://williams.best.vwh.net/avform.htm#LL
    % lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
    % dlon=atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(lat))
    % lon=mod(lon1+dlon +pi,2*pi)-pi
    % where:
    % lat1, lon1    - start point in radians
    % d             - distance in radians
    % tc            - course in radians

    % -> for the found implementation to work some value conversions are needed
    CourseDeg = calc_course(MoveX, MoveY),
    CourseRad = deg_to_rad(CourseDeg), % todo: cleanup: in course the calculated values are rad anyway, converting to deg is just an extra calculation
    Distance = calc_distance(MoveX, MoveY),
    DistanceDeg = calc_degrees_per_meter_at_equator(NewCurrAlt) * Distance,
    DistanceRad = deg_to_rad(DistanceDeg),
    Lat1Rad = deg_to_rad(LastCurrLat),
    Lon1Rad = deg_to_rad(LastCurrLong),

    LatRad = math:asin(math:sin(Lat1Rad) * math:cos(DistanceRad) + math:cos(Lat1Rad) * math:sin(DistanceRad) * math:cos(CourseRad)),
    Dlon = math:atan2(math:sin(CourseRad) * math:sin(DistanceRad) * math:cos(Lat1Rad), math:cos(DistanceRad) - math:sin(Lat1Rad) * math:sin(LatRad)),
    LonRad = remainder((Lon1Rad + Dlon + math:pi()), (2 * math:pi())) - math:pi(),

    NewCurrLat = rad_to_deg(LatRad),
    NewCurrLong = rad_to_deg(LonRad),

    {NewCurrLat, NewCurrLong, NewCurrAlt}.

% some trigonometry
% returns angle between adjacent and hypotenuse, with MoveX as adjacent and MoveY as opposite
calc_course(MoveX, MoveY) ->
    case MoveX > 0 of
        true ->
            case MoveY > 0 of
                true ->
                    % tan(alpha) = opposite / adjacent
                    % arc tan to get the alpha
                    % erlang returns radians -> convert to degrees
                    Deg = rad_to_deg(math:atan(MoveY / MoveX));
                false ->
                    Temp = 360 - rad_to_deg(math:atan((MoveY * -1) / MoveX)),
                    case Temp == 360 of
                        true ->
                            Deg = 0.0;
                        false ->
                            Deg = Temp
                    end
            end;
        false ->
            % attention! MoveX not > 0 -> can be 0 -> div by zero
            case MoveX == 0 of
                true ->
                    case MoveY > 0 of
                        true ->
                            Deg = 90.0;
                        false ->
                            case MoveY == 0 of
                                true ->
                                    Deg = 0.0;
                                false ->
                                    Deg = 270.0
                            end
                    end;
                false -> % MoveX < 0
                    case MoveY > 0 of
                        true ->
                            Deg = 180 - rad_to_deg(math:atan(MoveY / (MoveX * -1)));
                        false ->
                            Deg = 180 + rad_to_deg(math:atan((MoveY * -1) / (MoveX * -1)))
                    end
            end
    end,
    Deg.

rad_to_deg(X) ->
    X * 180 / math:pi().
deg_to_rad(X) ->
    X * math:pi() / 180.

% distance = hypetenuse in Pythagorean theorem
calc_distance(MoveX, MoveY) ->
    math:sqrt(math:pow(MoveX,2) + math:pow(MoveY,2)).

calc_degrees_per_meter_at_equator(Alt) ->
    Circumference = 2 * math:pi() * Alt,
    360 / Circumference.

% erlang rem only operates with integers
% https://stackoverflow.com/questions/9297424/stdremainder-in-erlang
remainder(A, B) ->
    A_div_B = A / B,
    N = round(A_div_B),

    case (abs(N - A_div_B) == 0.5) of
    true ->
        A_div_B_Trunc = trunc(A_div_B),

        New_N = case ((abs(A_div_B_Trunc) rem 2) == 0) of
        true -> A_div_B_Trunc;
        false ->
            case (A_div_B >= 0) of
            true -> A_div_B_Trunc + 1;
            false -> A_div_B_Trunc - 1
            end
        end,
        A - New_N * B;
    false ->
        A - N * B
    end.

テスト:緯度/経度/高度(10°、10°、6371000m)のオブジェクト。動きなし(0m、0m、0m)。期待される:

{1.000000e+001,1.000000e+001,6.371000e+006}

しかし、戻ります:

{1.000000e+001,-3.500000e+002,6.371000e+006}

予想より360度少ない...

(0°、10°、6371000m)にあるオブジェクト、移動している(10m、0m、0m)。期待される:

{0.000000e+000,1.000009e+001,6.371000e+006}

一部の数字が表示されていないかどうかわからない。経度は10.000089932160591のようになります。とにかく-戻り値:

{8.993216e-005,-3.500000e+002,6.371000e+006}

今移動していますが、同じ間違った経度の値ですか?そして、Y軸上を移動しなかったのに、緯度の値が変更されましたか?

同じ位置で、現在5,000,000m東に移動している場合はどうでしょうか。

{0.000000e+000,5.496608e+001,6.371000e+006} % expected
{4.496608e+001,-3.500000e+002,6.371000e+006} % returned

実装3:

calc_position3(LastCurrLat, LastCurrLong, LastCurrAlt, MoveX, MoveY, MoveZ) ->
    {CurrX, CurrY, CurrZ} = spherical_to_cartesian(LastCurrLat, LastCurrLong, LastCurrAlt),
    NewX = CurrX + MoveX,
    NewY = CurrY + MoveY,
    NewZ = CurrZ + MoveZ,
    {NewCurrLat, NewCurrLong, NewCurrAlt} = cartesian_to_spherical(NewX, NewY, NewZ),
    {NewCurrLat, NewCurrLong, NewCurrAlt}.

spherical_to_cartesian(Lat, Lon, Alt) ->
    X = Alt * math:cos(Lat) * math:cos(Lon),
    Y = Alt * math:cos(Lat) * math:sin(Lon),
    Z = Alt * math:sin(Lat),
    {X, Y, Z}.

cartesian_to_spherical(X, Y, Z) ->
    R = math:sqrt(math:pow(X,2) + math:pow(Y,2)),
    Alt = math:sqrt(math:pow(X,2) + math:pow(Y,2) + math:pow(Z,2)),
    Lat = math:asin(Z / Alt),
    case R > 0 of
        true ->
            Lon = math:acos(X / R);
        false -> % actually: if R == 0, but it can never be negative (see above)
            Lon = 0
    end,
    {Lat, Lon, Alt}.

上記のようなテスト:

(10°、10°、6371000m)の物体、動きなし

{1.000000e+001,1.000000e+001,6.371000e+006} % expected
{-5.752220e-001,5.752220e-001,6.371000e+006} % returned

(0°、10°、6371000m)で、移動(10m、0m、0m)

{0.000000e+000,1.000009e+001,6.371000e+006} % expected
{0.000000e+000,2.566370e+000,6.370992e+006} % returned

(0°、10°、6371000m)で、移動(5000000m、0m、0m)

{0.000000e+000,5.496608e+001,6.371000e+006} % expected
{0.000000e+000,1.670216e+000,3.483159e+006} % returned

だから:私はいくつかのラジアンから度への変換または同様のものを逃しましたか?

PS:構文の強調表示が悪いので申し訳ありませんが、Erlangが利用できないようですので、シェルスクリプトを使用しました。少し読みやすくなります。

4

2 に答える 2

1

コメントへの回答から、ようやく十分な情報が得られました。

オブジェクトの位置を地理的緯度、経度 (WGS84 の緯度/経度と同等または類似のもの) および高度値で指定しました。高度は地球の中心から測定されます。

latitude : [-90 , 90] geographical latitude in decimal degrees, 90° is Northpole<br>
longitude: [-180, 180] longitude in decimal degrees, 0° is Greenwhich
altitude: [0 , INF ] in meters from center of earth.

したがって、これらの座標はSpherical 座標として定義されますが、時計回りと反時計回りに注意してください (後述)。

さらに、現在の位置からの相対移動を定義するメートル単位で測定された移動ベクトル (dx,dy,dz) を指定しました。
これらのベクトルは直交ベクトルとして定義されます。

あなたのアプリケーションは、ナビゲーション用でも飛行制御用でもなく、むしろゲームの分野です。

計算のために、x、y、z Achsis がどこに関連しているかを知る必要があります。ECEFが使用するのと同じ軸配置を使用する必要があります。

次の手順を実行する必要があります。

最初に、地理的な度数は数学的な度数ではないことを知っておく必要があります。数学では度数が反時計回りであるのに対し、地理学では時計回りに測定されることを知っておくことが重要な場合があります。
その後、座標をラジアンに変換する必要があります。

球座標をデカルト空間に変換します。(球面からデカルトへの変換: http://en.wikipedia.org/wiki/Spherical_coordinate_systemを参照) ただし、atan() ではなく Math.atan2() を使用してください。

( http://www.random-science-tools.com/maths/coordinate-converter.htmでコードを確認できます) Ted Hopp の回答でもこの変換が使用されているかどうかを確認してください。

変換後、単位 = 1m のデカルト x、y、z 空間に座標があります。

次はデカルト移動ベクトルです。正しい軸の位置合わせ、dx が x、-dx が -x、y、dy、z、dz にも対応するように、必ず変換するか、変換してください。

次に、ポイントを dx に追加します。

p2.x = p.x + dx;
p2.y = p.y + dy;
p2.z = p.z + dz;

次に、Wiki リンクまたは Ted Hopp に示されているように、球座標に再変換します。

コメントで指定した他のリンク (stackoverflow へ) は、​​他の種類の変換を行いますが、問題では機能しません。

1 つの特別なテスト ケースをお勧めします: 球面ポイントを経度 = 179.9999999 に設定し、次に 100m を追加すると、結果は -180.0000xx + コンマの後に何かになります (2 機のジェット戦闘機がデータム リミットを通過するときにこの問題でクラッシュしました)

于 2012-12-09T14:02:39.720 に答える
1

仮定しましょう:

  • 赤道はxy平面にあります
  • 緯度 0、経度 0、高度 > 0 は +x 軸上
  • 極は経度 0 にある

これらの仮定を使用して、球面 (lat、lng、alt) からデカルト (x、y、z) に変換するには:

x = alt * cos(lat) * cos(lng)
y = alt * cos(lat) * sin(lng)
z = alt * sin(lat)

デカルト (x、y、z) から球面 (lat、lng、alt) に変換するには:

r = sqrt(x*x + y*y)
alt = sqrt(x*x + y*y + z*z)
lat = arcsin(z / alt)
       / arccos(x / r) if r > 0
lng = -|
       \ 0 if r == 0

次に、@Peter の提案に従います。

(lat, lng, alt) = toSpherical(movement + toCartesian(lat, lng, alt))
于 2012-12-04T21:42:08.920 に答える