Coordinate geospaziali e distanza in chilometri

Questo è un seguito a questa domanda .

Mi sembra di essere bloccato su questo. Fondamentalmente, ho bisogno di essere in grado di convertire avanti e indietro per riferirmi alle coordinate nel sistema standard di gradi O misurando una distanza nord dal polo sud lungo la linea di data internazionale, e poi una distanza est partendo da quel punto alla data linea. Per fare questo (così come alcune cose più generiche per misurare la distanza), ho un metodo per determinare la distanza tra due punti lat / lon e un altro metodo che prende un punto lat / lon, una direzione e una distanza, e restituisce il punto lat / lon alla fine di quel corso.

Ecco i due metodi statici che ho definito:

/* Takes two lon/lat pairs and returns the distance between them in kilometers. */ public static double distance (double lat1, double lon1, double lat2, double lon2) { double theta = toRadians(lon1-lon2); lat1 = toRadians(lat1); lon1 = toRadians(lon1); lat2 = toRadians(lat2); lon2 = toRadians(lon2); double dist = sin(lat1)*sin(lat2) + cos(lat1)*cos(lat2)*cos(theta); dist = toDegrees(acos(dist)) * 60 * 1.1515 * 1.609344 * 1000; return dist; } /* endOfCourse takes a lat/lon pair, a heading (in degrees clockwise from north), and a distance (in kilometers), and returns * the lat/lon pair that would be reached by traveling that distance in that direction from the given point. */ public static double[] endOfCourse (double lat1, double lon1, double tc, double dist) { double pi = Math.PI; lat1 = toRadians(lat1); lon1 = toRadians(lon1); tc = toRadians(tc); double dist_radians = toRadians(dist / (60 * 1.1515 * 1.609344 * 1000)); double lat = asin(sin(lat1) * cos(dist_radians) + cos(lat1) * sin(dist_radians) * cos(tc)); double dlon = atan2(sin(tc) * sin(dist_radians) * cos(lat1), cos(dist_radians) - sin(lat1) * sin(lat)); double lon = ((lon1-dlon + pi) % (2*pi)) - pi; double[] endPoint = new double[2]; endPoint[0] = lat; endPoint[1] = lon; return endPoint; } 

Ed ecco la funzione che sto usando per testarlo:

 public static void main(String args[]) throws java.io.IOException, java.io.FileNotFoundException { double distNorth = distance(0.0, 0.0, 72.0, 0.0); double distEast = distance(72.0, 0.0, 72.0, 31.5); double lat1 = endOfCourse(0.0, 0.0, 0.0, distNorth)[0]; double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[1]; System.out.println("end at: " + lat1 + " / " + lon1); return; } 

I valori “end at” dovrebbero essere appx. 72,0 / 31,5. Ma invece sto ottenendo circa 1,25 / 0,021.

Presumo che mi debba mancare qualcosa di stupido, dimenticando di convertire unità da qualche parte, o qualcosa … Qualsiasi aiuto sarebbe molto apprezzato!

AGGIORNAMENTO 1:

Ho scritto (correttamente) la funzione di distanza per restituire i contatori, ma ho scritto chilometri nei commenti per errore … che ovviamente mi hanno confuso quando sono tornato a farlo oggi. Ad ogni modo, ora è corretto, e ho corretto l’errore di factoring nel metodo endOfCourse, e ho anche realizzato che avevo dimenticato di convertire anche i gradi in radianti con quel metodo. Ad ogni modo: mentre sembra che ora stia ottenendo il corretto numero di latitudine (71.99 …), il numero di longitudine è lontano (ottengo 3.54 invece di 11.5).

AGGIORNAMENTO 2: Ho avuto un refuso nel test, come indicato di seguito. Ora è stato risolto nel codice. Il numero di longitudine è ancora, tuttavia, errato: ora sto ottenendo -11,34 anziché 11,5. Penso che ci sia qualcosa di sbagliato in queste righe:

 double dlon = atan2(sin(tc) * sin(dist_radians) * cos(lat1), cos(dist_radians) - sin(lat1) * sin(lat)); double lon = ((lon1-dlon + pi) % (2*pi)) - pi; 

Hai un caso serio dei numeri magici nel codice. L’espressione:

  (60 * 1.1515 * 1.609344 * 1000) 

appare due volte, ma non c’è molta spiegazione di ciò. Con un po ‘d’aiuto: 1.609344 è il numero di chilometri in un miglio; 60 è il numero di minuti in grado; 1000 è il numero di metri in un chilometro; e 1.1515 è il numero di miglia statutarie in un miglio nautico (grazie, DanM). Un miglio nautico corrisponde alla lunghezza di un minuto di latitudine all’equatore.

Immagino tu stia usando un modello di terra sferico, piuttosto che una terra sferoidale? L’algebra non è abbastanza complessa da essere sferoidale.

La prima formula – la conversione tra due coppie di latitudine e longitudine – è dispari. Hai bisogno sia delta-lat (Δλ) e delta-lon (Δφ) per risolvere la risposta. Inoltre, la distanza tra le coppie:

 (60° N, 30° W), (60° N, 60° W) (60° N, 60° W), (60° N, 90° W) 

dovrebbe essere lo stesso – ma sono abbastanza sicuro che il tuo codice produca risposte diverse.

Quindi, penso che tu debba tornare ai tuoi materiali di riferimento sulla trigonometria sferica e vedere cosa stai facendo male. (Mi ci vorrà un po ‘di tempo per trovare il mio libro sull’argomento – dovrebbe essere estratto dalla scatola in cui si trova.)

[ … il tempo passa … disfare le valigie … ]

Dato un triangolo sferico con gli angoli A , B , C ai vertici e ai lati a , b , c opposti a questi vertici (cioè, il lato a è da B a C , ecc.), La formula del coseno è:

 cos a = cos b . cos c + sin b . sin c . cos A 

Applicando questo al problema, possiamo chiamare i due punti dati B e C , e creiamo un triangolo sferico destro con un angolo retto in A.

Arte ASCII al suo peggio:

  + C /| / | a / | b / | / | / | B +------+ A c 

Il lato c è uguale alla differenza di longitudine; il lato b è uguale alla differenza di latitudine; l’angolo A è 90 °, quindi cos A = 0. Pertanto, credo che un’equazione per a sia:

 cos a = cos Δλ . cos Δφ + sin Δλ . sin Δφ . cos 90° a = arccos (cos Δλ . cos Δφ) 

L’angolo a in radianti viene quindi convertito in una distanza moltiplicando per il raggio della Terra. In alternativa, dato un grado (e una frazione di grado), ci sono 60 miglia nautiche in un grado, quindi 60 * 1,1515 miglia statute e 60 * 1,1515 * 1,609344 chilometri in un grado. A meno che tu non voglia la distanza in metri, non vedo il bisogno del fattore 1000.

Paul Tomblin indica Aviation Formulary v1.44 come fonte dell’equazione – e in effetti, è lì, insieme a una versione più numericamente stabile per quando la differenza di posizione è piccola.

Andando alla trigonometria di base, sappiamo anche che:

 cos (A - B) = cos A . cos B + sin A . sin B 

Applicare due volte l’equazione che ho dato potrebbe benissimo finire con la formula nel Formulario dell’aviazione.

(La mia referenza: “Astronomia: principi e pratica, quarta edizione” di AE Roy e D Clarke (2003), la mia copia è la prima edizione del 1977, Adam Hilger, ISBN 0-85274-346-7.)


NB Check out (Google) ‘define: “nautical mile”‘; sembra che un miglio nautico sia ora 1852 m (1.852 km) per definizione. Il moltiplicatore 1.1515 corrisponde alla vecchia definizione del miglio nautico come approssimativamente 6080 piedi. Usando bc con una scala di 10, ottengo:

 (1852/(3*0.3048))/1760 1.1507794480 

Quale fattore funziona per te dipende da quale sia la tua base.


Osservando il secondo problema dai primi principi, abbiamo un setup leggermente diverso, e abbiamo bisogno dell’equazione “altra” sferica della trigonometria, la formula Sine:

 sin A sin B sin C ----- = ----- = ----- sin a sin b sin c 

Adattamento del diagramma precedente:

  + C /| / | a / | b | / | |X/ | |/ | B +------+ A c 

Viene dato il punto di partenza B , l’angolo X = 90º – B, la lunghezza (angolo) a e l’angolo A = 90 °. Quello che stai cercando è b (il delta in latitudine) ec (il delta in longitudine).

Quindi, abbiamo:

 sin a sin b ----- = ---- sin A sin B 

O

  sin a . sin B sin b = ------------- sin A 

Oppure, poiché A = 90 °, sin A = 1, e sin B = sin (90 ° – X) = cos X:

 sin b = sin a . cos X 

Ciò significa che converti la distanza percorsa in un angolo a , prendi il seno di questo, moltiplica per il coseno della direzione del percorso e prendi l’arcoseno del risultato.

Dato a , b (appena calcolato) e A e B , possiamo applicare la formula del coseno per ottenere c . Nota che non possiamo semplicemente riapplicare la formula seno per ottenere c dato che non abbiamo il valore di C e, poiché stiamo giocando con la trigonometria sferica, non esiste una regola conveniente che C = 90 ° – B (la sum degli angoli di un triangolo sferico può essere maggiore di 180 °, considerare un triangolo sferico equilatero con tutti gli angoli pari a 90 °, che è perfettamente fattibile).


Controlla http://www.movable-type.co.uk/scripts/latlong.html

Quel sito ha un sacco di diverse formule e codice Javascript che dovrebbe aiutarti. L’ho tradotto con successo sia in C # che in una UDF di SQL Server e li uso ovunque.

Ad esempio per Javascript per calcolare la distanza:

 var R = 6371; // km var φ1 = lat1.toRadians(); var φ2 = lat2.toRadians(); var Δφ = (lat2-lat1).toRadians(); var Δλ = (lon2-lon1).toRadians(); var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ/2) * Math.sin(Δλ/2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c; 

Godere!

La tua conversione tra km e radianti è sbagliata. Un miglio nautico è 1/60 di grado, quindi supponendo che 1.15 … sia la tua conversione da miglia a miglia nautiche, e 1.6 … è la tua conversione da miglia a miglia statutarie,

  nm = km / (1.1515 * 1.609344); deg = nm / 60; rad = toRadians(deg); 

In altre parole, penso che tu abbia un fattore di 1000.

Per quanto riguarda la tua domanda aggiornata: non dovrebbe

 double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[0]; 

essere

 double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[1]; 

Ho capito il grande problema con queste formule, a parte gli errori di implementazione menzionati nelle altre risposte e aggiornamenti.

Il grosso problema era questo: il metodo Distance (per calcolare la distanza tra due punti) stava calcolando le distanze del grande cerchio. Il che, ovviamente, ha senso: questo è il percorso più breve tra i due punti. Tuttavia , la distanza del grande cerchio tra due punti che si trovano sullo stesso parallelo (linea di latitudine) NON è uguale alla distanza tra questi due punti quando si viaggia direttamente lungo la linea di latitudine, a meno che non si sia all’equatore.

Quindi: le funzioni stanno funzionando correttamente; tuttavia, il sistema di coordinate alternativo che ho proposto nella domanda originale richiede che guardiamo solo alla distanza nord lungo l’IDL seguito dalla distanza a est lungo il parallelo alla latitudine risultante. E calcolare la distanza lungo uno specifico parallelo è abbastanza diverso dal calcolare la distanza lungo un grande cerchio!

Comunque, ce l’hai.