【问题标题】:Fast way to find the closest polygon to a point找到离点最近的多边形的快速方法
【发布时间】:2019-12-07 23:35:26
【问题描述】:

我有一个Shapely 多边形列表和一个点​​,如下所示:

from shapely.geometry import Point, Polygon

polygons = [Polygon(...), Polygon(...), ...]
point = Point(2.5, 5.7)

我想在列表中找到离该点最近的多边形。我已经知道 object.distance(other) 函数返回两个几何形状之间的最小距离,我考虑计算循环中的所有距离以找到最近的多边形:

polygons = [Polygon(...), Polygon(...), ...]
point = Point(2.5, 5.7)
min_dist = 10000
closest_polygon = None

for polygon in polygons:
    dist = polygon.distance(point)
    if dist < min_dist:
        min_dist = dist
        closest_polygon = polygon

我的问题是:有没有更有效的方法?

【问题讨论】:

  • 多边形是固定的还是可以动态变化的?
  • @ma3oun 他们是固定的。
  • 它们是否都有相同数量的顶点?
  • 这有什么帮助吗:Looking for a fast way to find the polygon a point belongs to using Shapely?我从未使用过建议的 R-tree,所以我不知道它是否对您的情况有所帮助。
  • 顺便说一句,您可以将当前代码更简洁地编写为closest_polygon = min(polygons, key=point.distance)

标签: python polygon shapely


【解决方案1】:

还有更短的方法,例如

from shapely.geometry import Point, Polygon
import random
from operator import itemgetter


def random_coords(n):
    return [(random.randint(0, 100), random.randint(0, 100)) for _ in range(n)]


polys = [Polygon(random_coords(3)) for _ in range(4)]
point = Point(random_coords(1))

min_distance, min_poly = min(((poly.distance(point), poly) for poly in polys), key=itemgetter(0))

就像Georgy mentioned (++awesome!) 更简洁:

min_poly = min(polys, key=point.distance)

但距离计算通常是计算密集型的

【讨论】:

  • 这确实是一个更短的解决方案,但我只是测试了它,它只需要比循环多一点的时间。无论如何感谢您的分享!
【解决方案2】:

有一种方法可能会更快,但是如果没有进行任何实际测试,我很难确定。

这可能不适用于您的情况,但基本思想是每次将Shapely 对象添加到数组时,您都会调整不同数组元素的位置,以便始终以这种方式“排序”。在 Python 中,这可以通过 heapq 模块完成。该模块的唯一问题是很难选择一个函数来与不同的对象进行比较,因此您必须执行类似this answer 的操作,在其中为对象创建一个自定义类以放入heapq 这是一个元组。

import heapq

class MyHeap(object):
   def __init__(self, initial=None, key=lambda x:x):
       self.key = key
       if initial:
           self._data = [(key(item), item) for item in initial]
           heapq.heapify(self._data)
       else:
           self._data = []

   def push(self, item):
       heapq.heappush(self._data, (self.key(item), item))

   def pop(self):
       return heapq.heappop(self._data)[1]

元组中的第一个元素是“键”,在这种情况下是到点的距离,然后第二个元素是实际的Shapely 对象,你可以这样使用它:

point = Point(2.5, 5.7)
heap = MyHeap(initial=None, key=lambda x:x.distance(point))

heap.push(Polygon(...))
heap.push(Polygon(...))
# etc...

最后,您要查找的对象将位于heap.pop()

不过,最终,这两种算法似乎(大致)都是O(n),所以任何加速都不是一个重要的。

【讨论】:

    【解决方案3】:

    如果您至少有 2 个距离不为 0 的多边形,我有一个可行的解决方案。我们将这 2 个多边形称为“basePolygon0”和“basePolygon1”。这个想法是建立一个KD tree,每个多边形到每个“基础”多边形的距离。 KD树构建完成后,我们可以通过计算到每个基础多边形的距离来查询它。

    这是一个工作示例:

    from shapely.geometry import Point, Polygon
    import numpy as np
    from scipy.spatial import KDTree 
    
    # prepare a test with triangles
    poly0 = Polygon([(3,-1),(5,-1),(4,2)])
    poly1 = Polygon([(-2,1),(-4,2),(-3,4)])
    poly2 = Polygon([(-3,-3),(-4,-6),(-2,-6)])
    poly3 = Polygon([(-1,-4),(1,-4),(0,-1)])
    
    polys = [poly0,poly1,poly2,poly3]
    
    p0 = Point(4,-3)
    p1 = Point(-4,1)
    p2 = Point(-4,-2)
    p3 = Point(0,-2.5)
    
    testPoints = [p0,p1,p2,p3]
    
    # select basis polygons
    # it works with any pair of polygons that have non zero distance
    basePolygon0 = polys[0]
    basePolygon1 = polys[1]
    
    # compute tree query
    def buildQuery(point):
        distToBasePolygon0 = basePolygon0.distance(point)
        distToBasePolygon1 = basePolygon1.distance(point)
        return np.array([distToBasePolygon0,distToBasePolygon1])
    
    
    distances = np.array([buildQuery(poly) for poly in polys])
    
    # build the KD tree
    tree = KDTree(distances)
    
    # test it
    for p in testPoints:
        q = buildQuery(p)
        output = tree.query(q)
        print(output)
    

    这会按预期产生:

    # (distance, polygon_index_in_KD_tree)
    (2.0248456731316584, 0)
    (1.904237866994273, 1)
    (1.5991500555008626, 2)
    (1.5109986459170694, 3)
    

    【讨论】:

      猜你喜欢
      • 2016-01-23
      • 2021-12-24
      • 2021-12-06
      • 2014-06-16
      • 2020-05-10
      • 2021-07-20
      • 1970-01-01
      • 2020-12-28
      • 2016-07-06
      相关资源
      最近更新 更多