Appunti, scoperte e invenzioni

Tutto quello che mi viene in mente (se permettete l’esagerazione…)

  • Universal Declaration of Human Rights

    Article 19. Everyone has the right to freedom of opinion and expression; this right includes freedom to hold opinions without interference and to seek, receive and impart information and ideas through any media and regardless of frontiers.
  • My Last Twits

    • google wavin'!!! 1 month ago
    • chi è così buono da spedirmi un invito per la beta di Google Wave a mario.piccinelli@gmail.com? 1 month ago
    • perde tempo su internet.. la tesi aspetterà.. bah 1 month ago
    • Noemi Letizia premiata per il suo ruolo nel film Scaccomatto: è la preferita di un boss mafioso. Esattamente come nel film. (spinoza.it) :-) 2 months ago
    • I have sailed the world and seen his wonders, from the Dardinels to the mountains of Peru, but there's no place like.. Lovere! 3 months ago
  • Meta

  • Delicious Links

  •  

    Novembre: 2009
    L M M G V S D
    « Ott    
     1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30  
  • Archivi

  • Disclaimer

    Questo blog non rappresenta una testata giornalistica [...]

    L’autore del blog dichiara di non essere responsabile per i commenti inseriti dai lettori.[...]

    Le immagini pubblicate sono quasi tutte tratte da internet e quindi valutate di pubblico dominio. [...]

    L'autore declina qualunque responsabilità per danni a cose o persone derivanti dall'applicazione di istruzioni apprese da questo blog.[...]

    Per ulteriori info legali vi consiglio di passare da qui.

Posts contrassegnato dai tag ‘map’

Creare una mappa personalizzata da OSM: lo script

Pubblicato da piccimario su Febbraio 27, 2009

Come prometto a vuoto da mesi, finalmente mi voglio mettere a scrivere un articolo per spiegare un sistema completamente automatico mediante script bash per generare una mappa a partire dai dati di OpenStreetMap. Lo script è un allegro guazzabuglio di utility da riga di comando destinate a scaricare i dati dal server OSM sotto forma di xml, “compilarli” per generare un file SVG, convertire tale file in un PNG e aggiungerci qualche particolare utile: un header, un footer con il copyright, un frame di contorno e una scala kilometrica. Questo articolo, come i miei fedeli lettori avranno già intuito, nasce da una fusione di precedenti post: questo, questo, questo, questo.

Per iniziare i requisiti:

  • Avremo bisogno di un computer linux connesso alla rete (e fin qui…); io uso Ubuntu, non posso garantire il funzionamento di tutte le utility richiamate da questo script su altre piattaforme, anche se probabilmente su Mac si può fare (se qualcuno ci prova mi faccia sapere che aggiornerò l’articolo). Ovviamente Windows non è neanche preso in considerazione.
  • Avremo bisogno di queste utility, scaricabili dal repository: xsltproc (nell’installazione di default, a quanto mi risulta), wget (idem), convert+composite (nella suite ImageMagick), bc.
  • Avremo bisogno del programma per calcolare la distanza in chilometri tra due punti espressi in coordinate GPS, di cui ho parlato in precedenza (in questo post, nella sezione “un programma in C”). Copiarlo in un editor di testo, compilarlo seguendo le istruzioni nel post e avere cura che l’eseguibile si chiami “calcola” (senza alcuna estensione), non “converti” come nell’esempio.
  • Per finire, avremo bisogno di una serie di files da scaricare dai repository di openstreetmap, che ci serviranno per compilare la mappa vera e propria.

In riferimento all’ultimo punto dell’elenco, avremo bisogno di un ambiente di lavoro costituito dalla seguente struttura di cartelle:

data
|– osm-map-features-z17.xml
|– calcola
|– renderizza (così chiameremo lo script che andremo a utilizzare)
|– osmarenderer.xsl

stylesheets
|– symbols
|– il contenuto di questa cartella

Uhm.. dovremmo avere tutto, spero di non aver dimenticato nulla.. Per semplificarvi la vita, ho provveduto a uppare su una condivisione box.net uno zip con tutto il necessario per cominciare a renderizzare (sempre se non mi sono dimenticato nulla); scaricate pure qui. A questo punto manca solo lo script, che come ho detto prima si chiamerà, con molta fantasia, “renderizza” (beh, potete anche cambiargli il nome).

Ecco dunque l’agognato script, pezzo per pezzo:

Impostiamo un pò di variabili che ci verranno buone per dopo. Le uniche da modificare sono ovviamente le coordinate GPS (latitudine e longitune) della zona che vogliamo inserire nella mappa

# coordinate gps zona
# nb: max 0.25 gradi sia latitudine che longitudine

MAXLAT=45.8239
MINLAT=45.8045
MAXLON=10.0841
MINLON=10.0584

# nomi file
OSM=”data.osm”     # nome del file dati OSM
SVG=”map.svg”    # nome dell’output in formato svg
PNG=”map.png”    # nome dell’output in formato png

Recuperiamo i dati aggiornati:

echo “recupero dati dal server OSM…”
wget -O ${OSM} http://api.openstreetmap.org/api/0.5/map?bbox=$MINLON,$MINLAT,$MAXLON,$MAXLAT

Eseguiamo il rendering:

# livello del rendering
livello=17

# identifica il livello di dettaglio del rendering;
# per aree piccole conviene usare il livello 17;
# per eseguire il rendering sarà richiesto il
# file osm-map-features-zXX.xml (XX = livello).

echo “rendering mappa..”
xsltproc osmarender.xsl osm-map-features-z${livello}.xml > ${SVG}

Convertiamo la mappa (in formato SVG) in un file grafico PNG, più facilmente utilizzabile:

# —- conversione mappa in png

density=600     # risoluzione del file grafico.
scale=1000         # dimensione in px del file grafico

echo “conversione in PNG…”
convert -density ${density} -scale ${scale} ${SVG} ${PNG}

Aggiungiamo un header con un testo a scelta. In questo caso inserisco il mio nome e la data dell’aggiornamento (ovvero la data corrispondente al file dati).

# —- aggiunta header

echo “aggiunta della data alla cartina..”
convert xc:white -resize 1×15! blank.ppm
convert -append blank.ppm ${PNG} intermediate.ppm
convert intermediate.ppm -gravity “North” -draw “text 0,3 ‘Updated on: $(date -r ${OSM}) by PicciMario’” ${PNG}
rm blank.ppm intermediate.ppm

Aggiungo un footer con un copyright OSM.

# —- aggiunta footer

echo “aggiunta copyright alla cartina..”
convert xc:white -resize 1×20! blank.ppm
convert -append  ${PNG} blank.ppm intermediate.ppm
convert intermediate.ppm -gravity “South”
(continua) -draw “text 0,3 ‘Copyright 2008 OpenStreetMap (openstreetmap.org)’” ${PNG}
rm blank.ppm intermediate.ppm

La parte più incasinata: creo il simbolo della scala e lo inserisco nella mappa

# —- aggiunta scala

echo “aggiunta scala 1km”

# calcola larghezza in km della mappa
larghezza=$(./calcola $MINLON, $MAXLON, $MINLAT, $MINLAT )
# misura la larghezza in px della mappa
larghezzapixel=$(identify -format %w $PNG)
# calcola l’equivalenza px/km
pixel1km=$(echo “$larghezzapixel/$larghezza” | bc)

# creazione simbolo scala
framewidth=1
scalesymbol=scale.png
scaleheight=10
scalecolor1=xc:blue
scalecolor2=xc:white

pixel100m=$(echo “($pixel1km-(2*framewidth))/10″ | bc)
convert ${scalecolor1} -resize ${pixel100m}x${scaleheight}! block1.ppm
convert ${scalecolor2} -resize ${pixel100m}x${scaleheight}! block2.ppm
convert +append block1.ppm block2.ppm block1.ppm block2.ppm block1.ppm block2.ppm block1.ppm block2.ppm block1.ppm block2.ppm ${scalesymbol}
convert -mattecolor blue -frame ${framewidth}x${framewidth} ${scalesymbol} ${scalesymbol}
rm block1.ppm block2.ppm

# aggiunta del simbolo alla cartina
composite -geometry +10+30 -gravity southwest ${scalesymbol} ${PNG} ${PNG}

rm ${scalesymbol}

E per finire l’aggiunta di un bordino blu di rifinitura.

# —- aggiunta frame di contorno al file completo

echo “aggiunta frame…”
convert -mattecolor blue -frame 1×1 ${PNG} ${PNG}

echo “operazione completata.”

Facile, no? Si, lo so, è abbastanza contorto.. Ma ha l’innegabile vantaggio che, una volta pronto, non devo fare altro che andare nella cartella, scrivere ./renderizza e lui fa tutto e mi presenta la bellissima cartina completa.

map

Ad esempio, mi piacerebbe metterlo nel cron del mio server per mostrare su una pagina web la cartina del mio paese con aggiornamenti giornalieri (peccato che il mio server è un computer di 10 anni fa e per fare il rendering ci mette 20 minuti). Se poi pensiamo alla possibilità di modificare il file xml (osm-map-features ecc..), che descrive il modo in cui la mappa è creata, possiamo ottenere infinite potenzialità di personalizzazione della mappa da noi creata (modificare i simboli, le dimensioni e i colori delle strade, scegliere cosa inserire e cosa no, …).

Beh, per oggi mi accontento di questo.. Fatemi sapere se il sistema vi piace e in caso mandatemi un link delle vostre opere d’arte :-)

Ciao a tutti!

Pubblicato su Uncategorized | Contrassegnato da tag: , , , , , | 7 Commenti »

Aggiungere testo in cima o in fondo a un’immagine

Pubblicato da piccimario su Dicembre 8, 2008

Creare immagini è bello e divertente, ma a volte una parola vale più di mille pixel colorati. Questo delirio di luoghi comuni (per giunta mischiati) vorrebbe dire che a volte è necessario aggiungere del testo ad un’immagine, ad esempio una forma di copyright. “Facile, usiamo GIMP!” direte voi; si, è una buona soluzione, ma quando le immagini da modificare diventano 1000 (oh, che bel numero) voglio vedervi come vi divertite! Vogliamo che questa operazione sia automatizzata, che possa essere eseguita da uno script. Ovviamente useremo la magia di ImageMagick, fantastica suite di tools grafici da riga di comando di cui ho già avuto modo di parlare, disponibile per tutti i sistemi operativi e le architetture.

I passi da seguire sono pochi e semplici:

1) Creiamo uno spazio; questo sarà destinato ad essere aggiunto in cima o in coda all’immagine di partenza. L’altezza è un valore preimpostato (per il font predefinito suggerisco un 15 px), la larghezza dev’essere quella dell’immagine di partenza, in modo da combaciare.

larghezzapixel=$(identify -format %w immaginedipartenza.png)
convert xc:yellow -resize ${larghezza}x15! blank.ppm

Abbiamo creato un’immagine di nome “blank.ppm” larga come l’immagine di partenza (misurata con “identify”) e alta 15 pixel. Piccolo trucco: se creiamo uno spazio dello stesso colore dello sfondo, la larghezza non importa: in fase di sovrapposizione lo spazio mancante verrà aggiunto col colore di sfondo, che quindi sarà indistinguibile. Possiamo anche usare una larghezza di un pixel!

convert xc:white -resize 1×15! blank.ppm

Ecco cosa abbiamo creato:

addtext_blank

2) Concatenare lo spazio all’immagine di partenza

convert -append  immaginedipartenza.png blank.ppm intermedio.ppm

Abbiamo unito l’immagine di partenza al file “blank.ppm”, e il risultato è salvato in “intermedio.ppm”. NB: conviene utilizzare sempre file “.ppm” per i passaggi intermedi, dato che si tratta di formati lossless; se lavorassimo con formati compressi con perdita a ogni passaggio avremmo una degradazione della qualità dell’immagine.

addtext_intermedio1

3) Scrivere il testo nello spazio creato

convert intermedio.ppm -gravity “South” -draw “text 0,2 ’simpatico testo’” immaginefinale.png

Prendiamo l’immagine “intermedio.ppm” e vi aggiungiamo il testo “simpatico testo”. “Gravity” definisce la posizione (sud, ovvero in fondo), e lo “0,2″ indica l’offset in cui posizionarlo rispetto alla gravity stessa. Il risultato è salvato in “immaginefinale.png”.

addtesx_immaginefinale

Facile, no?

Io uso questo sistema per aggiungere testo in cima e fondo alle mappe che renderizzo con i dati di OpenStreetMap. Questa è la parte di script che uso:

# —- aggiunta header

echo “aggiunta della data alla cartina..”
convert xc:white -resize 1×15! blank.ppm
convert -append blank.ppm ${PNG} intermediate.ppm
convert intermediate.ppm -gravity “North” -draw “text 0,3 ‘Updated on: $(date -r ${OSM}) by PicciMario’” ${PNG}
rm blank.ppm intermediate.ppm

# —- aggiunta footer

echo “aggiunta copyright alla cartina..”
convert xc:white -resize 1×20! blank.ppm
convert -append  ${PNG} blank.ppm intermediate.ppm
convert intermediate.ppm -gravity “South” -draw “text 0,3 ‘Copyright 2008 OpenStreetMap (openstreetmap.org)’” ${PNG}
rm blank.ppm intermediate.ppm

E questo è il risultato:

addtext_map

E per oggi è tutto.. alla prossima!

Pubblicato su Uncategorized | Contrassegnato da tag: , | 1 Commento »

Map Tricks: aggiungere un riferimento di distanza a una mappa

Pubblicato da piccimario su Dicembre 5, 2008

Supponiamo di avere un file grafico rappresentante una mappa, e di volerci aggiungere un qualcosa che permetta di comprenderne le proporzioni. Normalmente le mappe prevedono, oltre alla dicitura della scala, anche un simbolo grafico di dimensione nota, ad esempio un chilometro. E’ possibile aggiungere un simbolo del genere a una mappa di cui si conoscono solo le coordinate geografiche in modo semplice ed automatico.

Lavorando sotto Linux (Ubuntu, per l’esattezza) ci occorreranno le utility ImageMagick (una suite di tool grafici da riga di comando), bc (un’utility per eseguire operazioni matematiche da riga di comando) e il programmino in C “calcoladistanza” che ho descritto in un precedente post (che calcola la distanza tra due punti in km a partire dalle loro coordinate geografiche). Se non li abbiamo li possiamo scaricare così (sotto ubuntu):

sudo apt-get install bc imagemagick

Per compilare il programmino invece basta seguire le istruzioni riportate sul post originale.

Le operazioni da svolgere sono le seguenti:

MINLON=…
MAXLON=…
MINLAT=…
MAXLAT=…

scriviamo in quatto variabili numeriche i valori estremi di latitudine e longitudine della mappa

larghezza=$(./calcoladistanza $MINLON, $MAXLON, $MINLAT, $MINLAT )

salva nella variabile “larghezza” la larghezza in km della superficie riportata sulla mappa, come distanza tra due punti sugli estremi della mappa stessa (notare che ho usato lo stesso valore di latitudine, altrimenti avrei calcolato la distanza diagonale).

larghezzapixel=$(identify -format %w immagine.png)

misura la larghezza in pixel dell’immagine, utilizzando il tool “identify” contenuto nella suite ImageMagick.

pixel1km=$(echo “$larghezzapixel/$larghezza” | bc)

calcola la larghezza in pixel di un km effettivo sulla mappa, dividendo (con l’utility “bc”) i due risultati precedenti

convert xc:white -resize ${pixel1km}x15! -frame 2×2 blank.ppm

crea (usando l’utility “convert” di imagemagick) un’immagine di nome blank.ppm, alta 15 pixel e larga esattamente un chilometro (ovvero il numero di pixel calcolati prima); poi vi aggiunge una cornice di 2 pixel

convert blank.ppm -gravity “Center” -draw “text 0,0 ‘Un kilometro!!’” blank.ppm

scrive il testo “Un kilometro!!” nel file precedentemente creato

composite -geometry +10+30 -gravity southwest blank.ppm immagine.png immagine_scala.png

usando “composite” (sempre contenuta in imagemagick, ovviamente) sovrappone la scala creata all’immagine di partenza e salva il risultato nel file “immagine_scala.png”. Il risultato sarà una cosa del genere:

lovereconscala

Che ve ne pare? Bello, eh? In realtà si può fare meglio.. ad esempio, invece di creare un rettangolo con una scritta si potrebbe usare un simbolo un pò più serio, tipo:

dili_1943_scale

(ovviamente opportunamente scalato e con tutti i controlli del caso), ma questo ve lo lascio come compito a casa :-) . Potete trovare un’infinità di informazioni ed esempi sull’utilizzo della suite ImageMagick qui. Ciao a tutti!

Pubblicato su Uncategorized | Contrassegnato da tag: , , | 2 Commenti »

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

Pubblicato da piccimario su Dicembre 4, 2008

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!

Pubblicato su Uncategorized | Contrassegnato da tag: , | 4 Commenti »