简体   繁体   中英

Maximum participant intersection area of given n geometric shapes

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;

  • none of the shapes may intersects (no intersection between any of shapes, 0-participant intersection)
  • all shapes may intersects (there is an intersection that is in all shapes, n-participant intersection)
  • there might be more than one intersection with k participant (shape ABC intersects, shape DEF intersects, there are 2 3-participant intersection, doesn't need to find both, return when first 3-participant found)

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.

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

  • add set_intersection(l, p) with previous count of l +1
  • add set_minus(l, p) with `previous count of l'
  • remember set_minus(p, l) and proceed to the next entry of 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.

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:

  • if the number of polygons involved in the currently processed intersection and the remaining indices do not surpass the highest number of polygons to have a non-empty intersection, we do not need to pursue this intersection any longer.

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 (eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM