Premessa
L’articolo descrive come realizzare un servizio WPS per generare un buffer di un dato vettoriale partendo dalla geometria e dalla distanza. Il materiale è ripreso dal talk svolto durante il FOSS4G 2010 e necessita di concetti base su Python, OpenLayers e pyWPS. Si presuppone di lavorare con Ubuntu 10.04.
Scaricare ed installare pyWPS
Al fine di utilizzare le ultime funzionalità presenti in pyWPS, in questa guida utilizzeremo la versione di sviluppo. Per scaricarla dovremo aver installato il pacchetto subversion recuperabile tramite apt-get. Se non ce l’abbiamo già installato, digitiamo:
sudo apt-get install subversion
Posizioniamoci nella cartella /tmp/ ed eseguiamo il seguente comando:
cd /tmp/ && svn checkout https://svn.wald.intevation.org/svn/pywps/trunk
A questo punto possiamo procedere con l’installazione:
cd trunk && sudo python setup.py install
Ora installiamo alcuni pacchetti necessari all’esecuzione di pyWPS e del processo:
sudo apt-get install python-xml python-magic python-gdal
Creazione delle cartelle necessarie, del file di configurazione e del wrapper CGI
PyWPS può essere configurato in modo da eseguire differenti servizi WPS. Ogni servizio necessita semplicemente di una directory dove sono presenti i processi disponibili ed un file di configurazione. Nell’esempio useremo la cartella /usr/local/wps/ per ospitare il nostro servizio.
Creiamo la cartella per contenere i processi:
sudo mkdir -p /usr/local/wps/processes
Creiamo la cartella per i file temporanei
sudo mkdir -p /var/www/tmp/wps && sudo chmod -R 777 /var/www/tmp/
Creiamo il file di configurazione usando il template presente in pyWPS
cp /tmp/trunk/pywps/default.cfg /usr/local/wps/pywps.cfg
Facendo riferimento al numero di riga, modifichiamo il file di configurazione appena copiato:
serveraddress=http://localhost/cgi-bin/pywps.cgi
outputUrl=http://localhost/tmp/wps
outputPath=/var/www/tmp/wps
A questo punto dobbiamo creare uno script CGI in cui impostiamo le variabili PYWPS_CFG e PYWPS_PROCESSES che spcificano il percorso al file di configurazione e alla cartella contenente i processi. Il file va creato nella cartella cgi-bin del nostro web server (di solito /usr/lib/cgi-bin).
sudo touch /usr/lib/cgi-bin/pywps.cgi
Ecco il contenuto dello script:
#!/bin/sh
# Author: Jachym Cepicky
# Purpose: CGI script for wrapping PyWPS script</span></li>
# Licence: GNU/GPL</span></li>
# Usage: Put this script to your web server cgi-bin directory, e.g.</span></li>
# /usr/lib/cgi-bin/ and make it executable (chmod 755 pywps.cgi)</span></li>
export PYWPS_CFG=/usr/local/wps/pywps.cfg</span></li>
export PYWPS_PROCESSES=/usr/local/wps/processes/
/usr/local/bin/wps.py $1
Rendiamolo eseguibile
sudo chmod 755 pywps.cgi
Per verificare la corretta installazione, apriamo il seguente indirizzo:
http://localhost/cgi-bin/pywps.cgi?request=GetCapabilities&service=WPS
In caso positivo, l’xml mostrato descriverà le informazioni sul nostro servizio WPS
Processo per la creazione del buffer
Il processo che utilizzeremo permette di generare un buffer delle feature presenti in un dato vettoriale; come input necessita del dato (che noi invieremo come formato GML) e dell’ampiezza del buffer. Questo tipo di elaborazione può venir svolta in differenti modi, ad esempio passando per GRASS, ma noi utilizzeremo OGR al fine di limitare il numero di pacchetti da installare.
Il processo è disponibile nella cartella di esempio, per cui copiamolo come abbiamo fatto in precedenza ed aggiorniamo il file __init__.py
sudo cp /tmp/trunk/tests/processes/buffer.py /usr/local/wps/processes/
cd /usr/local/wps/processes/
sudo echo "__all__=['ultimatequestionprocess','buffer']" > __init__.py
A questo punto facciamo alcune modifiche al processo così da adattarlo al tutorial. Occhio al numero di riga e all’indentazione.
Aggiungiamo:
type=type(0.0),
size = self.size.getValue()
Modifichiamo:
buff = inGeometry.Buffer(size)
La prima modifica serve a permettere valori decimali per il raggio di buffer, la seconda e la terza corregge lo script in modo da utilizzare effettivamente il valore passato come input (altrimenti usava 1000).
Verifichiamo che il processo sia stato aggiunto correttamente eseguendo una richiesta DescribeProcess:
http://localhost/cgi-bin/pywps.cgi?request=DescribeProcess&service=WPS&identifier=buffer&version=1.0.0
Lanciamo il processo prendendo dei dati di esempio presenti in rete. Eseguiamola in due differenti modi per vedere due differenti modalità con cui il WPS può restituire i risultati
http://localhost/cgi-bin/pywps.cgi?service=wps&version=1.0.0&request=execute&identifier=buffer&datainputs=[size=1;data=http://apps.esdi-humboldt.cz/classification/traning_areas/training_areas_en.gml]&responsedocument=buffer=@asreference=true
http://localhost/cgi-bin/pywps.cgi?service=wps&version=1.0.0&request=execute&identifier=buffer&datainputs=[size=10;data=http://apps.esdi-humboldt.cz/classification/traning_areas/training_areas_en.gml]
Come si vede, nella prima richiesta abbiamo aggiunto la proprietà asreference=true ed il risultato è un link all’output generato, mentre nell’altro caso l’output è presente direttamente nel documento generato dal servizio.
Configurazione di OpenLayers
Configurazione OpenLayers
pyWPS include anche una libreria Javascript basata su OpenLayers che permette di semplificare la gestione di chiamate effettuate ad un servizio WPS. Copiamo il file WPS.js dalla cartella di pyWPS alla root di apache:
sudo cp /tmp/trunk/webclient/WPS.js /var/www/
A questo punto configuriamo la parte relativa ad OpenLayers: per questo esempio, che ricordo consiste nel creare un buffer di un poligono disegnato sopra la mappa, abbiamo bisogno di un layer base, un vettoriale per disegnare il poligono ed uno per contenere il buffer di output.
Posizioniamoci nella cartella /var/www/ e creiamo un nuovo file HTML chiamato ad esmpio wps.html.
cd /var/www/ && sudo touch wps.html
A questo punto iniziamo a modificarlo inserendo le varie parti descritte di seguito:
<html xmlns="http://www.w3.org/1999/xhtml">
<script src="http://openlayers.org/api/OpenLayers.js"></script>
<script src="WPS.js"></script>
<script type="text/javascript">
var lon = 5;
var lat = 40;
var zoom = 5;
var map,layer,vlayer,rlayer;
function init(){
layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0",
{layers: 'basic'} );
vlayer = new OpenLayers.Layer.Vector("Editable");
map = new OpenLayers.Map( 'map', {
controls: [
new OpenLayers.Control.PanZoom(),
new OpenLayers.Control.EditingToolbar(vlayer),
new OpenLayers.Control.LayerSwitcher()
]
});
map.addLayers([layer, vlayer]);
map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);
}
Tramite OpenLayers generiamo una semplice mappa ed aggiungiamo la possibilità di disegnare a mano delle features (layer vlayer).
var onWPSClicked = function() {
//Istanziamo la classe WPS impostando l'indirizzo del server WPS e la funzione da eseguire in caso di elaborazione corretta.
var wps = new OpenLayers.WPS("http://localhost/cgi-bin/pywps.cgi",{onSucceeded: onWPSSussceeded});
//Definiamo gli input usando i nomi presenti nel processo (data e size)
var data = new OpenLayers.Format.GML();
var dataInput = new OpenLayers.WPS.ComplexPut({
identifier:"data",
value: data.write(vlayer.features)
});
var sizeInput = new OpenLayers.WPS.LiteralPut({
identifier:"size",
value: document.getElementById("radius").value
});
//Definiamo anche l'output, sempre con l'identificativo utilizzato dal processo (buffer)
var complexOutput = new OpenLayers.WPS.ComplexPut({
identifier: "buffer",
asReference: "true"
});
//Definiamo il processo ed associamogli l'input e l'output appena creati
var returnerProcess = new OpenLayers.WPS.Process({
identifier: "buffer",
inputs: [dataInput,sizeInput],
outputs: [complexOutput] });
wps.addProcess(returnerProcess);
//Eseguiamo il processo
wps.execute("buffer");
}
Questa seconda parte definisce gli elementi del processo che andremo ad eseguire. Tutti i nomi dei parametri di input e di output, nonchè le loro caratteristiche, sono presenti nella richiesta DescribeProcess che è sempre bene effettuare prima dell’esecuzione del processo.
var onWPSSussceeded = function(process) {
try {
map.removeLayer(rlayer);
rlayer.destroy();
} catch(e) {}
url = process.getOutput("buffer").value;
rlayer = new OpenLayers.Layer.GML("Result",url);
map.addLayer(rlayer);
};
</head>
Questa è la funzione che viene eseguita se il processo è svolto correttamente. Non fa altro che rimuovere l’output di precedenti elaborazioni, prendere il risultato (buffer) fornito da pyWPS, creare un nuovo layer GML ed aggiungerlo alla mappa.
<body onLoad="init()">
<div id="map"></div>
Raggio: <input type="text" value="1" id="radius" size="4">
<input type="button" onClick="onWPSClicked();" value="WPSit!">
</body>
</html>
La parte HTML serve a generare la mappa e ad inserire un input per il valore del raggio ed un pulsante per avviare l’elaborazione. E’ bene precisare che il sistema di riferimento della mappa è il WGS84 per cui il valore del raggio deve essere compatibile con questo sistema di riferimento (10 gradi sono una bella distanza
).
Conlcusione
L’esempio vuole mostrare come sia semplice realizzare un servizio WPS completo della parte Server e della parte Desktop. Maggiori informazioni si possono trovare sul sito di OpenLayers, su quello di pyWPS e sul wiki usato per il materiale del FOSS4G 2010.
Share this article