Я хотел бы провести тесты смежности на слое участков (полигонов) и объединить их, если они соответствуют определенным критериям (может быть размером). Согласно рисунку ниже, я хотел бы объединить полигоны 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