从多个几何创建溶解的缓冲区(按共享属性和空间交集合并)


10

我必须根据多点输入功能创建溶解的缓冲区。在下面的示例中,输入表包含4个功能。要素#2由两个点几何组成。创建缓冲区后,我得到了4个多边形几何:

在此处输入图片说明

有没有一种将结果分组的方法?点#1和的缓冲区#2已溶解,应为单个多面要素(a)。

到目前为止,我所做的是:

-- collect all buffers to a single multi-polygon feature
-- dissolve overlapping polygon geometries
CREATE TABLE public.pg_multibuffer AS SELECT
    row_number() over() AS gid,
    sub_qry.*
FROM (SELECT
    ST_Union(ST_Buffer(geom, 1000, 8))::geometry(MultiPolygon, /*SRID*/) AS geom
FROM
public.multipoints)
AS sub_qry;

编辑:

-- create sample geometries

CREATE TABLE public.multipoints (
gid serial NOT NULL,
geom geometry(MultiPoint, 31256),
CONSTRAINT multipoints_pkey PRIMARY KEY (gid)
);

CREATE INDEX sidx_multipoints_geom
ON public.multipoints
USING gist
(geom);

INSERT INTO public.multipoints (gid, geom) VALUES
(1, ST_SetSRID(ST_GeomFromText('MultiPoint(12370 361685)'), 31256)),
(2, ST_SetSRID(ST_GeomFromText('MultiPoint(13520 360880, 19325 364350)'), 31256)),
(3, ST_SetSRID(ST_GeomFromText('MultiPoint(11785 367775)'), 31256)),
(4, ST_SetSRID(ST_GeomFromText('MultiPoint(19525 356305)'), 31256));

您使用过多子查询。这消除了您要在其上集群的属性上使用GROUP BY的能力。
文斯

因此,您需要进行空间并集,然后再基于要素号进行并集,这就是为什么您希望从上图中获得3个多面体的原因。我怀疑这将需要两步过程,但是只是想在提供答案之前明确问题。
John Powell

是的,我想合并缓冲区多边形并根据输入要素的数量收集结果。
eclipsed_by_the_moon

这事有进一步更新吗?我想知道这是否对您有用,据我所知,我已经回答了这个问题。
John Powell

很抱歉收到延迟回复,我已经有两天没有上网了。
eclipsed_by_the_moon

Answers:


7

从一些随机点开始,首先尝试模仿OP图像中的那些点,其中前两个在空间上相交,然后第二个和第三个具有相同的属性id(2),另外两个点在空间上都不相交也没有相同的属性,以下查询产生3个群集:

WITH 
  temp (id, geom) AS 
     (VALUES (1, ST_Buffer(ST_Makepoint(0, 0), 2)),
        (2, ST_Buffer(ST_MakePoint(-0.7,0.5), 2)),
        (2, ST_Buffer(ST_MakePoint(10, 10), 2)), 
        (3, ST_Buffer(ST_MakePoint(-2, 12), 2)), 
        (4, ST_Buffer(ST_MakePoint(5, -6), 2))),
 unions(geoms) AS 
      (SELECT ST_Union(geom) FROM temp GROUP BY id),
 clusters(geoms) AS 
      (SELECT ST_CollectionExtract(unnest(ST_ClusterIntersecting(geoms)), 3) 
         FROM unions),
 multis(id, geoms) AS 
      (SELECT row_number() over() as id, geoms FROM clusters)
 SELECT ST_UNION(d.geom) FROM 
      (SELECT id, (ST_DUMP(geoms)).geom FROM multis) d GROUP BY id;

这里有几个步骤:

  1. 使用ST_Union,按ID分组,首先按属性分组
  2. 用于ST_ClusterIntersecting合并来自同一组的在空间上相交的对象
  3. 为每个集群添加一个ID(表多重)-尝试直接在ClusterIntersecting中执行此操作,导致所有几何体的ID为1
  4. 合并步骤2中转储的几何图形,并按步骤3中的id分组-这是可分解的部分。这将导致群集A中的两个重叠的多边形连接在一起,而不是像在步骤2末尾那样重叠。

相当长,但是它可以工作(而且我敢肯定还有更短的方法)。

使用QGIS中的WKT工具(并发现编辑工具对我的影响如何)会产生如下所示的簇,您可以在其中看到标记为a的簇在一起-即一种颜色。

在此处输入图片说明

如果将ST_AsText放在最后的ST_UNION(d.geom)周围,则可以直接查看结果。

编辑注释中的以下更多信息:从点开始,您需要将缓冲区合并到我的原始解决方案中-我在开始时就将其放在了临时CTE中,以模仿您的图表。在联合CTE中添加缓冲区会更容易,因此您可以一次完成所有几何。因此,以1000的缓冲距离为例,下面的代码现在按预期返回3个簇。

WITH temp(id, geom) AS 
  (VALUES 
      (1, ST_SetSRID(ST_GeomFromText('MultiPoint(12370 361685)'), 31256)),   
      (2, ST_SetSRID(ST_GeomFromText('MultiPoint(13520 360880, 19325 364350)'), 31256)),                                                
      (3, ST_SetSRID(ST_GeomFromText('MultiPoint(11785 367775)'), 31256)),
      (4, ST_SetSRID(ST_GeomFromText('MultiPoint(19525 356305)'), 31256))
),                                              
unions(geoms) AS 
  (SELECT st_buffer(ST_Union(geom), 1000) FROM temp GROUP BY id),
clusters(geoms) AS 
  (SELECT ST_CollectionExtract(unnest(ST_ClusterIntersecting(geoms)), 3) 
     FROM unions),
multis(id, geoms) AS 
  (SELECT row_number() over() as id, geoms FROM clusters)
SELECT id, ST_UNION(d.geom) FROM 
  (SELECT id, (ST_DUMP(geoms)).geom FROM multis) d GROUP BY id;

抱歉,花了很长时间才回复您。我在可视化QGIS中的缓冲区几何时遇到了一些麻烦。我曾尝试使用修改您的查询ST_SetSRIDST_Multi::geometry(Multipolygon, /*SRID*/),但目前它不工作。
eclipsed_by_the_moon

好的,如果您可以发布代码,甚至提供一些更好的数据,我也许可以提供帮助。
约翰·鲍威尔,

我添加了一些SQL以创建样本点。
eclipsed_by_the_moon

今天有点束手无策,我会尽快回复。也将不得不将多点工作到查询中。
约翰·鲍威尔,

3

一种方法是将ST_Union所有缓冲区放在一起,ST_Dump将结果取到结果多边形的组成部分,然后与ST_Intersects输入点结合起来,找出组成每个簇的点数/点数。

可以通过调用之前将点分组在一起而无需加入来完成此操作ST_Buffer。要使两个点位于同一溶解的缓冲区中,距离之间小于的点之间的跳跃必须可以到达它们eps。这只是一个最小链接聚类问题,可以使用ST_ClusterDBSCAN以下方法解决:

SELECT
  cluster_id,
  ST_Union(ST_Buffer(geom, 1000)) AS geom,
  count(*)                        AS num_points,
  array_agg(point_id)             AS point_ids
FROM (
  SELECT
    point_id,
    ST_ClusterDBSCAN(geom, eps := 2000, minpoints := 1) OVER() AS cluster_id ,
    geom
  FROM points) sq
 GROUP BY cluster_id;

请注意,这不会产生与缓冲区优先方法完全相同的结果,因为PostGIS缓冲区不是完美的圆,并且两个500m缓冲区可能不会连接相距1000m的两个点。


似乎我们有类似的想法。我还没有测试过您的产品,但是我敢肯定它能正常工作,并且比我的产品更干净。
John Powell

似乎PostGIS 2.2.1不支持ST_ClusterDBSCAN。我已经安装了PostGIS 2.3.2,但是pgAdmin中的新postgis扩展仍然是2.2.1版本。
eclipsed_by_the_moon

0

根据此答案,您想在子查询中执行ST_DUMP。

像这样:

-- collect all buffers to a single multi-polygon feature
-- dissolve overlapping polygon geometries
CREATE TABLE public.pg_multibuffer AS SELECT
    row_number() over() AS gid,
    sub_qry.*
FROM (SELECT
    ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8))::geometry(MultiPolygon, /*SRID*/)) AS geom
FROM
public.multipoints)
AS sub_qry;

原因是ST_UNION返回所有ST_DUMP要素的溶解多面体,并将其分解为单个的多边形要素(已溶解)。


1
这实际上将不起作用,因为将所需的多部分多边形聚类所需的任何属性都将丢失。
文斯

我试过ST_Multi((ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8)))).geom)::geometry(MultiPolygon, /*SRID*/) AS geom,但是这创造了4个功能而不是3
eclipsed_by_the_moon

哦,对,您要按数字分组吗?您需要先GROUP_BY进行操作ST_UNION
亚历克斯·里斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.