Calcul de la longitude correcte lorsqu'elle est supérieure à | 180 |?

11

J'essaie de développer une "formule" pour corriger les valeurs lat-lng.

J'utilise vue-leaflet mais quand vous vous déplacez en dehors du "premier" monde, vous obtenez de gros chiffres. Plus de +180 ou moins de -180.

Par exemple: lorsque je fais un panoramique vers l'Amérique vers la droite (direction est), j'obtiens le lng 215. Dans mon esprit, je le corrigerais simplement avec 215-360=-145

Il en va de même lorsque je fais un panoramique vers l'est de la russie vers la gauche (direction ouest) et j'obtiens par exemple -222. Maintenant, je dois calculer-222+360=138

Cependant, comme le monde est indéfini, l'utilisateur pouvait se déplacer vers le 8ème monde et j'ai dû ajuster les valeurs.

Est-il possible de calculer la bonne longitude? (et une autre exigence est lorsque l'utilisateur est dans le premier monde, 24 lng devraient toujours être 24 lng.

Shadrix
la source

Réponses:

16

Vous devez ajouter (ou soustraire) à plusieurs reprises 360 à votre valeur jusqu'à ce qu'elle se situe dans la plage de -180 à 180. Donc, généralement une paire de boucles comme:

lon = -187;
while(lon < -180){
  lon +=360;
}
while (lon > 180){
  lon -= 360;
}
Ian Turton
la source
signe le mauvais sens? Doit être lon + = 360 dans le premier cas.
JimT
4
vous pouvez le faire avec une seule boucle, while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }mais je ne fournis pas de réponse car votre version correspond en fait à l'explication, tandis que ma version n'est qu'une optimisation qui ne fait probablement aucune différence. Je le garde comme commentaire uniquement pour rappeler que les choses peuvent être faites de plusieurs façons, certaines plus optimisées que d'autres.
Andrei
2
Je ne pense pas que j'utiliserais celui-là car il utilise 2 appels de fonction par boucle et une seule de mes boucles s'exécuterait jamais. Cela ne fait probablement aucune différence dans cet exemple mais c'est mon préjugé
Ian Turton
bien qu'elles ressemblent à des fonctions, les fonctions mathématiques en JavaScript doivent être vues davantage comme des opérateurs avec des symboles verbeux. En ce sens, nous pouvons également voir + - et même <comme des fonctions. Edit: J'avais une solution ici qui ne fonctionnait pas réellement
Andrei
2
Tu ne peux pas faire lon %= 180?
Fund Monica's Lawsuit
15

Une réponse qui évite les appels conditionnels et de fonction:

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

J'ai écrit une référence rapide sur https://jsperf.com/longitude-normalisation et le code conditionnel semble être plus rapide (dans Chrome sur ma machine) pour des plages de valeurs d'entrée «raisonnables». En général, vous ne devriez probablement pas vous soucier à l'avance des performances dans les petits calculs comme celui-ci, ce qui donne plus de poids à la lisibilité et à la cohérence avec le reste de votre base de code.

Le plus important dans ce cas est probablement la question de savoir si votre code pourrait jamais rencontrer des valeurs d'entrée extrêmes (1e10, Infinity, etc.). Si tel est le cas, l'implémentation en boucle pourrait finir par s'exécuter très lentement ou silencieusement en bloquant votre programme. Cela peut se produire avec des calculs effectués près des pôles, par exemple, essayer de se déplacer vers l'est ou l'ouest à une certaine distance (plutôt que l'angle) d'un pôle pourrait facilement entraîner une longitude infinie.

Joe Lee-Moyet
la source
1
Intéressant. Faisons la course entre un jmp conditionnel et une division FP. Hmmm je me demande.
Joshua
1
@Joshua Vous ne pouvez pas utiliser un saut conditionnel. Vous devez utiliser plusieurs sauts conditionnels , alias une boucle. (De plus, la boucle contient des virgules flottantes supplémentaires, ce qui n'est pas gratuit.) Le nombre d'itérations dont la boucle a besoin dépend de l'entrée. Vous devez donc savoir quelque chose sur les données pour examiner les performances. Si la grande majorité est proche de la plage souhaitée et nécessite peu d'itérations, bien sûr, la boucle d'addition peut être plus rapide, mais ce n'est pas aussi évident que votre sarcasme le suggère.
jpmc26
1
@ jpmc26: Dans ce cas, s'attendre à faire le tour de la boucle plus d'une fois est idiot.
Joshua
1
Il n'y avait pas de sarcasme. En fait, je ne sais pas de quelle façon il tomberait.
Joshua
1
@Joshua yep, je n'étais pas sûr non plus :). J'ai ajouté plus à la réponse sur les performances (et un cas d'échec potentiel du code de boucle)
Joe Lee-Moyet
5

Bon mot:

normalized = remainder(longitude, 360);

Explication: Vous voulez savoir ce qui reste après avoir ignoré les rotations complètes (360 °).

Ce processus est appelé normalisation.

Exemple (cpp.sh)

Basé
la source
1
Cela ne donnerait-il pas une valeur [0, 360), et non [-180, 180] comme Shadrix l'a demandé?
The Guy with The Hat
@TheGuywithTheHat Vérifiez cet exemple: cpp.sh/7uy2v
Basé
Ah, je ne savais pas que c'était C ++. Dans le contexte de Shadrix de JavaScript, j'ai interprété remaindercomme modulus. Le module dans JS résulterait en [0, 360).
The Guy with The Hat
1
Je ne pense pas que cela fonctionnerait. Vous auriez besoin de soustraire 360 ​​si le résultat> 180. Un autre problème que je viens de réaliser avec JavaScript est que le modulo est symétrique sur 0, par exemple -1 % 3est -1, pas 2 comme cela serait nécessaire pour qu'il fonctionne ici. remainderest une excellente solution C ++, mais malheureusement il n'y a tout simplement pas de fonction / opérateur dans JS suffisamment similaire pour être utile.
The Guy with The Hat
0

Une autre option: longitude = atan2 (cos (long), sin (long))

Andres
la source
1
Cela ne semble pas être une bonne idée. Il est très difficile à comprendre, coûteux en calculs et potentiellement sujet à des erreurs d'arrondi.
David Richerby
0

Si le langage de programmation que vous utilisez prend en charge l'opérateur% (mod) sur les nombres à virgule flottante (comme Python et Ruby), je recommanderais de l'utiliser. Sinon, certains autres langages (comme C et C ++) vous permettent d'utiliser fmod ().

(Quel que soit l'opérateur de mod que vous utilisez, assurez-vous à l'avance qu'il effectuera des opérations de mod sur des nombres à virgule flottante et qu'il vous donnera toujours des réponses non négatives. Sinon, vous aurez une mauvaise surprise plus tard lorsque beaucoup de vos les points lat / lon ne sont pas corrects.)

Utilisez-le comme ceci:

# 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

Si vous préférez tout faire en une seule ligne:

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

Ces approches n'ont pas de boucles, donc elles normaliseront les valeurs de longitude sans avoir à ajouter ou à soustraire à plusieurs reprises, quel que soit le nombre de fois que votre observation a fait le tour de la Terre.

Éditer:

Hmmm ... Je viens de remarquer que Javascript ne semble pas gérer %les valeurs négatives comme je le pensais.

Dans ce cas, essayez ce one-liner:

longitude = (longitude + 36180) % 360 - 180

Le 36180nous est l' ajout 36000 + 180. Le 36000 est de déplacer une valeur négative dans le domaine positif, et le 180 est de décaler de telle sorte que lorsqu'il est modded par 360, ce sera dans la gamme de [0360) . La - 180pièce la ramène à la plage de [-180,180).

Voici un autre one-liner, qui ne dépend pas de 36 000 étant assez gros:

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

La longitude % 360 + 360partie garantira que la valeur reste dans le domaine positif lorsqu'elle sera modifiée par la suite 360. La + 180partie la décale de sorte que lorsqu'elle sera ensuite soustraite de 180 (avec - 180), elle sera dans la plage souhaitée de [-180,180).

JL
la source
1
Remarque: C, C ++ fmod(longitude, 360)-> (-360.0 ... +360.0) et ilongitude % 360-> [-359 ... +359].
chux
@chux - Je ne le savais pas, alors je viens de le tester, et il semble que vous ayez raison. Merci d'avoir fait remarquer cela.
JL