Skip to content

Use ST_MakeValid with method=structure instead of ST_Buffer with radius 0#306

Merged
olt merged 1 commit into
omniscale:masterfrom
andreasjunghans:fix-validated-geometry
Sep 29, 2025
Merged

Use ST_MakeValid with method=structure instead of ST_Buffer with radius 0#306
olt merged 1 commit into
omniscale:masterfrom
andreasjunghans:fix-validated-geometry

Conversation

@andreasjunghans
Copy link
Copy Markdown
Contributor

This PR fixes a problem we faced when generalizing this polygon: https://www.openstreetmap.org/relation/13319209. At one point, the following error occurred:

SQL Error: pq: GEOSBuffer: TopologyException: unable to assign hole to a shell in query CREATE TABLE "import"."osm_landcover_polygon_gen6" AS (SELECT "osm_id",
ST_Buffer(ST_SimplifyPreserveTopology("geometry", 611.496226), 0)::Geometry as "geometry",
"landuse",
"leisure",
"natural",
"wetland",
"area",
"webmerc_area" FROM "import"."osm_landcover_polygon_gen5" WHERE area>power(2445.984905125641,2))

The root cause is a problem in ST_SimplifyPreserveTopology which leaves a hole outside the outer shell, and ST_Buffer can't handle it (at least using GEOS 3.12.1 that came with PostGIS 3.4 in our installation).

Since GEOS 3.10 / PostGIS 3.2, the recommended approach to repair polygons is ST_MakeValid with method=structure (see PostGIS docs and also this post: https://www.crunchydata.com/blog/waiting-for-postgis-3.2-st_makevalid). This should yield the same results as an ST_Buffer with 0 radius, but in a more robust way. For this PR, I replaced the use of ST_Buffer accordingly, and the generalization now works for us.

An alternative approach for older versions would be to call ST_MakeValid (without the additional parameter) after ST_SimplifyPreserveTopology. This seems to get rid of "outer holes", and the result can be used as input for ST_Buffer (to fix the remaining problems that a simple ST_MakeValid can't handle). We could even add a version check to use different calls depending on the GEOS version, but that seems like overkill? PostGIS 3.2 was released in 2021, and looking at Ubuntu as an example, it's part of the main packages since 22.04 LTS. So simply replacing ST_Buffer should be fine nowadays?

@andreasjunghans
Copy link
Copy Markdown
Contributor Author

The failures with PostGIS < 3.2 are expected (see explanation above). I couldn't find mention of a minimum PostGIS version in the docs, but I guess now I know 🙂

Could the minimum version be increased? Otherwise, including a GEOS version check inside the SQL fragment would probably be the best solution.

@olt olt merged commit 2a6b586 into omniscale:master Sep 29, 2025
3 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants