QGIS web client | a few tricks and notes

ricerca e zoom sugli oggetti

Affinche’ il sistema di ricerca degli oggetti funzioni correttamente (ottenere lo zoom corretto sull’oggetto identificato) controllare il file “search.wsgi” (in “/wsgi/”) alle linee 59, 60 e 61. Per default viene abilitato un codice che funziona per Postgresql versione >9.0. Per Postgresql < 9.0 commentare la linea 59 e de-commentare la linea 61.

linea 59 # sql += “‘[‘||replace(regexp_replace(BOX2D(the_geom)::text,’BOX\(|\)’,”,’g’),’ ‘,’,’)||’]’::text AS bbox “
linea 60 # if the above line does not work for you, deactivate it and uncomment the next line
linea 61 sql += “‘[‘||replace(regexp_replace(BOX2D(the_geom)::text,’BOX[(]|[)]’,”,’g’),’ ‘,’,’)||’]’::text AS bbox “

Controllare inoltre i parametri di connessione al DB (nel nostro caso Postgresql-Postgis) all’interno del file “/wsgi/search.wsgi” alla riga 86 e all’interno del file “/wsgi/getsearchgeom.wsgi” alla riga 27.

Identify

modificare il file “WebgisInit.js” che si torva in “/site/js/” alle righe 325 e 326.

Per fare in modo che per default (nel menu’ a tendina che compare nell’interfaccia grafica del client) venga interrogato il layer attivo impostare a “activeLayer” il valore del parametro “ObjectIdentificationModeCombobox.setValue” e “identificationMode” come da esempio:

ObjectIdentificationModeCombobox.setValue(“activeLayers”);
                identificationMode = “activeLayers”;

impostare invece il valore “allLayers” per interrogare tutti i layer

ObjectIdentificationModeCombobox.setValue(“allLayers”);
                identificationMode = “allLayers”;

oppure “topMostFit” per interrogare il layer piu’ in alto (nella TOC)

ObjectIdentificationModeCombobox.setValue(“topMostFit”);
                identificationMode = “topMostFit“;

Theme switcher

Modificare il file GISProject Listing.js (in “/site/js/”) per configurare il passaggio da una mappa all’altra. E’ necessario prima di tutto impostare a “true” il valore del parametro

var mapthemeswitcherActive=true;

nel file “GlobaOptions.js”

Per visualizzare una miniatura dei progetti (o temi) sullo switcher creare una immagine (PNG) di dimensioni 300×200 pixel e denominarla “nome_progetto_qgis.png”. Salvarla in “../site/thumbnails/”

Stampa in PDF

Puo’ succedere che nella fase di stampa venga restituito un errore (sul server): per evitarlo nel layout di stampa del progetto “.qgs” impostare “Stampa come raster”.

Se viene configurato il “theme switcher” e’ necessario fare in modo che tutti i layout di stampa abbiamo lo stesso nome (es: A4, A3,..) nei vari progetti altrimenti compare il messaggio:

“Composer template not found”

e la mappa non viene stampata.

QGIS web client | reference map

In QGIS web client la configurazione della mappa di riferimento per la “navigazione” (o panoramica) avviene editando il file GlobalOptions….js (nella directory “../site/js”). Alla voce:

……..
var OverviewMapSize = new OpenLayers.Size(200,150);
var overviewLayer = new OpenLayers.Layer.WMS(“Overview Map”,
  “/cgi-bin/qgis_mapserv.fcgi?map=/var/www/qgiswc/projects/nome_progetto.qgs”,
  {layers:”nome_layer01,nome_layer02,nome_layer03″,format:”image/jpeg”},
  {buffer:0,singleTile:true,transitionEffect:”resize”});
……..

La parte importante e’ “/cgi-bin/qgi…” che deve puntare al file di progetto corretto ed il nome del layer (uno o piu’ separati da virgola) da utilizzare.

NB: assicurarsi che il layer da utilizzare come overview non abbia limiti di scala di visualizzazione altrimenti (essendo la panoramica una vista a scala molto piccola) non compare.

QGIS | conditional labeling

QGIS si rivela (almeno per le mie necessita’) uno strumento sempre piu’ potente e versatile. A riguardo lascio un breve post su come impostare una etichettatura condizionale. Per spiegarsi: come fare per visualizzare le etichette (label) solamente di determinati oggetti di un layer (nel mio caso PostGIS)? Per questo devo ringraziare la lista qgis-users ed in particolare Andreas Neumann, Giuseppe Sucameli, Nathan Woodrow, Martin Dobias e Mayeul Kauffmann per avere sollevato la questione ed averne indicato la soluzione.

Nel mio caso specifico volevo “etichettare” soltanto alcune zone territoriali omogenee di PRG: in particolare le zone A, B, C, e D tralasciando quelle a servizi ed agricole (E ed F). Nella tabella attributi del layer vettoriale poligonale si trova un campo chiamato “AmbitoIdZona” che contiene le informazioni necessarie.

– Apriamo lo strumento “Layer Labeling Options” cliccando sull’icona relativa o tramite la finestra delle proprieta’ del layer interessato.

– Spuntiamo il tick “Etichetta questo vettore” e clicchiamo sul pulsante “Modifica espressione” (quello con il simbolo dell’espressione);

– Nel frame in basso scriviamo l’espressione:

CASE WHEN “AmbitoIdZona” IN (‘A’,’B’,’C’,’D’) THEN “AmbitoIdZona” || ‘;’ || “NumeroZona” END

Nota: nell’espressione l’etichetta comprende il valore di due campi “AmbitoIdZona” e “NumeroZona”. Il punto e virgola ‘;’ indica di andare a capo. Questa impostazione si configura nella sezione “Formattazione” ed in particolare valorizzando il campo “A capo con il carattere” nel quale si indica un carattere a piacere (nel mio caso il ‘;’ appunto).

 

Aggiornamento: come impostare etichette di colore diverso a seconda del valore contenuto nel campo da etichettare o in altro campo

Facciamo un esempio concreto: ho un layer poligonale che riporta gli ambiti di alcuni strumenti urbanistica attuativi. Uno dei tanti attributi si chiama “Stato” che puo’ contenere i due valori: ‘vigente’ o ‘decaduto’. Vogliamo fare in modo che l’etichetta riporti il nome dello strumento urbanistico (dato che risiede nel campo “Nome”) e sia di colore rosso se lo “Stato”=’decaduto’ e di colore verde se “Stato”=’vigente’.

Andiamo sulle proprietà del layer e ci posizioniamo sulla scheda “Etichette” quindi su “Testo”. Definiamo un colore di default (nel nostro caso il verde con RGB=0,255,0 e poi clicchiamo sull’icona riportata a destra “Sovrascrittura definita dai dati (espressione)”. Compare la finestra di configurazione dell’espressione e digitiamo quanto segue:

CASE WHEN nome_campo=’valore’ THEN color_rgb(255,0,0) END

che tradotto riportando i nostri dati diventa:

CASE WHEN “Stato”=’decaduto’ THEN color_rgb(255,0,0) END

In questo modo vedremo le etichette (il testo dell’etichetta) rosse nel caso in cui il campo “Stato” ha valore=’decaduto’ e verdi negli altri casi

 

 

GRASS, QGIS | individuare collina e pianura di un territorio

Un collega mi ha chiesto di indicargli le percentuali di territorio (comunale) pianeggiante e collinare.

Avevo a disposizione un DEM con risoluzione 5m (realizzato con GRASS a partire dalle curve di livello della CTRN) ed il vettoriale del limite amministrativo.Tuttavia il DEM (chiamato dem_5m) ricopre un’area pressochè rettangolare ben più ampia del limite del comune ed avevo la necessità di “clipparlo” sul boundary di interesse. Ho agito per passi successivi utilizzando GRASS dall’interno di QGIS.

L’immagine sottostante illustra la situazione di partenza (dem e confine):

dtm e confine

dtm a 5 m e confine comunale

Ecco i passi seguiti:

– conversione del vettoriale del confine comunale in raster:

$ v.to.rast input=confine_comune out=confine_comune (comando lanciato dalla shell del plugin qgis grass)

– impostazione della regione di lavoro sul raster appena creato:

$ g.region rast=confine_comune res=5

– creazione di una MASK dal confine per clippare il dem su di esso in un secondo momento:

$ r.mask input=confine_comune

– clip del dem per delimitarlo al territorio comunale (con r.mapcalc); si ottiene un raster che chiameremo “dem_comune”:

$ r.mapcalc “dem_comune=dtm_5m – confine_comune”

– calcolo del territorio considerato collinare (da una stima si è deciso di considerare tale il territorio con quota > 120 m s.l.m. in quanto rappresenta la quota media del piede di collina dell’area di lavoro):

$ r.mapcalc “collina=dem_comune>120”

– e calcolo della pianura con il territorio che rimane a complemento:

$ r.mapcalc “pianura=dem_comune<=120”

Il risultato è il seguente:

i raster "collina" e "pianura" caricati con trasparenza al 50%

i raster “collina” e “pianura” caricati con trasparenza al 50%

Il passaggio succesivo consiste nel trasformare i raster in vettori mediante il modulo “r.to.vect“. Il calcolo della superficie e, di conseguenza, l’incidenza percentuale delle due porizioni di territorio sul totale vengono tralasciati (basta consultare le aree con lo strumento di interrogazione di QGIS o lanciare il modulo “v.report” in GRASS).

QGIS web client | hyperlink

Una delle cose “cool” (come dicono gli americani) di un web gis è la possibilità di consultare gli attributi di un oggetto e magari essere reindirizzati ad altro link o file o pagina web per approfondire o avere maggiori informazioni sull’attributo selezionato.
Ad oggi QGIS web client offre due modi per consultare gli attributi: mediante il “fumetto” o “tooltip” o cliccando sull’oggetto dopo avere attivato il pulsante di consultazione attributi e “leggendo” i dati nel frame di destra che compare.
Se però vogliamo creare un hyperlink cliccabile non possiamo farlo con il tooltip in quanto si sposta allo spostarsi del mouse. A questo riguardo Andreas Neumann sta lavorando per fare in modo che il fumetto sia in pieno stile Openlayers. Qui si trova l’issue in merito.
Ma chiedendo in lista qgis-user è arrivato un provvidissimo suggerimento di Bernhard Ströbl (che ringrazio vivamente). Bernahrd ha suggerito di creare una VIEW (in database PostgreSQL/PostGIS) contenente un campo “link” formattato in pieno stile html. Ho provato e funziona! Riporto di seguito un esempio testato.

pc=# CREATE OR REPLACE VIEW prp_view AS SELECT “Denominazi” AS denominazione, tipo, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione1 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta prima approvazione</a>’::TEXT AS link1, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione2 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta seconda approvazione</a>’::TEXT AS link2, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione3 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta terza approvazione</a>’::TEXT AS link3, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione4 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta quarta approvazione</a>’::TEXT AS link4, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione5 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta quinta approvazione</a>’::TEXT AS link5, ‘<a href=”http://ip_server/qgis-web-client/projects/deliberepdir/&#8217; || file_approvazione6 || ‘”‘ || ‘onclick=”window.open(this.href)”>consulta sesta approvazione</a>’::TEXT AS link6, the_geom, gid FROM sua;

In questo modo cliccando sulla voce relativa (“prima approvazione”, “seconda approvazione” e così via) che compare nel frame di destra si apre il file PDF in questione.

QGIS web client | search

Questo post tratta nuovamente Qgis web client: in particolare come viene gestita la ricerca delle feature.

Seguendo la doc disponibile in rete (e all’interno del pacchetto) al punto 6 si parla dello script python per la gestione della ricerca. Tutto sembra ok. Tuttavia la doc illustra come creare una tabella per la ricerca; ma una tabella puo’ diventare “statica” nel momento in cui i dati del database (nel nostro caso PostgreSQL/PostGIS) vengono aggiornati. In questo caso una view diventa l’ideale in quanto “dinamica” anche se i tempi di ricerca possono risultare superiori rispetto ad una tabella.

Calando il tutto nel concreto del nostro applicativo facciamo alcune considerazioni. Dispongo di un DB con molti strati informativi. Nel progetto “.qgs” in questione ci sono tre layer sui quali vorrei eseguire la ricerca: uno relativo agli edifici, uno relativo alle strade ed uno relativo alle particelle catastali. Il primo step consiste nella creazione di una view per la ricerca delle strade. Ecco come viene definita:

#= CREATE OR REPLACE VIEW search_particella AS SELECT ‘Foglio’ || “Foglio” || ‘,’ || ‘Mappale’ || “Mappale” AS searchstring, ‘Foglio’||”Foglio”||’, ‘||’Mappale’||”Mappale”::TEXT AS displaytext, ’03_particella’::TEXT AS search_category, the_geom, ‘MULTIPOLYGON’::TEXT AS geometry_type, to_tsvector(“Foglio”||’, ‘||”Mappale”::TEXT) AS searchstring_tsvector FROM particella;

Una seconda view è stata creata per la ricerca sugli edifici:

#= CREATE OR REPLACE VIEW search_schede_a AS SELECT codfoto AS searchstring, codfoto::TEXT AS displaytext, ’01_schede_a’::TEXT AS search_category, the_geom, ‘MULTIPOLYGON’::TEXT AS geometry_type, to_tsvector(codfoto::TEXT) AS searchstring_tsvector FROM schede_a;

Ed infine per le strade:

#= CREATE OR REPLACE VIEW search_strade AS SELECT nome AS searchstring, nome::TEXT AS displaytext, ’02_strade’::TEXT AS search_category, the_geom, ‘MULTILINESTRING’::TEXT AS geometry_type, to_tsvector(nome::TEXT) AS searchstring_tsvector FROM view_grafo_union_nome;

Altra considerazione importante: potendo gestire e pubblicare piu’ progetti (.qgs) differenti diventa essenziale fare in modo che ad ogni progetto possa essere abbinata una certa configurazione per la ricerca. Questo è possibile personalizando il file “search.wsgi” che si trova in “…/qgis-web-client/wsgi”. Basta rinominarlo in modo che richiami il progetto abbinato (es: “search_stradario.wsgi” per una progetto che pubblica lo stradario) e modificando la riga 18 secondo le proprie necessità. Esempio:

“…….
searchtables = [‘search_strade‘]; # enter your default searchtable(s) here # aggiungere qui ‘a mano’ i nomi delle tabella di ricerca
searchtablesstring = ”;
…”

Come si puo’ vedere abbiamo indicato qui il nome della tabella (nel nostro caso una VIEW) da usare per effettuare la ricerca. Se volessimo utilizzare piu’ tabelle (o VIEW) basta aggiungerle separandole con una virgola. Nel nostro caso potrebbe diventare:

“…….
searchtables = [‘search_strade‘, ‘search_particella‘]; # enter your default searchtable(s) here # aggiungere qui ‘a mano’ i nomi delle tabella di ricerca
searchtablesstring = ”;
…”

Non dimenticare poi che bisogna modificare anche il corrispondente file “GlobalOptions.js” relativo. Nel mio caso ho creato un file per ognuno dei progetti. Per esempio per il progetto dello stradario ho creato un “GlobalOptionsStradario.js” (ed un “getSearchGeom_stradario.js”) all’interno del quale alla righe 14 e 15 ho indicato il path ai file da utilizzare per la search.

“….

var searchBoxQueryURL = “/qgis-web-client/wsgi/search_stradario.wsgi?query=”; // “/wsgi/search.wsgi?query=”;
var searchBoxGetGeomURL = “/qgis-web-client/wsgi/getSearchGeom_stradario.wsgi”; // “/wsgi/getSearchGeom.wsgi”;

…..”

Allego snapshot che mostra la ricerca di un mappale; digitando semplicemente il numero del foglio (21) e ponendo una virgola subito dopo compariranno i mappali già filtrati per foglio. Cliccando su quello di interesse l’area geografica verrà portata alla sua boundingbox.

ricerca in qgis web client

QGIS web client | tooltip

Qgis web client è un framework webgis che consente di pubblicare un progetto Qgis (file con estensione .qgs) as is.

Tra le funzionalità presenti troviamo la possibilità di visualizzare come tooltip (una specie di “fumetto” dinamico che aggiorna i dati a seconda dell’oggetto su cui “insiste” il mouse) i dati delle feature.

Tuttavia attualmente non è possibile impostare quali attributi visualizzare; è necessario creare un nuovo campo chiamato proprio “tooltip” e popolarlo con i dati che si vogliono vedere. Nel mio esempio faccio riferimento a dati di alcuni edifici (memorizzati in tabella Postgis). Dopo avere creato il campo suddetto lo popoliamo:

=# UPDATE schede_a SET tooltip=’scheda: ‘ || codfoto || ‘ , tipologia: ‘ || tipologia_edilizia || ‘ , destinazione: ‘ || destusopre || E’\r\n’ || ‘volume: ‘ || volume_ft || ‘ , ‘ || ‘altezza: ‘ || altezza_media || ‘ , epoca: ‘ || epoca_costruzione || E’\r\n’ || ‘<img src=’ || ‘”‘ ||  immagine ||  ‘”‘ || ‘>’;

Analizziamo la stringa.

schede_a è il nome della tabella;

– poi si esegue un UPDATE sul campo “tooltip” popolandolo con note descrittive (le parti fra ‘apici singole’ unite (con il doppio pipe “||“) ai valori dei campi indicati (codfoto, tipologia_edilizia, destusopre,…..).

– la stringa E’\r\n consente di andare a capo. Questo è molto utile se i dati da visualizzare sono molti evitando di avere un “fumetto” troppo esteso in larghezza e di difficile lettura;

– l’ultima parte ‘<img src=’ || ‘”‘ ||  immagine ||  ‘”‘ || ‘>’ (in realtà un pezzo di condice html) consente di caricare e visualizzare una foto dell’edificio stesso; il campo “immagine” contiene il path (sul server di archiviazione) all’immagine da aprire.

Allego piccolo snapshot:

tooltip con visualizzazione dati di un edificio e relativa immagine

Una nota che potrebbe tornare utile: così facendo (creare un campo tootlip come “aggregazione” di piu’ campi) succede che nel tempo e’ necessario aggiornare di volta in volta i valori. Per evitare di doverlo fare manualmente si potrebbe creare un trigger che ad ogni INSERT o UPDATE dei record aggiorni di conseguenza tooltip. Altrimenti si potrebbe creare una VIEW che pesca tutti i valori della tabella edifici (escluso tooltip) aggiungendo il campo tooltip stesso in maniera “dinamica”. Ecco riportato il comando SQL per la creazione della VIEW che è stata poi caricata nel progetto QGIS.

#= SELECT schede_a.gid, schede_a.”KP”, schede_a.codfoto, schede_a.immagine, schede_a.codviaana4, schede_a.via1, schede_a.numciv1, schede_a.codviaana1, schede_a.via2, schede_a.numciv2, schede_a.codviaana2, schede_a.via3, schede_a.numciv3, schede_a.codviaana3, schede_a.via4, schede_a.numciv4, schede_a.destusopre, schede_a.utilizzazione, schede_a.epoca_costruzione, schede_a.altezza_media, schede_a.condizioni_fisiche, schede_a.tipologia_edilizia, schede_a.qual_stor_amb, schede_a.note, schede_a.fonte, schede_a.rilevatore, schede_a.dens_allog_utiliz, schede_a.dens_allog_nonutiliz, schede_a.tipo_mod, schede_a.data_mod, schede_a.link, schede_a.num_provv_orig, schede_a.num_provv_def, schede_a.volume_ft, schede_a.alloggi_occupati, schede_a.alloggi_nonoccupati, schede_a.superf_coperta, schede_a.alloggi_totali, schede_a.tipo_provv_orig, schede_a.tipo_provv_def, schede_a.the_geom, schede_a.anno, schede_a.”time”, schede_a.forever, ((((((((((((((((((‘scheda: ‘::text || schede_a.codfoto::text) || ‘ , tipologia: ‘::text) || schede_a.tipologia_edilizia::text) || ‘ , destinazione: ‘::text) || schede_a.destusopre::text) || ‘
‘::text) || ‘volume: ‘::text) || schede_a.volume_ft) || ‘ , ‘::text) || ‘altezza: ‘::text) || schede_a.altezza_media) || ‘ , epoca: ‘::text) || schede_a.epoca_costruzione::text) || ‘
‘::text) || ‘<img src=’::text) || ‘::text AS tooltip
FROM schede_a;