I have number of simple polygons which do not intersect each other but some polygons may be embedded into others.
For example:
+--------------------------------------------+
| |
| +----------------+ +--------+ |
| | | / | |
| | +--------+ | / | |
| | | | | / +----(2)-+ |
| | | | | / | |
| | +----(3)-+ | / | +---+ |
| | | +-----+ | | |
| +------------(2)-+ +(2)+ |
| |
+----------------------------------------(1)-+
How to find out the "depth" of all the polygons? In other words, how to find out by how many polygons a polygon is encompassed by? The "depth" are the numbers in parentheses.
I could count how many times a point of a polygon is inside of all the other polygons but this has quadratic complexity. How to compute those depths faster?
Put your polygons into some kind of spatial lookup structure, for example an R-tree based on the minimum bounding rectangles for the polygons. Then you should be able to compute the containment relation that you're after in O(n log n). (Unless you're in a pathological case where many of the minimum bounding rectangles for your polygons overlap, which seems unlikely based on your description.)
Edited to add: of course, you don't rely on the R-tree to tell you if one polygon is inside another (it's based on minimum bounding rectangles so it can only give you an approximation). You use the R-tree to cheaply identify candidate inclusions which you then verify in the expensive way (checking that a point in one polygon is inside the other).
Step 1: Orient your polygons in the same direction, say counter-clockwise.
Step 2: For any point (x, y) for which you need to compute the "depth" for compute the total winding number. This can be done in a number of ways; the fastest one in practice is to compute the SIGNED number of intersections between the horizontal (or vertical) ray originating in (x, y).
In particular, the depth for each polygon would be the depth of any of its vertices.
(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
andDy
, then you can create nine setstop,bottom,left,right,topright,topleft,bottomright,bottomleft,rest
and do the following: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
inleft
there can't possibly be any inclusion relationship with setright
, so you don't need to compare them. Likewise betweenbottomleft
andright
,bottomleft
andtopleft
, and so on. Here is what it would look like on your example: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
toc
,d
toe
, anda
to all others -- in fact, if you order the checks in a clever way, you won't need to comparea
to all others, because inclusion is transitive, so if you notice thatc
includesb
, anda
includesc
, then you do not need to check ifa
includesb
.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).Seems to me you get get away with sorting the polygons, using a test of whether one is inside another as the comparison operator.
Step 1
Suppose we define the relation '<' between polygons as follows: A < B iff A is inside B. It so happens that if A < B and B < C, then A < C (i.e. if polygon A is inside B and B is inside C, then A must be inside C). Now, we have a strict weak ordering between arbitrary polygons.
[Edit: You'd need to use some sort of point-inside-non-convex-polygon test, but presumably you are doing that already.]
Step 2
Sort the polygons according to this comparison using your favorite comparison-based sorting algorithm. For instance, merge sort has a worst-case time complexity of O(nlogn) comparisons where n is the number of polygons.
[Edit: This is the important step, because it gets rid of the quadratic complexity.]
Step 3
Ensure that the "largest" (i.e. outermost) element is first on your sorted array of polygons. (Reverse the list if necessary to achieve this - it is linear on the number of polygons).
Step 4
Now the "largest" (i.e. outermost) polygon should be the first element.
[Edit: In fact, the polygons have been sorted according to their depth. However, two polygons that have the same depth may appear in different orders depending on whether the sort was stable. This doesn't matter to us; what we are interested in is the change in depth.]
We will now assign a depth to each polygon as follows. Firstly, initialize the depth of each one to 0 ([Edit: initialize to 1, according to the example]). Next, iterate through your sorted list, but this time compare each element p only to the next element p+1. If (p+1 < p) is true, then increment the depth of p+1. Else, set the depth of p+1 to be the same as the depth of p.