-
Notifications
You must be signed in to change notification settings - Fork 353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
use RingClipper for polygon clip in RectangeIntersection #605
use RingClipper for polygon clip in RectangeIntersection #605
Conversation
OverlayNG has an optimization for intersection, which should provide very good performance for intersection with rectangles. Any idea if |
I think we might need to actually benchmark this out, since if NG is just faster for rectangles, the best thing to do us remove all the old rectangle code and delegate to NG. |
Absolutely. I can take this on. |
I tested from PostGIS using following query GEOSClipByRect is significantly faster but subdivision contains invalid polygons so maybe it's worth using NG for clip despite worse performance. |
Makes sense to me. The output from |
ST_Subdivide doesn't use GEOSClipByRect with current implementation, it uses OverlayNG. I made ST_Subdivide to use GEOSClipByRect for my benchmark.
Yes, GEOSClipByRect is still faster than OverlayNG. At least for my test input. But sometimes it produces invalid geometries. Actually it's noted in PostGIS documentation that invalid geometries might be produced https://postgis.net/docs/ST_ClipByBox2D.html. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This either needs to be a more thorough-going fix to the RectangleIntersection that does not produce new and exciting invalidities while getting rid of other ones, or to be abandoned on the principle of "the devil you know".
@@ -1565,7 +1565,7 @@ template<> template<> void object::test<139> | |||
{ | |||
doClipTest( | |||
"POLYGON ((-15 -15,-15 15,15 15,15 -15,-15 -15),(-5 5,-5 -5,5 -5,5 5,-5 5))", | |||
"POLYGON ((0 5,0 10,10 10,10 0,5 0,5 5,0 5))", | |||
"POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (0 0, 5 0, 5 5, 0 5, 0 0))", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are pretty big changes in behaviour...
@@ -1630,7 +1630,7 @@ template<> template<> void object::test<205> | |||
"(-5 6,5 6,5 4,-5 4,-5 6)" // CW | |||
")"; | |||
const char* exp = | |||
"POLYGON((0 8,8 8, 8 2, 0 2, 0 4, 5 4, 5 6, 0 6, 0 8))"; | |||
"POLYGON ((0 2, 0 8, 8 8, 8 2, 0 2), (0 4, 5 4, 5 6, 0 6, 0 4))"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of holes-over-shells cases come out of this change.
@@ -136,7 +136,7 @@ template<> template<> void object::test<10> | |||
{ | |||
geom1_ = GEOSGeomFromWKT("POLYGON((0 0, 0 30, 30 30, 30 0, 0 0),(10 10, 20 10, 20 20, 10 20, 10 10))"); | |||
geom2_ = GEOSClipByRect(geom1_, 10, 10, 20, 20); | |||
isEqual(geom2_, "POLYGON EMPTY"); | |||
isEqual(geom2_, "POLYGON((10 20, 20 20, 20 10, 10 10, 10 20), (10 10, 20 10, 20 20, 10 20, 10 10))"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is way worse than before... the result is a hole exactly on the shell. Which is, yes, empty, but far less legibly than what came before. Is the juice worth the squeeze here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pramsey thank you for review.
This is way worse than before... the result is a hole exactly on the shell. Which is, yes, empty, but far less legibly than what came before. Is the juice worth the squeeze here?
right, with these changes there are plenty of cases when geometry becomes invalid after clip whereas with current implementation it's fine but all these geometries are possible to fix with ST_MakeValid while the example I provided in description is unrepairable because polygon is constructed from wrong part of rectangle.
That is what happens when subdivision is done using current ST_ClipByBox2D:
So I would prefer to have more cases where invalid geometries are produces but these geometries are repairable over function that almost always ok but sometimes outputs completely broken geometry.
For me it looks like making ST_ClipByBox2D use OverlayNG like @dr-jts suggested is the best option here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it seems validity is the highest order concern. Although aren't we already using OverlayNG in subdivide?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, OverlayNG is already used in subdivide. I made it to use ST_ClipByBox2D for my testing purposes, it does plenty of clip operations which makes it easier to find these kind of issue.
This seems to have aged out. There is perhaps a use case for rectangle (or convex?) clipping if it can be made reliable, but I don't know that this is it? |
There is a bug in ST_ClipByBox2D.
In this example input geometry has coincident segments along the sides of clip rectangle. It is noted that output might be self-intersecting geometry but for this case produced polygon contains part of rectangle that doesn't has overlap with input geometry. The bug is located in the code that tries to build polygon from clipped lines and clip rectangle.
In this PR I replaced part of RectangleIntersection class responsible for polygon clip with RingClipper which still might produce invalid geometry but doesn't suffer from mentioned bug in current implementation.