Nous utilisons des cookies pour vous garantir la meilleure expérience sur notre site. Si vous continuez à utiliser ce dernier, nous considèrerons que vous acceptez l'utilisation des cookies. J'ai compris ! ou En savoir plus !.
banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

Annonce

Printemps des cartes 2024

#1 Sun 29 March 2020 22:16

preliator
Participant assidu
Date d'inscription: 17 Nov 2018
Messages: 433

[PostGis] Créer des centroides (couche bâtis de OSM)

Bonjour à tous,

Je travaille actuellement sur des polygones représentant les maisons dans un département (plus de 100 000 entités) . Cette donnée provient d'Open Street Map.
Dans cette couche de polygones, je voudrais créer un champ qui indique la distance minimale au plus proche voisin, pour faire une étude sur l'isolement des maisons. Pour cet exercice, je pensais me baser sur les centroides des polygones.

Malheureusement (ou heureusement !), cette couche de bâtiment est très précise et de nombreux bâtiments sont découpés en plusieurs polygones. De ce fait, je me retrouve avec plusieurs centroides pour un seul même bâtiment, ce qui biaise mes calculs.

Comme par exemple, sur cette image : https://zupimages.net/viewer.php?id=20/13/tg4m.png


Je me demandais donc s'il existait un moyen, sur PostGis, de créer UN seul centroide pour ces bâtiments qui se touchent, ou alors s'il existait un outil sur QGis pour regrouper ces polygones qui se touchent en une seule entité.

Merci.

Dernière modification par preliator (Sun 29 March 2020 22:22)

Hors ligne

 

#2 Mon 30 March 2020 11:07

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1536

Re: [PostGis] Créer des centroides (couche bâtis de OSM)

Bonjour,

Pkoi calculer des centroids pour avoir la distance entre objets ?
Ca sera faux dans certains cas (batiments en U, batiment avec cour, etc. (le centroid ne tombant pas dans le pg pour ces cas. IL faut mieux prendre st_pointOnSurface pour cela)

Calculez directement la distance la plus proche, elle sera 0 si le batiment en touche un autre ! (utilisez l'operateur distance KNN <-> pour cela, et surtout pas st_distance(geom, geom), qui prendrait un temps fou.

Sinon, pour regrouper des objets qui se touchent, plusieurs facons:
st_union(geom) => tous les objets qui se touchent seront unis en un seul objet, ou plus rapide:
st_clusterINtersecting: ca renvoie un tableau de geometryCollection contenant tous les objets qui se touchent, st_UnaryUnion pour avoir l'union de ces objets.

Mais dans le cas que vous décrivez, ca me parait inutile.

Nicolas

Hors ligne

 

#3 Mon 30 March 2020 15:26

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1536

Re: [PostGis] Créer des centroides (couche bâtis de OSM)

Un exemple de SQL pour
  regrouper les objets qui se touchent (st_clusterIntersecting),
  en faire un polygone unique (st_unaryUnion),
  croiser cette couche avec elle même pour trouver le plus proche voisin (t.geom <-> t2.geom),
  croiser avec les batiments pour faire un lien entre chaque cluster de batiments et les batiments qui le composent (array_agg(id),
  fabriquer une geom qui est la plus petite distance entre deux clusters de batiments (st_shortestLine) :

Image: https://zupimages.net/viewer.php?id=20/14/095n.png

En rose: cluster, id du cluster (générée avec WITH ORDINALITY), en gris, id des batiments, en vert: distance mini entre les objets (en m)

Code:

with tmp as (
    select st_clusterintersecting(geom) as arr
    from batiment
), tmp1 as (
    select u.ordinality as idcluster, u as geom
    from tmp, unnest(tmp.arr) with ordinality as u
), tmp2 as (
    select t.idcluster, t2.idcluster as idcluster2, t2.dist, st_unaryunion(t.geom) as geom, t2.geom as geom2
    from tmp1 t
             cross join lateral (
        select b.idcluster, b.geom <-> t.geom as dist, b.geom
        from tmp1 b
        where b.idcluster != t.idcluster
        order by b.geom <-> t.geom
        limit 1
        ) as t2
) select t.idcluster, t.idcluster2, dist, array_agg(b.id) as id_batiments,
         st_shortestline(t.geom, t.geom2) as geomline
from tmp2 t join batiment b on st_contains(t.geom, st_pointonsurface(b.geom))
group by 1,2,3,5; 


idcluster    idcluster2    dist    id_batiments
1           3            49.8    {1}
2           3            97.2    {2}
3           1            49.8    {3,4,5,6,7,8}
4           2            176.    {9}
5           6            78.3    {10,13}
6           7            41.7    {11}
7           6            41.7    {12}
8           1            99.1    {14}
9           8            100.    {15}

Avec une vraie grosse table de batiments, il faut passer par des tables intermédiaires et créer des index spatiaux qui vont bien (geom, st_pointOnSurface(geom), ...) pour optimiser la requête.

Nico

Dernière modification par Nicolas Ribot (Wed 01 April 2020 10:01)

Hors ligne

 

#4 Tue 31 March 2020 21:52

preliator
Participant assidu
Date d'inscription: 17 Nov 2018
Messages: 433

Re: [PostGis] Créer des centroides (couche bâtis de OSM)

Je vous dis un grand merci pour votre réponse smile cela résout mon problème en plus de m'apporter de nouveaux outils à apprendre !

Hors ligne

 

Pied de page des forums

Powered by FluxBB