locationtech / jts

The JTS Topology Suite is a Java library for creating and manipulating vector geometry.
Other
1.95k stars 440 forks source link

Buffer 0 of a Polygon returns a Multipolygon #1057

Closed james-willis closed 1 month ago

james-willis commented 4 months ago

I have the an invalid polygon with a bowtie in it. when I call buffer(0) on it I am returned a MultiPolygon when I was expecting a Polygon. Is this expected behavior? shapely/GEOS does the same thing as JTS on the example below.

I though buffering a polygon with an arg >= 0 should always return a polygon.

As a work around I am getting the first geometry from the MultiPolygon using .getGeometryN(0)

example polygon:

POLYGON ((0.2168424022222222 0.7856802211875938, 0.2168423616666666 0.7856805547357139, 0.216842553888889 0.78568063640693, 0.2168426177777778 0.7856804854181173, 0.2168427411111111 0.7856805005170004, 0.2168427861111111 0.7856801251037353, 0.2168428594444445 0.7856799528390603, 0.2168435277777778 0.7856802376591108, 0.2168431877777777 0.7856801964803175, 0.2168431094444445 0.7856803810985494, 0.2168428927777777 0.7856803550186543, 0.2168428677777778 0.785680560912529, 0.2168430827777779 0.7856806528784344, 0.2168431522222223 0.7856804902223075, 0.2168434072222223 0.785680521106386, 0.2168436483333334 0.7856799542116875, 0.2168427677777778 0.785679579484358, 0.2168426700000001 0.7856795678170193, 0.2168423383333333 0.7856794271226224, 0.2168421033333332 0.7856799789189748, 0.2168421794444444 0.7856793440785954, 0.2168418766666667 0.7856792157378013, 0.2168416766666668 0.7856796858630218, 0.2168416394444443 0.7856799940178721, 0.2168420844444443 0.7856801827540525, 0.2168424022222222 0.7856802211875938))

example result after calling buffer(0):

MULTIPOLYGON (((0.2168424022222222 0.7856802211875938, 0.2168423616666666 0.7856805547357139, 0.216842553888889 0.78568063640693, 0.2168426177777778 0.7856804854181173, 0.2168427411111111 0.7856805005170004, 0.2168427861111111 0.7856801251037353, 0.2168428594444445 0.7856799528390603, 0.2168435277777512 0.7856802376590994, 0.2168436483333334 0.7856799542116875, 0.2168427677777778 0.785679579484358, 0.2168426700000001 0.7856795678170193, 0.2168423383333333 0.7856794271226224, 0.2168421033333332 0.7856799789189748, 0.2168421794444444 0.7856793440785954, 0.2168418766666667 0.7856792157378013, 0.2168416766666668 0.7856796858630218, 0.2168416394444443 0.7856799940178721, 0.2168420844444443 0.7856801827540525, 0.2168424022222222 0.7856802211875938)), ((0.2168435277777479 0.7856802376591071, 0.2168431877777777 0.7856801964803175, 0.2168431094444445 0.7856803810985494, 0.2168428927777777 0.7856803550186543, 0.2168428677777778 0.785680560912529, 0.2168430827777779 0.7856806528784344, 0.2168431522222223 0.7856804902223075, 0.2168434072222223 0.785680521106386, 0.2168435277777479 0.7856802376591071)))
dr-jts commented 4 months ago

In general JTS does not guarantee results for invalid geometry inputs. Buffer does a bit better than this, in that it can produce reasonable results for invalid inputs. But it guarantees that the output is valid. In this case, the only way to produce a valid result that is faithful to the input linework is to convert the shape into a MultiPolygon.

Note that while in the past buffer(0) was the recommended way (hack!) to turn invalid polygons into valid geometry, this has been superseded by the GeometryFixer API. This is likely available in Shapely as well, as make_valid.

james-willis commented 4 months ago

Thanks for the quick and informative response.

I noticed the following quote from the GeometryFixer documentation:

Polygon: transform into a valid polygon...

However, my testing revealed that the GeometryFixer (and make_valid in shapely) has the same behavior as buffer(0).

Is this intended behavior? If so I could submit a PR to update the documentation to reflect that fixing a polygon may return a multipolygon

dr-jts commented 4 months ago

I noticed the following quote from the GeometryFixer documentation:

Polygon: transform into a valid polygon...

However, my testing revealed that the GeometryFixer (and make_valid in shapely) has the same behavior as buffer(0).

Is this intended behavior? If so I could submit a PR to update the documentation to reflect that fixing a polygon may return a multipolygon

Yes, that is intended behaviour. Feel free to submit a PR, or I can update it.