Nettoyage des géométries dans PostGIS?

12

J'essaie de faire du traitement sur de très grandes couches de polygones. Cependant, je rencontre diverses erreurs de géométrie telles que:

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

J'ai essayé la fonction suggérée ici: https://trac.osgeo.org/postgis/wiki/UsersWikiCleanPolygons

pour le nettoyage des géométries, le code que j'ai utilisé étant:

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

Avec le résultat:

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

et aussi

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

Celui-ci fonctionne, mais seulement si je change d'abord ma colonne de géométrie en géométrie

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

Ce qui me laisse alors une table qui ne fonctionne plus avec mes autres fonctions!

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

J'ai essayé de remettre les colonnes en géométrie (MultiPolygon)

ALTER TABLE public.my_table ALTER COLUMN geom SET TYPE DE DONNÉES geometry (MultiPolygon);

Mais cela échoue

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

J'ai essayé de passer par PostGIS in Action (Second Ed) http://www.manning.com/obe/ mais je ne peux trouver que des fonctions pour trouver des géométries invalides, mais mon ensemble de données est si gros pour corriger cela manuellement, j'ai vraiment besoin de quelque chose qui les réparera automatiquement.


J'ai pu isoler les polygones problématiques, lorsque j'essaie d'exécuter ST_MakeValid () j'obtiens le résultat:

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

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

J'ai fait une vérification de type sur ma colonne de géométrie, et il a dit que le type était "MULTIPOLYGON"

Marché
la source
ST_MakeValid corrige autant que possible.
user30184
Je vois, merci, j'avais en fait fait une erreur dans ma question où j'ai oublié de mentionner que c'est ST_Make_Valid qui cause les problèmes avec mes colonnes. J'ai utilisé ST_MakeValid mais je dois changer ma colonne geom pour le type de données geometry pour le faire fonctionner, et une fois que je le fais, je ne peux pas le ramener à une géométrie (MultiPolygon)
Mart
2
Vous pouvez utiliser le hack ST_Buffer (geom, 0) qui traitera de nombreuses géométries invalides. Vous pouvez également utiliser ST_MakeValid. Enfin, vous pouvez essayer de sélectionner une nouvelle table et de placer ST_IsValid (geom) dans la clause where.
John Powell
Merci, j'ai déjà essayé le hack de tampon, mais cela n'a pas fonctionné, il voulait une entrée de géométrie plutôt qu'une géométrie (MultiPolygon). Je vais essayer de sélectionner uniquement les polygones valides et voir combien sont filtrés.
Mart
1
D'accord. Cela vient de st_makevalid produisant des points et des LineStrings avec des polygones qui produiront une GeometryCollection. Il existe un correctif pour cela que j'écrirai dans quelques heures. Je suis sur le point d'aller surfer :-)
John Powell

Réponses:

15

Si vous souhaitez uniquement des polygones ou des multipolygones de ST_MakeValid, vous pouvez utiliser ST_Dump pour extraire les géométries constitutives, puis tester le type de géométrie. ST_MakeValid produira parfois des points ou des chaînes de lignes d'où vient la GeometryCollection. Essayez quelque chose comme:

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';

Vous pouvez utiliser une clause IN au lieu d'une condition OR, bien que le résultat et le plan de requête soient les mêmes. Si vous ne voulez que des multipolygones, vous pouvez encapsuler ST_Dump dans la fonction ST_Multi .

Le row_number () over () vous renverra simplement un identifiant unique, en commençant par un, pour chaque géométrie renvoyée par ST_Dump. Vous pouvez également utiliser l'élément path retourné par ST_Dump, avec le même résultat.

Vous souhaiterez probablement combiner cela avec une instruction de type CREATE TABLE cleaner_geoms AS SELECT ...., car une mise à jour directe ne fonctionnera probablement pas car ST_MakeValid ne produira généralement (ou toujours) un mappage un à un à partir de la sortie en sortie.

Ceci n'est pas testé car je n'ai aucun moyen, actuellement, donc il pourrait y avoir une parenthèse mal placée, mais le principe général est sain. J'espère que cela t'aides.

John Powell
la source
19

Vous pouvez essayer ST_CollectionExtract pour extraire [Multi] Polygones de GeometryCollections. Utilisez ST_Multi pour les forcer en tant que MuliPolygons.

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

Après avoir terminé, utilisez une contrainte CHECK pour vous assurer qu'ils restent valides. Voir les détails ici .

Mike T
la source