Questa risposta è divisa in più sezioni:
Analisi e riduzione del problema , mostrando come trovare il punto desiderato con routine "fisse".
Illustrazione: un prototipo funzionante , che fornisce un codice funzionante.
Esempio , che mostra esempi delle soluzioni.
Insidie , discutendo di potenziali problemi e come affrontarli.
Implementazione di ArcGIS , commenti sulla creazione di uno strumento ArcGIS personalizzato e su dove ottenere le routine necessarie.
Analisi e riduzione del problema
Cominciamo osservando che nel modello sferico (perfettamente rotondo) ci sarà sempre una soluzione , in realtà esattamente due soluzioni. Dati i punti base A, B e C, ciascuna coppia determina la sua "bisettrice perpendicolare", che è l'insieme di punti equidistanti dai due punti dati. Questa bisettrice è un geodetico (grande cerchio). La geometria sferica è ellittica : due geodetiche si intersecano (in due punti univoci). Pertanto, i punti di intersezione della bisettrice di AB e della bisettrice di BC sono - per definizione - equidistanti da A, B e C, risolvendo così il problema. (Vedi la prima figura in basso.)
Le cose sembrano più complicate su un ellissoide, ma poiché si tratta di una piccola perturbazione della sfera, possiamo aspettarci un comportamento simile. (L'analisi di questo ci porterebbe troppo lontano.) Le complicate formule utilizzate (internamente all'interno di un GIS) per calcolare distanze precise su un ellissoide non sono una complicazione concettuale, tuttavia: il problema è sostanzialmente lo stesso. Per vedere quanto sia semplice il problema, diciamolo in modo un po 'astratto. In questa affermazione, "d (U, V)" si riferisce alla distanza vera e precisa tra i punti U e V.
Dati tre punti A, B, C (come coppie lat-lon) su un ellissoide, trova un punto X per il quale (1) d (X, A) = d (X, B) = d (X, C) e ( 2) questa distanza comune è il più piccola possibile.
Queste tre distanze dipendono tutte dalla X sconosciuta . Pertanto, le differenze nelle distanze u (X) = d (X, A) - d (X, B) e v (X) = d (X, B) - d (X, C) sono funzioni con valore reale di X. Ancora una volta, in modo un po 'astratto, possiamo riunire queste differenze in una coppia ordinata. Useremo anche (lat, lon) come coordinate per X, permettendoci di considerarlo anche come una coppia ordinata, diciamo X = (phi, lambda). In questa configurazione, la funzione
F (phi, lambda) = (u (X), v (X))
è una funzione da una porzione di uno spazio bidimensionale che assume valori nello spazio bidimensionale e il nostro problema si riduce a
Trova tutti i possibili (phi, lambda) per i quali F (phi, lambda) = (0,0).
Qui è dove l'astrazione paga: esiste un sacco di ottimo software per risolvere questo problema (ricerca di radici multidimensionali puramente numeriche). Il modo in cui funziona è che si scrive una routine per calcolare F , quindi lo si passa al software insieme a tutte le informazioni sulle restrizioni sul suo input ( phi deve trovarsi tra -90 e 90 gradi e lambda deve essere tra -180 e 180 gradi). Si avvia per una frazione di secondo e restituisce (in genere) solo un valore di ( phi , lambda ), se riesce a trovarne uno.
Ci sono dettagli da gestire, perché c'è un'arte in questo: ci sono vari metodi di soluzione tra cui scegliere, a seconda di come " F " si comporta; aiuta a "guidare" il software fornendo un ragionevole punto di partenza per la sua ricerca (questo è un modo in cui possiamo ottenere la soluzione più vicina , piuttosto che qualsiasi altra); e di solito è necessario specificare la precisione della soluzione (in modo da sapere quando interrompere la ricerca). (Per ulteriori informazioni su ciò che gli analisti GIS devono sapere su tali dettagli, che emergono molto nei problemi GIS, visitare la sezione Consiglia argomenti da includere in un corso di Informatica per le tecnologie geospaziali e consultare la sezione "Miscellanea" verso la fine. )
Illustrazione: un prototipo funzionante
L'analisi mostra che dobbiamo programmare due cose: una stima iniziale approssimativa della soluzione e il calcolo di F stesso.
La stima iniziale può essere effettuata mediante una "media sferica" dei tre punti base. Ciò si ottiene rappresentandoli in coordinate cartesiane geocentriche (x, y, z), calcolando la media di tali coordinate e proiettando la media sulla sfera e re-esprimendola in latitudine e longitudine. La dimensione della sfera è irrilevante e quindi i calcoli sono resi semplici: poiché questo è solo un punto di partenza, non abbiamo bisogno di calcoli ellissoidali.
Per questo prototipo funzionante ho usato Mathematica 8.
sphericalMean[points_] := Module[{sToC, cToS, cMean},
sToC[{f_, l_}] := {Cos[f] Cos[l], Cos[f] Sin[l], Sin[f]};
cToS[{x_, y_, z_}] := {ArcTan[x, y], ArcTan[Norm[{x, y}], z]};
cMean = Mean[sToC /@ (points Degree)];
If[Norm[Most@cMean] < 10^(-8), Mean[points], cToS[cMean]] / Degree
]
(La If
condizione finale verifica se la media potrebbe non riuscire a indicare chiaramente una longitudine; in tal caso, ricade in una media aritmetica diritta delle latitudini e delle lunghezze del suo input - forse non un'ottima scelta, ma almeno valida. Per coloro che usano questo codice come guida all'implementazione, nota che gli argomenti di Mathematica ArcTan
sono invertiti rispetto alla maggior parte delle altre implementazioni: il suo primo argomento è la coordinata x, il secondo è la coordinata y e restituisce l'angolo creato dal vettore ( x, y).)
Per quanto riguarda la seconda parte, poiché Mathematica - come ArcGIS e quasi tutti gli altri GIS - contiene codice per calcolare distanze precise sull'ellissoide, non c'è quasi nulla da scrivere. Chiamiamo semplicemente la routine di ricerca radice:
tri[a_, b_, c_] := Block[{d = sphericalMean[{a, b, c}], sol, f, q},
sol = FindRoot[{GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, a] ==
GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, b] ==
GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, c]},
{{f, d[[1]]}, {q, d[[2]]}},
MaxIterations -> 1000, AccuracyGoal -> Infinity, PrecisionGoal -> 8];
{Mod[f, 180, -90], Mod[q, 360, -180]} /. sol
];
L'aspetto più degno di nota di questa implementazione è il modo in cui evita la necessità di limitare la latitudine ( f
) e la longitudine ( q
) calcolandoli sempre rispettivamente a modulo 180 e 360 gradi. Questo evita di dover limitare il problema (che spesso crea complicazioni). I parametri di controllo MaxIterations
ecc. Sono ottimizzati per rendere questo codice la massima precisione possibile.
Per vederlo in azione, appliciamolo ai tre punti base indicati in una domanda correlata :
sol = tri @@ (bases = {{-6.28530175, 106.9004975375}, {-6.28955287, 106.89573839}, {-6.28388865789474, 106.908087643421}})
{-6.29692, 106.907}
Le distanze calcolate tra questa soluzione e i tre punti sono
{1450.23206979, 1450.23206979, 1450.23206978}
(questi sono metri). Sono d'accordo attraverso l'undicesima cifra significativa (che in realtà è troppo precisa, dal momento che le distanze sono raramente precise a un millimetro o giù di lì). Ecco una foto di questi tre punti (nero), le loro tre bisettrici reciproche e la soluzione (rosso):
Esempio
Per testare questa implementazione e comprendere meglio come si comporta il problema, ecco un diagramma di contorno della discrepanza quadrata media radice nelle distanze per tre punti base ampiamente distanziati. (La discrepanza RMS si ottiene calcolando tutte e tre le differenze d (X, A) -d (X, B), d (X, B) -d (X, C) e d (X, C) -d (X , A), calcolando la media dei loro quadrati e prendendo la radice quadrata: è uguale a zero quando X risolve il problema e altrimenti aumenta quando X si allontana da una soluzione, e quindi misura quanto siamo vicini a essere una soluzione in qualsiasi posizione. )
I punti base (60, -120), (10, -40) e (45,10) sono mostrati in rosso in questa proiezione di Plate Carree; la soluzione (49.2644488, -49.9052992) - che ha richiesto 0,03 secondi per il calcolo - è in giallo. La sua discrepanza RMS è inferiore a tre nanometri , nonostante tutte le distanze rilevanti siano migliaia di chilometri. Le aree scure mostrano piccoli valori dell'RMS e le aree chiare mostrano valori elevati.
Questa mappa mostra chiaramente un'altra soluzione vicina (-49.2018206, 130,0297177) (calcolata su un RMS di due nanometri impostando il valore di ricerca iniziale diametralmente opposto alla prima soluzione).
insidie
Instabilità numerica
Quando i punti di base sono quasi collineari e vicini tra loro, tutte le soluzioni saranno a quasi mezzo mondo di distanza ed estremamente difficili da definire con precisione. Il motivo è che piccoli cambiamenti in una posizione in tutto il mondo - spostandolo verso o lontano dai punti di base - indurranno solo cambiamenti incredibilmente piccoli nelle differenze di distanze. Non c'è abbastanza accuratezza e precisione integrate nel normale calcolo delle distanze geodetiche per definire il risultato.
Ad esempio, iniziando con i punti base a (45.001, 0), (45, 0) e (44.999,0), che sono separati lungo il Meridiano Primo di soli 111 metri tra ogni coppia, tri
ottiene la soluzione (11.8213, 77.745 ). Le distanze da esso ai punti base sono 8.127.964.998 77; 8.127.964.998 41; e 8.127.964.998 65 metri, rispettivamente. Sono d'accordo con il millimetro più vicino! Non sono sicuro di quanto accurato possa essere questo risultato, ma non sarei minimamente sorpreso se altre implementazioni restituissero posizioni lontane da questa, mostrando quasi una buona uguaglianza delle tre distanze.
Tempo di calcolo
Questi calcoli, poiché comportano una notevole ricerca utilizzando calcoli di distanza complicati, non sono veloci, di solito richiedono una notevole frazione di secondo. Le applicazioni in tempo reale devono esserne consapevoli.
Implementazione di ArcGIS
Python è l'ambiente di scripting preferito per ArcGIS (a partire dalla versione 9). Il pacchetto scipy.optimize ha un rootfinder multivariato root
che dovrebbe fare ciò che FindRoot
fa nel codice Mathematica . Naturalmente ArcGIS stesso offre calcoli accurati della distanza ellissoidale. Il resto, quindi, sono tutti i dettagli dell'implementazione: decidere come verranno ottenute le coordinate del punto base (da un livello? Digitato dall'utente? Da un file di testo? Dal mouse?) E come verrà presentato l'output (come coordinate visualizzato sullo schermo? come un punto grafico? come un nuovo oggetto punto in un livello?), scrivi quell'interfaccia, porta il codice Mathematica mostrato qui (semplice) e sarai pronto.