Автоматическая фиксация кольцевых самопересечений в shp2pgsql

Мы импортируем целую кучу шейп-файлов ArcGIS в PostGIS, конвертируемых на лету с shp2pgsql, Проблема в том, что если у шейп-файлов есть самопересечения кольца, импортные дроссели:

NOTICE:  Ring Self-intersection at or near point -80.1338 25.8102
ERROR:  new row for relation "place_shapes" violates
  check constraint "shape_is_valid"

Как мы можем это исправить?

3 ответа

Решение

Хотя буферизация объекта по нулю является известным исправлением для самопересекающихся полигонов, которые слишком часто встречаются в файлах shp, как это было предложено Марсело, для этой цели также существует функция ST_MakeValid. Существует также связанная функция, ST_IsValidReason, которая будет информировать о том, где находится проблема, а не просто попытаться устранить ее вслепую.

На практике использование ST_MakeValid(geom) или ST_Buffer(geom, 0) может создать смесь типов геометрии, включая потерянные точки и линии линий. Следовательно, дальнейшее уточнение может заключаться в проверке возвращаемого типа геометрии и включении, например, только тех многоугольников, которые являются результатом ST_MakeValid.

create table valid_geoms as
with make_valid (id, geom) as 
   (select 
      row_number() over() as id, 
     (ST_Dump(ST_MakeValid(geom))).geom as geom from invalid_table
  )
select id, geom from make_valid where ST_GeometryType(geom)='ST_Polygon';

где invalid_table - таблица, полученная в результате первоначального импорта shp2pgsql.

Я включил сгенерированный идентификатор здесь, так как ST_MakeValid будет потенциально генерировать более одного полигона из входных геометрий. Запрос можно переписать, включив в него исходное поле id, но он больше не будет гарантированно уникальным.

Этот запрос часто исправляет это для меня:

UPDATE place_shapes
  SET geometry=ST_Buffer(geometry, 0.0);

Оказывается, что выполнение этого шага постобработки делает свое дело:

UPDATE place_shapes
  SET geometry=ST_SimplifyPreserveTopology(geometry, 0.0001)
  WHERE ST_IsValid(geometry) = false;

0.0001 Это допустимое отклонение в градусах, возможно, вам придется настроить его по своему вкусу, но для данных карты улиц это кажется правильным.

Кроме того, если ваша таблица форм обеспечивает достоверность (что и должно быть), вам необходимо использовать shp2pgsql чтобы создать временную непроверенную таблицу, исправьте там свои полигоны и только затем скопируйте их в основную таблицу.

Другие вопросы по тегам