Archivio

Posts Tagged ‘WFS’

Open data e Open service basati su standard: come ottenere lo shapefile dei Numeri Civici Open Data della Regione Sicilia partendo dai servizi resi disponibili


Tutto è nato da una mail di Andrea Borruso, apparsa sulla lista GFOSS proprio alla vigilia di Natale, in cui si annunciava, da parte della Regione Sicilia e per una serie di comuni, la disponibilità, in modalità WFS, di un dataset dei numeri civici georiferiti.

I servizi sono fruibili direttamente da client diversi, desktop, web, mobile, ecc …. che ovviamente supportino lo standard OGC WFS,  cosa oramai ampiamente diffusa, piuttosto facile da fare e alla portata di un’utenza, seppur tecnica, piuttosto ampia.

Con una chiamata standard è anche possibile avere l’elenco dei comuni per cui sono disponibili i dati dei numeri civici: la chiamata è la seguente:

ogrinfo -ro wfs:"http://map.sitr.regione.sicilia.it/ArcGIS/services/CART_2000/Numeri_Civici/GeoDataServer/WFSServer"

Bello ma, per il mio interesse cioè quello di raccogliere i civici open data disponibili sul panorama nazionale, mancava una visione di insieme che mi fornisse TUTTI i civici a livello regionale.

Ma, essendo tutto basato  su standard, si trattava solo di avere un po di voglia e tempo per fare un interessante (??? 🙂 ) esercizio informatico e “rinfrescare” alcune conoscenze messe un po’ da parte negli ultimi tempi.

Provo a riassumere quanto fatto, primo per mie note personali, ma anche perchè credo / spero possa interessare a chi voglia /debba poter replicare un’esigenza analoga.

Premetto che quello indicato NON è l’unico modo possibile per raggiungere l’obiettivo, ve ne possono essere diversi altri, anche più “eleganti”.

In tutto è organizzato in 3 passi logici.

Step 1: scaricare i dati collegandosi ai servizi

Nota organizzativa: gli eseguibili shell che illustro nel seguito operano nel rispetto di questa organizzazione su file system:

OrganizzazioneCartelle

I servizi sono esposti in WFS e quindi possono essere contattati via chiamata http ottendo in risposta, tra le altre cose, il dato in formato GML.

Purtroppo gli attuali servizi non permettono di ottenere i dati in formati diversi.

In questo caso, essendo 376 i comuni da scaricare, e quindi le chiamate da fare, ho creato un piccolo eseguibile shell, lanciabile da linea di comando, che, usando il comando CURL disponibile in ambiente Linux e/o Windows a seconda delle installazioni (nel mio caso ho utilizzato CygWin …), scaricherà, completamente, tutti i singoli GML, uno per ogni comune.

La chiamata, per un singolo comune è la seguente …

curl "http://map.sitr.regione.sicilia.it/ArcGIS/services/CART_2000/Numeri_Civici/GeoDataServer/WFSServer?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=CART_2000:NumeriCivici_81008_Erice&SRSNAME=EPSG:4326" -o CiviciComuniSicilia/GML/81008_Erice_4326.gml

Visto che i comuni erano molti ho realizzato un programmino shell, denominato DownloadCiviciByCurl.sh, reso parametrico ….

echo "Download civici $1 ......"
curl "http://map.sitr.regione.sicilia.it/ArcGIS/services/CART_2000/Numeri_Civici/GeoDataServer/WFSServer?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=CART_2000:NumeriCivici_$1&SRSNAME=EPSG:4326" -o CiviciComuniSicilia/GML/$1_4326.gml
echo "Sleeping for 30 sec: don't load too much the server ...."
sleep 30

il quale è poi richiamabile da un programmino di lancio denominato LauncherDownloadCiviciByCurl.sh

echo "Starting download civici Sicilia ......"
sleep 5
./DownloadCiviciByCurl.sh 81008_Erice
./DownloadCiviciByCurl.sh 83040_Limina
./DownloadCiviciByCurl.sh 87001_Aci_Bonaccorsi
......
......

da completare con l’elenco dei comuni ricavato dall’istruzione ogrinfo mostrata in precedenza.

I files .sh sono mantenuti nella cartella “Work”.

Ecco uno snapshot dell’esecuzione di questo primo passo …

DownloadCiviciSicilia

Step 2: convertire i dati in formato ESRI shapefile

Il mio obiettivo finale era quello di avere un unico file con tutti gli indirizzi georiferiti disponibili per la Regione Sicilia, e quindi dovevo in un qualche modo unire tra loro, geograficamente, i singoli files GML scaricati.

L’aggregazione geografica di più files GML non sembra sia possibile (dopo una veloce ricerca sul web …), e quindi ho deciso di convertire ogni singolo file GML in uno shapefile per poi unificali tra loro in uno step successivo.

Per eseguire l’operazione di cui sopra ovviamente il tool che meglio si adatta sono ancora le librerie GDAL con il seguente comando ogr2ogr

ogr2ogr -f "ESRI Shapefile" 81008_Erice_4326 CiviciComuniSicilia/GML/81008_Erice_4326.gml

Nel preparare questa trasformazione mi sono accorto che lo shapefile prodotto risultava privo del file di proiezione (.prj), e quindi, con una seconda operazione ogr2ogr ho provveduto ad aggiungere allo shapefile prodotto, il file .prj relativo al sistema di riferimento che volevo utilizzare (EPSG: 4326)

ogr2ogr -a_srs EPSG:4326 CiviciComuniSicilia/Shapefile/NumeriCivici_81008_Erice.shp 81008_Erice_4326/NumeriCivici_81008_Erice.shp

Anche in questo caso  ho poi realizzato un programmino shell, denominato ConvertShapefile.sh, reso parametrico ….

echo Convert $1 civici GML into ESRI shapefile .....
ogr2ogr -f "ESRI Shapefile" $1_4326 CiviciComuniSicilia/GML/$1_4326.gml
echo Adding .prj to $1 civici shapefile .....
ogr2ogr -a_srs EPSG:4326 CiviciComuniSicilia/Shapefile/NumeriCivici_%1.shp $1_4326/NumeriCivici_$1.shp
echo Delete temporary files .....
rm -R $1_4326

il quale è poi richiamabile da un programmino di lancio denominato LauncherConvertShapefile.sh …

echo "Starting converting civici Sicilia in shapefiles ......"
./ConvertShapefile.bat 81008_Erice
./ConvertShapefile.bat 83040_Limina
./ConvertShapefile.bat 87001_Aci_Bonaccorsi
......
......

I files .sh sono mantenuti nella cartella “Work”.

Ecco lo snapshot dell’esecuzione di questo secondo passo …

ConvertShapefile

Step 3: creare un unico shapefile di dati

A questo punto non restava che “fondere” insieme i vari shapefile dei singoli comuni in un unico shapefile a livello regionale.

Anche qui viene in aiuto la libreria GDAL con le ogr2ogr che permettono di effettuare questa operazione eseguendo un semplice ciclo: anche in questo caso ho racchiuso il tutto in un programmino shell che ho nominato UnionShapefileComuni.sh

#!/bin/bash
for f in `ls *.shp`
do
echo "Append shapefile " $f " ....."
ogr2ogr -update -append civici_sicilia.shp $f -f "ESRI Shapefile" -nln civici_sicilia
done

Il file .sh è mantenuto nella cartella “Shapefile”.

Ecco uno snapshot dell’esecuzione di questo terzo passo …

Append

Ed ecco che il gioco è fatto, replicabile e, volendo,  completamente automatizzabile mettendo i vari passi in un unico shell.

Il risultato è il seguente:

Sicilia1

Sicilia2

L’intero dataset è scaricabile e disponibile nel rispetto delle licenze originali dei dati di partenza (CC-BY SA).

Come detto in precedenza quello descritto non è l’unico metodo ma ve ne possono essere molti altri, anche più eleganti: ne cito uno, illustrato da Andrea Borruso, che mi sembra di particolare interesse e che si basa sul fatto che i servizi della Regione Sicilia sono contattabili anche via REST, e quindi, partedo da questo,  si potrebbe replicare l’esperienza fatta da Maurizio Napolitano nel caso di Regione Umbria.

Un primo utilizzo delle informazioni che ho aggreato? Per visualizzare i dati delle mia raccolta degli indirizzi georiferiti open data in Italia (di cui stò preparando la nuova release … stay tuned!!!): portando i dati su un db POSTGIS e poi usando TileMill ho prodotto i tiles che permettono di visualizzare rapidamente l’intero dataset insieme a tutti gli altri raccolti a livello nazionale.

Spero che queste info possano essere utili.

OpenGeoData: come utilizzarli su una mappa? Ad esempio sfruttando il cross layer filtering di Geoserver


Sempre più spesso si parla di open data e tra questi di quelli che maggiormente sono ricercati dagli utenti, vale a dire quelli georiferiti.

La disponibilità di open dati open georiferiti sta infatti pian piano aumentando come testimoniato nella recente conferenza sugli OpenGeoData tenutasi a Roma il 28 Febbraio. Gli ultimi esempi degni di nota in tale direzione sono stati la pubblicazione in modalità open data di informazioni georiferite messe a disposizione del Comune di Venezia, e da quello di Trento, mentre, ancora più recente, è la notizia relativa alla volontà di prossima pubblicazione in modalità open dei dati georiferiti della Provincia Autonoma di Bolzano.

L’aumentare della disponibilità va sicuramente a “saziare”, in parte, l’appetito di quel mondo di tecnici e appassionati che per skill personali, sanno cosa farci e come usare questi dati ma resta tutto un mondo di potenziali utenti (privati ma anche del mondo business), che, non provenendo dal mondo GIS classico o della neo-geography,  non hanno quindi dimestichezza con questa tipologia di dati e che quindi non sa bene come usarli o nemmeno, cosa peggiore, cosa si potrebbe fare per costruirci del valore aggiunto.

Resta quindi un gap da riempire, anche di conoscenza, per valorizzare questo patrimonio informativo messo liberamente a disposizione che, se non colmato, rischia di vanificare in parte il grosso sforzo che si sta facendo negli ultimi anni per rendere open data più informazioni possibili, le quali rischiano sì di uscire dal cassetto di un qualche funzionario della P.A, ma per finire, dimenticati, su un qualche portale open data che con il passare del tempo perderà di interesse.

Esempio

Lo scopo di questo post è quello di illustrare un possibile utilizzo di tali dati sfruttando le funzionalità di cross-layer filtering offerte da GeoServer.

I dati

Come dati di esempio ho utilizzato due shapefile messi a disposizione dal Comune di Torino e precisamente:

I dati sono praticamente direttamente utilizzabili: per mia comodità ho aggiunto ad entrambi i dati, visto che ne erano privi, un campo chiave univoco (KEY), numerico che ho valorizzato con un progressivo e poi ho trasformato l’SRS di riferimento adottando l’EPSG:900913. Per fare queste operazioni ho utilizzato QGIS Desktop ma sono operazioni che si possono fare con qualunque strumento GIS Desktop.

Per chi volesse replicare gli esmepi riportati in questo post i dati sono liberamente scaricabili.

Cross Layer Filtering in GeoServer

Come  ho anticipato in questo esempio ho sfruttato la funzionalità di cross-layer filtering offerte da GeoServer. Questa funzionalità permette di ricercare features di un layer (A) che abbiano una qualche relazione spaziale con features di un altro layer (B).

In generale quindi permette ad esempio di cercare tutte le stazioni di autobus (layer A)  che sono entro una certa distanza da un certo negozio (features del layer B), oppure che sono dentro un certo quartiere (layer B).

Ho utilizzato un pc Windows 7 con 4 core e 8 Gbyte di RAM con GeoServer 2.2.3 con le seguenti caratteristiche:

  • Git Revision 0fd3212ede1a8e13257ae5785cc8a752ee0a645c
  • Build Date 22-Dec-2012 15:59
  • GeoTools Version 8.5 (rev 06286dc3c15c2498aa5b3580de5df928f07d31dc)

Nello specifico l’esempio che ho implementato permette di individuare quali sono gli esercizi commerciali che sono nell’intorno di un certo indirizzo.

La funzionalità è stata implementata completamente in GeoServer quindi come funzionalità server-side esposta come WFS quindi potenzialmente fruibile da qualunque client in grado di mandare la richiesta secondo questo protocollo (con i corretti parametri ovviamente), interpretandone poi il GML ottenuto come risposta.

Ecco la chiamata POST nel caso in cui si cerchino le features del layer AttivitaCommerciali che rcadono nell’intorno di 100 metri dal numero civico identificato con la chiave 36748

<wfs:GetFeature

xmlns:wfs=”http://www.opengis.net/wfs&#8221;

xmlns:CesareWorkspace=”http://www.openplans.org/spearfish&#8221;

xmlns:ogc=”http://www.opengis.net/ogc&#8221;

service=”WFS” version=”1.0.0″>

<wfs:Query typeName=”CesareWorkspace:AttivitaCommerciali900913″>

<ogc:Filter>

<ogc:DWithin>

<ogc:PropertyName>the_geom</ogc:PropertyName>

<ogc:Function name=”collectGeometries”>

<ogc:Function name=”queryCollection”>

<ogc:Literal>CesareWorkspace:NumeriCivici900913</ogc:Literal>

<ogc:Literal>the_geom</ogc:Literal>

<ogc:Literal>KEY = 36748</ogc:Literal>

</ogc:Function>

</ogc:Function>

<ogc:Distance units=”meter”>100</ogc:Distance>

</ogc:DWithin>

</ogc:Filter>

</wfs:Query>

</wfs:GetFeature>

Il tutto lo potete eseguire dal Demo Request che trovate una classica installazione di GeoServer in

http://localhost:8080/geoserver/web/?wicket:bookmarkablePage=:org.geoserver.web.demo.DemoRequestsPage)

usando come url per l’esecuzione qualcosa di questo genere

http://localhost:8080/geoserver/CesareWorkspace/ows?

(in questo caso il mio layer si trova in un workspace denominato CesareWorkspace.

Il risultato sarà un GML con l’elenco delle features individuate dal filtro spaziale DWithin: faccio notare che nel GML sono restituite non solo le coordinate delle features ma le intere features come oggetti e quindi comprensive dei dati alfanumerici descrittivi

GMLGeoserver

Un esempio di utilizzo in OpenLayers

Per poter visualizzare questo risultato ho utilizzato OpenLayers 2.12 scrivendo una piccola applicazione web che illustra come visualizzare i dati di partenza, Numeri Civici e Attività Commerciali su sfondo OpenStreetMap e che al tempo stesso permette all’utente di selezionare un indirizzo e sulla base di questo indicare una distanza di ricerca: confermando l’operazione l’applicazione esegue una chiamata in POST verso GeoServer e ne visualizza i risultato sotto forma di VectorLayer di OpenLayers tratto dal GML di risposta.

L’intero codice dell’applicazione è scaricabile e liberamente utilizzabile. Il codice è ampiamente commentato e quindi dovrebbe essere piuttosto chiaro (ovviamente per chi conosce OpenLayers …), il suo modo di operare.

Ecco solo alcune note importanti per la sua esecuzione:

1) se Apache e GeoServer sono su server diversi o sono sullo stesso server ma rispondono su porte diverse è necessario usare un proxypass definito nell’httpd.conf di Apache. Nel mio caso Apache e GeoServer sono sullo stesso server ma Apache risponde sulla porta 80 mentre GeoServer sull’8080 e quindi nel file ci configurazione di Apache ho riportato quanto segue:

<Location /local-geoserver/>

             ProxyPass http://localhost:8080/geoserver/

             ProxyPassReverse http://localhost:8080/geoserver/

          </Location>

2) come anticipato i due layers adottano il sistema di riferimento EPSG:900913. Questa è stata una semplificazione voluta visto lo scopo didattico dell’esempio. Se si intende replicare ed adattare l’esempio con latri dati occorre tenere presente il sistema di riferimento adottato e fare le opportune modifiche

// *****************************************************************

            // ** Set up projection used                                      **

            // *****************************************************************

            var map_projection = new OpenLayers.Projection(“EPSG:900913”);           

            var map_display_projection = new OpenLayers.Projection(“EPSG:900913”);

e nella definzione del layer la riga

   projection: new OpenLayers.Projection(“EPSG:900913”) 

3) ad ogni cambio di indirizzo e/o di distanza di ricerca è necessario aggiornare la mappa ma al tempo stesso occorre anche eliminare le features precedentemente disegnate: nel mio caso ho deciso di essere un po “drastico” eliminando e ricreando i layer interessati ogni volta

// ***********************************************************************************

            // ** Remove overlay layers: I’ve to update them ….                                                                     **

            // ***********************************************************************************

            if (my_address_wfs != null) {              

               layers = map.getLayersByName(‘Indirizzo in esame’);                

               for(layerIndex = 0; layerIndex < layers.length; layerIndex++)

                  {

                 map.removeLayer(layers[layerIndex]);

                  }

            }

          

            if (my_address_wfs != null) {             

               layers = map.getLayersByName(‘Attività Commerciali vicino ad indirizzo’);                 

               for(var layerIndex = 0; layerIndex < layers.length; layerIndex++)

                  {

                 map.removeLayer(layers[layerIndex]);

                  }

            }

4) occorre considerare che la chiamata verso geoserver e la successiva elaborazione della risposta è un processo asincrono per cui si perde un po’ il controllo del flusso di esecuzione che è demandato completamente ad OpenLayers: può essere quindi un po’ complicato disegnare le features al momento giusto, effettuare i corretti zoom (le features potrebbero non ancora essere state disegnate e il layer risulta “vuoto” ….), ecc .. Nel mio caso per il layer che rappresenta il mio indirizzo in esame (my_address_wfs) ho deciso di utilizzare una strategia Fixed

strategies: [new OpenLayers.Strategy.Fixed()]

e un listener che “scatta” quando tutte le features sono state aggiunte così da poter fare, solo a quel punto, le necessarie considerazioni e azioni, nello specifico fare uno zoom all’indirizzo in esame solo se non siano state individuate attività commerciali nell’intorno dell’indirizzo stesso.

eventListeners: {

                “featuresadded”: function(event) {

                      if (theAttivitaExtent == null) {

                         this.map.zoomToExtent(this.getDataExtent());

                      }

                }

            }

Non potendo mettere a disposizione una versione live dell’esempio in oggetto eccovi un filmato di una sessione di utilizzo

(doveroso … un ringraziamento a Fabrizio C., Diego S. e Fabrizio M., in memoria dei vecchi tempi e per la pazienza ed il supporto che mi hanno dato nella realizzazione di questo esempio di fruizione in OpenLayers)

Conclusioni

Questo è solo un esempio ma illustra un principio di utilizzo che si può estendere e generalizzare, ad esempio:

  • il fatto di sfruttare una funzionalità offerta server-side da GeoServer basata su protocolli standard (WFS, GML), permette di riusare la funzionalità stessa da client diversi, sfruttando anche, in caso di necessità, la scalabilità server side offerta dal motore GIS
  • la stessa applicazione, pur didattica, sarebbe portabile su un dispositivo mobile. In questo caso la scelta dell’indirizzo potrebbe essere facilmente sostituita dalla posizione corrente dell’utente via localizzazione GPS
  • i dati messi a disposizione potrebbero essere più significativi di quelli utilizzati nell’esempio per rendere più utile l’applicazione stessa. Ad esempio localizzazione di servizi di pubblica utilità (ad esempio nel caso in cui si sia in una città che non si conosce …), offerte di business nel campo del commercio (quali negozi offrono quali opportunità nell’intorno di un indirizzo o posizione … ), micro-marketing (caratteristiche dell’utenza nell’intorno di un indirizzo o in un’area), ecc ..
  • utilizzo di altre tipologie di filtro spaziale