Home > Open Source > Rendering Transformation in GeoServer: calcolo dinamico di interpolated surface e di contour map

Rendering Transformation in GeoServer: calcolo dinamico di interpolated surface e di contour map


Partendo da un post sul blog di OpenGeo ho voluto approfondire un po’ la potenzialità che GeoServer offre sia in termini di:

  • rendering transformation
  • chaining di processi
  • utilizzo di processi WPS all’interno di stili SLD

Ho provato a replicare l’esempio del calcolo delle isoterme partendo da dei dati “inventati” che simulano la presenza di centraline meteo sul territorio piemontese: non ho infatti trovato in rete dati analoghi georeferenziati e disponibili. Per chi volesse replicare ecco i dati che ho utilizzato.

Ho quindi creato per prima cosa un layer in GeoServer delle Centraline Meteo la cui visualizzazione corrisponde ad una getMap WMS con la seguente struttura

http://localhost:8080/geoserver/MyWorkspace/wms?service=WMS&version=1.1.0&request=GetMap&layers=MyWorkspace:CentralineMeteo&styles=&bbox=318287.0,4880823.0,515945.0,5142603.0&width=386&height=512&srs=EPSG:32632&format=application/openlayers

CentralineMeteo

La creazione delle isoterme la si può ottenere concatenando (chaining), due processi WPS messi a disposizione da GeoServer e precisamente, Barnes Surface Process e Contour Process, usando il meccanismo delle rendering transformation definite come stile SLD. L’output del primo processo (il calcolo della superficie, che è sostanzialmente quello delle fasce di temperatura), costituisce l’input del secondo processo (che è il calcolo delle isoterme).

Vediamo quindi dapprima il solo calcolo delle fasce di temperatura la cui visualizzazzione viene ottenuta con la medesima getMap vista in precedenza con in più l’utilizzo di un opportuno stile SLD al cui interno viene utilizzato il processo WPS Barnes Surface valorizzando opportunamente i parametri necessari.

La nuova getMap WMS sarà quindi di questo tipo (in evidenza l’utilizzo dello stile):

http://localhost:8080/geoserver/MyWorkspace/wms?service=WMS&version=1.1.0&request=GetMap&layers=MyWorkspace:CentralineMeteo&styles=FasceTemperatura&bbox=318287.0,4880823.0,515945.0,5142603.0&width=386&height=512&srs=EPSG:32632&format=application/openlayers

BarnesSurface

Ecco invece la definizione dello stile SLD utilizzato

<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<StyledLayerDescriptor version=”1.0.0″
xsi:schemaLocation=”http://www.opengis.net/sld StyledLayerDescriptor.xsd”
xmlns=”http://www.opengis.net/sld&#8221;
xmlns:ogc=”http://www.opengis.net/ogc&#8221;
xmlns:xlink=”http://www.w3.org/1999/xlink&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”&gt;
<NamedLayer>
<Name>Barnes surface</Name>
<UserStyle>
<Title>Barnes Surface</Title>
<Abstract>A style that produces a Barnes surface using a rendering transformation</Abstract>
<FeatureTypeStyle>
<Transformation>
<ogc:Function name=”gs:BarnesSurface”>
<ogc:Function name=”parameter”>
<ogc:Literal>data</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>valueAttr</ogc:Literal>
<ogc:Literal>Temperatur</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>scale</ogc:Literal>
<ogc:Literal>1000</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>convergence</ogc:Literal>
<ogc:Literal>0.3</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>passes</ogc:Literal>
<ogc:Literal>100</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>minObservations</ogc:Literal>
<ogc:Literal>2</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>maxObservationDistance</ogc:Literal>
<ogc:Literal>0</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>pixelsPerCell</ogc:Literal>
<ogc:Literal>25</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>queryBuffer</ogc:Literal>
<ogc:Literal>2000</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>outputBBOX</ogc:Literal>
<ogc:Function name=”env”>
<ogc:Literal>wms_bbox</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>outputWidth</ogc:Literal>
<ogc:Function name=”env”>
<ogc:Literal>wms_width</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>outputHeight</ogc:Literal>
<ogc:Function name=”env”>
<ogc:Literal>wms_height</ogc:Literal>
</ogc:Function>
</ogc:Function>
</ogc:Function>
</Transformation>
<Rule>
<RasterSymbolizer>
<!– specify geometry attribute of input to pass validation –>
<Geometry><ogc:PropertyName>the_geom</ogc:PropertyName></Geometry>
<Opacity>0.8</Opacity>
<ColorMap type=”ramp” >
<ColorMapEntry color=”#FFFF00″ quantity=”-990″ label=”nodata” opacity=”0″/>
<ColorMapEntry color=”#2E4AC9″ quantity=”-6″ label=”nodata”/>
<ColorMapEntry color=”#41A0FC” quantity=”-5″ label=”values” />
<ColorMapEntry color=”#58CCFB” quantity=”-4″ label=”values” />
<ColorMapEntry color=”#76F9FC” quantity=”-3″ label=”values” />
<ColorMapEntry color=”#6AC597″ quantity=”-2″ label=”values” />
<ColorMapEntry color=”#479364″ quantity=”-1″ label=”values” />
<ColorMapEntry color=”#2E6000″ quantity=”0″ label=”values” />
<ColorMapEntry color=”#579102″ quantity=”1″ label=”values” />
<ColorMapEntry color=”#9AF20C” quantity=”2″ label=”values” />
<ColorMapEntry color=”#B7F318″ quantity=”3″ label=”values” />
<ColorMapEntry color=”#DBF525″ quantity=”4″ label=”values” />
<ColorMapEntry color=”#FAF833″ quantity=”5″ label=”values” />
<ColorMapEntry color=”#F9C933″ quantity=”6″ label=”values” />
<ColorMapEntry color=”#F19C33″ quantity=”7″ label=”values” />
<ColorMapEntry color=”#ED7233″ quantity=”8″ label=”values” />
<ColorMapEntry color=”#EA3F33″ quantity=”9″ label=”values” />
<ColorMapEntry color=”#BB3026″ quantity=”10″ label=”values” />
</ColorMap>
</RasterSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>

Occorre osservare che, mentre è piuttosto semplice l’applicazione del processo, è  molto più delicato il processo che porta alla corretta definizione e valorizzazione dei parametri che ne governano il risultato e la sua rappresentazione. Non è infatti chiarissima la documentazione riportata in GeoServer a tale scopo e per raggiungere un qualche risultato apprezzabile sono dovuto ricorrrere al supporto della GeoServer user list di cui vi lascio il riferimento per i dettagli.

Per la creazione delle isoterme la visualizzazzione viene ottenuta sempre con la stessa getMap vista in precedenza con l’utilizzo di un nuovo stile SLD al cui interno sono concatenati il processo di WPS Barnes Surface visto in precedenza che fornisce in input il proprio risulttao al processo WPS Contours.

La nuova getMap WMS sarà quindi di questo tipo (in evidenza l’utilizzo dello stile):

http://localhost:8080/geoserver/MyWorkspace/wms?service=WMS&version=1.1.0&request=GetMap&layers=MyWorkspace:CentralineMeteo&styles=FasceTemperatura-Isoterme&bbox=318287.0,4880823.0,515945.0,5142603.0&width=386&height=512&srs=EPSG:32632&format=application/openlayers

Isoterme

Ecco invece la definizione dello stile SLD utilizzato

<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<StyledLayerDescriptor version=”1.0.0″
xsi:schemaLocation=”http://www.opengis.net/sld StyledLayerDescriptor.xsd”
xmlns=”http://www.opengis.net/sld&#8221;
xmlns:ogc=”http://www.opengis.net/ogc&#8221;
xmlns:xlink=”http://www.w3.org/1999/xlink&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”&gt;
<NamedLayer>
<Name>BarnesContours</Name>
<UserStyle>
<Title>Barnes Surface Contours</Title>
<Abstract>Extracts contours from a computed surface</Abstract>
<FeatureTypeStyle>
<Transformation>
<ogc:Function name=”gs:Contour”>
<ogc:Function name=”parameter”>
<ogc:Literal>data</ogc:Literal>
<ogc:Function name=”gs:BarnesSurface”>
<ogc:Function name=”parameter”>
<ogc:Literal>data</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>valueAttr</ogc:Literal>
<ogc:Literal>Temperatur</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>scale</ogc:Literal>
<ogc:Literal>10000</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>convergence</ogc:Literal>
<ogc:Literal>0.5</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>passes</ogc:Literal>
<ogc:Literal>3</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>minObservations</ogc:Literal>
<ogc:Literal>1</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>maxObservationDistance</ogc:Literal>
<ogc:Literal>70000</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>pixelsPerCell</ogc:Literal>
<ogc:Literal>10</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>outputBBOX</ogc:Literal>
<ogc:Function name=”env”>
<ogc:Literal>wms_bbox</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>outputWidth</ogc:Literal>
<ogc:Function name=”env”>
<ogc:Literal>wms_width</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>outputHeight</ogc:Literal>
<ogc:Function name=”env”>
<ogc:Literal>wms_height</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>queryBuffer</ogc:Literal>
<ogc:Literal>10000</ogc:Literal>
</ogc:Function>
</ogc:Function>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>levels</ogc:Literal>
<ogc:Literal>-6</ogc:Literal>
<ogc:Literal>-5</ogc:Literal>
<ogc:Literal>-4</ogc:Literal>
<ogc:Literal>-3</ogc:Literal>
<ogc:Literal>-2</ogc:Literal>
<ogc:Literal>-1</ogc:Literal>
<ogc:Literal>0</ogc:Literal>
<ogc:Literal>1</ogc:Literal>
<ogc:Literal>2</ogc:Literal>
<ogc:Literal>3</ogc:Literal>
<ogc:Literal>4</ogc:Literal>
<ogc:Literal>5</ogc:Literal>
<ogc:Literal>6</ogc:Literal>
<ogc:Literal>7</ogc:Literal>
<ogc:Literal>8</ogc:Literal>
<ogc:Literal>9</ogc:Literal>
<ogc:Literal>10</ogc:Literal>
</ogc:Function>
<ogc:Function name=”parameter”>
<ogc:Literal>simplify</ogc:Literal>
<ogc:Literal>true</ogc:Literal>
</ogc:Function>
</ogc:Function>
</Transformation>
<Rule>
<Name>rule1</Name>
<Title>Isotherm</Title>
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:Function name=”IEEERemainder”>
<ogc:Function name=”int2ddouble”>
<ogc:PropertyName>value</ogc:PropertyName>
</ogc:Function>
<ogc:Function name=”parseDouble”>
<ogc:Literal>1.0</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Literal>0</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
<LineSymbolizer>
<Stroke>
<CssParameter name=”stroke”>#000000</CssParameter>
<CssParameter name=”stroke-width”>1</CssParameter>
</Stroke>
</LineSymbolizer>
<TextSymbolizer>
<Label>
<ogc:Function name=”round”>
<ogc:PropertyName>value</ogc:PropertyName>
</ogc:Function>
</Label>
<Font>
<CssParameter name=”font-family”>Arial</CssParameter>
<CssParameter name=”font-style”>Normal</CssParameter>
<CssParameter name=”font-size”>12</CssParameter>
</Font>
<LabelPlacement>
<LinePlacement/>
</LabelPlacement>
<Halo>
<Radius>
<ogc:Literal>2</ogc:Literal>
</Radius>
<Fill>
<CssParameter name=”fill”>#FFFFFF</CssParameter>
<CssParameter name=”fill-opacity”>0.6</CssParameter>
</Fill>
</Halo>
<Fill>
<CssParameter name=”fill”>#000000</CssParameter>
</Fill>
<Priority>2000</Priority>
<VendorOption name=”followLine”>true</VendorOption>
<VendorOption name=”repeat”>100</VendorOption>
<VendorOption name=”maxDisplacement”>50</VendorOption>
<VendorOption name=”maxAngleDelta”>30</VendorOption>
</TextSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>

Ecco infine la visualizzazione contemporanea dei tre layers

AllTogheter

Come si vede la mappa è sempre ottenuta grazie ad una chiamata http su un protocollo OGC standard quale il WMS ampiamente adottato nel mondo GIS e questo permette di rendere indipendente il “servzio di business” dal suo fruitore, tant’è che la medesima mappa la si può fruire da un client GIS Desktop quale QGIS come mostra l’immagine successiva.

GeoServer-QGIS

come pure un’applicazione gis mobile in grado di “consumare” WMS: ho provato con Locus Free  installato su un Samsung Galaxy e via wi-fi non ho avuto problemi ad agganciare il mio GeoServer installato localmente sul mio pc e a visualizzare le mie isoterme anche da questo tipo di fruitore.

Al tempo stesso questo approccio permette di nascondere completamente la complessità del processo (anzi, nel caso specidico “dei” processi visto che sono due e concatenati …..), sottostanti mentre ne permette la fruizone secondo meccanismi noti e standard (chiamata wms via http ….), che qualunque fruitore GIS sa già utilizzare.

Concludo con un paio di punti:

  • quanto ho provato è una sorta di proof of concepts ed è ben lungi dall’essere un’algoritmo definitivo: non sono state fatte ad esempio considerazioni sui dati che probabilmente andrebbero fatte, quali ad  esempio la valutazione della quota altimetrica a cui si trova la stazione meteo (sfruttando un DEM?): i dati al momento sono stati considerati “piatti” tutti allo stesso livello
  • ho untilizzato GeoServer 2.2.3 su un pc Windows 7, 4 CPU, 8 Gbyte di RAM

 

  1. Non c'è ancora nessun commento.
  1. No trackbacks yet.

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: