Cálculo de la longitud correcta cuando termina | 180 |?

11

Estoy tratando de desarrollar una "fórmula" para corregir los valores de lat-lng.

Estoy usando vue-leaflet pero cuando se desplaza fuera del "primer" mundo obtiene grandes números. Más de +180 o menos de -180.

Por ejemplo: cuando me desplazo hacia América a la derecha (dirección este), obtengo como lng 215. En mi mente, simplemente lo corregiría con 215-360=-145

Lo mismo ocurre cuando me desplazo hacia el este de Rusia hacia la izquierda (dirección oeste) y obtengo, por ejemplo, -222. Ahora necesito calcular-222+360=138

Sin embargo, dado que el mundo es indefinido, el usuario podría desplazarse al octavo mundo y tuve que ajustar los valores.

¿Es posible calcular la longitud correcta? (y otro requisito es cuando el usuario está en el primer mundo, 24 lng aún debe ser 24 lng.

Shadrix
fuente

Respuestas:

16

Debe sumar repetidamente (o restar) 360 a su valor hasta que se encuentre en el rango de -180 a 180. Por lo general, un par de bucles como:

lon = -187;
while(lon < -180){
  lon +=360;
}
while (lon > 180){
  lon -= 360;
}
Ian Turton
fuente
Señales al revés? Debe ser lon + = 360 en el primer caso.
JimT
44
puedes hacerlo con un solo bucle while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }. Sin embargo, no lo estoy proporcionando como respuesta porque tu versión realmente coincide con la explicación, mientras que mi versión es solo una optimización que probablemente no haga ninguna diferencia. Lo mantengo como un comentario solo como un recordatorio de que las cosas se pueden hacer de múltiples maneras, algunas más optimizadas que otras.
Andrei
2
No creo que alguna vez lo use, ya que usa 2 llamadas de función por ciclo y solo uno de mis ciclos se ejecutará. Probablemente no hay diferencia en este ejemplo, pero ese es mi prejuicio
Ian Turton
Si bien parecen funciones, las funciones matemáticas en JavaScript deberían verse más como operadores con símbolos detallados. En este sentido, también podemos ver + - e incluso <como funciones también. Editar: Tenía una solución aquí que en realidad no funcionaba
Andrei
2
No puedes hacer lon %= 180?
Financia la demanda de Mónica el
15

Una respuesta que evita condicionales y llamadas a funciones:

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

Escribí un microbenchmark rápido en https://jsperf.com/longitude-normalisation y el código condicional parece ser más rápido (en Chrome en mi máquina) para rangos 'razonables' de valores de entrada. En general, probablemente no debería preocuparse de antemano por el rendimiento en pequeños cálculos como este, lo que da más peso a la legibilidad y la coherencia con el resto de su base de código.

Probablemente más importante en este caso es la cuestión de si su código podría encontrarse con valores de entrada extremos (1e10, Infinito, etc.). Si es así, la implementación en bucle podría terminar ejecutándose muy lenta o silenciosamente colgando su programa. Esto podría ocurrir con los cálculos realizados cerca de los polos, por ejemplo, intentar desplazarse hacia el este o el oeste a cierta distancia (en lugar de ángulo) desde un poste podría resultar fácilmente en una longitud infinita.

Joe Lee-Moyet
fuente
1
Interesante. Vamos a correr un jmp condicional contra una división de FP. Hmmm, me pregunto.
Joshua
1
@Joshua No puedes usar un salto condicional. Tienes que usar múltiples saltos condicionales , también conocido como un bucle. (Además, el bucle contiene coma flotante adicional, que no es gratuito). La cantidad de iteraciones que necesita el bucle depende de la entrada. Por lo tanto, debe saber algo sobre los datos para observar el rendimiento. Si la gran mayoría está cerca del rango deseado y requiere pocas iteraciones, seguro, el ciclo de adición puede ser más rápido, pero no es tan obvio como sugiere su sarcasmo.
jpmc26
1
@ jpmc26: En este caso, esperar dar la vuelta al circuito más de una vez es una tontería.
Joshua
1
No hubo sarcasmo. En realidad no sé de qué manera se caería.
Joshua
1
@ Joshua sí, tampoco estaba seguro :). Agregué más a la respuesta sobre el rendimiento (y un posible caso de falla del código de bucle)
Joe Lee-Moyet
5

Un trazador de líneas:

normalized = remainder(longitude, 360);

Explicación: Desea saber qué queda después de ignorar las rotaciones completas (360 °).

Este proceso se llama normalización.

Ejemplo (cpp.sh)

Establecido
fuente
1
¿No resultaría esto en un valor [0, 360), no [-180, 180] como lo solicitó Shadrix?
El chico con el sombrero
@TheGuywithTheHat Verifique este ejemplo: cpp.sh/7uy2v
Basado en
Ah, no sabía que esto era C ++. En el contexto de JavaScript de Shadrix, interpreté remaindercomo modulus. El módulo en JS daría como resultado [0, 360).
El chico con el sombrero
1
No creo que eso funcione. Debería restar 360 si el resultado es> 180. Otro problema que acabo de dar cuenta con JavaScript es que el módulo es simétrico en 0, por ejemplo, -1 % 3es -1, no 2, ya que sería necesario para que funcione aquí. remainderes una excelente solución de C ++, pero desafortunadamente no hay una función / operador en JS que sea lo suficientemente similar como para ser útil.
El chico con el sombrero
0

Otra opción: longitud = atan2 (cos (largo), sin (largo))

Andres
fuente
1
Esto no parece una buena idea. Es muy difícil de entender, computacionalmente costoso y potencialmente sujeto a errores de redondeo.
David Richerby
0

Si el lenguaje de programación que está utilizando admite el operador% (mod) en números de coma flotante (como Python y Ruby), recomendaría usarlo. De lo contrario, algunos otros lenguajes (como C y C ++) le permiten usar fmod ().

(Cualquiera que sea el operador de mod que utilice, asegúrese con anticipación de que realizará operaciones de mod en números de punto flotante, y que siempre le dará respuestas no negativas. De lo contrario, recibirá una desagradable sorpresa más tarde cuando muchos de sus los puntos lat / lon no son correctos)

Úselo así:

# 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 prefiere hacerlo todo en una línea:

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

Estos enfoques no tienen bucles, por lo que normalizarán los valores de longitud sin necesidad de sumar o restar repetidamente, sin importar cuántas veces su observación haya dado vueltas alrededor de la tierra.

Editar:

Hmmm ... acabo de notar que Javascript no parece manejarse %con valores negativos como pensé que lo haría.

En ese caso, intente con esta frase:

longitude = (longitude + 36180) % 360 - 180

Lo 36180que estamos agregando es 36,000 + 180. El 36,000 es mover un valor negativo al dominio positivo, y el 180 es desplazarlo para que cuando sea modificado por 360, esté en el rango de [0,360) . La - 180parte la desplaza nuevamente al rango de [-180,180).

Aquí hay otro one-liner, uno que no depende de que 36,000 sean lo suficientemente grandes:

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

La longitude % 360 + 360parte asegurará que el valor permanezca en el dominio positivo cuando luego sea modificado por 360. La + 180parte lo desplaza de modo que cuando luego se reste 180 (con - 180), esté en el rango deseado de [-180,180).

JL
fuente
1
Nota: C, C ++ fmod(longitude, 360)-> (-360.0 ... +360.0) y ilongitude % 360-> [-359 ... +359].
chux - Restablece a Mónica el
@chux: no sabía eso, así que lo probé y parece que estás en lo correcto. Gracias por señalar eso.
JL