Créer un tampon dissous à partir de plusieurs géométries (union par attribut partagé et intersection spatiale)


10

Je dois créer des tampons dissous à partir de fonctionnalités d'entrée multipoints. Dans l'exemple ci-dessous, le tableau d'entrée contient 4 fonctionnalités. La fonction se #2compose de deux géométries de points. Après avoir créé un tampon, j'obtiens 4 géométries de polygone:

entrez la description de l'image ici

Existe-t-il un moyen de regrouper le résultat? Les tampons des points #1et #2sont dissous et doivent être une seule entité multi-polygone ( a).

Ce que j'ai fait jusqu'à présent:

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

ÉDITER:

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

Vous utilisez trop de sous-requêtes. Cela élimine votre capacité à GROUP BY sur l'attribut sur lequel vous souhaitez regrouper.
Vince

Vous devez donc effectuer une union spatiale, puis également une union basée sur le numéro d'entité, c'est pourquoi vous vous attendez à 3 multipolygones dans le diagramme ci-dessus. Je soupçonne que cela nécessitera un processus en deux étapes, mais je voulais juste être clair sur la question, avant d'offrir une réponse.
John Powell

Oui, je veux réunir les polygones tampons et collecter le résultat en fonction du nombre d'entités en entrée.
eclipsed_by_the_moon

Une mise à jour pour ceci? Je voudrais savoir si cela fonctionne pour vous, pour autant que je sache, j'ai répondu à la question.
John Powell

Désolé pour la réponse tardive, je ne suis pas en ligne depuis quelques jours.
eclipsed_by_the_moon

Réponses:


7

En commençant par quelques points aléatoires, dans un attept pour imiter ceux de l'image de l'OP, où les deux premiers se croisent spatialement, puis les 2ème et 3ème ont le même attribut id (2), avec quelques autres points qui ne se croisent pas spatialement ni n'ont le même attribut, la requête suivante produit 3 clusters:

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;

Il y a plusieurs étapes ici:

  1. utiliser ST_Union, regroupement par id, au premier groupe par attribut
  2. utiliser ST_ClusterIntersectingpour combiner ceux du même groupe qui se croisent spatialement
  3. ajouter un identifiant à chacun des clusters (table multis) - en essayant de le faire directement dans ClusterIntersecting, toutes les géométries obtiennent un identifiant de 1
  4. Union des géométries sous-évaluées de l'étape 2, regroupées par l'ID de l'étape 3 - il s'agit de la partie de dissolution . Cela provoque les deux polygones qui se chevauchent dans votre cluster A, à se réunir, plutôt que de se chevaucher, comme ils le sont à la fin de l'étape 2.

Plutôt long, mais ça marche (et, je suis sûr qu'il y a un chemin plus court).

L'utilisation de l'outil WKT dans QGIS (et en découvrant à quel point je suis affreux avec les outils d'édition) produit des clusters comme celui-ci, où vous pouvez voir le cluster que vous étiquetez comme un, est tout ensemble - c'est-à-dire une couleur.

entrez la description de l'image ici

Si vous mettez un ST_AsText autour de la finale, ST_UNION (d.geom), vous pouvez voir les résultats directement.

EDIT suivant plus d'informations dans les commentaires: Comme vous commencez avec des points, vous devrez incorporer le tampon dans ma solution d'origine - que j'ai mis dans le CTE temporaire au début pour imiter votre diagramme. Il serait plus facile d'ajouter le tampon dans les unions CTE, donc vous pouvez faire toutes les géométries à la fois. Ainsi, en utilisant une distance tampon de 1000, par exemple, ce qui suit renvoie désormais 3 clusters, comme prévu.

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;

Désolé, il vous a fallu si longtemps pour vous répondre. J'ai du mal à visualiser les géométries de tampon dans QGIS. J'ai essayé de modifier votre requête en utilisant ST_SetSRID, ST_Multiet ::geometry(Multipolygon, /*SRID*/), mais pour le moment cela ne fonctionne pas.
eclipsed_by_the_moon

OK, si vous pouvez publier votre code et encore mieux certaines données, je pourrais peut-être vous aider.
John Powell

J'ai ajouté du SQL pour créer des exemples de points.
eclipsed_by_the_moon

Peu attaché aujourd'hui, je reviendrai dès que possible. Devra également travailler le multipoint dans la requête.
John Powell

3

Une façon de le faire est ST_Unionde rassembler tous les tampons, ST_Dumple résultat pour obtenir les composants du polygone résultant, et de rejoindre ST_Intersectsles points d'entrée pour découvrir combien / quels points constituaient chaque cluster.

Cela peut être fait sans exiger une jointure en regroupant les points avant d' appeler ST_Buffer. Pour que deux points soient situés dans le même tampon dissous, ils doivent être accessibles par sauts entre des points d'une distance inférieure à eps. Ceci est juste un problème de clustering de liaison minimale, qui peut être résolu en utilisant 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;

Notez que cela ne produira pas exactement le même résultat que la méthode tampon d'abord, car les tampons PostGIS ne sont pas des cercles parfaits et deux points distants de 1000 m peuvent ne pas être connectés par deux tampons de 500 m.


Il semble que nous ayons eu une idée similaire. Je n'ai pas testé le vôtre, mais je suis sûr qu'il fonctionne et plus proprement que le mien.
John Powell

Il semble que PostGIS 2.2.1 ne prend pas en charge ST_ClusterDBSCAN. J'ai installé PostGIS 2.3.2, mais les nouvelles extensions postgis dans pgAdmin sont toujours la version 2.2.1.
eclipsed_by_the_moon

0

Selon cette réponse, vous souhaitez effectuer ST_DUMP dans votre sous-requête.

Quelque chose comme ç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_Dump(ST_Union(ST_Buffer(geom, 1000, 8))::geometry(MultiPolygon, /*SRID*/)) AS geom
FROM
public.multipoints)
AS sub_qry;

La raison en est que cela ST_UNIONrenvoie un multipolygone dissous de toutes les entités, et le ST_DUMPdécompose en entités polygonales individuelles (qui ont été dissoutes).


1
Cela ne fonctionnera pas réellement, car tous les attributs qui seraient nécessaires pour regrouper le polygone multipartie souhaité auront été perdus.
Vince

J'ai essayé ST_Multi((ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8)))).geom)::geometry(MultiPolygon, /*SRID*/) AS geom, mais cela crée 4 fonctionnalités au lieu de 3.
eclipsed_by_the_moon

Oh, d'accord, vous voulez regrouper par numéro? Vous devrez le faire GROUP_BYavant vous ST_UNION.
Alex Leith
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.