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.


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)"

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;
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.