Geometrias de limpeza no PostGIS?

12

Estou tentando fazer algum processamento em algumas camadas de polígono muito grandes. No entanto, estou com vários erros de geometria, 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

Eu tentei a função sugerida aqui: https://trac.osgeo.org/postgis/wiki/UsersWikiCleanPolygons

para limpeza de geometrias, o código que usei sendo:

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

Com o resultado:

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

e também

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

Este funciona, mas somente se eu mudar minha coluna de geometria pela primeira vez para geometria

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

O que me deixa com uma tabela que não funciona mais com minhas outras funções!

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

Tentei alterar as colunas de volta para geometria (MultiPolygon)

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

Mas isso falha

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

Eu tentei passar pelo PostGIS in Action (Second Ed) http://www.manning.com/obe/, mas só consigo encontrar funções para encontrar geometrias inválidas, mas meu conjunto de dados é tão grande para corrigir isso manualmente, eu realmente precisa de algo que os conserte automaticamente.


Consegui isolar os polígonos do problema. Quando tento executar ST_MakeValid (), obtenho o 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

Fiz uma verificação de tipo na minha coluna de geometria e dizia que o tipo era "MULTIPOLYGON"

Mart
fonte
ST_MakeValid corrige o máximo possível.
User30184
Entendo, obrigado, eu realmente cometi um erro na minha pergunta, onde esqueci de mencionar que foi ST_Make_Valid que causou problemas nas minhas colunas. Eu tenho usado ST_MakeValid mas eu tenho que mudar minha coluna geom para o tipo de dados de geometria para obtê-lo para o trabalho, e uma vez eu faço isso eu não posso obtê-lo de volta para uma geometria (MultiPolygon)
Mart
2
Você pode usar o hack ST_Buffer (geom, 0), que lida com muitas geometrias inválidas. Você também pode usar ST_MakeValid. Por fim, você pode tentar selecionar uma nova tabela e colocar ST_IsValid (geom) na cláusula where.
John Powell
Obrigado, eu tentei o buffer hack já, mas não funcionou, ele queria uma entrada de geometria em vez de uma geometria (MultiPolygon). Vou tentar selecionar apenas os polígonos válidos e ver quantos são filtrados.
Mart
1
Está bem. Isso vem dos pontos de produção st_makevalid e LineStrings junto com polígonos que produzirão uma GeometryCollection. Existe uma correção para isso, que escreverei em algumas horas. Estou prestes a ir surfar :-)
John Powell

Respostas:

15

Se você quiser apenas polígonos ou multipolígonos a partir de ST_MakeValid, poderá usar ST_Dump para extrair as geometrias constituintes e, em seguida, testar o tipo de geometria. Às vezes, ST_MakeValid produz pontos ou LineStrings, que é a origem do GeometryCollection. Tente 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';

Você pode usar uma cláusula IN em vez da condição OR, embora o resultado e o plano de consulta sejam os mesmos. Se você deseja apenas Multipolígonos, pode envolver ST_Dump na função ST_Multi .

O número da linha () sobre () retornará simplesmente um ID exclusivo, começando por um, para cada geometria retornada pelo ST_Dump. Você também pode usar o elemento do caminho retornado por ST_Dump, com o mesmo resultado.

Você provavelmente combinará isso com uma instrução do tipo CREATE TABLE clean_geoms AS SELECT ...., pois é improvável que uma atualização direta funcione, já que ST_MakeValid geralmente não produz (ou sempre) um mapeamento de um para um do que eu coloco na saída.

Isso não foi testado, uma vez que atualmente não tenho meios, portanto pode haver um parêntese incorreto, mas o princípio geral é sólido. Espero que isto ajude.

John Powell
fonte
19

Você pode tentar ST_CollectionExtract para extrair [Multi] polígonos de GeometryCollections. Use ST_Multi para forçá-los como MuliPolygons.

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

Após concluir, use uma restrição CHECK para garantir que eles permaneçam válidos. Veja detalhes aqui .

Mike T
fonte