(This approach follows a similar idea to @GarethRees 's: first, cheaply discover which pairs of polygons you don't need to check for inclusion. Once the number of pairs still needed to check is acceptable, do the exact (expensive) geometric check.)
It's easy to calculate for each polygon p the bounding rectangle, i.e. the left, right, top and bottom, so let's do that first. E.g. for left: p.L = min { x : (x,y) is a vertex of p }
Time is linear in the number of points.
To avoid having to compare each polygon to each other one, you could divide up the area into a 2x2 grid. Suppose the width and height of the area are respectively given by Dx
and Dy
, then you can create nine sets top,bottom,left,right,topright,topleft,bottomright,bottomleft,rest
and do the following:
for p in polygons:
in_top = p.B > Dy/2
in_bottom = p.T < Dy/2
in_left = p.R < Dx/2
in_right = p.L > Dx/2
if in_top:
if in_left:
add p to topleft
elsif in_right:
add p to topright
else:
add p to top
elsif in_bottom:
if in_left:
add p to bottomleft
elsif in_right:
add p to bottomright
else:
add p to bottom
if in_right and not (in_top or in_bottom):
add p to right
elsif in_left and not (in_top or in_bottom):
add p to left
if not (in_top or in_bottom or in_left or in_right):
add p to rest
This is again linear time. Each polygon has been binned into its most "tightly" containing sector. What have you gained by this? Well, you know for example that for any polygon p
in left
there can't possibly be any inclusion relationship with set right
, so you don't need to compare them. Likewise between bottomleft
and right
, bottomleft
and topleft
, and so on. Here is what it would look like on your example:
Dx/2
+----------------------|---------------------+
| | |
| +----------------+ | +--------+ |
| | | | / | |
| | +--------+ | | / | |
|___|___|________|___|_|____ /__+===d(2)=+___|_ Dy/2
| | | | | | / | |
| | +---b(3)-+ | | / | +---+ |
| | | | +-----+ | | |
| +-----------c(2)-+ | e(2)+ |
| | |
+----------------------|----------------a(1)-+
So rest = {a}, top = {}, bottom = {}, left = {b,c}, right = {d}
topleft = {}, topright = {}, bottomleft = {}, bottomright = {e}
So basically now you need to compare (with the expensive exact check) at most b
to c
, d
to e
, and a
to all others -- in fact, if you order the checks in a clever way, you won't need to compare a
to all others, because inclusion is transitive, so if you notice that c
includes b
, and a
includes c
, then you do not need to check if a
includes b
.
Another point is that you can apply the above reasoning recursively. Say for example the set topright
is too big for your taste; you can then apply the same technique by further dividing up that subregion (just need to get the book-keeping right).