Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Communes limitrophes et intersection #716

Closed
jbdesbas opened this issue Aug 9, 2019 · 12 comments
Closed

Communes limitrophes et intersection #716

jbdesbas opened this issue Aug 9, 2019 · 12 comments

Comments

@jbdesbas
Copy link
Contributor

jbdesbas commented Aug 9, 2019

Salut,
Je viens de tomber sur un comportement un peu dérangeant mais logique :

quand une avec une géométrie communale est importée dans la synthèse, elle est référencée dans la table cor_area_synthese comme étant située sur la bonne commune + toutes les communes limitrophes. Ce qui est logique car, les géométries partagent bien une frontière commune.

Le patch immédiat que je vois serait de remplacer st_intersects(s.the_geom_local, a.geom) par
st_intersects(s.the_geom_local, a.geom) AND NOT st_touches(s.the_geom_local,a.geom). Après quelques tests rapides ca ne semble pas vraiment changer niveau performances. Vous en pensez quoi ?

Ou alors ont se dit que cela rejoint la discussion sur la saisie de données biblio #362 et/ou de rattachement de données géo #362 (comment) .

@camillemonchicourt
Copy link
Member

Oui en effet si la limite est exactement la même, il faudrait mieux pas inclure les zonages limitrophes.

@camillemonchicourt
Copy link
Member

Intégré dans la version 2.4.0 à venir car ce mécanisme est mieux en effet.
Mais à affiner ou revoir car @amandine-sahl a identifié le cas particulier où une observation est exactement sur une limite de zonage et où le zonage ne sera alors pas associé : #719 (comment)

Un SQL permet de nettoyer les données existantes (#719 (comment)) mais à utiliser avec vigilance car il peut supprimer les associations aux zonages des observations sans géométrie.

@camillemonchicourt
Copy link
Member

@joelclems a indiqué (#719 (comment)) que cette évolution est bien moins performante (jusqu'à 10 fois moins) alors que pour les points (la grande majorité des données) elle n'est pas forcément pertinente :

La fonction ST_TOUCHES est assez coûteuse par rapport a ST_INTERSECTS, et il n'y a pas vraiment sens de l'utiliser pour des points.

En assumant que le point est le type de géométrie le plus largement répandu dans les données, on peut gagner beaucoup de temps sur le trigger gn_synthese.fct_trig_insert_in_cor_area_synthese si on traite différemment :

  • les points (ST_INTERSECT seulement)
  • et les autres géométries (ST_INTERSECT et ST_TOUCHES)

Ça me semble en effet une bonne piste, car pour les points le ST_TOUCHES n'a pas grand intérêt.
Cependant le fait de tester en amont si l'objet est un point ou une ligne/polygone peut aussi ajouter de la complexité et du temps de traitement ?
D'autres avis ? @jbdesbas qui avait proposée cette solution de ST_TOUCHES ?
@amandine-sahl proposait aussi d'utiliser les matrices DE9-IM (#719 (comment)), voir https://postgis.net/workshops/postgis-intro/de9im.html

@jbrieuclp
Copy link
Contributor

En rapport à ces question d'intersection, je suis face à un cas "nouveau" lié à la possibilité de rattacher un objet de ref_geo.l_areas à une donnée.
Dans le cas d'une donnée localisée au département par exemple, les fonctions ST_INTERSECT et ST_TOUCHES vont matcher avec l'ensemble des communes du département. Du coup dans la synthèse lors de l'utilisation du filtre commune, les données localisée au département sortent comme résultat. Est-ce un comportement attendu ?
Si ce n'est pas le cas, il peut être nécessaire, dans le cas de polygone, de vérifier que la géométrie croisée ne soit pas totalement inclue dans la géométrie de la donnée (avec par exemple ST_INTERSECT et ST_TOUCHES et ST_Intersection <> geometrie_croisée)

@camillemonchicourt
Copy link
Member

Pas sur que cela fonctionne. Car si une observation est à cheval partiellement sur 2 communes alors elle ne plus associée à aucune des 2 communes ?

@jbdesbas
Copy link
Contributor Author

Le comportement est plutôt logique est bienvenu (car effectivement la commune est potentiellement concerné par cette obs départementale)
Dans Clicnat, ca avais été plutôt relou quand on à commencé à intégré des obs rattachés à des mailles 10x10.

La seule piste que je verrai serait un filtre permettant d'exclure les entités rattachées à certains type de areas .

@jbrieuclp
Copy link
Contributor

Voici ce que donnerait la vérification supplémentaire résultat_du_croisement <> geometrie_croisée (ST_Intersection <> geometrie_croisée).

g5296

Actuellement les 4 communes ressortent pour l'exemple 3 et 4.

@jbrieuclp
Copy link
Contributor

Le comportement est plutôt logique est bienvenu (car effectivement la commune est potentiellement concerné par cette obs départementale)

Pour le coup c'est bien le "potentiellement" qui nous pose problème. ;-)

Si on recherche les données présentes dans un département on est certain que les données localisées à la communes correspondent à la demande.
Si on recherche une données communale on est vraiment pas certain que la donnée localisée au département correspond à la demande. Potentiellement elle peut l'être, potentiellement elle ne l'est pas. Potentiellement nous pensons qu'il est préférable de les écarter du résultat.

@camillemonchicourt
Copy link
Member

Y en a marre des données floutées et dégradées qui nous font faire des trucs tordus et galères pour essayer d'en faire à peu prêt quelque chose 😭

@jbdesbas
Copy link
Contributor Author

jbdesbas commented Oct 30, 2020

Si on veut rester carrés, le 2ème cas que tu présentes ne devrait verdir aucune commune, car là encore on est sur une présence potentielle, mais pas certaine, dans chaque commune. De manière plus pragmatique, je comprend tout à fait la logique de verdir les communes dans le cas 2 et pas le cas 3. Sauf que la cas 4 risque d'être assez fréquent si on considère d'autres types de polygones que les communes (Znieff par exemple, ou réserves, etc...).

Même si arbitraire, pourquoi ne pas instaurer une règle du type : si le polygone inventoriel a une superficie plus de X (2 ?) fois plus importante que le polygone area, alors le area ne sera jamais verdit. (ce qui devrait régler le cas 4). Ca me parait raisonnable de considérer qu'au delà de 2 fois la taille, l'incertitude de présence est trop importante pour considéré que l'espèce est présente sur la commune. Coté technique, le filtre sur la surface ne devrait pas être trop coûteux (surtout si la surface est pré-calculé).

Il me semble indispensable de séparer les polygones inventoriels et stationnels dans cette réflexion. Le stationnel devant verdir tout polygone qu'il intersecte.
De plus le problème ne concerne pas que des données dégradés, mais également des données imprécise dès la production (données de gestionnaires de sites ou de bureau d'étude, localisés au niveau du site d'étude).

Enfin, en prenant un peu de recul, je ne sais pas si ces questions doivent être traité au niveau de la synthèse ?

@TheoLechemia
Copy link
Member

TheoLechemia commented Nov 26, 2020

Le trigger a été légèrement revu pour ne faire la fonction st_touches() seulement pour les géométries qui ne sont pas des points. Le trigger a également été passé en on "each statement", c'est à dire que la fonction est lancée une seule fois à la fin de la transaction (mais ce point ne semble pas faire gagner beaucoup en performance)

CREATE OR REPLACE FUNCTION gn_synthese.fct_trig_insert_in_cor_area_synthese_on_each_statement()
  RETURNS trigger AS
$BODY$
  DECLARE
  BEGIN
  -- Intersection avec toutes les areas et écriture dans cor_area_synthese
      INSERT INTO gn_synthese.cor_area_synthese 
        SELECT
          updated_rows.id_synthese AS id_synthese,
          a.id_area AS id_area
        FROM NEW as updated_rows
        JOIN ref_geo.l_areas a
          ON public.ST_INTERSECTS(updated_rows.the_geom_local, a.geom)  
        WHERE a.enable IS TRUE AND (ST_GeometryType(updated_rows.the_geom_local) = 'ST_Point' OR NOT public.ST_TOUCHES(updated_rows.the_geom_local,a.geom));
  RETURN NULL;
  END;
  $BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

Petite analyse de performance:

-- sans trigger
-- 1000: 541ms
-- 10 000: 4s
-- 100 000: 47s

-- trigger area on each row initial (st_touches sur toutes les geom)
-- 1000: 2s
-- 10 000: 22s
-- 100 000: 3m34s

--trigger area on each statement (st_touches sur toutes les geom)
--- 1000: 2s
--- 10 000: 20s
-- 100 000: 3m30

-- triger area on each statement optimisé (st_touches seulement sur les geom non ponctuelles)
-- 1000: 826ms
-- 10 000: 9s
-- 100 000: 1m11s

@camillemonchicourt
Copy link
Member

Intersections optimisées dans la 2.6.0, en repassant les points en st_intersect()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants