Calcolo della longitudine corretta quando supera i | 180 |?


11

Sto cercando di sviluppare una "formula" per correggere i valori lat-lng.

Sto usando vue-leaflet ma quando ti muovi fuori dal "primo" mondo ottieni grandi numeri. Oltre +180 o meno -180.

Ad esempio: quando pan verso l'America a destra (direzione est), ottengo lng 215. Nella mia mente, lo correggerei semplicemente con 215-360=-145

Lo stesso vale per quando eseguo una panoramica verso la Russia orientale a sinistra (direzione ovest) e ottengo ad esempio -222. Ora devo calcolare-222+360=138

Tuttavia, poiché il mondo è indefinito, l'utente potrebbe spostarsi nell'ottavo mondo e ho dovuto regolare i valori.

È possibile calcolare la giusta longitudine? (e un altro requisito è quando l'utente è nel primo mondo, 24 lng dovrebbe comunque essere 24 lng.

Risposte:


16

Devi aggiungere (o sottrarre) ripetutamente 360 ​​al tuo valore fino a quando non si trova nell'intervallo -180 - 180. Quindi di solito una coppia di loop come:

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

segni sbagliati? Dovrebbe essere lon + = 360 nel primo caso.
JimT,

4
puoi farlo con un solo ciclo, while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }ma non lo sto fornendo come risposta perché la tua versione corrisponde effettivamente alla spiegazione, mentre la mia versione è solo un'ottimizzazione che probabilmente non fa alcuna differenza. Lo tengo come commento solo per ricordare che le cose possono essere fatte in molti modi, alcuni più ottimizzati di altri.
Andrei,

2
Non penso che lo userei mai perché usa 2 chiamate di funzione per loop e solo uno dei miei loop verrà mai eseguito. Probabilmente non fa differenza in questo esempio, ma questo è il mio pregiudizio
Ian Turton

mentre sembrano funzioni, le funzioni matematiche in JavaScript dovrebbero essere viste più come operatori con simboli dettagliati. In questo senso possiamo anche vedere + - e anche <come funzioni. Modifica: ho avuto una soluzione qui che in realtà non funzionava
Andrei

2
Non puoi fare lon %= 180?
Finanzi la causa di Monica il

15

Una risposta che evita i condizionali e le chiamate di funzione:

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

Ho scritto un microbenchmark rapido su https://jsperf.com/longitude-normalisation e il codice condizionale sembra essere più veloce (in Chrome sulla mia macchina) per intervalli "ragionevoli" di valori di input. In generale, probabilmente non dovresti preoccuparti in anticipo delle prestazioni in piccoli calcoli come questo, dando più peso alla leggibilità e coerenza con il resto della tua base di codice.

Probabilmente più importante in questo caso è la questione se il tuo codice potrebbe mai imbattersi in valori di input estremi (1e10, Infinity ecc.). In tal caso, l'implementazione in loop potrebbe finire con l'esecuzione del programma in modo molto lento o silenzioso. Ciò potrebbe verificarsi con calcoli eseguiti vicino ai poli, ad esempio tentando di spostarsi verso est o ovest di una distanza (piuttosto che di un angolo) da un polo, si potrebbe facilmente ottenere una longitudine infinita.


1
Interessante. Corriamo un jmp condizionale contro un divario FP. Hmmm mi chiedo.
Giosuè,

1
@Joshua Non puoi usare un salto condizionale. Devi usare più salti condizionali , noti anche come loop. (Inoltre il loop contiene punti in virgola mobile aggiuntivi, che non sono gratuiti.) Di quante iterazioni il loop necessita dipende dall'input. Quindi devi sapere qualcosa sui dati per vedere le prestazioni. Se la stragrande maggioranza si trova vicino all'intervallo desiderato e richiede poche iterazioni, il ciclo di addizione potrebbe essere più veloce, ma non è così ovvio come suggerisce il tuo sarcasmo.
jpmc26,

1
@ jpmc26: in questo caso, aspettarsi di fare il giro più di una volta è sciocco.
Giosuè,

1
Non c'era sarcasmo. In realtà non so in che modo sarebbe caduta.
Giosuè,

1
@Joshua sì, neanche io ero sicuro :). Ho aggiunto altro alla risposta sulle prestazioni (e un potenziale caso di errore del codice loop)
Joe Lee-Moyet,

5

One-liner:

normalized = remainder(longitude, 360);

Spiegazione: Volete sapere cosa rimane dopo aver ignorato le rotazioni complete (360 °).

Questo processo si chiama normalizzazione.

Esempio (cpp.sh)


1
Questo non comporterebbe un valore [0, 360), non [-180, 180] come richiesto da Shadrix?
The Guy with The Hat,

@TheGuywithTheHat Dai un'occhiata a questo esempio: cpp.sh/7uy2v
Basato il

Ah, non sapevo che fosse C ++. Nel contesto di JavaScript di Shadrix, ho interpretato remaindercome modulus. Il modulo in JS comporterebbe [0, 360).
The Guy with The Hat,

1
Non penso che funzionerebbe. Dovresti sottrarre 360 ​​iff risultato> 180. Un altro problema che ho appena realizzato con JavaScript è che il modulo è simmetrico su 0, ad esempio -1 % 3-1, non 2 come sarebbe necessario per farlo funzionare qui. remainderè un'ottima soluzione C ++, ma sfortunatamente non esiste alcuna funzione / operatore in JS abbastanza simile da essere utile.
The Guy with The Hat,

0

Un'altra opzione: longitudine = atan2 (cos (long), sin (long))


1
Questa non sembra una buona idea. È molto difficile da capire, computazionalmente costoso e potenzialmente soggetto ad errori di arrotondamento.
David Richerby,

0

Se il linguaggio di programmazione che stai utilizzando supporta l'operatore% (mod) su numeri in virgola mobile (come Python e Ruby), ti consiglio di usarlo. Altrimenti, alcuni altri linguaggi (come C e C ++) consentono di usare fmod ().

(Qualunque operatore mod utilizzi, assicurati in anticipo che eseguirà operazioni mod su numeri in virgola mobile e che ti darà sempre risposte non negative. Altrimenti riceverai una brutta sorpresa in seguito quando molti dei tuoi i punti lat / lon non sono corretti.)

Usalo in questo modo:

# 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 preferisci fare tutto in una riga:

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

Questi approcci non hanno anelli, quindi normalizzeranno i valori di longitudine senza la necessità di aggiungere o sottrarre ripetutamente, indipendentemente da quante volte la tua osservazione abbia girato attorno alla terra.

Modificare:

Hmmm ... Ho appena notato che Javascript non sembra gestire %con valori negativi come pensavo.

In tal caso, prova questo one-liner:

longitude = (longitude + 36180) % 360 - 180

La 36180stiamo aggiungendo è 36.000 + 180. Il 36.000 è quello di spostare un valore negativo nel dominio positivo, e la 180 è di spostare sopra in modo che quando è modded dai 360, sarà nel range di [0360) . La - 180parte lo sposta di nuovo nell'intervallo di [-180.180).

Ecco un altro one-liner, uno che non si basa sul fatto che 36.000 siano abbastanza grandi:

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

La longitude % 360 + 360parte assicurerà che il valore rimanga nel dominio positivo quando viene successivamente modificato da 360. La + 180parte lo sposta in modo tale che quando successivamente viene sottratto 180 (con - 180), sarà nell'intervallo desiderato di [-180,180).


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

@chux - Non lo sapevo, quindi l'ho appena provato e sembra che tu abbia ragione. Grazie per averlo sottolineato.
JL
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.