Reputation: 709
I have n geometric shapes defined in GeoJson
, I would like to calculate the intersection which involves maximum number of shapes.
I have the following constraints;
So, as a starting point, I though I could do that by using brute force (trying to intersects n, n-1, n-2 combination of given shapes) but it's time complexity will be O(n!). I'm wondering that if the algorithm could be optimized?
EDIT:
Well, I forgot the tell about data types. I'm using Esri/geometry library for shapes. Specifically, Polygon class instances.
Upvotes: 2
Views: 216
Reputation: 6257
A list of unprocessed (non-empty) intersections together with the polygon indices from which the intersection was created is maintained. Initially it is filled with the single polygons. Always the intersection from most polygons and least maximal index of involved polygons is taken out and intersected with all polygons with higher indices (to avoid looking at the same subset of polygons again and again). This allows an efficient pruning:
Here is the algorithm in Python-like notation:
def findIntersectionFromMostMembers(polygons):
unprocessedIntersections = [(polygon, {i}) for i, polygon in enumerate(polygons)]
unprocessedIntersections.reverse() # make polygon_0 the last element
intersectionFromMostMembers, indicesMost = (polygons[0], {0})
while len(unprocessedIntersections) > 0:
# last element has most involved polygons and least maximal polygon index
# -> highest chance of being extended to best intersection
intersection, indices = unprocessedIntersections.pop() # take out unprocessed intersection from most polygons
if len(indices) + n - max(indices) - 1 <= len(indicesMost):
continue # pruning 1: this intersection cannot beat best found solution so far
for i in range(max(indices)+1, n): # pruning 2: only look at polyong with higher indices
intersection1 = intersection.intersect(polygons[i])
if not intersection1.isEmpty(): # pruning 3: empty intersections do not need to be considered any further
unprocessedIntersections.insertSorted(intersection1, indices.union({i}), key = lambda(t: len(t[1]), -max(t[1])))
if len(indices)+1 > len(indicesMost):
intersectionFromMostMembers, indicesMost = (intersection1, indices.union({i}))
return intersectionFromMostMembers, indicesMost
The performance highly depends on how many polygons in average do have an area in common. The fewer (<< n
) polygons have areas in common, the more effective pruning 3 is. The more polygons have areas in common, the more effective pruning 1 is. Pruning 2 makes sure that no subset of polygons is considered twice. The worst scenario seems to be when a constant fraction of n
(e.g. n/2
) polygons have some area in common. Up to n=40
this algorithm terminates in reasonable time (in a few seconds or at most in a few minutes). If the non-empty intersection from most polygons involves only a few (any constant << n
) polygons, much bigger sets of polygons can be processed in reasonable time.
Upvotes: 0
Reputation: 3755
This problem feels like you can construct hard cases that cannot be solved efficiently, specifically if the shapes are not convex. Here are two ideas that you could try:
1. Iterative Intersection
Keep a list L
of (disjoint) polygons with counts that is empty in the beginning. Now iterate through your given polygons P
. For each polygon p
from P
intersect it with all polygons l
from L
. If there is an intersection between p
and l
then remove l
from L
and
previous count of l +1
L
when you are through all elements of L
then add the remaining part of p
to L with count 1.
Eventually you will have a list of disjoint polygons with counts that is equvalent to the number of participant polygons.
2. Space Decomposition
Build a bounding box around all polygons. Then iteratively split that space (similar to a KD-Tree). For each half (rectangle), compute the number of polygons from P intersecting that rectangle. Proceed best-first (always evaluate the rectangle that has the highest count). When you are at a certain level of the KD-Tree then stop and evaluate by brute-force or Iterative Intersection.
Both methods will benefit from a filter using minimum bounding rectangles around the polygons.
Upvotes: 2