Come dicevamo nella precedente lezione, i layer di immagini si differenziano in base a come li vogliamo rappresentati (immagine intera o a tasselli) e alla sorgente da cui otteniamo le immagini stesse, che poi OL comporrà nella mappa. In questo capitolo vedremo i due tipi di layer + sorgenti più tipiche di un’applicazione WebGIS.

Sorgenti XYZ

Per sorgenti XYZ si intendono quei servizi che mettono a disposizione tasselli di immagini (tiles), normalmente di dimensione quadrata 256 x 256 pixel, strutturati in base al livello di zoom e di coordinate X/Y dei taselli all’interno della griglia utilizzata per la loro generazione. I tipici esempi di questo tipo sono i servizi cartografici globali come OSM o Google Maps, i servizi esposti da strumenti di caching come MapProxy, TileStache o GeoWebCache,o più semplicemente una cartella di tile statiche generate con gdal2tiles.

Esistono diversi modi di definire le coordinate griglia di una tile ma il sistema più comune è quello utilizzato da OSM, Mapbox, CartoDB, e molti altri provider globali, definito comunemente XYZ. Al primo livello di zoom (zoom = 0) la griglia è un unico tassello che copre l’estensione massima prevista per la proiezione EPSG:3857 (-180° < lon < 180°, -85.0511° < lat < 85.0511° 1). Al livello successivo (zoom = 1) i tasselli orizzontali e verticali diventano 2 x 2, e le loro coordinate sono quelle rappresentate nella seguente immagine (qui indicate come “Google”, anche se in realtà Google Maps usa un sistema di coordinate un po’ diverso):

Zoom 1 (immagine ottenuta da 'Tiles à la Google Maps' - Copyright © 2008 Klokan Petr Přidal)

Ad ogni livello di zoom il numero di tasselli aumenta con legge esponenziale 2^2zoom, e così a zoom = 10 per l’area di Firenze otteniamo le seguenti coordinate X/Y

Zoom 1 (immagine ottenuta da 'Tiles à la Google Maps' - Copyright © 2008 Klokan Petr Přidal)

Questi tre parametri, zoom e coordinate X/Y, sono sufficienti per ottenere l’immagine della tile d’interesse. Nel formato XYZ questo si traduce in una chiamata del tipo

https://a.tile.openstreetmap.org/Z/X/Y.png

Ad esempio per ottenere una delle tile dell’ultima immagine da OpenStreetMap Standard https://a.tile.openstreetmap.org/10/544/373.png oppure da una mappa MapBox https://api.mapbox.com/styles/v1/mapbox/streets-v10/tiles/256/10/544/373.

OpenLayers offre sia un tipo di sorgente generica ol.source.XYZ, che calcola le coordinate per la porzione di mappa visualizzata e le chiede al server indicato nella URL di configurazione, sia delle classi derivate e specializzate per alcuni dei servizi principali. Una di queste è quella usata già nel primo esempio ol.source.OSM.

var map = new ol.Map({
    layers: [
      new ol.layer.Tile({
        source: new ol.source.OSM() // ol.source.XYZ preconfigurato per OpenStreetMap
      })
    ],
    ...
});

Nel caso volessimo usare un layer Mapbox dovremo invece utilizzare direttamente ol.source.XYZ, perché non esiste una classe specifica per questo provider.

1
2
3
4
5
6
7
8
9
10
var map = new ol.Map({
  layers: [
    new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'https://api.mapbox.com/styles/v1/mapbox/streets-v10/tiles/256/{z}/{x}/{y}?access_token=<token di accesso al layer>'
      })
    })
  ],
  ...
});

Abbiamo istanziato un’immagine a tile, a cui abbiamo associato una sorgente XYZ. A riga 5 abbiamo configurato la sorgente con l’URL del servizio, inserendo i parametri template {z}/{x}/{y} che via via OL andrà a valorizzare in base alla posizione e allo zoom della mappa.

Un altro formato abbastanza diffuso, sempre basato sulla tassellizzazione di una griglia di riferimento, è quello del protocollo TMS (Tiled Map Service). L’unica differenza sostanziale è l’inversione delle coordinate Y delle tile, secondo la formula y = (2^zoom)-y-1.

Per facilitare l’uso di questo formato OpenLayers permette di inserire il carattere - nel parametro template e in quel caso il suo valore sarà invertito automaticamente, per cui per poter usare un servizio TMS sfruttando ol.layer.XYZ dovremo usare un template con le y invertite: {-y}.

Infine citiamo il protocollo OGC WMTS, meno frequente ma importante in quanto standard ufficiale, per il quale OL offre la sorgente ol.source.WMTS.

Sorgenti WMS

L’altro tipo di servizi di immagini comunemente usato è quello esposto secondo lo standard OGC WMS. Tutti i principali server cartografici (Geoserver, QGIS Server, Mapserver, ArcGIS Server, ecc.) sono in grado di esporre servizi WMS, e ormai quasi tutti supportano l’ultima versione dello standard che è la 1.3.0.

Le sorgenti ol.source.ImageWMS possono essere usate sia con layer di tipo ol.layer.Tile che ol.layer.Image. Nel primo caso OpenLayers chiede al server di generare le immagini delle singole tile, mentre nel secondo caso viene richiesta un’unica immagine che copra tutta la porzione di mappa visibile. In linea di massima la modalità a singola immagine risulta la più performante perché evita di eseguire richieste multiple verso il server, il che si traduce in un minor carico di lavoro sia per il server che per il client. Quindi, se non ci sono validi motivi per fare diversamente, con i servizi cartografici WMS si consiglia l’utilizzo di ol.layer.Image.

Come abbiamo già visto in un precedente esempio, un layer WMS viene configurato con l’URL del servizio e con i parametri supplementari necessari per generare le richieste WMS:

1
2
3
4
5
6
7
8
var ortofoto = new ol.layer.Image({
  source: new ol.source.ImageWMS({
    url: "http://www502.regione.toscana.it/ows_ofc/com.rt.wms.RTmap/wms?map=owsofc&map_resolution=91&",
    params: {
      layers: ["rt_ofc.5k16.32bit"]
    }
  })
});

La proprietà params è un oggetto le cui chiavi vengono utilizzate da OL per generare la richiesta HTTP verso il server. Mentre alcuni parametri WMS, come il BBOX, il sistema di riferimento e la dimensione dell’immagine richiesta vengono calcolati e inseriti automaticamente da OL, tutti gli altri parametri aggiuntivi devono essere configurati da noi. Come minimo il parametro “LAYERS” nel quale indicheremo l’elenco dei layer di cui richiediamo l’immagine, secondo l’indicativo previsto dal server (eventualmente ottenuto in forma machine readable con una richiesta GetCapabilities).

Qualsiasi coppia chiave/valore che andremo ad inserire in params sarà inserita nella URL. Possiamo definire anche parametri non standard, e questo è il meccanismo che ci permette ad esempio di poter sfruttare i parametri WMS custom che i vari server mettono a disposizione. Un esempio tipico è l’impostazione di filtri: motli server offrono la possibilità di usare espressioni per limitare la richiesta ad un sottoinsieme di dati, e ognuno richiede l’utilizzo di sintassi non standard specifiche di ogni server. Geoserver ad esempio permette di usare espressioni CQL, QGIS Server ha la propria sintassi, Mapserver per ora ha una cosa un po’ diversa, ma altrettanto potente, che sono le run-time substitutions, mentre ArcGIS Server usa il parametro layerDefs.

Ipotizziamo di avere un database spaziale con uno strato vettoriale dei piezometri, contenente i campi dei singoli valori misurati e un campo giorno contenente la data della misurazione. Supponiamo di esporre questo strato con il nome piezometri tramite un servizio WMS di Geoserver e di averlo stilizzato, magari con una tematizzazione a colori graduati, in base al valore di altezza della colonna d’acqua nel piezometro. In OpenLayers vogliamo mostrare l’immagine del layer soltanto per i valori odierni. Potremmo considerare di usare un filtro simile a questo:

1
2
3
4
5
6
7
8
9
10
11
12
var date = Date.now();
var today = date.getDate() + '-' + (date.getMonth()+1) + '-' + date.getFullYear(); // giorno formattato come D-M-YYYY

var piezometri = new ol.layer.Image({
  source: new ol.source.ImageWMS({
    url: "http://urldelnostroserver.it/wms",
    params: {
      layers: ["piezometri"],
      cql_filter:"giorno = "+today 
    }
  })
});

Il risultato sarà una URL simile alla seguente:

http://urldelnostroserver.it/wms?&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&layers=piezometri&CRS=EPSG%3A3857&STYLES=&WIDTH=490&HEIGHT=245&BBOX=1252230.0854781903%2C5429813.706021478%2C1253400.5274738069%2C5430398.927019287&CQL_FILTER=giorno+%3d+21-8-2017

Il contenuto del parametro CQL_FILTER è stato codificato (nel nostro caso il carattere = è stato trasformato nella rappresentazione UTF-8 %3d) ed aggiunto ai parametri standard della richiesta.

Riproiezione al volo di immagini

Se non specificato diversamente abbiamo già visto che al layer viene associato il sistema di riferimento della mappa in cui è stato inserito. Per questo, ad esempio, nella richiesta WMS degli esempi precedenti OL valorizza il parametro CRS con il codice EPSG:3857 e, di conseguenza, chiede un BBOX secondo queste coordinate. Tuttavia, per ogni singolo layer, è possibile indicare una projection specifica. Ammesso che esista la definizione PROJ4 per quella proiezione, OL farà una richiesta opportunamente ritrasformata ed eseguirà una riproiezione al volo dell’immagine per trasformarla nel SR della mappa.

Sconsiglio tuttavia di forzare OL a fare questa elaborazione, se non strettamente necessario, sia per le ovvie imprecisioni dovute alle ripoiezioni con parametri generali (che comunque affligge qualsiasi GIS a meno di non usare griglie di trasformazioni ufficiali), che per il carico di lavoro che graverebbe sul browser, rendendo molto meno performante l’applicazione soprattutto su macchine non particolarmente prestanti.

[1] Derivato da arctan(sinh(π)), in modo che la rappresentazione della terra rientri perfettamente in un quadrato.