Qualche tempo fa feci un video un cui spiegavo perchè è importante rispettare le regole topologiche. Ma cosa succede se abbiamo un vettore che è afflitto da problemi su tutte o alcune delle sue geometrie?
In questo articolo ti spiego come puoi correggere un particolare tipo di problema topologico, direi abbastanza rognoso quando lo si incontra, e cioè il Self-intersection. Questo tipo di errore si genera spesso effettuando un doppio click quando si posiziona l'ultimo nodo di una geometria, oppure capita di generarlo quando si incrociano archi della stessa geometria.
A volte sono errori accidentali dati dalla fretta, altre sono errori di "imprinting", come li definisco io, cioè quegli errori di gestione del dato GIS dati dal passaggio dall'ambiente CAD a quello GIS. Ad esempio in un CAD si ultima la creazione di una linea con un doppio click sinistro, mentre in ambiente GIS con un click sinistro si posiziona l'ultimo noto e con un successivo click destro si interrompe l'editing della geometria. Questo vale tanto per un vettore lineare che per uno poligonale.
Quando generi un Self-intersection in una geometria non ha importanza che tu abbia attivato l'editing topologico, quel punto o quei punti daranno sempre problemi di puntamento e sarai costretto a correggerli prima di procedere perchè altrimenti rischi di dover buttare via tutto il tuo lavoro.
Qualche anno fa mi sono imbattuto in questa problematica collaborando con una persona che, causa errori di imprinting, generava spessissimo Self-intersection. La risoluzione rapida degli errori l'ho ricevuta da Andrea Peri su GFoss. Non si finisce mai di imparare e capita che non si ha la soluzione ad una problematica, ma fortunatamente esistono i forum tecnici in cui è possibile ricevere aiuto da parte di persone più esperte disposte a mettere in condivisione le loro competenze.
Fatto questo dovuto cappello iniziale, passiamo alla parte pratica. Userò PostGIS per risolvere i problemi di Self-intersection.
Funzioni
Le funzioni di PostGIS coinvolte in questo articolo sono:
- ST_Multi
- ST_CollectionExtract
- ST_ForceCollection
- ST_MakeValid
- ST_IsValid
ST_Multi genera geometrie multiple come MultiPolygon o MultiLineString. Queste sono geometrie diverse dai semplici Polygon e LineString perchè sono composte da elementi non contingui. Immagine il vettore poligonale dell'Italia con le isole maggiori. Sarà composto o da tre poligoni: Italia continentale, Sicilia e Sardegna, che insieme comporranno un vettore di tipo Polygon, oppure sarà un vettore con un unico elemento geometrico poligonale di tipo MultiPolygon. In quest'ultimo caso i poligoni che rappresentano le isole maggiori non sono in contiguità con l'Italia continentale ma sono parte dello stesso elemento geometrico multipoligonale che a sua volta appartiene al vettore Italia. Detto questo avrai intuito che ST_Multi non è fondamentale per il processo che ti spiegherò a breve perchè va usato solo se si sta usando un vettore di tipo "Multi".
ST_CollectionExtract è una funzione che estrae determinate tipologie di geometrie da un vettore di tipo GeometryCollection. La funzione infatti da la possibilità di assegnare un numero, da 1 a 3, che rappresenta la tipologia di geometria di nostro interesse. Se ad esempio il nostro vettore contiene sia linee che poligoni usando il valore 3 la funzione estrarrà solo i poligoni, con 2 estrarrà solo le linee.
ST_ForceCollection è una funzione che forza la geometria ad essere una GeometryCollection. Unita con la funzione precedente è una specie di check, una verifica, che le geometrie trattate siano di tipo GeometryCollection e se non lo sono, allora vengono forzate ad esserlo.
ST_MakeValid è la funzione che pulisce le geometrie affette da Self-intersection.
ST_IsValid è una funzione che restituisce i valori booleani True o False nel caso in cui la geometria analizzata sia corretta dal punto di vista topologico.
Query
Le funzioni precedentemente viste, unite in una query, ci consentono di ripulire il nostro vettore e quindi di poterlo usare per le nostre necessità.
Possiamo usare le funzioni precedenti sia per creare una copia "pulita" del nostro vettore, sia per pulire direttamente il vettore su cui stiamo lavorando.
Nuovo vettore corretto
CREATE TABLE cleaned_polygons AS
SELECT
id,
ST_Multi(ST_CollectionExtract(ST_ForceCollection(ST_MakeValid(geom)),3)) as geom,
ST_IsValid(ST_Multi(ST_CollectionExtract(ST_ForceCollection(ST_MakeValid(geom)),3))) as is_valid
FROM polygon_source;
La query precedente crea il vettore corretto cleaned_polygons a partire da polygon_source; la colonna is_valid è stata aggiunta solo per fare una verifica finale e può essere eliminata senza problemi.
Vettore originale corretto
UPDATE polygon_source
SET geom = ST_Multi(ST_CollectionExtract(ST_ForceCollection(ST_MakeValid(geom)),3))
WHERE ST_IsValid(geom)=false;
La query precedente aggiorna direttamente il vettore originale,polygon_source, correggendone le geometrie.
Nel video che segue troverai tutto il processo per intero.