boolean-contains: incorrectly returns true for Polygon with bite taken out of the side and the polygon's boundary box#1897
Conversation
…out the side (but not the corner) and the polygon boundary, the function currently returns true. It should return false. same logic appled to boolean-within
|
Hey @mglasgow Thanks for the thoughtful PR - these boolean modules probably need a bit of rework in general. Ideally I think we want to avoid having to do a difference operation because that's quite expensive and these boolean modules are supposed to be fast - that said I probably broke that rule because I didn't know much about algorithms when I wrote them :) Given the changes at this stage are relatively minor I'm probably happy to merge and tackle a bigger overhaul down the track, but I'd like a few days to ponder just in case anything comes to mind Cheers PS Greetings from Canberra! |
|
Hi Rowan, I am up in Sydney! I did give some thought to the implementation. I agree, difference is definitely a heavier operation than the current point-in-poly comparisons. I erred on the side of correctness over performance in this instance. It would be nice if the Martinez implementation had a "short-circuiting" ability: return true or false if any of the polygons have a difference, rather than computing the entire geometry (which we throw away). The other option I considered was to check that none of the containing polygon points in the boundary lie in the interior (but not exterior) of the polygon that is to be contained. This seems to be going down the path of the segment intersection logic that JTS implements in it's PreparedGeometry implementation. The simpler solution for my needs was definitely using a difference operator. I've just considered another general optimisation that could be made in regards to the bounding boxes: rather than checking for overlap, the function could check that the bounding box is contained as well? |
|
I wonder if we could use something like https://github.com/rowanwins/shamos-hoey or https://github.com/rowanwins/sweepline-intersections ? |
npm testat the sub modules where changes have occurred.npm run lintto ensure code style at the turf module level.When using Turfjs to generate quadtiles from OpenStreetMap country boundaries, I ran into scenario where boolean-contains returns true when it should not have. The polygons in question are:
I am checking if the polygon with the "bite" taken out the side contains the rectangular tile that clipped it. boolean-contains returns true, when it should return false.
The current logic does a check that all the points of the contained polygon lie within the containing polygon. This is obviously a good short-cut test to perform, but cannot give a definitive yes answer.
I looked at the JTS implementation of cover() to get an idea of how they are doing it. They have some point-in-poly shortcut tests, then have to do a full topological comparison. I used cover() rather than contains() because it matches the implementation of how turfjs has defined contains, in regards to polygon boundaries. The comments on JTS contains() vs compare() code do a good job outlining the difference.
My PR to fix this adds another check to the logic. Only return true if the difference between the polygon being contained and the containing polygon is null. IE, check that there is no part of the contained polygon outside of the containing polygon.
I have added equivalent logic to boolean-within, as well as test cases to both.
On the topic of boolean-within, the logic is slightly different to boolean-contains, specifically it's handling of features with null geometries. If this is meant to be an exact opposite of boolean-contains, perhaps it can simply import the boolean-contains package and call it with swapped parameters, rather than duplicating the code in both packages?