mar 04

Condividi


Questo articolo è il seguito di “sextante parte prima” e si consiglia la lettura prima di proseguire.
Nel primo tutorial abbiamo creato il progetto Java e scritto un semplice algoritmo di manipolazione dei dati raster. Ora procederemo con la scrittura di un nuovo algoritmo nel mondo vettoriale. L’algoritmo prevederà un dato vettoriale di input, un campo della tabella attributi ed un parametro numerico per generare un nuovo layer vettoriale in cui i valori del campo di input saranno moltiplicati per il parametro numerico inserito. Il primo passo consiste nella creazione di un nuovo package “es.unex.sextante.multiplyVector”  ed una nuova classe “MultiplyVectorFieldAlgorithm”.

Definiamo i parametri di input e le caratteristiche del nuovo algoritmo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package es.unex.sextante.multiplyVector;
import com.vividsolutions.jts.geom.Geometry;
import es.unex.sextante.additionalInfo.AdditionalInfoNumericalValue;
import es.unex.sextante.core.GeoAlgorithm;
import es.unex.sextante.dataObjects.IFeature;
import es.unex.sextante.dataObjects.IFeatureIterator;
import es.unex.sextante.dataObjects.IVectorLayer;
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
import es.unex.sextante.exceptions.RepeatedParameterNameException;
 
public class MultiplyVectorFieldAlgorithm extends GeoAlgorithm{
 
	public static final String RESULT       = "RESULT";
	public static final String INPUT       = "INPUT";
        public static final String FIELD       = "FIELD";
        public static final String VALUE       = "VALUE";
 
	@Override
	public void defineCharacteristics() {
		this.setName("Multiply vector");
		this.setGroup("My algorithm");
 
		try {
		    m_Parameters.addInputVectorLayer(INPUT, "Vectorlayer",IVectorLayer.SHAPE_TYPE_POLYGON,true);
		    m_Parameters.addTableField(FIELD, Sextante.getText("field"), INPUT);
                    m_Parameters.addNumericalValue(VALUE,"Value",1,AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE);
                    addOutputVectorLayer(RESULT, "Result");
			} catch (final RepeatedParameterNameException e) {
	                   Sextante.addErrorToLog(e);
	                }
	                 catch (final UndefinedParentParameterNameException e) {
	                   Sextante.addErrorToLog(e);
	               }
	                 catch (final OptionalParentParameterException e) {
	                   Sextante.addErrorToLog(e);
	                }
		    }

Definiti i parametri di input dell’algoritmo, si procede con la definizione del corpo del processo, ovvero con il metodo processAlgorithm().

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
 
int iField;
double dValue;
double dConstant;
IVectorLayer layer;
 
layer = m_Parameters.getParameterValueAsVectorLayer("INPUT");
iField = m_Parameters.getParameterValueAsInt("FIELD");
dConstant = m_Parameters.getParameterValueAsDouble("VALUE");
 
Class type = layer.getFieldType(iField);
if !(Number.isAsignableFrom(type)){
throw new GeoalgorithmExecutionException(
"Selected field is not numeric");
}

Dalla riga 50 alla 54 è chiaro come stiamo catturando un’eventuale eccezione relativa alla tipologia del campo definito come input. Se il campo non è di tipo numerico, l’algoritmo non potrà procedere con la moltiplicazione della costante e restituirà un errore.
Proseguiamo con la definizione dei campi attributi di input ed output e con il layer vettoriale risultato.

55
56
57
58
59
60
61
62
63
64
65
66
67
Class[] fieldTypes = layer.getFieldTypes();
Class[] outputFieldTypes = new Class[fieldTypes.length];
 
for(int i = 0; i < fieldTypes.length; i++){
	if (i == iTop || i == iBottom){
	     outputFieldTypes[i] = Double.class;
	     }
	     else{
	     outputFieldTypes[i] = fieldTypes[i];
	      }
}
 
IVectorLayer output = getNewVectorLayer("RESULT",nome,layer.getShapeType(),outputFieldTypes,layer.getFieldNames());

Procediamo con il vero corpo dell’algoritmo in cui il layer vettoriale è letto nella sua componente geometrica ed alfanumerica. Tale procedura avviene tramite due metodi:
public Geometry getGeometry();
public IRecord getRecord();
Il primo legge e archivia e ritorna le geometrie attraverso la JTS (Java Topology Suite), mentre il secondo ritorna l’oggetto record implementato nell’interfaccia IRecord di Sextante.

Nel codice seguente andremo a copiare tutti i valori in un nuovo array che sarà usato per popolare i record del nuovo layer di output, eccetto che per il campo selezionato e dove andremo a moltiplicare i valori per la costante dConstant. Chiarita la procedura principale non sarà difficile comprendere dal codice che il layer di input “smontato” ed analizzato sarà successivamente ristrutturato nella sua componente geometrica ed alfanumerica.
Continue reading »

Tagged with:
gen 28

Condividi

Da un po’ di mesi sono passato da utente a “sviluppatore in erba” di algoritmi con la potente libreria di Sextante GIS (qualcuno la conoscerà come integrazione di gvSIG) interamente scritta in Java e che ha un papà attivissimo: Victor Olaya 8-) . Per chi non la conoscesse, Sextante è una libreria di geoalgoritmi in grado di interfacciarsi con i dati geografici attraverso specifici Bindings (tra cui per gvSIG, OpenJump ed anche le GeoTools). Non entro nel merito su come funzionano i bindings, ma possiamo intenderli come delle interfacce tra Sextante e le applicazioni desktop GIS.

Credo che molti di noi utenti GIS abbiano una volta almeno desiderato sviluppare un algoritmo di analisi spaziale per uno scopo ben preciso :-) A volte ci viene in aiuto la possibilità di costruire dei flussi di lavoro (workflow) possibili anche con Sextante attraverso il suo modelbuilder, ma in questo post proveremo a sviluppare ex novo un geoalgoritmo basato sulla libreria di Sextante.

Ciò che troverete scritto è sostanzialmente tratto e basato sull’ottimo manuale di programmazione Sextante scritto da V. Olaya. Lo scenario applicativo è il seguente: abbiamo installato sul nostro calcolatore un software GIS Open Source (es. gvSIG) esteso con Sextante. Questo breve tutorial presuppone anche una conoscenza di base di Java e un ambiente di sviluppo, in questo caso mi baserò su Eclipse.

Per prima cosa scarichiamo i binari dal sito di Sextante. Appena aperta la cartella, troveremo delle sotto cartelle (bindings, core e help). Ciò di cui avremo bisogno sono i file .jar contenuti nella cartella “core” e che costituiranno le nostre librerie per lo sviluppo dei nostri geoalgoritmi.

A questo punto possiamo avviare Eclipse e creare un nuovo progetto nominandolo “Tutorial”. Adesso creaimo una cartella “lib” dove andremo a collocare i file .jar presenti nella cartella “core” di Sextante. Non ci resta che aggiungere al Build Path del nostro progetto i file presenti nella cartella “lib”.

Bene, adesso dovremo creare un nuovo package (es. it.mionome.sextante.testraster). La struttura di Sextante prevede che ciascun package contenga un algoritmo ed eventuali classi di supporto. Per questo motivo creeremo una nuova classe (senza metodo main)  nominandola MoltplicaRasterAlgorithm – nota bene che il suffisso Algorithm è necessario per essere riconosciuto nel Framework di Sextante come nuovo algoritmo.
Tutti gli algoritmi estendono la classe GeoAlgorithm di Sextante e, pertanto, implementano due metodi:

  • defineCharacteristics()
  • processAlgorithm()

Il primo definisce i parametri dell’algoritmo che serviranno anche per la sua interfaccia grafica; il secondo definisce la struttura dell’algoritmo in termini di calcolo e processi. Procediamo con lo sviluppo di un semplice algoritmo che moltiplica ogni cella di un dato raster in ingresso per un dato valore e restituisce un nuovo raster. Questo esempio è tratto proprio dalla guida citata, ovvero la Programming Guide di Sextante scritta da Victor Olaya.
Ecco come si presenterà la nostra classe dopo averla estesa con GeoAlgorithm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package es.unex.sextante.multiplyRaster;
import es.unex.sextante.core.GeoAlgorithm;
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
public class MoltiplicaRasterAlgorithm extends GeoAlgorithm{
 
@Override
 
public void defineCharacteristics() {
// TODO Auto-generated method stub
 
}
 
@Override
 
public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
// TODO Auto-generated method stub
 
return false;
}
}

Passiamo con il definire il contenuto del primo metodo e, dunque, le caratteristiche del nostro algoritmo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static final String RESULT = "RESULT";
public static final String INPUT = "INPUT";
public static final String VALUE = "VALUE";
public void defineCharacteristics() {
	this.setName("Multiply raster");
	this.setGroup("My algorithm");
	this.setGeneratesUserDefinedRasterOutput(false);
 
	try {
		m_Parameters.addInputRasterLayer("INPUT", "Raster layer", true);
		m_Parameters.addNumericalValue("VALUE", "Value", 1,
				AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE);
		addOutputRasterLayer("RESULT", "Result");
	} catch (RepeatedParameterNameException e) {e.printStackTrace();
	}
}

Analizziamo il codice passo passo. Dalla riga 5 alla riga 6 vengono definiti il nome ed il gruppo di appartenenza del nuovo algoritmo riferito all’interfaccia grafica della toolbar di Sextante. La riga 7 è necessaria perchè creando un nuovo dato raster in uscita, dovremmo definire le estensioni di tale dato in termini di cella e regione. In questo caso impostiamo di default che il dato in uscita avrà le stesse caratteristiche del dato di ingresso e disattiviamo l’opzione con un false.
Le righe 10,11 e 12 rispondono alle semplici domande: quali sono i dati ed i parametri di input (definibili nella GUI del nostro algoritmo) e quali sono i dati in uscita prodotti. In questo caso necessitiamo di un raster in ingresso, un valore numerico come moltiplicatore ed un dato raster in uscita per cui si debba definire il path di scrittura.

Passiamo adesso a definire il processo di calcolo dell’algoritmo:

1
2
3
4
5
6
7
	public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
		int x,y;
		int iNX, iNY;
		double dValue;
		double dConstant;
		IRasterLayer layer;
                IRasterLayer result;

Per prima cosa definiamo le variabili. Come potrete approfondire nel manuale, Sextante si interfaccia con dati raster, vector e tabelle tramite classi apposite: IRasterLayer, IVectorLayer e ITable.
Adesso possiamo inizializzare le nostre variabili notando come definiamo, a livello di codice, anche l’estensione del raster in uscita (ricordiamo che abbiamo disattivato l’opzione tramite GUI).

8
9
10
11
    layer = m_Parameters.getParameterValueAsRasterLayer("INPUT");
    dConstant = m_Parameters.getParameterValueAsDouble("VALUE");
    GridExtent extent = new GridExtent(layer);
    result = getNewRasterLayer("RESULT", Sextante.getText("Result"), IRasterLayer.RASTER_DATA_TYPE_FLOAT, extent);

Dalla riga 8 alla 11 impostiamo come parametri dell’algoritmo i dati di input immessi tramite GUI. Non ci resta che definire il processo di calcolo. Abbiamo bisogno di due semplici cicli for che scandisca cella per cella ne recuperi il value e lo moltiplichi per il nostro moltiplicatore restituendo il risultato come nuovo value.

12
13
14
15
16
17
18
19
20
21
22
23
layer.setWindowExtent(extent);
		iNX = extent.getNX();
		iNY = extent.getNY();
		for (y = 0; y < iNY && setProgress(y, iNY); y++){
			for(x = 0; x < iNX; x++){
				dValue = layer.getCellValueAsDouble(x, y);
				result.setCellValue(x, y, dValue * dConstant);
			}
		}
		return !m_Task.isCanceled();
	}
}

La riga 21 contiene il codice con cui terminare la procedura del nostro algoritmo.
Ricapitolando…il codice completo sarà il seguente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package es.unex.sextante.multiplyRaster;
import es.unex.sextante.additionalInfo.AdditionalInfoNumericalValue;
import es.unex.sextante.core.*;
import es.unex.sextante.dataObjects.IRasterLayer;
import es.unex.sextante.exceptions.RepeatedParameterNameException;
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
import es.unex.sextante.rasterWrappers.GridExtent;
 
public class MultiplyRasterAlgorithm extends GeoAlgorithm{
 
public static final String RESULT = "RESULT";
public static final String INPUT = "INPUT";
public void defineCharacteristics() {
 
this.setName("Multiply raster");
 
this.setGroup("My algorithm");
 
this.setGeneratesUserDefinedRasterOutput(false);
 
try {
 
m_Parameters.addInputRasterLayer("INPUT", "Raster layer", true);
m_Parameters.addNumericalValue("VALUE", "Value", 1,
AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE);
addOutputRasterLayer("RESULT", "Result");
 
} catch (RepeatedParameterNameException e) {e.printStackTrace();
 
}
 
}
 
public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
 
int x,y;
int iNX, iNY;
double dValue;
double dConstant;
IRasterLayer layer;
IRasterLayer result;
 
layer = m_Parameters.getParameterValueAsRasterLayer("INPUT");
dConstant = m_Parameters.getParameterValueAsDouble("VALUE");
GridExtent extent = new GridExtent(layer);
result = getNewRasterLayer("RESULT", Sextante.getText("Result"), IRasterLayer.RASTER_DATA_TYPE_FLOAT, extent);
 
layer.setWindowExtent(extent);
iNX = extent.getNX();
iNY = extent.getNY();
for (y = 0; y < iNY && setProgress(y, iNY); y++){
for(x = 0; x < iNX; x++){
dValue = layer.getCellValueAsDouble(x, y);
result.setCellValue(x, y, dValue * dConstant);
}
 
}
return !m_Task.isCanceled();
}
}

Siamo pronti per testare il nostro algoritmo. Esportiamo i nostri sorgenti come file .jar prestando attenzione al nome del file che dovrà contenere il prefisso “sextante”. Ad esempio potremmo nominare il nostro file: “sextante_test”.
Copiamo il nostro jar nella cartella “es.unex.sextante” presente nella directory “extensiones” di gvSIG. A questo punto troveremo nella toolbar di Sextante un nuovo gruppo di algoritmi “My Algorithm” con il geoalgoritmo “Multiply raster”.
Spero che possa avere stimolato la vostra curiosità e vi invito ancora una volta a consultare e approfondire questi argomenti nel manuale scritto da Olaya (a cui si riferisce questo post).

Spero presto di aggiungere la seconda parte con un algoritmo nel mondo vector (..tratto sempre dallo stesso manuale in inglese) :lol:

Tagged with:
feb 25

Dopo essermi documentato ed averlo testato per circa un anno, ho proposto ed introdotto gvSIG come applicazione open source desktop GIS (distribuito con licenza GNU GPL) nella didattica. Prima di esporvi le grandi potenzialità di questo software, è utile tracciarne le origini…

Logo

gvSIG (Generalità Valenziana Sistema d’Informazione Geografica) è prima di tutto un progetto avviato nel 2002 dalla Direzione Infrastrutture e Trasporti della Comunità Valenziana e finanziato con fondi europei (FEDER) – una buona pratica su come “investire” e promuovere progetti sostenibili ed innovativi!
La base di gvSIG è il linguaggio di programmazione java e tra i punti di forza vi è quello di essere platform indipendent (Win, MacOS e Linux), ma il vero valore aggiunto (come da buona tradizione open source) consiste nel suo continuo sviluppo e cura da parte dell’intera comunità sia di utenti che di sviluppatori! gvSIG è, infatti, supportato da una lista di utenti internazionale e nazionale in continua crescita e animata dalla condivisa voglia di contribuire al suo miglioramento.
Tale contesto creativo ha consentito, all’intero progetto, di crescere e di mettere a disposizione alla comunità una suite di strumenti non soltanto desktop (gvSIG desktop è giunto alla release 1.9), ma anche mobile e mini, oltre ad una ricca disponibilità di estensioni per l’analisi topologica, analisi di rete, 3D, strumenti per il telerilevamento, per l’analisi di dati Lidar e Sextante (Sistema Extremeño di Analisi Territoriale) una cassetta degli attrezzi con oltre 250 algoritmi per analisi vector e raster ed in grado di costruire modelli e flussi di processamento sulla scia del model builder di ESRI.

Screenshot tematizzazione rischio frana con gvSIG

Questa breve presentazione di gvSIG era doverosa oltre che necessaria per introdurre le sue potenzialità che lo hanno reso protagonista anche nella mia esperienza di didattica nel laboratorio GIS. L’occasione didattica è stata un buon banco di prova in cui ho potuto testarne le potenzialità dalla semplice restituzione spaziale dei dati sia vector che raster alle analisi più complesse per l’elaborazione di modelli digitali del terreno, operazioni di map algebra e analisi della visibilità, solo per citarne alcune.

modello delle ombreggiature con Sextante

Un altro aspetto interessante di gvSIG è l’integrazione con gli standard OGC per la condivisione e l’interoperabilità delle informazioni territoriali sul web. L’uso di gvSIG come client desktop OGC consente, infatti, di effettuare chiamate WMS, WCS, WFS e WFS-T.

E’ chiaro che oggi vi sono molti sw GIS open source performanti, basti citare GRASS, Kosmo, uDIG e Qgis, ma ciò che mi ha colpito di gvSIG abbinato a SEXTANTE è la semplicità di utilizzo (importante nella didattica per focalizzare l’attenzione sul problema da risolvere piuttosto che sul sw in se) unita alla possibilità, ad esempio, di scegliere l’algoritmo più idoneo in funzione della morfologia del territorio in analisi – es. Travis o Zevenbergen & Thorne per le pendenze?

Non mi dilungo oltre anche perchè credo che sia più utile fornirvi le fonti web per provarlo e trarne da voi le potenzialità.

Link ufficiale del progetto
Link del repository da cui scaricare gvSIG e le estensioni disponibili
Link della Lista Utenti in italiano (un altro valore aggiunto!)

Tagged with:

 
preload preload preload