| 180 |を超えたときに正しい経度を計算していますか?


11

緯度経度の値を修正する「式」を開発しようとしています。

私はVueリーフレットを使用していますが、「最初の」世界の外でパンすると、大きな数字が表示されます。+180以上または-180未満。

例:アメリカに向かって右(東方向)にパンすると、lng 215になります。私の考えでは、次のように修正するだけです。 215-360=-145

同じことは、東ロシアに向かって左(西方向)に画面移動した場合も同様で、たとえば-222になります。今計算する必要があります-222+360=138

ただし、世界は無期限であるため、ユーザーは8番目の世界に移動でき、値を調整する必要がありました。

正しい経度を計算することは可能ですか?(そして別の要件は、ユーザーが最初の世界にいるとき、24 lngはまだ24 lngであるべきです。

回答:


16

-180から180の範囲になるまで、値に360を繰り返し加算(または減算)する必要があります。通常、次のようなループのペアです。

lon = -187;
while(lon < -180){
  lon +=360;
}
while (lon > 180){
  lon -= 360;
}

間違った方法で署名しますか?最初のケースではlon + = 360である必要があります。
JimT 2018年

4
1つのループだけでそれを実行できwhile (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }ます。バージョンは実際に説明と一致しているため、答えとしては提供していませんが、私のバージョンは最適化であり、ほとんど違いはありません。私はそれをコメントとして保持していますが、物事は複数の方法で実行できることを思い出させるためだけに残しています。
Andrei

2
ループごとに2つの関数呼び出しを使用し、ループの1つだけが実行されるため、これを使用することはないと思います。この例ではおそらく違いはありませんが、それが私の偏見です
Ian Turton

それらは関数のように見えますが、JavaScriptの数学関数は、詳細な記号を持つ演算子のように見えるはずです。この意味で、+-や<も関数として見ることができます。編集:私はそれが実際に機能しないという解決策をここに持っていました
Andrei

2
あなたはできませんlon %= 180か?
モニカの訴訟に資金を

15

条件文と関数呼び出しを回避する答え:

longitude = (longitude % 360 + 540) % 360 - 180

私はhttps://jsperf.com/longitude-normalizationで簡単なマイクロベンチマークを書きました。条件付きコードは、「妥当な」範囲の入力値に対して(私のマシンのChromeでは)より高速のようです。一般に、このような小さな計算のパフォーマンスについて事前に心配する必要はないでしょう。読みやすさと、コードベースの他の部分との一貫性がより重視されます。

この場合、おそらくより重要なのは、コードが極端な入力値(1e10、Infinityなど)に遭遇する可能性があるかどうかという問題です。その場合、ループの実装は、プログラムの実行が非常に遅くなるか、静かに停止する可能性があります。これは、極の近くで実行される計算で発生する可能性があります。たとえば、極から(角度ではなく)ある距離だけ東または西にパンしようとすると、簡単に無限の経度になる可能性があります。


1
面白い。条件付きjmpをFP除算と競いましょう。うーん。
ジョシュア

1
@ジョシュア条件付きジャンプは使用できません。複数の条件付きジャンプ、つまりループを使用する必要があります。(さらに、ループには浮動小数点の追加が含まれていますが、これは無料ではありません。)ループに必要な反復回数は入力によって異なります。したがって、パフォーマンスを確認するには、データについて何かを知っている必要があります。大部分が目的の範囲に近く、反復がほとんど必要ない場合、確かに、追加ループはより高速になる可能性がありますが、皮肉が示唆するほど明確ではありません。
jpmc26

1
@ jpmc26:この場合、ループを複数回実行することを期待するのはばかげています。
ジョシュア

1
皮肉はありませんでした。どちらの方向に落ちるのか、実際にはわかりません。
ジョシュア

1
@ジョシュアうん、私もどちらかわからなかった:)。パフォーマンスに関する回答(およびループコードの潜在的な失敗例)にさらに追加しました
Joe Lee-Moyet

5

一発ギャグ:

normalized = remainder(longitude, 360);

説明:完全な回転(360度)を無視した後に残っているものを知りたいとします。

このプロセスは正規化と呼ばれます。

例(cpp.sh)


1
これは、Shadrixが要求したような[-180、180]ではなく、[0、360)の値になりますか?
帽子をかぶった男

@TheGuywithTheHatこの例を確認してください:cpp.sh/7uy2v
基づく

ああ、これがC ++だとは知らなかった。ShadrixのJavaScriptのコンテキストでは、と解釈しremainderましたmodulus。JSの係数は[0、360)になります。
帽子をかぶった男

1
私はそれがうまくいくとは思いません。結果が180を超える場合は360を引く必要があります。JavaScriptで今気付いたもう1つの問題は、-1 % 3ここで機能するために必要なように、モジュロが0では対称であるということです。remainderは優れたC ++ソリューションですが、残念ながら、JSには便利で十分に類似した関数/演算子がありません。
帽子をかぶった男

0

別のオプション:経度= atan2(cos(long)、sin(long))


1
これは良い考えではないようです。理解するのが非常に難しく、計算コストが高く、丸め誤差が発生する可能性があります。
David Richerby

0

使用しているプログラミング言語が浮動小数点数(PythonやRubyなど)で%(mod)演算子をサポートしている場合は、それを使用することをお勧めします。それ以外の場合、他のいくつかの言語(CやC ++など)では、fmod()を使用できます。

(どちらのmod演算子を使用する場合でも、それが浮動小数点数に対してmod操作を実行すること、および常に非負の答えが得られることを事前に確認してください。それ以外の場合は、後で多くの緯度/経度ポイントは正しくありません。)

次のように使用します。

# Put the longitude in the range of [0,360):
longitude %= 360

# Put the longitude in the range of [-180,180):
if longitude >= 180:
    longitude -= 360

すべてを1行で実行したい場合:

# Put the longitude in the range of [-180,180):
longitude = (longitude + 180) % 360 - 180

これらのアプローチにはループがないため、観測値が地球を周回した回数に関係なく、繰り返し加算または減算する必要なく経度値を正規化します。

編集:

うーん... Javascriptは、%思ったように負の値を処理できないようです。

その場合は、次のワンライナーを試してください。

longitude = (longitude + 36180) % 360 - 180

36180私たちが追加している36,000が正の領域に負の値を移動させることで、180はそれがでモッドされたときにことをそれを上にシフトすることである36000 + 180である360)、それは[0360の範囲になります。- 180それは[-180180)の範囲に後部移行します。

これは、36,000の十分な大きさに依存しない別のワンライナーです。

longitude = (longitude % 360 + 360 + 180) % 360 - 180

longitude % 360 + 360それは、後によりモッドだときの部分は、正の領域での値の滞在を保証します360+ 180それは後で(とから差し引か180を取得したときに一部シフトは、それが上ように- 180)、それは[-180180)の所望の範囲内になるだろう。


1
注:C、C ++ fmod(longitude, 360)->(-360.0 ... +360.0)およびilongitude % 360-> [-359 ... +359]。
chux-モニカを

@chux-私はそれについて知らなかったので、私はそれをテストしたところ、あなたは正しいようです。指摘いただきありがとうございます。
JL
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.