geos icon indicating copy to clipboard operation
geos copied to clipboard

`PolygonizeValid` result differs from JTS

Open dr-jts opened this issue 2 years ago • 11 comments

This set of linework:

MULTILINESTRING ((0 20, 8 20), (8 20, 20 20, 24 10, 11 10), (11 10, 4 10, 0 20), (8 20, 11 10), (11 10, 12 8, -4 10, 0 20))

produces the following result for a Polygonizer operation with extractOnlyPolygonal = true:

MULTIPOLYGON (((11 10, 12 8, -4 10, 0 20, 4 10, 11 10)), ((11 10, 8 20, 20 20, 24 10, 11 10)))
image

However, in GEOS the same operation

bin/geosop -a 'MULTILINESTRING ((0 20, 8 20), (8 20, 20 20, 24 10, 11 10), (11 10, 4 10, 0 20), (8 20, 11 10), (11 10, 12 8, -4 10, 0 20))' polygonizeValid

produces:

POLYGON ((0 20, 8 20, 11 10, 4 10, 0 20))
image

dr-jts avatar May 23 '23 19:05 dr-jts

This is due to different logic in Polygonizer.findDisjointShells between JTS and GEOS.

This logic was changed in this commit: https://github.com/libgeos/geos/commit/c5c826b340045c6e1581afb7587f41acf57237fa

dr-jts avatar May 23 '23 19:05 dr-jts

I can see that they're different but don't understand why one or the other would be preferable.

dbaston avatar May 23 '23 19:05 dbaston

The original logic was intended to include the outermost polygons. This is ambiguous in some cases (such as two adjacent rectangles), but not in this case.

dr-jts avatar May 23 '23 20:05 dr-jts

Isn't it pretty much the same as

MULTILINESTRING ((1 0, 2 0, 2 1, 1 1, 1 0), 
  (2 0, 3 0, 3 1, 2 1), 
  (1 0, 0 0, 0 1, 1 1))

as there are no containment relationships between the polygons?

dbaston avatar May 23 '23 21:05 dbaston

Scratch that -- the polygonizer throws errors on it.

dbaston avatar May 23 '23 21:05 dbaston

Here is one in which the "middle" polygon is returned:

MULTILINESTRING ((0 1, 0 0, 1 0, 1 1), 
  (0 2, -1 1.5, 0 1), 
  (0 1, 1 1), 
  (0 2, 1 2), 
  (1 2, 1 1), 
  (1 2, 1 3, 0 3, 0 2))

image

dbaston avatar May 23 '23 21:05 dbaston

Or, modifying the example, from the top,

MULTILINESTRING ((0 20, -10 21, 8 20), 
  (8 20, 20 20, 24 10, 11 10), 
  (11 10, 4 10, 0 20), 
  (8 20, 11 10), 
  (11 10, 12 8, -4 10, 0 20))

image

vs

MULTIPOLYGON (((11 10, 12 8, -4 10, 0 20, 4 10, 11 10)), 
  ((8 20, 20 20, 24 10, 11 10, 8 20)))

image

Is "outermost" here just referring to "minimum X coordinate?

dbaston avatar May 23 '23 21:05 dbaston

Is "outermost" here just referring to "minimum X coordinate?

That heuristic would make the results deterministic, which is important to have (for testing purposes if nothing else). Not sure if that's the way it's implemented right now.

dr-jts avatar May 23 '23 21:05 dr-jts

The heuristic actually needs to be "polygon containing minimum segment", where segments are ordered using the standard lexicographic XY ordering of their endpoints.

Actually perhaps it should be "segment with lowest endpoint and smallest/lowest angle at that node".

image

PolygonizeValid on this case produces:

image

dr-jts avatar May 23 '23 21:05 dr-jts

Isn't the purpose of this operation to exclude interior polygons from the result? In all of these cases there are no interior polygons so there is no "correct" result. I feel like I'm missing something fundamental about what the bug is here.

dbaston avatar May 23 '23 21:05 dbaston

The goal is to make the output deterministic, so it is repeatable between JTS and GEOS for all cases.

This may require adding a sort to both libs. And then ensure the polygon alternation algorithm behaves the same.

dr-jts avatar May 23 '23 22:05 dr-jts