我想在宗地(多边形)层上进行邻接测试,并在它们符合特定条件(可能是大小)的情况下合并它们。根据下面的图片,我想合并多边形1,2,3和4,但不合并5。
我有两个问题:


ST_TOUCHES如果仅角接触而不是线段。我想我需要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_Relate是正确的方法。我通过检查相交的长度是否大于零以排除单点相交来解决了类似的问题。骇客,但有效。

如果有一种方法可以将连续的多边形组合成数组,则可以修改ST_IntersectionArray [function] [1]以与ST_Union [1]一起使用:gis.stackexchange.com/a/60295/36886

关于将连续的多边形分组在一起,您可以修改我在此处编写的自底向上聚类算法(gis.stackexchange.com/a/115715/36886),以测试邻接性而不是空间,然后在对结果cluster_ids分组时使用ST_Union br />
还有ST_ClusterIntersectimg可能会满足您的需求。您需要Postgis 2.2

#1 楼

我不禁想到您的示例实际上是一个栅格,尽管您提到您希望基于“某些条件(可能是大小)”进行合并,但我还是想通过栅格转换对其进行尝试。 >
对于您的特定示例,这将起作用: 10x20细胞大小)。 dumpaspolygons通过将所有相邻单元格合并为一个单元,并与原始多边形进行比较,可以在这里为您提供帮助。您甚至可以获得非合并的poly的id。

已经解释了这一点,我非常很好奇这将如何扩展以及您的数据集有多大:D

评论


聪明的主意。不过,这只是一个玩具示例-我的实际数据是一个宗地图层,不会很好地映射到栅格。

–ako
16 Dec 9'在18:17

#2 楼

这是一个如何以程序方式在后台进行多次操作的示例。

CREATE TABLE joined_testpoly AS SELECT array[id] ids, geom FROM testpoly; 


您应该能够携带更多的列并应用附加条件进行连接通过修改以下LIMIT 1选择的工作方式:

CREATE OR REPLACE FUNCTION reduce_joined_testpoly()
RETURNS void
AS $$
DECLARE
  joined_row joined_testpoly%ROWTYPE;
BEGIN
  LOOP
     SELECT array_cat(a.ids, b.ids), st_union(a.geom, b.geom)
         INTO joined_row 
     FROM joined_testpoly a INNER JOIN joined_testpoly b
           on a.ids != b.ids
              and ST_Touches(a.geom, b.geom) and a.geom && b.geom 
              and ST_Relate(a.geom, b.geom)='FF2F11212'
         LIMIT 1;
     IF NOT FOUND THEN
           EXIT;
     END IF;
     INSERT INTO joined_testpoly VALUES (joined_row.ids, joined_row.geom);
     DELETE FROM joined_testpoly
         WHERE joined_testpoly.ids <@ joined_row.ids 
           AND joined_testpoly.ids != joined_row.ids;
  END LOOP;
  RETURN;
END;
$$ LANGUAGE plpgsql;


运行东西:

SELECT reduce_joined_testpoly();


正确的联合,没有多面体:

SELECT ids, st_geometrytype(geom), st_area(geom), st_numgeometries(geom) 
FROM joined_testpoly;
    ids    | st_geometrytype | st_area | st_numgeometries 
-----------+-----------------+---------+------------------
 {5}       | ST_Polygon      |     200 |                1
 {1,2,3,4} | ST_Polygon      |     800 |                1


#3 楼

这是另一种(无效的)参考策略(我无法排除单个接触点的情况)。它应该比我的其他答案更快,因为它只需要“一次通过”。

SELECT st_numgeometries(g), (SELECT st_union(x.geom) FROM st_dump(g) x GROUP BY g)
FROM (
    SELECT unnest(st_clusterintersecting(geom)) g, id < 100 as other_arbitrary_grouping 
    FROM testpoly
    GROUP BY other_arbitrary_grouping) c;


(如果有人可以获取id =,可以随意修改并发布另一个答案= 5个几何体属于自己的组)

要获取ID等的列表,您必须使用st_contains重新加入testpoly表,如以下答案中所述:https:// stackoverflow。 com / a / 37486732/6691
,但是由于某种原因,我无法将其用于多边形。

#4 楼

这是使用原始查询稍作调整后的快速解决方法: