Separa i poligoni in base all'intersezione usando PostGIS


36

Ho una tabella di poligoni PostGIS in cui alcuni si intersecano. Questo è quello che sto cercando di fare:

  • Per un dato poligono selezionato da id, dammi tutti i poligoni che si intersecano. Fondamentalmente,select the_geom from the_table where ST_Intersects(the_geom, (select the_geom from the_table where source_id = '123'))
  • Da questi poligoni, devo creare un nuovo poligono in modo tale che l'intersezione diventi un nuovo poligono. Quindi se il poligono A si interseca con il poligono B, otterrò 3 nuovi poligoni: A meno AB, AB e B meno AB.

Qualche idea?


1
Hmmm, penso di vedere cosa stai ottenendo, ma una semplice grafica potrebbe fare miracoli per aiutare me (e gli altri) a vedere esattamente quello che vuoi.
— Jason,

Aggiunti alcuni nella mia risposta.
— Adam Matan,

Risposte:


29

Dato che hai detto di ottenere un gruppo di poligoni che si intersecano per ogni poligono a cui sei interessato, potresti voler creare quello che viene chiamato "overlay poligonale".

Questo non è esattamente ciò che sta facendo la soluzione di Adam. Per vedere la differenza, dai un'occhiata a questa immagine di un incrocio ABC:

Incrocio ABC

Credo che la soluzione di Adam creerà un poligono "AB" che copre sia l'area di "AB! C" e "ABC", sia un poligono "AC" che copre "AC! B" e "ABC", e un " BC "poligono che è" BC! A "e" ABC ". Quindi i poligoni di output "AB", "AC" e "BC" si sovrappongono all'area "ABC".

Una sovrapposizione di poligoni produce poligoni non sovrapposti, quindi AB! C sarebbe un poligono e ABC sarebbe un poligono.

La creazione di un overlay poligonale in PostGIS è in realtà piuttosto semplice.

Ci sono sostanzialmente tre passaggi.

Il passaggio 1 è quello di estrarre le linee [Nota che sto usando l' anello esterno del poligono, diventa un po 'più complicato se vuoi gestire correttamente i fori]:

SELECT ST_ExteriorRing(polygon_col) AS the_geom FROM my_table) AS lines

Il passaggio 2 consiste nel "nodo" della linea (produrre un nodo ad ogni intersezione). Alcune librerie come JTS hanno classi "Noder" che puoi usare per farlo, ma in PostGIS la funzione ST_Union lo fa per te:

SELECT ST_Union(the_geom) AS the_geom FROM (...your lines...) AS noded_lines

Il passaggio 3 è creare tutti i possibili poligoni non sovrapposti che possono provenire da tutte quelle linee, fatto dalla funzione ST_Polygonize :

SELECT ST_Polygonize(the_geom) AS the_geom FROM (...your noded lines...)

È possibile salvare l'output di ciascuno di questi passaggi in una tabella temporanea oppure combinarli tutti in un'unica istruzione:

CREATE TABLE my_poly_overlay AS
SELECT geom FROM ST_Dump((
    SELECT ST_Polygonize(the_geom) AS the_geom FROM (
        SELECT ST_Union(the_geom) AS the_geom FROM (
            SELECT ST_ExteriorRing(polygon_col) AS the_geom FROM my_table) AS lines
        ) AS noded_lines
    )
)

Sto usando ST_Dump perché l'output di ST_Polygonize è una raccolta di geometrie ed è (di solito) più conveniente avere una tabella in cui ogni riga è uno dei poligoni che compongono la sovrapposizione di poligoni.


Si noti che ST_ExteriorRingrilascia eventuali buchi. ST_Boundaryconserverà gli anelli interni, ma creerà anche un poligono al loro interno.
— jpmc26,

L'unione degli anelli esterni si schianta quando ci sono troppi poligoni. Sfortunatamente questa soluzione "semplice" funziona solo per piccole coperture.
— Pierre Racine,

13

Se ho capito bene, vuoi prendere (A è la geometria sinistra, B è la destra):

Immagine di A∪B http://img838.imageshack.us/img838/3996/intersectab1.png

Ed estrarre:

Un ∖ AB

Immagine di A ∖ AB http://img830.imageshack.us/img830/273/intersectab2.png

AB

Immagine di AB http://img828.imageshack.us/img828/7413/intersectab3.png

e B ∖ AB

Immagine di B ∖ AB http://img839.imageshack.us/img839/5458/intersectab4.png

Cioè - tre diverse geometrie per ogni coppia intersecante.

Innanzitutto, creiamo una vista di tutte le geometrie che si intersecano. Supponendo che il nome della tua tabella sia polygons_table, utilizzeremo:

CREATE OR REPLACE VIEW p_intersections AS    -- Create a view with the 
SELECT t1.the_geom as t1_geom,               -- intersecting geoms. Each pair
       t2.the_geom as t2_geom                -- appears once (t2.id<t2.id)
    FROM polygons_table t1, polygons_table t2  
         WHERE t1.id<t2.id AND t1.the_geom && t2.the_geom 
                           AND intersects t1.the_geom, t2.the_geom;

Ora abbiamo una vista (praticamente una tabella di sola lettura) che memorizza coppie di geomi che si intersecano, in cui ogni coppia appare solo una volta a causa della t1.id<t2.idcondizione.

Ora cerchiamo di raccogliere i vostri incroci - A∖AB, ABe B∖AB, usando SQL di UNIONsu tutti e tre domande:

--AB:
SELECT ST_intersection(t1.the_geom, t2.the_geom) 
    AS geom 
    FROM p_intersections

UNION 

--A∖AB:
SELECT ST_Difference(t1.the_geom, t2.the_geom) 
    AS geom 
    FROM p_intersections

UNION

--B∖AB:
SELECT ST_Difference(t2.the_geom, t1.the_geom) 
    AS geom 
    FROM p_intersections;

Gli appunti:

  1. L' &&operatore viene utilizzato come filtro prima intersectsdell'operatore, per migliorare le prestazioni.
  2. Ho scelto di creare una VIEWquery gigantesca anziché una; Questo è solo per comodità.
  3. Se intendevi ABdire unione, non intersezione, di Ae B- Usa ST_Union invece di st_intersection nella UNIONquery nei punti appropriati.
  4. Il ∖segno è un segno unicode per Imposta differenza; rimuoverlo dal codice se confonde il database.
  5. Immagini per gentile concessione della bella categoria della teoria degli insiemi di Wikimedia Commons .


Bella spiegazione! I risultati sono gli stessi della soluzione scw, ma il suo modo dovrebbe essere più veloce (non calcola / o memorizza / intersezioni aggiuntive di A e B)
— stachu,

Grazie! Penso di non archiviare alcuna informazione aggiuntiva, in quanto creo solo viste SQL, non tabelle.
— Adam Matan,

Sì, è vero, ma si calcola l'intersezione aggiuntiva tra A e B, il che non è necessario
— stachu,

5
Le immagini in questa risposta non funzionano più.
— Fezter

8

Quello che stai descrivendo è il modo in cui l' operatore Union lavora in ArcGIS, ma è un po 'diverso da Union o Intersection nel mondo GEOS. Il manuale di Shapely contiene esempi di come funzionano i set in GEOS . Tuttavia, il wiki di PostGIS ha un buon esempio usando il linework che dovrebbe fare al caso tuo.

In alternativa, potresti calcolare tre cose:

  1. ST_Intersection (geom_a, geom_b)
  2. ST_Difference (geom_a, geom_b)
  3. ST_Difference (geom_b, geom_a)

Questi dovrebbero essere i tre poligoni che hai citato nel tuo secondo punto elenco.


2
L'esempio della wiki di PostGIS è buono
— segna il

ST_Intersects non restituirebbe un valore booleano se si intersecano o no? Penso che ST_Intersection avrebbe funzionato.
— Jason,

Sì, errore di battitura da parte mia - risolto nell'originale ora, grazie Jason!
— scw,

-2

Qualcosa di simile a:

INSERISCI IN new_table VALUES ((seleziona id, the_geom da old_table dove st_intersects (the_geom, (seleziona the_geom da old_table dove id = '123')) = true

MODIFICA: è necessaria l'intersezione effettiva del poligono.

INSERT INTO valori new_table ((seleziona id, ST_Intersection (the_geom, (seleziona the_geom dalla vecchia dove id = 123))

vedere se funziona.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.