geodjango | primo approccio

GeoDjango è un add-on per Django che consente di gestire e manipolare dati geografici all’interno di un progetto django.

Questo post riassume i passi iniziali per implementare una class geografica in una applicazione….spero di espandere il post non appena avro’ fatto qualche test ed esperienza ulteriore. Andiamo per step:

1. Creazione del db geografico (nel mio caso si tratta di un db Postgis).

Se ancora non esiste creiamo un template per i db gis (sarà molto comodo anche in futuro):

– autenticarsi come utente postgres ed entrae in un template (esempio il “template1”):

postgres@debian:/home/sit$ psql template1;

–  creare un nuovo db che chiameremo template_gis sul modello del template0;

postgres=# CREATE DATABASE template_gis template=template0;

– uscire da psql e creare il linguaggio per il db appena creato:

postgres@debian:/home/sit$ createlang plpgsql template_gis

– poi:

postgres@debian:/home/sit$ psql -f /usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql -d template_gis

– popoliamo la tabella spatial_ref_sys:

postgres@debian:/home/sit$ psql -d template_gis -f /usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql

– entrare nuovamente in un template e indicare che template_gis è un template:

postgres=# UPDATE pg_database set datistemplate=’t’ WHERE datname=’template_gis’;

– a questo punto possiamo creare il nostro db per django usando il template_gis appena creato:

postgres=# CREATE DATABASE energia_django template=template_gis OWNER sit;

– ci spostiamo all’interno del database appena creato:

postgres=# \connect energia_django

– poi è necessario dare i GRANT di SELECT sulla spatial_erf_sys e ALL sulla geometry_columns:

postgres=# GRANT SELECT on spatial_ref_sys to sit;

postgres=# grant ALL on geometry_columns to sit;

2. Configurazione del progetto django (geodjango)

Andiamo all’interno del nostro progetto django (il progetto sia chiama “energia” e una prima applicazione si chiama “manager”)

– Configurare il file settings.py modificando le impostazioni del database come segue:

DATABASES = {
    'default': {
         'ENGINE': 'django.contrib.gis.db.backends.postgis',
         'NAME': 'energia_django',
         'USER': 'sit',
     }
}

Aggiungere:

django.contrib.gis tra le INSTALLED_APPS

3. Preparazione dei dati geografici

Partiamo da dati in formato SHP (nel nostro caso si tratta di uno SHP di punti chiamato “quadri.shp”.

– creare una directory chiamata “data” all’interno della nostra applicazione:

$ mkdir manager/data

e salviamo al suo interno gli SHP relativi:

– con ogrinfo ispezioniamo lo SHP:

$ ogrinfo -so quadro.shp quadro

ottenendo una lista di dati relativi allo SHP (tra cui il numero di feature, SRS, nomi dei campi). Questo è molto importante per creare la class (nel file models.py) che andrà ad “accogliere” i dati. Definiamo quindi la class nel nostro models.py dell’applicazione.

class QuadroIlluminazione(models.Model):
 kp = models.IntegerField()
 numnuovo = models.CharField(max_length=5)
 via = models.CharField(max_length=30)
 codanagr = models.IntegerField()
 norma = models.CharField(max_length=2)
 regolato = models.CharField(max_length=2)
 contenel = models.CharField(max_length=15)
 contpote = models.CharField(max_length=20)
 elettronic = models.CharField(max_length=2)
 ncliente = models.CharField(max_length=10)
 gmrotation = models.FloatField()
 geom = models.MultiPointField(srid=3003)
 objects = models.GeoManager()
 class Meta:
 verbose_name_plural = "Quadri illuminazione pubblica"

 # Returns the string representation of the model.
 def __unicode__(self):
 return self.numnuovo

NB: attenzione all’indentazione; in questo post puo’ non essere corretta; vedere la guida di python per una corretta scrittura del codice)

Abbiamo definito la nuova tabella che conterrà i dati geografici con gli stessi attributi trovati nello SHP. Gli unici due campi che vengono aggiunti sono “geom” e “objects“.

– Controlliamo che tutto sia a posto prima di generare il DB con:

$ python manage.py sqlall manager

l’output è simile a questo (la parte finale):

……………..

CREATE INDEX “manager_contrattoaperturagasnaturale_utente_id” ON “manager_contrattoaperturagasnaturale” (“utente_id”);
CREATE INDEX “manager_contrattofornituragasnaturale_utente_id” ON “manager_contrattofornituragasnaturale” (“utente_id”);
SELECT AddGeometryColumn(‘manager_quadroilluminazione’, ‘geom’, 3003, ‘MULTIPOINT’, 2);
ALTER TABLE “manager_quadroilluminazione” ALTER “geom” SET NOT NULL;
CREATE INDEX “manager_quadroilluminazione_geom_id” ON “manager_quadroilluminazione” USING GIST ( “geom” GIST_GEOMETRY_OPS );COMMIT;

– a questo punto sincronizziamo il DB con:

$ python manage.py syncdb

compariranno una serie di messaggi (con la richiesta di creazione del superutente). alla fine avremo il nostro db pronto.

4. Ridefinizione del models.py

Il models.py deve essere modificato inserendo classe e dizionario. Una funzione ci viene in aiuto per automatizzare il processo:

$ python manage.py ogrinspect manager/data/quadro.shp QuadroIlluminazione –srid=3003 –mapping –multi

Questo comando produce in output la definizione della class e del dizionario necessario per il nostro layer geografico. Tale output puo’ essere copiato/incollato nel nostro models.py

5. Caricamento dei dati del database

Per il caricamento dei dati è necessario creare un modulino python per l’import. Per farlo creare un file chiamato “load.py” e salvarlo all’interno della nostra applicazione. Copiare al suo interno il seguente codice:

import os
from django.contrib.gis.utils import LayerMapping
from models import QuadroIlluminazione

quadroilluminazione_mapping = {
 'kp' : 'KP',
 'numnuovo' : 'NumNuovo',
 'via' : 'Via',
 'codanagr' : 'CodAnagr',
 'norma' : 'Norma',
 'regolato' : 'Regolato',
 'contenel' : 'ContEnel',
 'contpote' : 'ContPote',
 'elettronic' : 'Elettronic',
 'ncliente' : 'Ncliente',
 'gmrotation' : 'GMRotation',
 'geom' : 'MULTIPOINT',

}

quadroilluminazione_shp = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data/quadro.shp'))

def run(verbose=True):
 lm = LayerMapping(QuadroIlluminazione, quadroilluminazione_shp, quadroilluminazione_mapping, transform=True, encoding='iso-8859-1')
 lm.save(strict=True, verbose=verbose)

– Ora invochiamo la shell python per importare i dati mediante il modulo appena creato

$ python manage.py shell

Al prompt di python impartiamo i seguenti comandi (prima richiamiamo il modulo e poi la funzione di “load”):

>>> from manager import load
>>> load.run()

Seguirà una serie di messaggi di import (uno per ogni feature).

6. Caricamento del layer geografico

All’interno del file “admin.py” inserire le seguenti stringhe di codice:

from django.contrib.gis import admin
from manager.models import *
........
admin.site.register(QuadroIlluminazione, admin.GeoModelAdmin)

…to be continued as soon as possible

18-19 (20) novembre 2010, GFOSS DAY a Foligno

L’associazione Italiana per l’Informazione Geografica Libera GFOSS.IT (Geospatial Free and Open Source Software) organizza, per i giorni 18 e 19 novembre 2010, a Foligno, la 3a conferenza italiana sul software geografico libero, per fare il punto sullo stato dell’arte del software geografico libero ed Open Source in Italia, ponendo particolare attenzione alle applicazioni nel campo delle pubbliche amministrazioni e delle aziende.

L’associazione GFOSS.IT (http://www.gfoss.it), costituita nel febbraio 2007 da docenti universitari, ricercatori e professionisti provenienti da diverse regioni italiane, ha, tra gli altri, gli obiettivi di:
– favorire lo sviluppo, la diffusione e la tutela del software esclusivamente libero ed open source per l’informazione geografica;
– promuovere gli standard aperti per l’informazione geografica e il libero accesso ai dati geografici.
Il Gfoss Day, tenutosi in precedenza nelle città di Pontedera e Bolzano (http://www.gfoss.it/drupal/convegno e http://www.gfoss.it/drupal/gfossday ), rappresenta uno dei momenti in cui l’associazione GFOSS.IT riunisce soci, aziende, professionisti e pubbliche amministrazioni attive nell’applicazione, sviluppo, promozione e diffusione di software libero geografico.

L’evento sarà aperto e gratuito per tutti i partecipanti. La prima giornata sarà dedicata a momenti formativi durante i quali esperti di fama nazionale ed internazionale terranno corsi mirati su Software GIS (Geographic Information System) e/o WebGIS.

La seconda giornata della conferenza sarà orientata a discutere aspetti tecnologici e legali relativi alla circolazione dei dati geografici. Sono previsti interventi orientati a fare il punto sul processo di adeguamento delle PA italiane alla direttiva Europea INSPIRE (http://inspire.jrc.ec.europa.eu/ – anche alla luce del decreto legislativo 27 gennaio 2010 , n. 32) e sulla promozione di servizi di distribuzione di dati in rete secondo standard condivisi ed internazionali – OGC e ISO (Web Services).

Per questo saranno ospitati interventi di pubbliche amministrazioni che illustreranno i loro progetti ed il loro stato di avanzamento.

Il terzo giorno sara’ dedicato ad una attivita’ di mappatura della citta’ di Foligno (mapping party) coinvolgendo i ragazzi di alcune scuole. I dati raccolti mediante ricevitori GPS saranno poi riversati nel database libero mondiale di OpenStreetMap.

Maggiori informazioni: http://www.gfoss.it/drupal/gfossday2010

il primo “Hello world” in C

Non sono un programmatore; non conosco nessun linguaggio di programmazione. Per questo, approfittando di una piccola necessita’ lavorativa, mi sono avvicinato al C.

Bazzicando in rete ho trovato alcuni “punti di partenza” molto ben fatti:

introduzione alla programmazione in C;

piccolo corso di programmazione in C;

E da qui ne e’ uscito un piccolo programmino per convertire le coordinate geografiche (lat/long) da DMS (Gradi Primi Secondi) a DD (Gradi decimali).

L’ho scritto usato l’editor “nano” (semplice quanto efficace editor che offre colorazione del testo ben fatta).

Una volta scritto il testo sottostante salvarlo con il nome di “primo_test.c” (i codici sorgente in C vengono contraddistinti dal suffisso .c).

#include <stdio.h>
float a,b,c,d;
main()
{
printf(“inserisci i gradi:  \n”);
scanf(“%f”, &a);
printf(“inserisci i primi: \n”);
scanf(“%f”, &b);
printf(“inserisci i secondi: \n”);
scanf(“%f”, &c);
d=a+(((c/60)+b)/60);
printf(“l’angolo in formato decimale e’ %f \n”, d);
}

Una volta salvato il codice deve essere compilato. Per fare questo ho usato il compilatore “gcc” mediante la seguente sintassi:

$ gcc primo_test.c -o primo_test.out

Viene creato un file eseguibile chiamato primo_test.out (nel caso non avessimo indicato il nome del file di outptu, gcc avrebbe nominato il file “a.out”).

Il programma si lancia con il comando

$ ./primo_test.out

Vediamo il codice. All’inizio del testo viene indicata la libreria da caricare per eseguire le operazioni (#include <stdio.h>).

Poi si passa al processo. Stampa a console la richiesta di inserire i valore dei gradi dell’angolo da convertire; fatto questo cattura il valore inserito e lo memorizza nella prima variabile dichiarata (di tipo float). Poi chiede di inserire il valore del primi e memorizza il valore nella seconda variabile. Infine richiede i secondi e li memorizza nella terza variabile.

Fatto questo esegue l’operazione di conversione e propone in output il valore dell’angolo calcolato.

L’unita’ di tutte le scienze e’ trovata nella geografia

Colgo la bellissima proposta di Andrea Borruso (che ringrazio!) di divulgare questo post in maniera coordinata ad altri blogger.

La riforma della scuola in approvazione in questi giorni, ed in particolar modo delle scuole superiori, releghera’ la geografia ad un ruolo marginale e sempre piu’ debole. Per questo ci uniamo all’AIIG (Associazione Italiana Insegnanti di Geografia) che ha lanciato una raccolta di firme.

L’unità di tutte le scienze è trovata nella geografia. Il significato della geografia è che essa presenta la terra come la sede duratura delle occupazioni dell’uomo. (John Dewey)

Alle elementari avevo un maestro che insegnava geografia e che tirava giù una carta geografica del mondo davanti alla lavagna. Avevo un compagno di classe al sesto anno che un giorno ha alzato la mano e ha indicato la costa orientale del Sudamerica; poi ha indicato la costa occidentale dell’Africa e ha chiesto: «Sono state mai unite?». E il maestro ha risposto: «Certo che no, è una cosa ridicola!». Lo studente cominciò a fare uso di droghe e sparì. L’insegnante è diventato consigliere scientifico dell’attuale amministrazione (ndr Bush). (dal film documentario statunitense del 2006 “Una scomoda verità”,  diretto da Davis Guggenheim).

Nella mia geografia ancora sta scritto che tra Catanzaro e il mare si trovano i Giardini delle Esperidi. (George Robert Gissing, da Sulle rive dello Jonio).

L’arma del giornalista è la penna o la macchina da scrivere. L’arma del giornalista sotto vetro smerigliato è la bacchetta o la carta geografica. (Sergio Saviane).

Lungo la costa dell’Africa del Sud-Ovest, delimitato da montagne di origine vulcanica da una parte e dall’Atlantico dall’altra, si stende uno dei più antichi e selvaggi deserti della terra. I geografi chiamano questa zona la Costa degli Scheletri, perché le sue spiagge sono disseminate dei relitti delle navi che vi hanno fatto naugùfragi. (Ronald Schiller da “Nel mondo dei diamanti”).

Insieme a:


QGIS – spostamento di piu’ oggetti vettoriali

Ho digitalizzato una serie di poligoni (SHP) avendo come base una carta raster georeferenziata in GB Fuso Ovest.

Una volta terminata la digitalizzazione e “acceso” un raster relativo all’ortofoto della zona mi sono accorto che gli oggetti erano tutti traslati rigidamente verso Nord di qualche metro (7.81 per la precisione). Mi era stato chiesto di produrre uno snapshot del layer di  interesse sovrapposto all’ortofoto. Non dovendo fare un lavoro di estrema precisione ho pensato di “traslare” tutti gli oggetti del layer poligonale creato della distanza necessaria.

Abilitata la modalita’ “modifca” per lo SHP in questione viene attivato lo strumento di spostamento.

Lo strumento "muovi elemento" nei tool didigitalizzazione agisce su un solo oggetto

Ho selezionato tutti gli oggetti e provato a spostarli. Non sapevo che lo strumento per spostare oggetti funziona sono su un oggetto alla volta. Come fare? Cercando tra i vari plugin ho trovato “qgsAffine”. E fa proprio al caso mio.

Consente di effettuare operazioni di scalatura, rotazione e traslazione su tutti gli oggetti di un layer o soltanto su quelli precedentemente selezionati (e’ necessario avere abilitato la modalita’ “modifica”). Nel mio caso ho impostato soltanto una traslazione verso sud (negativa, quindi ho anteposto il segno “-“) di 7.81 m.

La finestra di impostazione dei parametri del plugin "Vector Affine transformation"

Cliccando su “Run” vengono traslati (o ruotati/scalati) gli oggetti e per il layer viene automaticamente disattivata la modalita’ “modifica”.

OSM e Haiti earthquake

OSM e’ entrata in azione anche per contribuire alla realizzazione della cartografia della zone colpite dal terremoto ad Haiti.

“La mancanza di mappe aggiornate alla reale situazione post terremoto rischiava di compromettere le attività di salvataggio. Appena sono state rese disponibili foto aeree delle zone colpite, i nostri volontari si sono, indipendentemente, messi all’opera e hanno iniziato a inserire dati nel nostro database, questo ha portato, nel giro di
poche ore, alla generazione di mappe aggiornate dell’isola, con indicate tutte le strade ancora percorribili, le posizioni dei campi profughi, ponti inagibili, eccetera.

Le mappe vengono continuamente aggiornate e sono rese immediatamente disponibili per qualsiasi uso, commerciale, o umanitario. Esse sono scaricabili sui navigatori portatili e usate sui cellulari dotati di GPS.

E’ uno straordinario esempio di come un approccio partecipato puo’ funzionare anche in questi drammatici casi”

fonte: http://wiki.openstreetmap.org/wiki/WikiProject_Haiti/Press_info

QGIS hackfest a Pisa – 18-22 marzo 2010

E’ ufficiale: si terra’ a Pisa, dal 18 al 22 marzo 2010, presso il Parco di San Rossore-Migliarino-Massaciuccoli (sala Gronchi) il 3° QGIS hackfest:Gli sviluppatori di QGIS si troveranno per dare forte impulso allo sviluppo del progetto, risoluzione di bug, traduzioni,….Molto probabilmente ci sara’ la possibilita’ di seguiri anche alcuni flashcourses (tipo “Scrivere un plugin in python per QGIS”); a pagamento, in modo da avere le risorse per pagare la trasferta agli sviluppatori che vengono a donare il loro tempo.

Si puo’ partecipare a molti livelli diversi, dal supporto logistico, all’hard coding, passando per la documentazione, traduzione, bug checking, e molte altre cose.
Per ulteriori informazioni contattare Paolo Cavallini (cavallini at faunalia dot it).

geopy | geocoding con gmaps

Ho provato geopy. Un fenomeno. Cito dal sito geopy makes it easy for developers to locate the coordinates of addresses, cities, countries, and landmarks across the globe using third-party geocoders and other data sources, such as wikis.”

Per installarlo ho seguito le istruzioni riportate in questa pagina.

svn co http://geopy.googlecode.com/svn/trunk/ geopy-trunk
cd geopy-trunk/
sudo python setup.py install

(al primo tentativo mi avvisava della mancanza di un pacchetto richiamto dal setup; si trattava di “python-setuptools” che ho poi installato via apt-get).

Fatto questo ho seguito le istruzioni della pagina “gettingstarted“.

In particolare questo metodo (dopo aver reperito una APIKEY da qui):

Lanciato python con:

$ python

mi si presenta il prompt >>>. Inserire la seguente chiamata:

>>> from geopy import geocoders

quindi ho provato con il codice di prova indicato nella pagina:

>>> g = geocoders.Google('YOUR_API_KEY_HERE')  [INVIO]
>>> place, (lat, lng) = g.geocode("10900 Euclid Ave in Cleveland")  [INVIO]
>>> print "%s: %.5f, %.5f" % (place, lat, lng)  [INVIO]
10900 Euclid Ave, Cleveland, OH 44106, USA: 41.50489, -81.61027

E tutto e’ andato a buon fine.

Ora sto provando con alcuni civici del comune in cui lavoro: devo dire che i risultati sono molto confortanti. Devo creare uno scriptino per automatizzare l’inserimento degli indirizzi ed avere in output un file popolato con le coppi di coordinate (lat/long)…tosto davvero!


pgrouting | calcolo percorso minimo tra due punti

Prima di tutto e’ necessario creare un database Postgresql ed aggiungerci l’estensione spaziale Postgis.

come utente postgres si entra in un database esistente o in un template:

# psql template1;

– Creiamo il database e impostiamo la proprietà all’utente (nel nostro caso “sit”):

template1=# CREATE DATABASE routing OWNER sit template template_gis;

il template_gis e’ stato creato a priori (database con estensioni spaziali postgis incorporate; questo per evitare ogni volta di dover aggiungere le tabelle “geometry_column” e “spatial_ref_sys”);

– Ci colleghiamo al database appena creato:

template1=# /connect routing;

e diamo i permessi necessari all’utente “sit” sulla tabella spaziali:

routing=# GRANT ALL ON geometry_columns to sit;
routing=# GRANT SELECT ON spatial_ref_sys to sit;

– Aggiungiamo le funzioni di routing (dopo essere usciti dal database ed esserci autenticati come utente “postgres”):

# psql -d routing -f /usr/share/postlbs/routing_core.sql

# psql -d routing -f /usr/share/postlbs/routing_wrappers.sql

# psql -d routing -f /usr/share/postlbs/routing_topology.sql

– Reperiamo i dati: nel mio caso ho reperito il planet italiano dal sito http://download.geofabrik.de/osm/europe/. Ho scaricato gli SHP. Dopo aver fatto un clip dei dati sul confine regionale di interesse (Veneto) medianti i preziosissimi ftools di qgis ho ottenuto il grafo stradale del territorio veneto.

– Importiamo i dati del database mediante il modulo shp2pgsql. Ecco la sintassi del comando (con SRID settato a 4326, i dati sono in lat-long WGS84).

$ shp2pgsql -S -s 4326 /home/sit/geodatabase/shp/stradario_regione/stradario_regione_seg.shp stradario_regione routing > /home/sit/sql/stradario_regione.sql

$ psql -h localhost -U postgres -d routing -f /home/sit/sql/stradario_regione.sql

Per i passi successivi ho seguito questo ottimo tutorial ):

– Aggiungiamo 3 colonne alla tabella: una per memorizzare gli ID dei nodi iniziali, una per gli ID dei nodi finali e la’ltra per la lunghezza:

routing=> ALTER TABLE stradario_regione ADD COLUMN source integer;

routing=> ALTER TABLE stradario_regione ADD COLUMN target integer;

routing=> ALTER TABLE stradario_regione ADD COLUMN length double precision;

– Creiamo la topologia e aggiungiamo il valore della lunghezza al campo appena creato:

routing=> SELECT assign_vertex_id(‘stradario_regione’, 0.0001, ‘the_geom’, ‘gid’);

routing=> UPDATE stradario_regione SET length = length(the_geom);

– Creiamo gli indici per le colonne “source”, “target” e “the_geom”;

routing=> CREATE INDEX source_idx ON stradario_regione(source);

routing=> CREATE INDEX target_idx ON stradario_regione(target);

routing=> CREATE INDEX geom_idx ON stradario_regione USING GIST(the_geom GIST_GEOMETRY_OPS);

– Impostiamo la query di routing e salviamo il tutto in una nuova tabella chiamata “dijkstra_resust” (prima di tutto cancelliamo una eventuale tabella omonima precedentemente creata):

routing=> DROP TABLE IF EXISTS dijsktra_result;

routing=> CREATE TABLE dijsktra_result(gid int4) with oids;

routing=> SELECT AddGeometryColumn(‘dijsktra_result’, ‘the_geom’, ‘4326’, ‘MULTILINESTRING’, 2);

routing=> INSERT INTO dijsktra_result(the_geom) SELECT the_geom FROM dijkstra_sp(‘stradario_regione’, 73441, 13547);

Questa query trova il percorso minimo tra due vertici (con ID pari a 73441 e 133547).

In prima battuta, nel mio caso, ho ottenuto un messaggio d’errore per violazione di un CONSTRAINT:

ERROR: new row for relation “dijkstra_result” violates check constraint “enforce_geotype_the_geom”

Ho cancellato questo constraint (via pgadmin3) e re-impartito la query ottenendo la nuova tabella dijkstra popolata. Il risultato si può visualzzare in qgis.