Cálculo da longitude correta quando terminar | 180 |?


11

Estou tentando desenvolver uma "fórmula" para corrigir os valores de lat-lng.

Estou usando o vue-leaflet, mas quando você se desloca para fora do "primeiro" mundo, obtém grandes números. Acima de +180 ou abaixo de -180.

Por exemplo: quando percorro a América para a direita (direção leste), fico com o número 215. Em minha mente, eu o corrigia com 215-360=-145

O mesmo é para quando eu movo para o leste da Rússia à esquerda (direção oeste) e recebo, por exemplo, -222. Agora eu preciso calcular-222+360=138

No entanto, como o mundo é indefinido, o usuário pode se deslocar para o 8º mundo e eu tive que ajustar os valores.

É possível calcular a longitude correta? (e outro requisito é quando o usuário está no primeiro mundo, 24 lng ainda deve ser 24 lng.

Respostas:


16

Você precisa adicionar (ou subtrair) 360 repetidamente ao seu valor até que ele fique no intervalo de -180 a 180. Geralmente, um par de loops como:

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

sinais errado ao redor? Deve ser lon + = 360 no primeiro caso.
JimT

4
você pode fazer isso com apenas um loop. while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }Não estou fornecendo como resposta, porque sua versão realmente corresponde à explicação, enquanto minha versão é apenas uma otimização que provavelmente não faz diferença. Eu mantenho isso como um comentário apenas como um lembrete de que as coisas podem ser feitas de várias maneiras, algumas mais otimizadas que outras.
187 Andrei

2
Eu acho que nunca usaria esse, pois ele usa 2 chamadas de função por loop e apenas um dos meus loops seria executado. Provavelmente não faz diferença neste exemplo, mas esse é o meu preconceito
Ian Turton

Embora pareçam funções, as funções matemáticas em JavaScript devem ser vistas mais como operadores com símbolos detalhados. Nesse sentido, também podemos ver + - e até <como funções também. Edit: Eu tinha uma solução aqui que isso não aconteceu realmente trabalho
Andrei

2
Você não pode fazer lon %= 180?
Fund Monica's Lawsuit

15

Uma resposta que evita condicionais e chamadas de função:

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

Eu escrevi uma marca rápida de microbench em https://jsperf.com/longitude-normalisation e o código condicional parece ser mais rápido (no Chrome na minha máquina) para intervalos 'razoáveis' de valores de entrada. Em geral, você provavelmente não deve se preocupar com o desempenho em pequenos cálculos como esse, dando mais peso à legibilidade e consistência com o restante da sua base de código.

Provavelmente mais importante nesse caso é a questão de saber se o seu código pode se deparar com valores extremos de entrada (1e10, Infinity etc.). Nesse caso, a implementação de loop pode acabar sendo executada muito lenta ou silenciosamente, interrompendo seu programa. Isso pode ocorrer com cálculos realizados perto dos polos, por exemplo, tentar deslocar-se para leste ou oeste a alguma distância (em vez de ângulo) de um polo pode facilmente resultar em uma longitude infinita.


1
Interessante. Vamos correr um jmp condicional contra uma divisão de FP. Hmmm eu me pergunto.
Joshua

1
@ Josué Você não pode usar um salto condicional. Você precisa usar vários saltos condicionais , também conhecidos como loop. (Além disso, o loop contém pontos flutuantes adicionais, o que não é gratuito.) Quantas iterações o loop precisa depende da entrada. Então você precisa saber algo sobre os dados para analisar o desempenho. Se a grande maioria estiver perto do intervalo desejado e exigir poucas iterações, o loop de adição poderá ser mais rápido, mas não é tão óbvio quanto sugere o seu sarcasmo.
jpmc26

1
@ jpmc26: Nesse caso, esperar dar a volta no loop mais de uma vez é bobagem.
Joshua

1
Não houve sarcasmo. Na verdade, eu não sei para que lado isso aconteceria.
Joshua

1
@ Joshua sim, eu também não tinha certeza :). Eu adicionei mais para a resposta sobre o desempenho (e um potencial caso de falha do código circular)
Joe Lee-Moyet

5

Uma linha:

normalized = remainder(longitude, 360);

Explicação: Você deseja saber o que resta depois de desconsiderar as rotações completas (360 °).

Esse processo é chamado de normalização.

Exemplo (cpp.sh)


1
Isso não resultaria em um valor de [0, 360), não em [-180, 180], como Shadrix solicitou?
O cara com o chapéu

@TheGuywithTheHat Verifique este exemplo: cpp.sh/7uy2v
base em

Ah, não sabia que isso era C ++. No contexto de JavaScript de Shadrix, eu interpretei remaindercomo modulus. O módulo em JS resultaria em [0, 360).
O cara com o chapéu

1
Eu não acho que isso funcionaria. Você precisaria subtrair 360 se o resultado> 180. Outro problema que acabei de perceber com JavaScript é que o módulo é simétrico em 0, por exemplo, -1 % 3é -1, e não 2, pois seria necessário para que ele funcionasse aqui. remainderé uma ótima solução C ++, mas infelizmente não há função / operador em JS que seja semelhante o suficiente para ser útil.
O cara com o chapéu

0

Outra opção: longitude = atan2 (cos (long), sin (long))


1
Isso não parece uma boa ideia. É muito difícil de entender, computacionalmente caro e potencialmente sujeito a erros de arredondamento.
David Richerby

0

Se a linguagem de programação que você está usando suportar o operador% (mod) em números de ponto flutuante (como Python e Ruby), eu recomendo usar isso. Caso contrário, algumas outras linguagens (como C e C ++) permitem que você use fmod ().

(Qualquer que seja o operador de mod que você usa, verifique com antecedência que ele fará operações de mod em números de ponto flutuante e que sempre fornecerá respostas não negativas. Caso contrário, você terá uma surpresa desagradável mais tarde, quando muitos de seus os pontos lat / lon não estão corretos.)

Use-o assim:

# 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

Se você preferir fazer tudo em uma linha:

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

Essas abordagens não possuem loops, portanto normalizam os valores da longitude sem a necessidade de adicionar ou subtrair repetidamente, não importa quantas vezes sua observação tenha circulado pela Terra.

Editar:

Hmmm ... Acabei de perceber que o Javascript não parece lidar %com valores negativos como eu pensava.

Nesse caso, tente este one-liner:

longitude = (longitude + 36180) % 360 - 180

O 36180que estamos adicionando é 36.000 + 180. O 36.000 é mover um valor negativo para o domínio positivo, e o 180 é movê-lo para que, quando modificado 360, ele esteja no intervalo de [0,360) . A - 180peça volta para o intervalo de [-180.180).

Aqui está outra linha única, que não depende de 36.000 serem grandes o suficiente:

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

A longitude % 360 + 360peça garantirá que o valor permaneça no domínio positivo quando mais tarde for modificado por 360. A + 180parte a desloca para que, quando mais tarde ela for subtraída 180 (com - 180), ela esteja no intervalo desejado de [-180.180).


1
Nota: C, C ++ fmod(longitude, 360)-> (-360,0 ... +360,0) e ilongitude % 360-> [-359 ... +359].
chux - Restabelece Monica

@chux - Eu não sabia disso, então acabei de testá-lo e parece que você está correto. Obrigado por apontar isso.
JL
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.