Message posté par : neskuik01
----------------------------------------
-----------------
Nicolas Ribot écrit :
Bonjour,
Dans votre cas, de ce que je comprends, il vous faut identifier les enfants de chaque
tronçon, puis faire la somme des valeurs portées par ces enfants pour avoir un cumul des
valeurs amont pour chaque tronçon du graphe.
Je vous conseille de travailler avec des linestring pour votre réseau, et non pas des
multilinestrings avec 1 élément.
Je vois également dans le dataset qu'il y a des doublons géométriques dans votre
réseau: c'est pas pratique en terme de traitement: vous pouvez soit virer les doublons
et ne garder qu'un segment (a vous de choisir lequel), soit garder un seul segment
géométrique et faire la somme des valeurs des segments identiques.
Enfin, dans le dataset fourni, quasiment toutes les valeurs v19 sont à 0, ce qui ne permet
pas de calculer des valeurs en aval: dans mon exemple, je change v19 pour contenir la
longueur du segment concerné comme valeur.
Le WITH RECURSIVE est pratique pour trouver les enfants de chaque tronçon. Mais à chaque
itération, s'il y a plusieurs segments connectés au segment courant, on cumule trop
d'info et la somme des valeurs est fausse.
Vous pouvez alors utiliser la récursion pour trouver les enfants, puis ensuite
"nettoyer" le résultat pour virer les doublons et bien avoir, pour chaque
segment, la liste des enfants sans doublons. Vous pouvez ensuite faire la somme des
valeurs des enfants + segment courant.
En SQL:
"'nettoyage" et conversion en LINESTRING simples
-----------------
Code :
alter table data_subset rename column wkb_geometry to geom;
alter table data_subset alter column geom type geometry(LINESTRING, 2972) using
st_geometryn(geom, 1);
-----------------
On vire les doublons géometriques en ne gardant qu'une entrée: ici, vous pouvez aussi
cumuler les valeurs pour les segments superposés, au lieu de ne prendre qu'une valeur
de segment, au pif.
Avec array_agg, on peut cumuler les id des segments superposés et virer le premier element
du tableau: restent alors les id des segments qu'on veut virer;
-----------------
Code :
with tmp as (
select unnest((array_agg(ogc_fid))[2:]) as ogc_fid
from data_subset
group by id_bdcarth
) delete from data_subset d
using tmp t
where d.ogc_fid = t.ogc_fid;
-----------------
pas de valeurs pertinentes dans v19: on maj avec une valeur fictive: la longueur de chaque
segment
-----------------
Code :
alter table data_subset alter column v19 type float;
update data_subset set v19 = round(st_length(geom)::numeric, 1)::float;
-----------------
Pour trouver les segments de départ, on cherche les segments dont le startpoint n'est
pas connecté à un autre segment => un seul point dans le group start/end point:
-----------------
Code :
select (array_agg(ogc_fid))[1] as ogc_fid,
1::int as iter,
(array_agg(v19))[1] as v19,
(array_agg(st_endpoint(geom)))[1] as geom
from data_subset
group by unnest(ARRAY[st_startpoint(geom), st_endpoint(geom)])
having count(*) = 1;
-----------------
pour ne pas cumuler les valeurs du segments courant, s'il y a plusieurs enfants, on
peut extraire les enfants de chaque segments:
et calculer les ids uniques des enfants pour chaque segment:
ca permettra de faire la somme des valeurs qu'on veut:
Comme attributs, on veut surtout la valeur du segment courant, la liste des ogc_fid de ses
enfants, et le endpoint du segment courant qui permet de trouver le segment connecté.
Ici je fais la recherche du voisin connecté avec postgis: si le réseau est orienté, le
endpoint d'un enfant est connecté au startpoint de son parent.
Une fois la recursion faite, il suffit de fabriquer le tableau des identifiants des
enfants (le tableau complet calculé dans la récursion, moins le premier élément qui est
l'id du segment courant (donc pas un enfant)
On peut alors construire le tableau des id uniques des enfants pour chaque segment.
Une jointure finale permet de calculer la somme des valeurs des enfants d'un segment
et d'ajouter la valeur du segment courant (ou pas, suivant votre contexte)
-----------------
Code :
with recursive toto as (
select (array_agg(ogc_fid))[1] as ogc_fid,
(array_agg(v19))[1] as v19,
1::int as iter,
array_agg(ogc_fid) as fids,
(array_agg(st_endpoint(geom)))[1] as geom
from data_subset
group by unnest(ARRAY[st_startpoint(geom), st_endpoint(geom)])
having count(*) = 1
UNION ALL
select d.ogc_fid,
d.v19,
iter+1,
t.fids || d.ogc_fid,
st_endpoint(d.geom)
from data_subset d join toto t on st_dwithin(t.geom, st_startpoint(d.geom), 0.001)
), tmp as (
select ogc_fid, v19, unnest(fids[1:cardinality(fids) - 1]) as childs
from toto
), tmp1 as (
select t.ogc_fid, t.v19, array_agg(distinct childs) as childs
from tmp t
group by t.ogc_fid, t.v19
) select t.ogc_fid, t.v19 + sum(d.v19) as vals, dd.geom
from tmp1 t join data_subset d on d.ogc_fid = any(t.childs)
join data_subset dd on t.ogc_fid = dd.ogc_fid
group by t.ogc_fid, t.v19, dd.geom;
-----------------
Nicolas
-----------------
Je rebondis juste sur cette partie :
-----------------
Citation :
Enfin, dans le dataset fourni, quasiment toutes les valeurs v19 sont à 0, ce qui ne permet
pas de calculer des valeurs en aval: dans mon exemple, je change v19 pour contenir la
longueur du segment concerné comme valeur.
-----------------
si je comprend bien je dois remplacer mes valeurs ? (en gros 1 /0 c'était un peu
équivalent à vrai / faux pour la présence d'un phénomène)
----------------------------------------
Le message est situé
https://georezo.net/forum/viewtopic.php?pid=346678#p346678
Pour y répondre : geobd(a)ml.georezo.net ou reply de votre messagerie
Pour vous désabonner connectez-vous sur le forum puis Profil / Abonnement
--
Association GeoRezo - le portail géomatique
https://georezo.net