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

Rencontres QGIS 2025

L'appel à participation est ouvert jusqu'au 19 janvier 2025!

#1 Thu 20 February 2014 12:29

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3941

Trigger avec st_contains et sommets différents

Bonjour,
J'ai une fonction trigger before que j'utilise pour récupérer sur des entités le numéro de la parcelle qui est en dessous. Généralement, (sous QGIS) on copie-colle la parcelle et on en modifie la géométrie si besoin est (jamais en allant au-delà des limites de la parcelle). voici le bout de code qui m'interpelle

Code:

CREATE OR REPLACE FUNCTION foncier.insert_site()
  RETURNS trigger AS
$BODY$BEGIN
    if new.num_parcelle is null or new.num_parcelle='' then
        select into new.num_parcelle id_par from cadastre.parcelle 
        where  st_contains(geom, new.geom) 
    end if;    
    return new;    
END;
 $BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

Or, je constate un comportement bizarre qui me fait m'interroger sur la pertinence de la fonction st_contains dans le cas présent.
Lorsqu'on modifie (sous QGIS) la géométrie de la nouvelle entité et que ses sommets correspondent toujours à celle de la parcelle ou que ses sommets sont clairement à l'intérieur de la parcelle, ça marche. Par contre, si on crée un seul nouveau sommet sur un des segments de la parcelle, là, le trigger ne fonctionne pas.
Quand je lis dans la doc de PostGIS

ST_Contains — Returns true if and only if no points of B lie in the exterior of A, and at least one point of the interior of B lies in the interior of A


, je me demande quelle est la place de la frontière dans ce cas? Le nouveau sommet de mon entité est-il considéré à l'intérieur ou à l'extérieur de la parcelle? Et quelle(s) fonction(s) semblent donc plus appropriée(s) à ma requête?

Une autre question que je souhaiterais éclaircir, si possible: quelle est la différence (performance, traitements effectués ...) entre st_contains(geomA,geomB) et le couple geomA && geomB and _st_contains(geomA,geomB) ?

Merci par avance,
Santanna

Hors ligne

 

#2 Thu 20 February 2014 13:51

VianneyD
Participant assidu
Date d'inscription: 30 May 2011
Messages: 153

Re: Trigger avec st_contains et sommets différents

Bonjour,

En regardant de plus près l'exemple donné dans la doc, on lit que ST_Contains(geomA, ST_Boundary(geomA)) renvoie false, j'aurais donc tendance à penser que la frontière est considérée comme non contenue dans la géométrie.

Ca a l'air d'être une subtile différence avec ST_Covers et ST_Within... Peut-être auras-tu plus de succès avec l'une de ces dernières...


Vianney Dugrain

Hors ligne

 

#3 Thu 20 February 2014 15:29

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3941

Re: Trigger avec st_contains et sommets différents

Merci Vianney de te pencher sur la question

Il me semble que ST_WITHIN n'est que l'écriture inversée de ST_CONTAINS

ST_Contains is the inverse of ST_Within. So ST_Contains(A,B) implies ST_Within(B,A)


En lisant plus en détails la page ST_COVERS et l'article qui renvoie sur la page des subtilités de compréhension et d'usage de ces différentes fonctions (lien d'ailleurs présent sur la page de chacune de ces fonctions et que je n'avais encore jamais vu),  COVERS devrait faire l'affaire. Et effectivement, les premiers tests semblent concluants.

MERCI ENCORE....

Hors ligne

 

#4 Thu 20 February 2014 15:32

Cornet Jérémie
Participant assidu
Lieu: Nouméa
Date d'inscription: 6 Apr 2008
Messages: 229

Re: Trigger avec st_contains et sommets différents

Je confirme ce que dit Vianney :
ST_CONTAINS c'est entièrement contenu (y compris pas de bordure commune donc de sommets communs) alors que ST_COVERS autorise la bordure.

Pour  la différence "st_contains(geomA,geomB) et le couple geomA && geomB and _st_contains(geomA,geomB)", les 2 cas doivent être autant rapide (différence infime).

Toutes les fonctions st_ font le préfiltrage d'index alors que les anciennes fonctions (sans st_) ne le faisaient pas et que les _st_ ne le font pas non plus.

Dernière modification par Cornet Jérémie (Thu 20 February 2014 15:36)

Hors ligne

 

#5 Thu 20 February 2014 16:00

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

Re: Trigger avec st_contains et sommets différents

Bonjour,

Si le point de la nouvelle parcelle est exactement sur la frontiere de l'ancienne frontiere, st_contains doit renvoyer vrai:

Code:

select st_contains (
    'POLYGON((0 0, 3 0, 3 3, 0 3, 0 0))'::geometry,
    'POLYGON((2 0, 2.5 2, 1.5 2, 2 0))'::geometry
);

A la precision près, le point est peut etre considéré comme légèrement en dehors.
st_snapToGrid peut aider a résoudre le problème, surement:
J'ai fait un test en numerisant deux polygones, le deuxieme ayant un point sur la frontiere du premier (fonction snapping de mon outil):
Le test renvoie faux (contains(a, b))
Si je rajoute st_snapToGrid(geom, 0.00000001), le test renvoie vrai.

Nicolas

Hors ligne

 

#6 Thu 20 February 2014 16:04

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

Re: Trigger avec st_contains et sommets différents

Cornet Jérémie a écrit:

Je confirme ce que dit Vianney :
ST_CONTAINS c'est entièrement contenu (y compris pas de bordure commune donc de sommets communs) alors que ST_COVERS autorise la bordure.


Non: la définition est:
Geometry A contains Geometry B if and only if no points of B lie in the exterior of A, and at least one point of the interior of B lies in the interior of A.

La géométrie contenue peut donc avoir des sommets communs avec la frontières de la geométrie contenante. Contains renvoie faux qd toute la frontiere du contenu est confondue avec celle du contenant.
D'ou le fait qu'un polygone ne contiennent pas sa frontiere, mais se contient lui-meme hmm


Pour  la différence "st_contains(geomA,geomB) et le couple geomA && geomB and _st_contains(geomA,geomB)", les 2 cas doivent être autant rapide (différence infime).

Toutes les fonctions st_ font le préfiltrage d'index alors que les anciennes fonctions (sans st_) ne le faisaient pas et que les _st_ ne le font pas non plus.

Hors ligne

 

#7 Fri 21 February 2014 10:25

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3941

Re: Trigger avec st_contains et sommets différents

Bonjour à tous,
et merci pour ces échanges.

Nicolas, j'ignore si c'est du fait des balises mais je ne comprends pas et ne suis pas d'accord quand tu écris

Contains renvoie faux qd toute la frontiere du contenu est confondue avec celle du contenant.
D'ou le fait qu'un polygone ne contiennent pas sa frontiere, mais se contient lui-meme


Lorsque je duplique une entité, si le polygone se contient lui-même, ça doit pouvoir dire qu'il contient sa copie, alors même que toute la frontière de sa copie est confondue avec la sienne.
Et ça, ça n'a jamais posé de problème dans mon cas; le trigger st_contains retournait vrai et récupérait l'info. De même, lorsque la frontière du contenu était une partie de celle du contenant (sommets identiques sur la frontière).
Par contre, c'est quand

La géométrie contenue [a] des sommets communs avec la frontière de la geométrie contenante


et que ces sommets ne sont pas des sommets de la géométrie contenante que st_contains renvoyait faux. Ce que st_covers semble gérer.

Pour ceuqx que ça intéresse, ci-après le lien que j'évoquais plus haut et qui parle de ces subtilités http://lin-ear-th-inking.blogspot.fr/20 … atial.html

Hors ligne

 

#8 Fri 21 February 2014 12:04

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

Re: Trigger avec st_contains et sommets différents

Bonjour,

Oui, ma phrase sur la frontiere n'est pas claire et prete a confusion: qd je parle de frontière d'un polygone, il s'agit de la linestring qui compose la frontiere.
Je vais essayer d'etre un peu plus clair, avec des exemples simples (a noter que les définitions topologiques des fonctions définies par l'OGC sont parfois contre intuitives, mais décrivent toujours toutes les combinaisons entre intérieurs, exterieur et frontieres des objets:

Soit un polygone simple: POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))

Il se contient lui-meme ?

Code:

nicolas=# select st_contains (
nicolas(#     'POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry,
nicolas(#     'POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry
nicolas(# );
 st_contains 
-------------
 t
(1 ligne)

Contient-il sa frontiere ?

Code:

nicolas=# select st_contains (
nicolas(#     'POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry,
nicolas(#     st_boundary('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry)
nicolas(# );
 st_contains 
-------------
 f
(1 ligne)

C'est en ce sens que ce n'est pas intuitif: un polygone peut contenir un autre polygone, mais ne contient pas une "partie" de ce polygone qui est sa frontiere.

St_contains renvoie également vrai si un ou plusieurs sommets du polygone contenu sont sur la frontière du polygone contenant:

Code:

select st_contains (
    'POLYGON((0 0, 3 0, 3 3, 0 3, 0 0))'::geometry,
    'POLYGON((2 0, 2.5 2, 1.5 2, 2 0))'::geometry
);
 st_contains 
-------------
 t
(1 ligne)

Dans cet exemple, les deux polygones partagent des points sur leur frontiere et st_contains renvoie vrai.

st_covers, opérateur non défini par l'OGC, a ete introduit pour permettre de répondre vrai aux deux cas précédents: Il y a souvent des process géomatiques dans lesquels les objets sont décomposés en leurs frontière et intérieur, et st_contains pose donc des pb dans ces cas.

Code:

select st_covers (
    'POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry,
    'POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry
);
 st_covers 
-----------
 t
(1 ligne)

select st_covers (
    'POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry,
    st_boundary('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'::geometry)
);
 st_covers 
-----------
 t
(1 ligne)

Dans votre cas de numérisation, le problème vient, a mon sens, de problèmes de précision: le point numérisé "sur la frontière" de l'autre polygone n'est pas sur la frontière, a la précision prés: contains renvoie faux.
Ces problèmes de précisions peuvent etre particulièrement piégeux (cf forum postgis users): il y a des cas ou st_distance(point, ligne) renvoie 0: le point est donc sur la ligne, mais st_contains ou st_within utilisé avec les memes géométries renverra faux. Postgis n'est pas robuste dans tous les cas, d'ou souvent le conseil de travailler en coordonnées entières ou d'utiliser st_snapToGrid pour eviter ces pb d'arrondis.

Si je reprends votre phrase:

Par contre, c'est quand La géométrie contenue [a] des sommets communs avec la frontière de la geométrie contenante
et que ces sommets ne sont pas des sommets de la géométrie contenante que st_contains renvoyait faux.


Non ! D'abord parce qu'il n'y a pas, dans Postgis, la notion de "ces sommets ne sont pas des sommets de la géométrie contenante": Pour postgis, il n'y a que des points communs entre géométries, que ce soit les memes points (des sommets), ou un sommet et un point sur un segment.
Le probleme vient du fait que quand postgis calcule la coordonnée commune entre deux objets, il peut y avoir des erreurs d'arrondis qui font que le résultat de la fonction est faux.

Ce que st_covers semble gérer.


Pas plus que st_contains: pour des polygones, st_contains et st_covers renverront tjs le meme résultat... aux erreurs d'arrondi près: les algorithmes étant différents, une des deux fonctions peut "planter" alors que l'autre marchera, pour les meme geometries.

Pour résumer, dans votre cas de numérisation:
Vous travaillez avec des polygones et vous voulez controler que le nouveau polygone est bien contenu dans le polygone d'origine: st_contains et st_covers renverront vrai.
Vous trouvez des résultats curieux avec l'une ou l'autre des fonctions: il faut controler la précision des données.
Et enfin, les algorithmes étant différents entre les deux fonctions, une est peut etre plus "robuste" que l'autre et sera moins sensible aux erreurs d'arrondis, mais il ne faut pas compter sur ce comportement dans votre application.

Nicolas

Hors ligne

 

#9 Mon 24 February 2014 11:39

SANTANNA
Moderateur
Lieu: Angers
Date d'inscription: 18 Jan 2008
Messages: 3941

Re: Trigger avec st_contains et sommets différents

Bonjour,
Merci pour toutes ces précisions, Nicolas.
Je vais voir comment intégrer st_snapToGrid dans ma fonction de récupération pour consolider un peu tout ceci. A première vue, je vais surement revenir poser des questions sur cette fonction mais bon... je vais chercher de mon côté avant.

PS: Si ce n'est pas indiscret, comment fait-on pour connaître autant de choses que toi sur le fonctionnement de PostgreSQL/PostGIS smile ?

Hors ligne

 

#10 Mon 24 February 2014 12:38

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

Re: Trigger avec st_contains et sommets différents

Bonjour,

Avec OpenJump, j'ai observé le meme probleme que vous: un polygone de départ (pg1), je numérise un polygone a l'intérieur (pg2), avec des sommets qui se trouvent sur le bord de pg1 grâce à l'option de snapping des points:

st_contains(pg1, pg2) renvoie faux.

Avec st_contains(pg1, st_snapToGrid(pg2, 0.00000001)) j'obtiens vrai.

Un petit arrondi sur les coordonnées pour éviter le problème de précision des calculs.

PS: no life... big_smile

Hors ligne

 

Pied de page des forums

Powered by FluxBB