Map Tricks: calcolare la distanza tra due punti a partire dalle coordinate GPS

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!

Questa voce è stata pubblicata in Uncategorized e contrassegnata con , . Contrassegna il permalink.

13 risposte a Map Tricks: calcolare la distanza tra due punti a partire dalle coordinate GPS

  1. Pingback: Map Tricks: aggiungere un riferimento di distanza a una mappa « Appunti, scoperte e invenzioni

  2. Pingback: Creare una mappa personalizzata da OSM: lo script « Appunti, scoperte e invenzioni

  3. pelliz71 ha detto:

    Ciao, ho provato a copiare pari pari la parte in C (di cui sono un completo ignorante), ma lanciando la compilazione da ubuntu mi da una continua serie di messaggi di errore (la maggior parte mi da degli undeclared ).
    Eventualmente sarebbe possibile averlo già compilato, oppure mi puoi dare qualche dritta per risolvere?

    Grazie.

  4. pelliz71 ha detto:

    Scusa, ho visto solo ora che è presente all’interno di uno zip nell’articolo “mappa personalizzara”.
    La fretta a volte …. 😉

  5. It’s very easy to find out any topic on net as compared to books, as I found this post at this site.

  6. hca stock ha detto:

    Hi there, just became alert to your blog through Google, and found that it is truly informative.
    I’m gonna watch out for brussels. I’ll be grateful if
    you continue this in future. A lot of people will be benefited from your writing.
    Cheers!

  7. Admiring the hard work you put into your site and detailed information you offer.
    It’s great to come across a blog every once in a while that isn’t the same outdated rehashed information.
    Fantastic read! I’ve bookmarked your site and I’m adding your RSS feeds
    to my Google account.

  8. It’s appropriate time to make some plans for the future and it is time to be happy. I’ve
    read this post and if I could I desire to suggest you few
    interesting things or suggestions. Maybe you could write next articles referring to this article.
    I wish to read even more things about it!

  9. hey there and thank you for your information – I have certainly
    picked up something new from right here. I did however expertise
    some technical points using this web site, since I experienced to reload the web
    site a lot of times previous to I could get it
    to load properly. I had been wondering if your hosting is OK?

    Not that I am complaining, but slow loading
    instances times will very frequently affect your placement in
    google and could damage your high quality score if ads and marketing with Adwords.
    Anyway I am adding this RSS to my email and can look out for much more of your respective exciting
    content. Make sure you update this again very soon.

  10. Its like you read my mind! You seem to know a lot about
    this, like you wrote the book in it or something.

    I think that you could do with some pics to drive the message home a little bit, but other than that, this is great blog.
    A great read. I will definitely be back.

  11. Hi there! Quick question that’s entirely off topic. Do you know how to make your site mobile friendly? My web site looks weird when browsing from my iphone 4. I’m
    trying to find a template or plugin that might be able to correct this problem.

    If you have any suggestions, please share. Thanks!

  12. Have you ever considered publishing an ebook or guest
    authoring on other sites? I have a blog based upon
    on the same topics you discuss and would love to have you share some stories/information.
    I know my visitors would enjoy your work. If you’re even remotely interested, feel free to shoot me an email.

  13. marco ha detto:

    Per compilare il programma in c converti, usare:

    gcc -o converti converti.c -lm

    invece di, come scritto nel post sopra

    gcc -o converti -lm converti.c

    altrimenti si ottiene errore… in compilazione:

    /tmp/ccE9zf1X.o: nella funzione “main”:
    converti.c:(.text+0x143): riferimento non definito a “sin”
    converti.c:(.text+0x153): riferimento non definito a “sin”
    converti.c:(.text+0x167): riferimento non definito a “cos”
    converti.c:(.text+0x177): riferimento non definito a “cos”
    converti.c:(.text+0x18f): riferimento non definito a “cos”
    converti.c:(.text+0x19f): riferimento non definito a “acos”
    collect2: error: ld returned 1 exit status

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...