Очистить геометрию в PostGIS?

12

Я пытаюсь сделать некоторые обработки на очень больших слоях полигонов. Однако я сталкиваюсь с различными ошибками геометрии, такими как:

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

Я попробовал функцию, предложенную здесь: https://trac.osgeo.org/postgis/wiki/UsersWikiCleanPolygons

для очистки геометрии я использовал следующий код:

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

С результатом:

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

а также

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

Это работает, но только если я сначала изменю свой столбец геометрии на геометрию

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

Который затем оставляет меня с таблицей, которая больше не работает с моими другими функциями!

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

Я попытался изменить столбцы обратно в геометрию (MultiPolygon)

ALTER TABLE public.my_table ALTER COLUMN geom УСТАНОВИТЬ ТИП ДАННЫХ геометрия (MultiPolygon);

Но это не удается

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

Я попытался пройти PostGIS в действии (Второе издание) http://www.manning.com/obe/, но я могу найти только функции для поиска неверных геометрий, но мой набор данных настолько велик, чтобы исправить это вручную, я действительно нужно что-то, что исправит их автоматически.


Мне удалось выделить проблемные полигоны, когда я пытаюсь запустить ST_MakeValid (), я получаю результат:

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

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

Я сделал проверку типа в моем столбце геометрии, и он сказал, что тип был "MULTIPOLYGON"

рынок
источник
ST_MakeValid исправляет столько, сколько может.
user30184
Я вижу, спасибо, я действительно допустил ошибку в своем вопросе, где я забыл упомянуть, что именно ST_Make_Valid вызывает проблемы с моими столбцами. Я использовал ST_MakeValid , но я должен изменить столбец GeoM к типу геометрии данных , чтобы получить его на работу, и когда я делаю , что я не могу получить его обратно к геометрии (MultiPolygon)
Март
2
Вы можете использовать хак ST_Buffer (geom, 0), который будет иметь дело со многими неверными геометриями. Вы также можете использовать ST_MakeValid. Наконец, вы можете попробовать выбрать новую таблицу и поместить ST_IsValid (geom) в предложение where.
Джон Пауэлл
Спасибо, я уже пробовал взломать буфер, но он не работал, он хотел ввод геометрии, а не геометрию (MultiPolygon). Я постараюсь выбрать только действительные полигоны и посмотреть, сколько из них отфильтровано.
Март
1
Хорошо. Это происходит из st_makevalid, создающего точки и LineStrings вместе с полигонами, которые будут создавать GeometryCollection. Для этого есть исправление, которое я напишу через пару часов. Я собираюсь заняться серфингом :-)
Джон Пауэлл

Ответы:

15

Если вам нужны только полигоны или мультиполигоны из ST_MakeValid, вы можете использовать ST_Dump для извлечения составляющих геометрий, а затем проверить тип геометрии. ST_MakeValid иногда генерирует Points или LineStrings, откуда и происходит GeometryCollection. Попробуйте что-то вроде:

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

Вы можете использовать предложение IN вместо условия OR, хотя результат и план запроса будут одинаковыми. Если вам нужны только мультиполигоны, вы можете обернуть ST_Dump в функцию ST_Multi .

Row_number () over () просто вернет вам уникальный идентификатор, начиная с единицы, для каждой геометрии, возвращаемой из ST_Dump. Вы также можете использовать элемент пути, возвращаемый ST_Dump, с тем же результатом.

Вероятно, вы захотите объединить это с оператором типа CREATE TABLE cleaned_geoms AS SELECT ...., поскольку прямое обновление вряд ли будет работать, так как ST_MakeValid не будет обычно (или всегда) производить сопоставление «один к одному» из того, что я положил для вывода.

Это не проверено, так как в настоящее время у меня нет средств, поэтому могут быть неуместные скобки, но общий принцип обоснован. Надеюсь это поможет.

Джон Пауэлл
источник
19

Вы можете попробовать ST_CollectionExtract для извлечения [Multi] полигонов из GeometryCollections. Используйте ST_Multi, чтобы сделать их мультиполигонами.

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

По завершении используйте ограничение CHECK, чтобы убедиться, что они остаются действительными. Подробности здесь .

Майк Т
источник