ST_Intersectes avec LINESTRING dégénéré

9

J'ai, dans PostGIS, un tas d'objets LINESTRING Z (qui représentent des pôles), et je veux trouver ceux qui sont à l'intérieur d'une zone (représentée par un POLYGON). Dans le cadre de cet exercice, nous pouvons supposer en toute sécurité qu'un poteau est à peu près vertical, de sorte qu'il ne coupera pas la limite de la zone.

Le problème est que parfois le pôle est exactement vertical.

Cette requête, celle que j'aimerais faire, ne réussit pas:

SELECT ST_Intersects(ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356),
ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356));

En explorant quelques variantes, cela réussit:

SELECT ST_Intersects(ST_GeomFromText('POINT (544483.525 6849134.28)',28356),
ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356));

Cela ne réussit pas:

SELECT ST_Intersects(ST_GeomFromText('LINESTRING (544483.525 6849134.28,544483.525 6849134.28)',28356),
ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356));

Si vous effectuez une requête 3DIntersects, elle réussit:

SELECT ST_3DIntersects(ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356),
ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356));

cependant, il soulève un AVIS que:

One or both of the geometries is missing z-value. The unknown z-value will be regarded as "any value"

Donc cela fonctionne, en quelque sorte, mais cela remplit mes journaux de bruit et je préfère ne pas désactiver les avertissements.

Ma lecture du standard d'accès à la fonctionnalité OpenGIS Simple (voir partie 1, section 4.14) est que même si le LINESTRING est dégénéré, il doit toujours être interprété comme topologiquement fermé, donc ils doivent se croiser.

Est-ce correct?

ÉDITER

Après quelques expérimentations, je peux répondre à une partie de ma propre question. La raison pour laquelle les requêtes ci-dessus retournent false est la suivante, car la LINESTRING Z n'est pas considérée comme valide:

SELECT ST_IsValidReason(ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356));
                           st_isvalidreason                           
----------------------------------------------------------------------
 Too few points in geometry component[544483.525 6849134.28 104.1098]
(1 row)

C'est une façon polie de dire que OGC ne prend pas en charge la 3D, et en tant que tel, GDAL / PostGIS ne le prend en charge qu'en quelque sorte.

Je peux accepter cela, bien que je n'aie toujours rien trouvé dans la spécification OGC qui indique que la LINESTRING correspondante n'est pas valide.

Je suppose donc que ma question est vraiment: existe-t-il un moyen officiellement béni de trouver l'empreinte d'une pièce de géométrie 3D qui renvoie toujours une géométrie 2D valide?

Pseudonyme
la source

Réponses:

6

Un correctif très simple sur la première requête consiste à utiliser ST_MakeValid pour créer une géométrie "valide" pour retourner vrai:

SELECT ST_Intersects(ST_MakeValid(A), B), ST_AsText(ST_MakeValid(A)) AS ST_MakeValid
FROM (
  SELECT ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356) AS A,
         ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356) AS B
) AS d;

-[ RECORD 1 ]-+-----------------------------------------
st_intersects | t
st_makevalid  | POINT Z (544483.525 6849134.28 104.1098)

La requête d'origine a échoué car l'objet LineString n'était pas valide, comme découvert par ST_IsValid ou ST_IsValidReason . En effet, ST_Intersects est un opérateur 2D, de sorte que la géométrie a été forcée à deux dimensions LINESTRING(544483.525 6849134.28,544483.525 6849134.28), ce qui n'est pas valide.

ST_MakeValid supprime les coordonnées répétées (dans l'espace 2D) et les change en type de point car la géométrie résultante n'a qu'une seule coordonnée.

Vous pouvez voir que la coordonnée Z est partiellement encore là, mais elle est ignorée. Si cela vous dérange, vous pouvez également utiliser ST_Force2D pour n'utiliser que des géométries 2D pour des choses comme ST_Intersects:

SELECT ST_Intersects(ST_MakeValid(ST_Force2D(A)), B),
  ST_AsText(ST_Force2D(A)) AS ST_Force2D,
  ST_AsText(ST_MakeValid(ST_Force2D(A))) AS ST_MakeValid
FROM (
  SELECT ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356) AS A,
         ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356) AS B
) AS d;

-[ RECORD 1 ]-+--------------------------------------------------------
st_intersects | t
st_force2d    | LINESTRING(544483.525 6849134.28,544483.525 6849134.28)
st_makevalid  | POINT(544483.525 6849134.28)
Mike T
la source
Merci! C'était une bonne explication de ce qui se passe, et la solution de contournement est également bonne.
Pseudonyme