PostGIS ST_Intersection de polígonos puede devolver líneas

9

Al recortar los polígonos de una tabla con polígonos en otra, ST_Intersection puede devolver un conjunto de resultados que se pueden manejar con ST_Dump. Las geometrías múltiples devueltas no son necesariamente ST_Polygon sino también ST_LineString (probablemente también un punto). Entonces cuando se ejecuta una consulta

INSERT INTO c (geom)
  (SELECT (ST_Dump(ST_Intersection(a.geom,b.geom))).geom
  FROM a INNER JOIN b ON ST_Intersects(a.geom, b.geom));

al intentar llenar la tabla "c" con polígonos recortados, falla con ERROR: el tipo de geometría (LineString) no coincide con el tipo de columna (polígono)

Hice otra instrucción SELECT anidada para que solo aparecieran las geometrías de polígonos, como:

INSERT INTO c (geom)
  (SELECT geom FROM
    (SELECT (ST_Dump(ST_Intersection(a.geom,b.geom))).geom
    FROM a INNER JOIN b ON ST_Intersects(a.geom, b.geom))) AS cl
    WHERE ST_GeometryType(cl.geom)='ST_Polygon');

Como esto es un poco engorroso, me pregunto si hay una solución más elegante para descartar geometrías no válidas.

Robert Špendl
fuente
Por cierto, pongo <! - language: lang-sql -> antes de que el código se bloquee pero todavía no hay resaltado. ¿Alguna pista para un novato?
Robert Špendl
Para formatear el código, simplemente péguelo, selecciónelo y use el botón Muestra de código {}sobre la ventana de edición de Preguntas.
PolyGeo
Hm, lo hice, el código está marcado como "código", pero las palabras clave todavía no están coloreadas.
Robert Špendl
Normalmente no trato de prettificar el código SQL aquí, pero acabo de encontrar una publicación Meta que parece útil en meta.stackexchange.com/questions/90521/… . ¿Ha dejado una "línea en blanco entre el comentario y el código"?
PolyGeo
Una intersección de dos geometrías puede producir cualquier tipo de geometría, por lo que creo que su solución actual es la más directa.
Mike T

Respuestas:

9

Este podría ser un buen lugar para usar una función de lenguaje SQL. Aquí hay uno rápido que debería funcionar para esta situación:

CREATE OR REPLACE FUNCTION PolygonalIntersection(a geometry, b geometry)
RETURNS geometry AS $$
SELECT ST_Collect(geom)
FROM 
(SELECT (ST_Dump(ST_Intersection(a, b))).geom 
UNION ALL
-- union in an empty polygon so we get an 
-- empty geometry instead of NULL if there
-- is are no polygons in the intersection
SELECT ST_GeomFromText('POLYGON EMPTY')) SQ
WHERE ST_GeometryType(geom) = 'ST_Polygon';
$$ LANGUAGE SQL;

Esto retendrá los componentes poligonales de una intersección, pero tirará todo lo demás. Siempre devuelve un MultiPolygon, incluso si tiene uno o ningún componente.

WITH 
      square   as (SELECT ST_GeomFromText('POLYGON ((0 0, 0  1,  1  1,  1  0, 0 0))') AS geom),
biggersquare   as (SELECT ST_GeomFromText('POLYGON ((0 0, 0 10, 10 10, 10  0, 0 0))') AS geom),
adjacentsquare as (SELECT ST_GeomFromText('POLYGON ((0 0, 1  0,  1 -1, -1 -1, 0 0))') AS geom)   

SELECT ST_AsText(PolygonalIntersection(square.geom, biggersquare.geom))
  FROM square, biggersquare;
--"MULTIPOLYGON(((0 0,0 1,1 1,1 0,0 0)))"

SELECT ST_AsText(PolygonalIntersection(square.geom, adjacentsquare.geom))
  FROM square, adjacentsquare;
--"MULTIPOLYGON(EMPTY)"
dbaston
fuente
3

Muy buena respuesta de @dbaston. Sin embargo, devolver una geometría vacía en lugar de nulo podría causar problemas porque la geometría vacía devuelta no tiene cuadrícula. St_Intersection también puede devolver MultiPolygon. Esta función actualizada fue realmente útil para mí:

CREATE OR REPLACE FUNCTION PolygonalIntersection(a geometry, b geometry)
RETURNS geometry AS $$
SELECT ST_Collect(geom)
FROM 
(SELECT (ST_Dump(ST_Intersection(a, b))).geom 
) SQ
WHERE ST_GeometryType(geom) = 'ST_Polygon' OR ST_GeometryType(geom) = 'ST_MultiPolygon';
$$ LANGUAGE SQL;
thoomasbro
fuente