Esistono diverse formule per calcolare la distanza tra due punti della superficie terrestre a partire dalle coordinate. Potete trovarne qui un’adeguata trattazione. Si tratta naturalmente di formule approssimate, poichè la superficie terrestre non è regolare nè tantomeno una sfera (come alcune di queste formule suppongono), ma i risultati sono comunque molto buoni a fronte di una complessità di calcolo limitata. Alla fine ho scelto di utilizzare la “spherical law of cosines” (qualcosa del tipo “legge sferica dei coseni”), che calcola la distanza in km tra due punti, identificati dalle coordinate:
p1 = (minlon, minlat) //longitudine e latitudine in radianti
p2 = (maxlon, maxlat) //longitudine e latitudine in radianti
dist = arccos( sin(minlat) * sin(maxlat) + cos(minlat) * cos(maxlat) * cos(maxlon – minlon) ) * 6371
(6371 è il raggio della Terra in Km; dist è espressa in Km).
Ho bisogno di sfruttare questa formula all’interno di uno script bash per un mio lavoro di creazione di mappe personalizzate di cui vi parlerò in seguito. Come si può fare? Ho pensato a due metodi possibili:
Korn Shell
Il primo metodo prevede l’utilizzo della Korn Shell. Si tratta di una shell Unix alternativa alla normale console Bash, che prevede però una serie di operatori matematici e trigonometrici che mancano alla sua più nota controparte. E’ sviluppata dalla AT&T ma ormai da diversi anni è rilasciata opensource. E’ inclusa di default in MacOsX (almeno in Tiger) e facilmente installabile sotto Ubuntu (“sudo apt-get install ksh”).
In ksh è possibile assegnare a una variabile il risultato di un calcolo mediante l’uso delle doppie parentesi rotonde:
(( variabile=3+5/2*6 ))
(( variabile=$variabile1+$variabile2 ))
(( variabile=cos(30) ))
e così via. Gli operatori matematici supportati sono numerosi. Un elenco con altri esempi è disponibile qui. A questo punto, lo script per implementare tutto quanto è qualcosa del genere:
#!/bin/ksh #indica la shell da utilizzare
#coordinate (in gradi)
MINLAT=45.8018
MAXLAT=45.8278
MINLON=10.0533
MAXLON=10.0993
R=6371
#conversione delle coordinate da gradi a radianti
(( MINLAT1=$MINLAT*(2*3.14)/360 ))
(( MAXLAT1=$MAXLAT*(2*3.14)/360 ))
(( MINLON1=$MINLON*(2*3.14)/360 ))
(( MAXLON1=$MAXLON*(2*3.14)/360 ))
#calcolo della distanza
(( dist=acos(sin($MINLAT1)*sin($MAXLAT1)
+cos($MINLAT1)*cos($MAXLAT1)
*cos($MAXLON1-$MINLON1))*$R ))
#stampa della distanza (in chilometri)
echo $dist
Ecco fatto. Salviamo il file col nome “calcola”, lo rendiamo eseguibile
chmod +x calcola
E lo eseguiamo:
./calcola
4.58016572203
Purtroppo però questo sistema bellissimo ha un grosso problema: non funziona sotto Ubuntu. Esiste infatti un bug report che descrive la mancata implementazione nella versione attuale di ksh per Ubuntu delle funzioni aritmetiche, rendendo di fatto la shell inutile. Poichè il bug report risale a giugno di quest’anno, ovvero a sei mesi fa, e nessuno l’ha ancora preso in carico direi che ci sono modeste speranze per il futuro. Come ulteriore nota amara verso gli Ubuntiani convinti detrattori di MacOs vorrei solo dire che sul mio MacBook il ksh è installato di default e funziona perfettamente, mentre sul server Ubuntu sul quale mi serviva no; devo quindi rinunciare a questa strada.
Un programma in C
Beh, se non so come fare a eseguire quei calcoli trigonometrici da shell non mi resta altro da fare se non crearmi un programmino in C da richiamare alla bisogna. Il programma è molto semplice:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <strings.h>
int main(int argc, char* argv[]){
double minlat, maxlat, minlon, maxlon;
double pi=3.1415926535;
double distance;
double R = 6371;
//prevediamo di stampare un messaggio di help..
if (argc < 5){
if ((argc == 1) || (argc > 1 && strcmp(argv[1], “-h”) == 0 ||
strcmp(argv[1], “help”) == 0)) {
printf(“\nCalcolo della distanza tra due punti a partire dalle coordinate GPS\n”);
printf(“Restituisce la distanza in km tra due punti, identificati rispettivamente\n”);
printf(“dalle coordinate (minlon, minlat) e (maxlon, maxlat).\n\n”);
printf(“Sono richiesti 4 argomenti numerici: minlon, maxlon, minlat, maxlat\n\n”);
}
else printf(“0\n”);
return 1;
}
//lettura delle coordinate inserite da riga di comando
//e conversione in radianti
minlon = atof(argv[1])*2*pi/360;
maxlon = atof(argv[2])*2*pi/360;
minlat = atof(argv[3])*2*pi/360;
maxlat = atof(argv[4])*2*pi/360;
distance = acos(sin(minlat)*sin(maxlat)+cos(minlat)*cos(maxlat)*cos(maxlon-minlon))*R;
printf(“%f\n”, distance);
return 0;
}
A questo punto basta salvare il file come “converti.c”, compilarlo:
gcc -o converti -lm converti.c
Ed eseguirlo, passando da riga di comando i parametri nell’ordine minlon, maxlon, minlat, maxlat:
./converti 10.0533 10.0993 45.8018 45.8278
4.589957
L’output non è formattato (a meno che non venga chiesto l’help) ed è messo a zero in caso di errore; in questo modo il programma può essere richiamato per eseguire calcoli, ad esempio da script bash, in quanto restituisce il semplice valore numerico senza testo aggiunto.
Ecco fatto! Un modo semplice e rapido per calcolare la distanza tra due punti a partire dalla loro coordinate. Commenti? Dubbi? Errori? Fatemi sapere!