Berechnung der korrekten Länge, wenn sie über | 180 | liegt?

11

Ich versuche eine "Formel" zu entwickeln, um die lat-lng-Werte zu korrigieren.

Ich benutze eine Vue-Broschüre, aber wenn Sie außerhalb der "ersten" Welt schwenken, erhalten Sie große Zahlen. Über +180 oder unter -180.

Zum Beispiel: Wenn ich nach rechts (Richtung Osten) nach Amerika schwenke, erhalte ich lng 215. In meinen Gedanken würde ich es einfach mit korrigieren 215-360=-145

Das gleiche gilt, wenn ich nach Ostrussland nach links schwenke (Westrichtung) und zum Beispiel -222 bekomme. Jetzt muss ich rechnen-222+360=138

Da die Welt jedoch unbestimmt ist, konnte der Benutzer zur 8. Welt schwenken, und ich musste die Werte anpassen.

Ist es möglich, den richtigen Längengrad zu berechnen? (und eine andere Anforderung ist, wenn sich der Benutzer in der ersten Welt befindet, sollten 24 lng immer noch 24 lng sein.

Shadrix
quelle

Antworten:

16

Sie müssen 360 wiederholt zu Ihrem Wert addieren (oder subtrahieren), bis er im Bereich von -180 - 180 liegt. Normalerweise sind also zwei Schleifen wie:

lon = -187;
while(lon < -180){
  lon +=360;
}
while (lon > 180){
  lon -= 360;
}
Ian Turton
quelle
Zeichen falsch herum? Sollte im ersten Fall lon + = 360 sein.
JimT
4
Sie können es mit nur einer Schleife tun. while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }Ich gebe es jedoch nicht als Antwort, da Ihre Version tatsächlich der Erklärung entspricht, während meine Version nur eine Optimierung ist, die wahrscheinlich keinen Unterschied macht. Ich behalte es nur als Kommentar, um daran zu erinnern, dass Dinge auf verschiedene Arten erledigt werden können, von denen einige optimierter sind als andere.
Andrei
2
Ich glaube nicht, dass ich diesen jemals verwenden würde, da er 2 Funktionsaufrufe pro Schleife verwendet und nur eine meiner Schleifen jemals ausgeführt werden würde. Wahrscheinlich macht es in diesem Beispiel keinen Unterschied, aber das ist mein Vorurteil
Ian Turton
Während sie wie Funktionen aussehen, sollten mathematische Funktionen in JavaScript eher als Operatoren mit ausführlichen Symbolen gesehen werden. In diesem Sinne können wir auch + - und sogar <als Funktionen sehen. Edit: Ich hatte hier eine Lösung, dass es nicht wirklich funktionierte
Andrei
2
Das kannst du nicht lon %= 180?
Fund Monica Klage
15

Eine Antwort, die Bedingungen und Funktionsaufrufe vermeidet:

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

Ich habe unter https://jsperf.com/longitude-normalization ein schnelles Mikrobenchmark geschrieben, und der bedingte Code scheint für "angemessene" Bereiche von Eingabewerten schneller zu sein (in Chrome auf meinem Computer). Im Allgemeinen sollten Sie sich bei kleinen Berechnungen wie diesen wahrscheinlich nicht im Voraus Gedanken über die Leistung machen, um der Lesbarkeit und Konsistenz mit dem Rest Ihrer Codebasis mehr Gewicht zu verleihen.

Wahrscheinlich wichtiger in diesem Fall ist die Frage, ob Ihr Code jemals auf extreme Eingabewerte stoßen könnte (1e10, Infinity usw.). In diesem Fall läuft die Schleifenimplementierung möglicherweise sehr langsam oder hängt Ihr Programm stillschweigend auf. Dies kann bei Berechnungen in der Nähe der Pole auftreten, z. B. kann der Versuch, nach Osten oder Westen um einen gewissen Abstand (und nicht um einen Winkel) von einem Pol zu schwenken, leicht zu einer unendlichen Länge führen.

Joe Lee-Moyet
quelle
1
Interessant. Lassen Sie uns einen bedingten JMP gegen eine FP-Kluft fahren. Hmmm, ich frage mich.
Joshua
1
@Joshua Du kannst keinen bedingten Sprung verwenden. Sie müssen mehrere bedingte Sprünge verwenden , auch bekannt als Schleife. (Außerdem enthält die Schleife zusätzliches Gleitkomma, was nicht frei ist.) Wie viele Iterationen die Schleife benötigt, hängt von der Eingabe ab. Sie müssen also etwas über die Daten wissen, um die Leistung zu überprüfen. Wenn sich die überwiegende Mehrheit in der Nähe des gewünschten Bereichs befindet und nur wenige Iterationen erforderlich sind, ist die Additionsschleife möglicherweise schneller, aber nicht so offensichtlich, wie es Ihr Sarkasmus vermuten lässt.
jpmc26
1
@ jpmc26: In diesem Fall ist es dumm, zu erwarten, dass man die Schleife mehr als einmal umgeht.
Joshua
1
Es gab keinen Sarkasmus. Ich weiß eigentlich nicht, in welche Richtung es fallen würde.
Joshua
1
@ Joshua yep, ich war mir auch nicht sicher :). Ich habe der Antwort zur Leistung (und einem möglichen Fehlerfall des Schleifencodes) mehr hinzugefügt
Joe Lee-Moyet
5

Einzeiler:

normalized = remainder(longitude, 360);

Erläuterung: Sie möchten wissen, was übrig bleibt, nachdem Sie die vollen Umdrehungen (360 °) ignoriert haben.

Dieser Vorgang wird als Normalisieren bezeichnet.

Beispiel (cpp.sh)

Basierend
quelle
1
Würde dies nicht zu einem [0, 360) -Wert führen, nicht zu [-180, 180], wie Shadrix es verlangt hat?
Der Kerl mit dem Hut
@TheGuywithTheHat Überprüfen Sie dieses Beispiel: cpp.sh/7uy2v
Basierend auf dem
Ah, wusste nicht, dass dies C ++ ist. In Shadrix 'Kontext von JavaScript interpretierte ich remainderals modulus. Der Modul in JS würde zu [0, 360] führen.
Der Kerl mit dem Hut
1
Ich denke nicht, dass das funktionieren würde. Sie müssten 360 iff result> 180 subtrahieren. Ein weiteres Problem, das ich gerade mit JavaScript erkannt habe, ist, dass Modulo über 0 symmetrisch ist, z. B. -1 % 3-1, nicht 2, wie es erforderlich wäre, damit es hier funktioniert. remainderist eine großartige C ++ - Lösung, aber leider gibt es in JS keine Funktion / keinen Operator, die ähnlich genug ist, um nützlich zu sein.
Der Kerl mit dem Hut
0

Eine weitere Option: longitude = atan2 (cos (lang), sin (lang))

Andres
quelle
1
Dies scheint keine gute Idee zu sein. Es ist sehr schwer zu verstehen, rechenintensiv und kann Rundungsfehlern unterliegen.
David Richerby
0

Wenn die von Ihnen verwendete Programmiersprache den Operator% (mod) für Gleitkommazahlen (wie Python und Ruby) unterstützt, würde ich die Verwendung empfehlen. Andernfalls können Sie in einigen anderen Sprachen (wie C und C ++) fmod () verwenden.

(Unabhängig davon, welchen Mod-Operator Sie verwenden, stellen Sie im Voraus sicher, dass Mod-Operationen für Gleitkommazahlen ausgeführt werden und dass Sie immer nicht negative Antworten erhalten. Andernfalls erhalten Sie später eine böse Überraschung, wenn viele von Ihnen Lat / Lon-Punkte sind nicht korrekt.)

Verwenden Sie es so:

# 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

Wenn Sie es vorziehen, alles in einer Zeile zu erledigen:

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

Diese Ansätze haben keine Schleifen, daher normalisieren sie Längengrade, ohne dass wiederholt addiert oder subtrahiert werden muss, unabhängig davon, wie oft Ihre Beobachtung um die Erde kreist.

Bearbeiten:

Hmmm ... Ich habe gerade bemerkt, dass Javascript nicht %mit negativen Werten umzugehen scheint, wie ich es mir vorgestellt hatte.

Versuchen Sie in diesem Fall diesen Einzeiler:

longitude = (longitude + 36180) % 360 - 180

Das, was 36180wir hinzufügen, ist 36.000 + 180. Die 36.000 sollen einen negativen Wert in den positiven Bereich verschieben, und das 180 soll ihn verschieben, so dass er, wenn er von modifiziert wird 360, im Bereich von [0,360] liegt. . Das - 180Teil verschiebt es zurück in den Bereich von [-180,180].

Hier ist ein weiterer Einzeiler, der nicht davon abhängt, dass 36.000 groß genug sind:

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

Das longitude % 360 + 360Teil stellt sicher, dass der Wert in der positiven Domäne bleibt, wenn er später von geändert wird 360. Das + 180Teil verschiebt es so, dass es, wenn es später um 180 subtrahiert wird (mit - 180), im gewünschten Bereich von [-180,180] liegt.

J L
quelle
1
Hinweis: C, C ++ fmod(longitude, 360)-> (-360.0 ... +360.0) und ilongitude % 360-> [-359 ... +359].
chux
@chux - Ich wusste nichts davon, also habe ich es gerade getestet und es scheint, dass Sie richtig sind. Vielen Dank für den Hinweis.
JL