- Polygon rings must be simple; i.e. they may not touch or cross themselves
- MultiPolygon elements may not overlap or touch at more than a finite number of points (i.e they may not intersect along an edge)
This problem has limped along for many years now, never being quite enough of a pain point to motivate the effort needed to find a fix (or to fund one!). And to be honest, the buffer code is some of the most complicated and delicate in JTS, and I was concerned about wading into it to add what seemed poised to be a fiddly correction.
But recently there has been renewed interest in providing a Make-Valid capability for JTS. This inspired me to revisit the usage of buffer(0), and think more deeply about ring orientation and its role in determining valid polygonal topology. And this led to discovering a surprisingly simple solution for the buffer issue.
The fix is to use an orientation test which takes into account the entire ring. This is provided by the Signed-Area Orientation test, implemented in Orientation.isCCWArea using the Shoelace Formula. This effectively determines orientation based on the largest area enclosed by the ring. This corresponds more closely to user expectation based on visual assessment. It also minimizes the change in area and (usually) extent.
And indeed it works:
It fixes the simplification issue nicely:
The fix consists of about 4 lines of actual code. To paraphrase a great orator, never in the history of JTS has so much benefit been given to so many by so few lines of code. Now buffer(0) can be recommended unreservedly as an effective, performant way to fix polygonal geometry. And all those helpful documentation pages can drop any qualifications they might have.
As usual, this fix will soon show up in GEOS, and from there in PostGIS and other downstream projects.
This isn't the end of the story. There are times when the effect of buffer(0) is not what is desired for fixing polygon topology. This is discussed nicely in this blog post. The ongoing research into Make Valid will explore alternatives and how to provide an API for them.