Crear búfer disuelto a partir de geometría múltiple (Unión por atributo compartido e intersección espacial)

10

Tengo que crear buffers disueltos a partir de características de entrada multipunto. En el siguiente ejemplo, la tabla de entrada contiene 4 características. La característica #2consta de dos geometrías de puntos. Después de crear un búfer, obtengo 4 geometrías de polígonos:

ingrese la descripción de la imagen aquí

¿Hay alguna forma de agrupar el resultado? Los búferes de los puntos #1y #2se disuelven y deben ser una sola característica de múltiples polígonos ( a).

Lo que he hecho hasta ahora:

-- 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;

EDITAR:

-- 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));
eclipsado_por_la_luna
fuente
Usas subconsultas demasiado. Esto elimina su capacidad de GROUP BY en el atributo en el que desea agrupar.
Vince
Por lo tanto, debe hacer una unión espacial y luego también una unión basada en el número de característica, por lo que espera 3 multipolígonos del diagrama anterior. Sospecho que esto requerirá un proceso de dos pasos, pero solo quería dejar en claro la pregunta, antes de ofrecer una respuesta.
John Powell
Sí, quiero unir los polígonos del búfer y recopilar el resultado en función del número de características de entrada.
eclipsed_by_the_moon
¿Algún avance en esto? Me gustaría saber si esto funciona para usted, por lo que puedo ver, he respondido la pregunta.
John Powell
Perdón por la respuesta tardía, no he estado en línea por un par de días.
eclipsed_by_the_moon

Respuestas:

7

Comenzando con algunos puntos aleatorios, en un intento de imitar aquellos en la imagen del OP, donde los dos primeros se cruzan espacialmente, luego el segundo y el tercero tienen el mismo id de atributo (2), con un par de otros puntos que ni se cruzan espacialmente ni tienen Con el mismo atributo, la siguiente consulta produce 3 grupos:

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;

Aquí hay varios pasos:

  1. uso ST_Union, agrupación por id, al primer grupo por atributo
  2. se usa ST_ClusterIntersectingpara combinar aquellos del mismo grupo que se cruzan espacialmente
  3. agregue una identificación a cada uno de los grupos (tabla multis): intente hacer esto directamente en ClusterIntersecting conduce a todas las geometrías obteniendo una identificación de 1
  4. Une las geometrías volcadas del paso 2, agrupando por la identificación del paso 3: esta es la parte de disolución . Esto hace que los dos polígonos superpuestos en su grupo A se unan, en lugar de superponerse, ya que se encuentran al final del paso 2.

Es bastante largo, pero funciona (y estoy seguro de que hay un camino más corto).

El uso de la herramienta WKT en QGIS (y descubrir lo horrible que soy con las herramientas de edición) produce grupos como el siguiente, donde puede ver que el grupo que está etiquetado como a, está todo junto, es decir, un color.

ingrese la descripción de la imagen aquí

Si coloca un ST_AsText alrededor de la final, ST_UNION (d.geom), puede ver los resultados directamente.

EDITE después de más información en los comentarios: a medida que comience con los puntos, deberá incorporar el búfer en mi solución original, que puse en el CTE temporal al principio para imitar su diagrama. Sería más fácil agregar el búfer en las uniones CTE, para que pueda hacer todas las geometrías a la vez. Entonces, usando una distancia de búfer de 1000, como ejemplo, lo siguiente ahora devuelve 3 grupos, como se esperaba.

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;
John Powell
fuente
Lo siento, tomó tanto tiempo volver a contactarte. Tengo algunos problemas para visualizar las geometrías del búfer en QGIS. He intentado modificar su consulta usando ST_SetSRID, ST_Multiy ::geometry(Multipolygon, /*SRID*/), pero por el momento no funciona.
eclipsed_by_the_moon
De acuerdo, si puede publicar su código, y aún mejor algunos datos, podría ayudarlo.
John Powell el
He agregado algunos SQL para crear puntos de muestra.
eclipsed_by_the_moon
Un poco atado hoy, volveré tan pronto como pueda. Tendrá que trabajar el multipunto en la consulta también.
John Powell el
3

Una forma de hacer esto es ST_Unionuniendo todos los búferes, ST_Dumpel resultado para obtener los componentes del polígono resultante, y unirse de ST_Intersectsnuevo a los puntos de entrada para descubrir cuántos / qué puntos formaron cada grupo.

Esto se puede hacer sin requerir una unión al agrupar los puntos antes de llamar ST_Buffer. Para que dos puntos se ubiquen dentro del mismo búfer disuelto, deben ser accesibles mediante saltos entre puntos de una distancia menor que eps. Este es solo un problema de agrupamiento de vinculación mínima, que se puede resolver usando 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;

Tenga en cuenta que esto no producirá exactamente el mismo resultado que el método de primero en el búfer, porque los búferes PostGIS no son círculos perfectos y dos puntos separados 1000 m pueden no estar conectados por dos búferes de 500 m.

dbaston
fuente
Parece que tuvimos una idea similar. No he probado el tuyo, pero estoy seguro de que funciona, y más limpiamente que el mío.
John Powell
Parece que PostGIS 2.2.1 no es compatible con ST_ClusterDBSCAN. He instalado PostGIS 2.3.2, pero las nuevas extensiones postgis en pgAdmin siguen siendo la versión 2.2.1.
eclipsed_by_the_moon
0

Según esta respuesta , desea hacer ST_DUMP dentro de su subconsulta.

Algo como esto:

-- 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;

La razón es que ST_UNIONdevuelve un multipolígono disuelto de todas las características, y lo ST_DUMPdivide en las características individuales del polígono (que se disolvieron).

Alex Leith
fuente
1
En realidad, esto no funcionará, porque se habrán perdido todos los atributos que serían necesarios para agrupar el polígono multiparte deseado.
Vince
Lo he intentado ST_Multi((ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8)))).geom)::geometry(MultiPolygon, /*SRID*/) AS geom, pero esto crea 4 funciones en lugar de 3.
eclipsed_by_the_moon
Oh, cierto, ¿quieres agrupar por el número? Tendrás que hacerlo GROUP_BYantes que tú ST_UNION.
Alex Leith