我有一个功能
get_polygon(polygon_collection, point):
for polygon in polygon_collection:
if polygon.intersects(point):
return polygon
return None
此方法有效,但是在O(n)* O(单多边形检查)中。如果可以构建树数据结构,则可以肯定地将其减少为O(log(n))* O(单多边形检查)。
是否直接支持它?
多边形列表可以是德国的邮政编码区域。那将是几千。然后我有我和一些朋友的GPS位置,也有数千个。我想说我们在哪个区域获得最多的数据点。
答案 0 :(得分:2)
RTrees正是您想要的。 Shapely现在支持RTree的构造和使用。但问题是,形状优美的rtree仅支持矩形。因此,使用它的方法如下:
除非您的多边形非常奇怪,否则这将为您提供均值的对数时间(每个点的多边形数量的对数)。 当然,您需要付出构建RTree结构的代价,但是如果多边形以某种方式均等分布,并且可以将rtree序列化以供以后使用,那也将在对数时间内完成。 (也就是说,向树中添加新框与树中已经存在的框数量成对数关系,因此总复杂度小于n * log(n)。)
其实现如下。
from rtree import index
from shapely.geometry import Polygon, Point
def get_containing_box(p):
xcoords = [x for x, _ in p.exterior.coords]
ycoords = [y for _, y in p.exterior.coords]
box = (min(xcoords), min(ycoords), max(xcoords), max(ycoords))
return box
def build_rtree(polys):
def generate_items():
pindx = 0
for pol in polys:
box = get_containing_box(pol)
yield (pindx, box, pol)
pindx += 1
return index.Index(generate_items())
def get_intersection_func(rtree_index):
MIN_SIZE = 0.0001
def intersection_func(point):
# Inflate the point, since the RTree expects boxes:
pbox = (point[0]-MIN_SIZE, point[1]-MIN_SIZE,
point[0]+MIN_SIZE, point[1]+MIN_SIZE)
hits = rtree_index.intersection(pbox, objects='raw')
#Filter false positives:
result = [pol for pol in hits if pol.intersects(Point(point)) ]
return result
return intersection_func
我用来测试的示例:
triangles = [
[(8.774239095627754, 32.342041683826224),
(8.750148703126552, 32.899346596303054),
(4.919576457288677, 35.41040289384488)],
[(8.485955148136222, 32.115258769399446),
(9.263360720698277, 30.065319757618354),
(4.562638192761559, 38.541192819415855)],
[(2.613649959824923, 38.14802347408093),
(7.879211442172622, 35.97223726358858),
(0.9726266770834235, 32.12523430143625)]
]
polys = [Polygon(t) for t in triangles]
my_rtree = build_rtree(polys)
my_func = get_intersection_func(my_rtree)
my_intersections = my_func((5, 35))
for pol in my_intersections:
print pol.exterior.coords[:]