Я хотел бы провести тесты смежности на слое участков (полигонов) и объединить их, если они соответствуют определенным критериям (может быть размером). Согласно рисунку ниже, я хотел бы объединить полигоны 1,2,3 и 4, но не 5.
У меня две проблемы:
ST_TOUCHES
возвращает TRUE, если касаются только углы, а не отрезок. Я думаю, что мне нужно ST_RELATE, чтобы проверить для сегментов общей линии.- В идеале я хотел бы объединить ВСЕ смежные полигоны в один, но я не уверен, как масштабировать дальше двух - как, например, объединить 1,2,3 и 4 (и, возможно, больше на реальных данных) в один раунд.
Структура, которая у меня сейчас есть, основана на самостоятельном соединении ST_TOUCHES
.
Данные игрушки
CREATE TABLE testpoly AS
SELECT
1 AS id, ST_PolyFromText('POLYGON ((0 0, 10 0, 10 20, 00 20, 0 0 ))') AS geom UNION SELECT
2 AS id, ST_PolyFromText('POLYGON ((10 0, 20 0, 20 20, 10 20, 10 0 ))') AS geom UNION SELECT
3 AS id, ST_PolyFromText('POLYGON ((10 -20, 20 -20, 20 0, 10 0, 10 -20 ))') AS geom UNION SELECT
4 AS id, ST_PolyFromText('POLYGON ((20 -20, 30 -20, 30 0, 20 0, 20 -20 ))') AS geom UNION SELECT
5 AS id, ST_PolyFromText('POLYGON ((30 0, 40 0, 40 20, 30 20, 30 0 ))') AS geom ;
выбор
SELECT
gid, adj_gid,
st_AStext(st_union(l2.g1,l2.g2)) AS geo_combo
from (
--level 2
SELECT
t1.id AS gid,
t1.geom AS g1,
t2.id AS adj_gid,
t2.geom AS g2
from
testpoly t1,
testpoly t2
where
ST_Touches( t1.geom, t2.geom )
AND t1.geom && t2.geom
)
l2
Вот вывод:
+-----+---------+-------------------------------------------------------------------------------+
| gid | adj_gid | geo_combo |
+-----+---------+-------------------------------------------------------------------------------+
| 1 | 2 | POLYGON((10 0,0 0,0 20,10 20,20 20,20 0,10 0)) |
+-----+---------+-------------------------------------------------------------------------------+
| 1 | 3 | MULTIPOLYGON(((10 0,0 0,0 20,10 20,10 0)),((10 0,20 0,20 -20,10 -20,10 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 2 | 1 | POLYGON((10 20,20 20,20 0,10 0,0 0,0 20,10 20)) |
+-----+---------+-------------------------------------------------------------------------------+
| 2 | 3 | POLYGON((10 0,10 20,20 20,20 0,20 -20,10 -20,10 0)) |
+-----+---------+-------------------------------------------------------------------------------+
| 2 | 4 | MULTIPOLYGON(((20 0,10 0,10 20,20 20,20 0)),((20 0,30 0,30 -20,20 -20,20 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 3 | 1 | MULTIPOLYGON(((10 0,20 0,20 -20,10 -20,10 0)),((10 0,0 0,0 20,10 20,10 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 3 | 2 | POLYGON((20 0,20 -20,10 -20,10 0,10 20,20 20,20 0)) |
+-----+---------+-------------------------------------------------------------------------------+
| 3 | 4 | POLYGON((20 -20,10 -20,10 0,20 0,30 0,30 -20,20 -20)) |
+-----+---------+-------------------------------------------------------------------------------+
| 4 | 2 | MULTIPOLYGON(((20 0,30 0,30 -20,20 -20,20 0)),((20 0,10 0,10 20,20 20,20 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 4 | 3 | POLYGON((20 0,30 0,30 -20,20 -20,10 -20,10 0,20 0)) |
+-----+---------+-------------------------------------------------------------------------------+
| 4 | 5 | MULTIPOLYGON(((30 0,30 -20,20 -20,20 0,30 0)),((30 0,30 20,40 20,40 0,30 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 5 | 4 | MULTIPOLYGON(((30 0,30 20,40 20,40 0,30 0)),((30 0,30 -20,20 -20,20 0,30 0))) |
+-----+---------+-------------------------------------------------------------------------------+
Обратите внимание, что многоугольник id = 3 разделяет точку с id = 1 и, таким образом, возвращается как положительный результат. Если я изменю предложение WHERE на, ST_Touches( t1.geom, t2.geom ) AND t1.geom && t2.geom AND ST_Relate(t1.geom, t2.geom ,'T*T***T**');
я не получаю никаких записей вообще.
Итак, во- первых , как мне указать ST_Relate, чтобы убедиться, что рассматриваются только участки, разделяющие отрезок линии.
И затем, как мне объединить полигоны 1, 2, 3, 4 в один раунд, свернув результаты вышеупомянутого вызова, при этом признавая, что смежность от 1 до 2 совпадает с противоположной?
Обновить
Если я добавлю это к where
предложению, я, очевидно, получу только полигоны, а не мультиполигоны, таким образом отсеивая ложные срабатывания для моих целей - угловые касания будут игнорироваться.
GeometryType(st_union(t1.geom,t2.geom)) != 'MULTIPOLYGON'
Хотя это не идеально (я бы предпочел использовать проверки топологии ST_RELATE
в качестве более общего решения), это путь вперед. Тогда остается вопрос об обманывании и объединении этих. Возможно, если бы я мог сгенерировать последовательность только для касания полигонов, я мог бы объединиться на этом.
Обновление II
Кажется, что этот работает для выбора полигонов, разделяющих линии (но не углы), и, таким образом, является более общим решением, чем приведенный выше MULTIPOLYGON
тест. Мое предложение where теперь выглядит так:
WHERE
ST_Touches( t1.geom, t2.geom )
AND t1.geom && t2.geom
-- 'overlap' relation
AND ST_Relate(t1.geom, t2.geom)='FF2F11212') t2
Теперь остается то, как сделать слияние не только для пары многоугольников, но и для произвольного числа, соответствующего критериям, за один раз.
ST_IntersectionArray
[функции] [1] для работы с ST_Union [1]: gis.stackexchange.com/a/60295/36886Ответы:
Я не мог не подумать, что ваш пример на самом деле является растром, и хотя вы упомянули, что вы хотели бы объединить на основе «определенных критериев (может быть размера)», я хотел бы дать ему шанс с преобразованием растра.
Для вашего конкретного примера это будет работать:
Что происходит, так как ваши полигоны представляют собой идеально выровненные ячейки, они будут красиво преобразованы в растр (размер ячейки 10x20). Здесь вам помогает dumpaspolygons, объединяя все соседние ячейки в одну, и сравнивая с исходными полигонами, вы даже сможете получить идентификатор обратно для не слитых поли.
Объяснив это, мне очень любопытно, как это будет масштабироваться и насколько велик ваш набор данных: D
источник
Вот пример того, как сделать это в процедурном стиле с несколькими проходами под капотом.
Вы должны иметь возможность переносить больше столбцов и применять дополнительные критерии для объединения, изменив способ
LIMIT 1
выбора ниже:Запустите вещь:
Правильные союзы, нет мультиполигонов:
источник
Вот еще одна (не работающая) стратегия для справки (которую я не смог исключить из одного случая соприкосновения). Это должно быть быстрее, чем мой другой ответ, так как он занимает всего «один проход».
(не стесняйтесь вносить изменения и публиковать другой ответ, если кто-то может получить геометрию id = 5 в своей группе)
Чтобы вернуться к списку идентификаторов и т. Д., Вам нужно будет
st_contains
снова присоединиться к таблице testpoly, как подробно описано в следующем ответе: /programming//a/37486732/6691, но я не смог заставить это работать для полигонов по какой-то причине.источник
Вот быстрый пример использования вашего исходного запроса, немного скорректированного:
Ссылки: https://postgis.net/docs/using_postgis_dbmanagement.html#DE-9IM
источник