查找最接近点的多边形的快速方法

时间:2019-07-30 14:24:57

标签: python polygon shapely

我有一个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

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

3 个答案:

答案 0 :(得分: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(++太棒了!)更加简洁:

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

但是距离计算通常需要大量计算

答案 1 :(得分:0)

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

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

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(),因此任何提高速度都不是一个重要的方法。

答案 2 :(得分:0)

我有一个解决方案,如果您至少有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)