Limpieza de geometrías en PostGIS?


12

Estoy tratando de hacer un procesamiento en algunas capas poligonales muy grandes. Sin embargo, me encuentro con varios errores de geometría como:

NOTICE:  Ring Self-intersection at or near point 470396.52017068537 141300.52235257279
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 504154.61769969884 140782.04115761846
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 505255.50242871145 140803.34860398644
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 510312.46970004693 141215.29256710084
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 510312.46970004693 141215.29256710084
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 511839.50335641927 141115.85781738357
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 515064.03024010791 140895.68087158105
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 519233.18724611058 140881.47590733573
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 521072.73011588014 141044.83299615697
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 523331.31943088671 141144.26774587421
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 523331.31943088671 141144.26774587424
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 523395.24176999065 140725.22130063715
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1
NOTICE:  Ring Self-intersection at or near point 524531.63890961662 140810.45108610913
CONTEXT:  PL/pgSQL function st_intersection(geometry,raster,integer) line 10 at RETURN QUERY
SQL function "st_intersection" statement 1

He probado la función sugerida aquí: https://trac.osgeo.org/postgis/wiki/UsersWikiCleanPolygons

para limpiar geometrías, el código que he usado es:

UPDATE public.mytable
SET geom=cleangeometry(geom);

Con el resultado:

ERROR:  GEOSisSimple: IllegalArgumentException: This method does not support GeometryCollection arguments

y también

UPDATE public.valid_mytable
SET geom=ST_MakeValid(geom);

Este funciona, pero solo si primero cambio mi columna de geometría a geometría

ALTER TABLE public.mytable  ALTER COLUMN geom SET DATA TYPE geometry;

¡Lo que me deja con una tabla que ya no funciona con mis otras funciones!

ERROR:  Relate Operation called with a LWGEOMCOLLECTION type.  This is unsupported.

He intentado cambiar las columnas a geometría (MultiPolygon)

ALTER TABLE public.my_table ALTER COLUMN geom SET DATA TYPE geometry (MultiPolygon);

Pero esto falla

ERROR:  Geometry type (GeometryCollection) does not match column type (MultiPolygon)

He intentado pasar por PostGIS en acción (Segunda edición) http://www.manning.com/obe/ pero solo puedo encontrar funciones para encontrar geometrías no válidas, pero mi conjunto de datos es tan grande para solucionar esto manualmente, realmente necesita algo que los arregle automáticamente.


He podido aislar los polígonos problemáticos, cuando intento ejecutar ST_MakeValid () obtengo el resultado:

ERROR:  Geometry type (GeometryCollection) does not match column type      (MultiPolygon)
 ********** Error **********

 ERROR: Geometry type (GeometryCollection) does not match column type      (MultiPolygon)
SQL state: 22023

Hice una verificación de tipo en mi columna de geometría, y decía que el tipo era "MULTIPOLYGON"


ST_MakeValid corrige tanto como puede.
usuario30184

Ya veo, gracias, en realidad cometí un error en mi pregunta en la que olvidé mencionar que fue ST_Make_Valid el que causa los problemas con mis columnas. He utilizado ST_MakeValid pero tengo que cambiar mi columna geom al tipo de datos de geometría para conseguir que funcione, y una vez que hago lo que puedo conseguir de nuevo a una geometría (MultiPolygon)
Mart

2
Puedes usar el hack ST_Buffer (geom, 0) que tratará con muchas geometrías inválidas. También puede usar ST_MakeValid. Finalmente, podría intentar seleccionar en una nueva tabla y poner ST_IsValid (geom) en la cláusula where.
John Powell

Gracias, ya probé el hack de búfer, pero no funcionó, quería una entrada de geometría en lugar de una geometría (MultiPolygon). Intentaré seleccionar solo los polígonos válidos y veré cuántos se filtran.
Martes

1
Okay. Esto viene de st_makevalid produciendo puntos y LineStrings junto con polígonos que producirán una GeometryCollection. Hay una solución para esto que escribiré en un par de horas. Estoy a punto de ir a surfear :-)
John Powell

Respuestas:


15

Si solo desea polígonos o multipolígonos de ST_MakeValid , puede usar ST_Dump para extraer las geometrías constituyentes y luego probar el tipo de geometría. ST_MakeValid a veces producirá Points o LineStrings, que es de donde proviene GeometryCollection. Intenta algo como:

SELECT 
  g.geom, 
  row_number() over() AS gid,
FROM 
  (SELECT 
     (ST_DUMP(ST_MakeValid (geom))).geom FROM your_table
  ) AS g
WHERE ST_GeometryType(g.geom) = 'ST_MultiPolygon' 
   OR ST_GeometryType(g.geom) = 'ST_Polygon';

Puede usar una cláusula IN en lugar de una condición OR, aunque el resultado y el plan de consulta serían los mismos. Si solo desea Multipolígonos, puede ajustar ST_Dump en la función ST_Multi .

Row_number () over () simplemente le devolverá una identificación única, comenzando por una, para cada geometría devuelta por ST_Dump. También puede usar el elemento de ruta devuelto por ST_Dump, con el mismo resultado.

Probablemente querrá combinar esto con una declaración de tipo CREATE TABLE clean_geoms AS SELECT ...., ya que es poco probable que una actualización directa funcione ya que ST_MakeValid generalmente no (o siempre) producirá una asignación uno a uno desde que pongo a la salida.

Esto no se ha probado ya que actualmente no tengo medios, por lo que puede haber un paréntesis fuera de lugar, pero el principio general es sólido. Espero que esto ayude.


19

Puede probar ST_CollectionExtract para extraer [Multi] Polygons de GeometryCollections. Usa ST_Multi para forzarlos como MuliPolygons.

UPDATE public.valid_lcmsouthshapefile
  SET geom=ST_Multi(ST_CollectionExtract(ST_MakeValid(geom), 3))
  WHERE NOT ST_IsValid(geom);

Después de que haya terminado, use una restricción CHECK para asegurarse de que sigan siendo válidos. Ver detalles aquí .

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.