Search code examples
javascriptmathintersectionrectanglesocclusion

2D overlapping rectangles occlusion


I'm looking for an algorithm that can find intersecting rectangles that overlap each other.

The catch is that my data structure is similar to a quadtree with bounding boxes instead of points. I'm doing a basic rectangle intersection check but the problem is as I zoom into the tree the child nodes get detected and the parents, I would like to exclude the parent if its fully occluded by a child for the given camera rectangle.

zoom animation

As you can see from the image above as the camera rectangle (black box) sits inside the green node the purple node is still highlighted (filled), consequently as I zoom more and more the parents are always highlighted, even though the camera rectangle can be fully filled with child nodes only.

This makes sense since the camera rectangle is still inside the parent but I have searched and thought about the problem for a while and can't seem to figure out an elegant solution. There seems to be several ways of doing this for 3D spaces but I can't find anything simple for 2D AABB rectangles.

A few solutions that I thought of:

  • Subtract the child nodes from the parents resulting in concave polygons and then perform polygon intersection.
  • Use the fill color to check which rectangles are visible, therefore occluding the ones behind.
  • Perform raycasting or sub-division and check which is the smallest node for a given section.

Is there a better way to do this? Thank you

Update 1

I have solved the problem by subdividing the camera into smaller sections and for each section the smallest intersecting node is found. This works but there must be a more efficient and cleaner way of doing this.

Update 2

Thank you Trentium for your answer. I can clearly see that an algorithm like that would be a lot more performant than what I'm currently doing.

Eventually I will implement it as splitting a rectangle into smaller rectangles and not polygons sounds like a fun challenge.

Also, I did some very non scientific benchmarks on the current approach and it takes 0.5ms-1ms to both filter and draw everything, so for now performance is still not a concern.


Solution

  • Suggest considering a variation of your first solution proposed "Subtract the child nodes from the parents resulting in concave polygons and then perform polygon intersection."

    Specifically, if the immediate children are wholly contained within the parent, then suggest that for each rectangle, that an associated array of visible residual rectangles also be maintained. And then use this array of residual rectangles as the means of determining if the camera / viewport rectangle includes the parent or not.

    For example, let's say the parent rectangle is (0,0) - (100,100) and there is an initial child rectangle added at (75,75)-(100,100). The data structure will appear as...

    • parent.rectangle = {0,0,100,100}
    • parent.visible = [ {0,0,100,75}, {0,75,75,100} ]
    • child1.rectangle = {75,75,100,100}
    • child1.visible = [ {75,75,100,100} ]

    enter image description here ...and then if a second child comes along, say at {50,50,75,90}, then this new child is checked against each residual rectangle in the parent.visible array, subdividing the parent visible rectangles further as necessary...

    • parent.rectangle = {0,0,100,100}
    • parent.visible = [ {0,0,100,50}, {0,50,50,75}, {75,50,100,75}, {0,75,50,100}, {50,90,75,100} ]
    • child1.rectangle = {75,75,100,100}
    • child1.visible = [ {75,75,100,100} ]
    • child2.rectangle = {50,50,75,90}
    • child2.visible = [ {50,50,75,90} ]

    This method will add a bit of work up front adjusting the immediate parent's visible rectangles as children are added, but should greatly reduce the amount of rectangle intersection tests relative to the current algorithm that involves subdivision of the camera / viewport. Plus this proposed algorithm only makes use of rectangle-to-rectangle intersection tests (both when adding a child to a parent, and when testing the camera / viewport intersections!) rather than the suggested rectangle-to-polygon tests...