Opened 35 hours ago

Last modified 8 hours ago

#5868 new defect

Add Function to Detect Valid Polygons with Point Touching Rings

Reported by: gravitystorm Owned by: pramsey
Priority: medium Milestone: PostGIS 3.5.3
Component: postgis Version: 3.4.x
Keywords: Cc: gravitystorm

Description (last modified by gravitystorm)

Certain functions are not implemented for valid polygons with point touching rings (see https://trac.osgeo.org/postgis/ticket/5867).

For some use-cases, it would be handy if there was a function that could be used to detect such polygons ahead of time, in order to handle them separately. I haven't been able to find any existing postgis function that does this, but if I've missed one please let me know.

With such a function, you could choose to ignore these polygons, e.g.

select CG_StraightSkeleton(geom)
  from table
 where !ST_ValidPolygonHasPointTouchingInnerRing(geom)

Alternatively, you could buffer only the geometries that have point touching rings, without buffering the vast majority that don't, e.g.

select CG_StraightSkeleton(
       case when ST_ValidPolygonHasPointTouchingInnerRing(geom)
       then st_buffer(geom, 0.0001)
       else geom
       end)
  from table

Change History (6)

comment:1 by gravitystorm, 34 hours ago

Cc: gravitystorm added

comment:2 by mdavis, 33 hours ago

Can you just use ST_IsValid? It will report false for self-touching rings.

There is also a flag on ST_IsValid which allows polygons with self-touching rings to be considered valid. You could combine this with the default ST_Valid to test whether a geometry is valid but with a self-touch (i.e. to identify geometries to be ignored or fixed):

SELECT (NOT ST_IsValid(geom)) AND ST_IsValid(geom, 1) AS is_valid_with_selftouch
FROM ST_GeomFromText('POLYGON ((5 9, 9 1, 1 1, 5 6, 3 2, 5 2, 5 9))') AS t(geom);


is_valid_with_selftouch
---------------------
t

comment:3 by mdavis, 33 hours ago

Have you considered using ST_MakeValid to fix this problem? It causes less change than buffering.

Last edited 33 hours ago by mdavis (previous) (diff)

comment:4 by gravitystorm, 11 hours ago

Thanks for looking into this mdavis, and I'm sorry I wasn't clear enough about the situation.

This issue is about valid polygons only, so st_isvalid and st_makevalid don't help. Specifically, this is not about polygons with self-touching rings, it's about polygons with an inner ring(s) that touch(es) the outer ring at one vertex (valid polygon example (i) in https://postgis.net/docs/manual-dev/using_postgis_dbmanagement.html#OGC_Validity ).

Despite being valid, these valid polygons throw an error with certain functions, see #5867

So we have two sub-groups of valid polygons:

  • Group A - valid polygons that work with GC_StraightSkeleton (and similar functions)
  • Group B - valid polygons that error with GC_StraightSkeleton (and similar functions)

An example of group A is POLYGON((0 0, 3 0, 3 3, 0 3, 0 0)) (a square)

An example of group B is POLYGON((0 0, 3 0, 3 3, 0 3, 0 0),(0 0, 1 2, 2 1, 0 0)) (a square with an inner ring that touches at one vertex, which despite being valid, still causes the error in those functions).

gis=# select st_straightskeleton(st_geomfromtext('POLYGON((0 0, 3 0, 3 3, 0 3, 0 0),(0 0, 1 2, 2 1, 0 0))'));
NOTICE:  During straight_skeleton(A) :
NOTICE:    with A: POLYGON((0/1 0/1,3/1 0/1,3/1 3/1,0/1 3/1,0/1 0/1),(0/1 0/1,1/1 2/1,2/1 1/1,0/1 0/1))
ERROR:  straight skeleton of Polygon with point touching rings is not implemented.

So I'm looking for a function that can detect Group B valid polygons, so that the function can be used to avoid triggering errors in GC_StraightSkeleton.

comment:5 by gravitystorm, 11 hours ago

Description: modified (diff)

comment:6 by mdavis, 8 hours ago

Thanks for the clarification.

One option is to make a SQL function to check whether the shell ring of a valid polygon and the inner hole rings intersect.

In fact, there is code in GEOS to transform polygons with touching holes into equivalent self-touching rings (AKA inverted/exverted rings). This currently isn't exposed, but it could be - either as a PostGIS function, or simply as a preprocessing step inside the affected CG functions.

Note: See TracTickets for help on using tickets.