将一个匀称的多边形切割成 N 个大小相等的多边形
Cut a shapely polygon into N equally sized polygons
我有一个 Shapely 多边形。我想将这些多边形切割成 n 个多边形,这些多边形都具有或多或少相同大小的区域。大小相等最好,但近似值也可以。
我已经尝试使用这两种方法 described here,这两种方法都是朝着正确方向迈出的一步,而不是我所需要的。两者都不允许目标 n
我调查了 voronoi,我对它基本不熟悉。此分析给出的结果形状将是理想的,但它需要点,而不是输入的形状。
这是我能做到的最好的。它不会导致每个多边形的表面积相等,但事实证明它可以满足我的需要。这会用特定数量的点填充形状(如果参数保持不变,点数也会保持不变)。然后将点转换为 voronoi,然后将其转换为三角形。
from shapely import affinity
from shapely.geometry.multipolygon import MultiPolygon
from scipy.spatial import Voronoi
# Voronoi doesn't work properly with points below (0,0) so set lowest point to (0,0)
shape = affinity.translate(shape, -shape_a.bounds[0], -shape_a.bounds[1])
points = shape_to_points(shape)
vor = points_to_voronoi(points)
triangles = MultiPolygon(triangulate(MultiLineString(vor)))
def shape_to_points(shape, num = 10, smaller_versions = 10):
points = []
# Take the shape, shrink it by a factor (first iteration factor=1), and then
# take points around the contours
for shrink_factor in range(0,smaller_versions,1):
# calculate the shrinking factor
shrink_factor = smaller_versions - shrink_factor
shrink_factor = shrink_factor / float(smaller_versions)
# actually shrink - first iteration it remains at 1:1
smaller_shape = affinity.scale(shape, shrink_factor, shrink_factor)
# Interpolate numbers around the boundary of the shape
for i in range(0,int(num*shrink_factor),1):
i = i / int(num*shrink_factor)
x,y = smaller_shape.interpolate(i, normalized=True).xy
points.append( (x[0],y[0]))
# add the origin
x,y = smaller_shape.centroid.xy
points.append( (x[0], y[0]) ) # near, but usually not add (0,0)
points = np.array(points)
return points
def points_to_voronoi(points):
vor = Voronoi(points)
vertices = [ x for x in vor.ridge_vertices if -1 not in x]
# For some reason, some vertices were seen as super, super long. Probably also infinite lines, so take them out
lines = [ LineString(vor.vertices[x]) for x in vertices if not vor.vertices[x].max() > 50000]
return MultiLineString(lines)
这是输入形状:
这是在shape_to_points
之后:
这是在points_to_voronoi
之后
然后我们可以对 voronoi 进行三角测量:
另一个 out-of-the-box 选项是 h3 polyfill 函数。基本上任何重复结构都可以工作(三角形、正方形、六角形),但 Uber 的库使用六角形,所以你只能坚持使用它,除非你编写一个模块来对其他形状之一做同样的事情。您仍然遇到未直接指定“n”的问题(仅通过离散缩放级别选项间接指定)。
只是结合@user3496060提供的响应和基本的polyfill文档(对我很有帮助,谢谢),这是一个简单的功能。
这是来自 h3 存储库的很棒的 notebook。查看“人口普查多边形到十六进制”部分,了解他们如何使用 polyfill()
.
def h3_fill_shapely_poly(poly = shape, res = 10):
"""
inputs:
- poly: must be a shapely Polygon, cannot be any other shapely object
- res: resolution (higher means more specific zoom)
output:
- h3_fill: a Python set() object, generated by polypill
"""
coordinates = [[i[0], i[1]] for i in poly.exterior.coords]
geo_json = {
"type": "Polygon",
"coordinates": [coordinates]
}
h3_fill = h3.polyfill(geo_json, res, geo_json_conformant=False)
print(f'h3_fill =\n{type(h3_fill), h3_fill}')
return h3_fill
我有一个 Shapely 多边形。我想将这些多边形切割成 n 个多边形,这些多边形都具有或多或少相同大小的区域。大小相等最好,但近似值也可以。
我已经尝试使用这两种方法 described here,这两种方法都是朝着正确方向迈出的一步,而不是我所需要的。两者都不允许目标 n
我调查了 voronoi,我对它基本不熟悉。此分析给出的结果形状将是理想的,但它需要点,而不是输入的形状。
这是我能做到的最好的。它不会导致每个多边形的表面积相等,但事实证明它可以满足我的需要。这会用特定数量的点填充形状(如果参数保持不变,点数也会保持不变)。然后将点转换为 voronoi,然后将其转换为三角形。
from shapely import affinity
from shapely.geometry.multipolygon import MultiPolygon
from scipy.spatial import Voronoi
# Voronoi doesn't work properly with points below (0,0) so set lowest point to (0,0)
shape = affinity.translate(shape, -shape_a.bounds[0], -shape_a.bounds[1])
points = shape_to_points(shape)
vor = points_to_voronoi(points)
triangles = MultiPolygon(triangulate(MultiLineString(vor)))
def shape_to_points(shape, num = 10, smaller_versions = 10):
points = []
# Take the shape, shrink it by a factor (first iteration factor=1), and then
# take points around the contours
for shrink_factor in range(0,smaller_versions,1):
# calculate the shrinking factor
shrink_factor = smaller_versions - shrink_factor
shrink_factor = shrink_factor / float(smaller_versions)
# actually shrink - first iteration it remains at 1:1
smaller_shape = affinity.scale(shape, shrink_factor, shrink_factor)
# Interpolate numbers around the boundary of the shape
for i in range(0,int(num*shrink_factor),1):
i = i / int(num*shrink_factor)
x,y = smaller_shape.interpolate(i, normalized=True).xy
points.append( (x[0],y[0]))
# add the origin
x,y = smaller_shape.centroid.xy
points.append( (x[0], y[0]) ) # near, but usually not add (0,0)
points = np.array(points)
return points
def points_to_voronoi(points):
vor = Voronoi(points)
vertices = [ x for x in vor.ridge_vertices if -1 not in x]
# For some reason, some vertices were seen as super, super long. Probably also infinite lines, so take them out
lines = [ LineString(vor.vertices[x]) for x in vertices if not vor.vertices[x].max() > 50000]
return MultiLineString(lines)
这是输入形状:
这是在shape_to_points
之后:
这是在points_to_voronoi
然后我们可以对 voronoi 进行三角测量:
另一个 out-of-the-box 选项是 h3 polyfill 函数。基本上任何重复结构都可以工作(三角形、正方形、六角形),但 Uber 的库使用六角形,所以你只能坚持使用它,除非你编写一个模块来对其他形状之一做同样的事情。您仍然遇到未直接指定“n”的问题(仅通过离散缩放级别选项间接指定)。
只是结合@user3496060提供的响应和基本的polyfill文档(对我很有帮助,谢谢),这是一个简单的功能。
这是来自 h3 存储库的很棒的 notebook。查看“人口普查多边形到十六进制”部分,了解他们如何使用 polyfill()
.
def h3_fill_shapely_poly(poly = shape, res = 10):
"""
inputs:
- poly: must be a shapely Polygon, cannot be any other shapely object
- res: resolution (higher means more specific zoom)
output:
- h3_fill: a Python set() object, generated by polypill
"""
coordinates = [[i[0], i[1]] for i in poly.exterior.coords]
geo_json = {
"type": "Polygon",
"coordinates": [coordinates]
}
h3_fill = h3.polyfill(geo_json, res, geo_json_conformant=False)
print(f'h3_fill =\n{type(h3_fill), h3_fill}')
return h3_fill