Выявление «длинных и узких» полигонов в PostGIS

10

У меня есть набор полигонов, представляющих большие площади, скажем, городские кварталы. Я хочу определить большие перекрывающиеся области между ними.

Но есть проблема: иногда эти многоугольники перекрываются по периметру (потому что они нарисованы с небольшой точностью). Это создаст длинные и узкие перекрытия, которые меня не волнуют.

Но в других случаях будут существенные перекрытия надежных многоугольников, то есть большие области, где многоугольник соседства перекрывает другой. Я хочу выбрать только эти.

Смотри картинку ниже только перекрытий. Представьте, что я хочу выделить только синий многоугольник в левом нижнем углу.

перекрытие

Я мог бы смотреть на области, но иногда узкие были такими длинными, что в итоге они имели такие же большие области, как синий многоугольник. Я пытался сделать соотношение площади / периметра, но это также дало смешанные результаты.

Я даже пытался использовать ST_MinimumClearance, но иногда к большим областям прикрепляется узкая часть или две очень близкие вершины.

Есть идеи о других подходах?


В конце концов, для меня лучше всего было использовать отрицательный буфер, как предложили @Cyril и @FGreg ниже.

Я использовал что-то вроде:

ST_Area(ST_Buffer(geom, -10)) as neg_buffer_area

В моем случае единицы измерения были метрами, поэтому 10 м отрицательного буфера.

Для узких полигонов эта область вернула ноль (также геометрия была бы пустой). Затем я использовал этот столбец, чтобы отфильтровать узкие полигоны.

bplmp
источник
4
Конечно, отношение площадь / периметр может быть использовано для этого.
Винс
Трудно сказать, откуда взяты различные полигоны, но что-то подобное gis.stackexchange.com/a/265233/64838 может работать? Рассчитайте минимальное количество вращающихся ограничивающих рамок, затем отбросьте те, которые имеют небольшую ширину или высоту
FGreg
Вы также можете попробовать использовать отрицательный буфер, как описано здесь: Как я могу определить действительно тонкие полигоны в моем файле формы?
FGreg

Ответы:

5

Я бы попытался создать отрицательный буфер, если он ест тонкие многоугольники, тогда хорошо, если он не ест многоугольник, то он мой ... :-)

запустите этот скрипт, предварительно установив 2/3 ширины линейных полигонов ...

create table name_table as
SELECT ST_Buffer(
(ST_Dump(
(ST_Union(
ST_Buffer(
(geom),-0.0001))))).geom,
0.0001)) as geom from source_table

ОПЕРАЦИОННЫЕ СИСТЕМЫ :-)...

Кирилл Михальченко
источник
в конце концов, ваше предложение - то, что лучше всего сработало для меня. Я закончил, используя что-то вроде ST_Area(ST_Buffer(geom, -10))-10 в моем случае -10 метров. Если что-то вернуло 0 из этого выражения, я мог бы отфильтровать его.
bplmp
9

Вместо площади / периметра лучше использовать площадь, разделенную на квадрат периметра (или его инверсию).

Это также называется «индекс формы». Квадрат периметра, деленный на площадь, имеет минимальное значение 4 * Pi () (в случае диска, который является самой компактной 2D геометрией), поэтому его можно нормализовать с помощью 4 * Pi () для простого интерпретация (нормализованные значения, близкие к 1, означают, что у вас очень компактные объекты, а квадраты имеют значения приблизительно 1,27).

РЕДАКТИРОВАТЬ: порог на области будет полезным для удаления очень маленьких артефактов, которые могут быть компактными. Тогда индекс формы показал бы лучший контраст. РЕДАКТИРОВАТЬ: в дополнение к этому ответу, использование ST_Snap может помочь вам решить проблему до ее возникновения.

radouxju
источник
Спасибо! Но я не уверен, как ST_Snap может помочь в этом случае ... Если я правильно понял, вы предлагаете что-то подобное (o.overlap_perimeter^2 / o.overlap_area) / (4 * Pi()) as overlap_ratio? Это имеет худшие результаты для меня, чем просто площадь / периметр.
bplmp
Теперь, используя в o.overlap_perimeter / (4 * sqrt(o.overlap_area)) as overlap_ratioсоответствии с этой статьей, но все еще худшие результаты (хотя трудно определить, что я имею в виду под худшими) isprs-ann-photogramm-remote-sens-spatial-inf-sci.net/I-7/135/… , стр. 183.
bplmp
2
Спасибо за это, я никогда не слышал о «индексе формы». Я всегда думал, что использование минимального ограничивающего прямоугольника - лучший способ ответить на этот вопрос. Я нашел это, repository.asu.edu/attachments/111230/content/… , что интересно.
Джон Пауэлл
@JohnPowell, интересная статья, спасибо. Я вижу, что то, что я знаю как индекс формы, называется индексом круглости в статье. Моя проблема с минимальными ограничивающими прямоугольниками состоит в том, что они не работают с очень вогнутыми объектами (например, U-образными)
radouxju
@bplmp ST_Snap поможет вам привязать вершины «почти» соседних полигонов, чтобы они больше не перекрывались. На ваших фигурах нет масштаба, но ваш артефакт выглядит как линии, поэтому я предполагаю, что вы можете использовать значение допуска, которого достаточно, чтобы избежать артефактов, но это не влияет на большие полигоны.
Radouxju
5

Одним из вариантов будет использование отношения площади многоугольника к самой длинной линии, которую можно нарисовать с использованием его конечностей. Выявление длинных узких полигонов.

select * from polygons where ST_Length(ST_LongestLine(geom, geom)) < ST_Area(geom) * 4

Это работает очень хорошо для многоугольников. Вы можете настроить соотношение (с которым вы умножаете площадь) в соответствии с вашими потребностями и проекцией.

HeikkiVesanto
источник
1

Похоже, это может соответствовать вашему варианту использования: устранить выбранные полигоны

Объединяет выбранные полигоны входного слоя с некоторыми смежными полигонами, стирая их общую границу. Соседним многоугольником может быть либо тот, у которого наибольшая или наименьшая площадь, либо тот, который имеет наибольшую общую границу с подлежащим удалению многоугольником.

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

Похоже, вы хотели бы попробовать вариант «Крупнейшая общая граница».

FGreg
источник
Теперь я понимаю, что вы спрашивали о решениях Postgis, а не QGIS. Мои извинения, я не думаю, что у postgis есть эквивалентная функция, но я оставлю это для потомков.
FGreg
0

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

Одним словом, стратегия такова:

1. Включите расширение топологии

CREATE EXTENSION postgis_topology;

2. Создайте новую пустую топологию

SELECT topology.CreateTopology('neighborhoods_topo', 4326, 1e-7);

Третий параметр - это допуск в единицах CRS; выбирай мудро. В идеале, вы хотите CRS, где единица измерения метров. Если единица CRS не является метрами, как в WGS 84 или 4326, используйте ST_Transformдля перепроектирования ваших полигонов.

3. Добавьте столбец TopoGeometry в таблицу полигонов

SELECT topology.AddTopoGeometryColumn('neighborhoods_topo', 'public', 'neighborhoods', 'topogeom', 'POLYGON');

Это возвращает новый layer_id. Сохраните, это понадобится позже. Это будет слой, 1если вы начинаете с нуля, и увеличивается при каждом новом вызове.

4. Добавьте все полигоны в топологию.

UPDATE public.neighborhoods
SET topogeom = topology.toTopoGeom(geom, 'neighborhoods_topo', 1, 1e-7);

Это может занять несколько часов для большого набора данных, будьте терпеливы. 1это layer_id, возвращенный ранее.

5. Найдите лица, появляющиеся в нескольких кварталах

Найти все грани из топологии, которые присутствуют в 2 или более топогеометрии. Я оставлю запрос в качестве упражнения. Возможно, проще всего это с помощью GetTopoGeomElementsфункции, затем сгруппировать по идентификатору лица и посмотреть на те из них, которые насчитывают 2 или более. В качестве альтернативы, вы можете создать новую таблицу с очищенной геометрией из столбца topogeom, просто привести ее к стандартной геометрии topogeom::geometryи повторить то, что у вас уже есть, но теперь с чистым набором данных без накладок.

Франсуа
источник