简体   繁体   English

将一个匀称的多边形切割成 N 个大小相等的多边形

[英]Cut a shapely polygon into N equally sized polygons

I have a Shapely polygon.我有一个匀称的多边形。 I want to cut these polygon into n polygons, which all have more-or-less equally sized areas.我想将这些多边形切割成n 个多边形,它们都具有或多或少相同大小的区域。 Equally sized would be best, but an approximation would be okay too.大小相同是最好的,但近似值也可以。

I have tried to use the two methods described here , which both are a step in the right direction by not what I need.我尝试使用这里描述的两种方法,这两种方法都是朝着正确方向迈出的一步,而不是我需要的。 Both don't allow for a target n两者都不允许目标n

I looked into voronoi , with which I am largely unfamiliar.我调查了voronoi ,对此我很陌生。 The resulting shapes this analysis gives would be ideal, but it requires points, not a shape as input.此分析给出的最终形状将是理想的,但它需要点,而不是形状作为输入。

This is the best I could manage.这是我能做到的最好的。 It does not result in equal surface area per polygon, but it turned out to work for what I needed.它不会导致每个多边形的表面积相等,但事实证明它可以满足我的需要。 This populates a shape with a specific number of points (if the parameters are kept constant, the number of points will be too).这会使用特定数量的点填充形状(如果参数保持不变,点数也会保持不变)。 Then the points are converted to a voronoi, which was then turned into triangles.然后将这些点转换为 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)

This is the input shape:这是输入形状:

在此处输入图像描述

This is after shape_to_points :这是在shape_to_points之后:

在此处输入图像描述

This is after points_to_voronoi这是在points_to_voronoi之后

在此处输入图像描述

And then we can triangulate the voronoi:然后我们可以对 voronoi 进行三角测量:

在此处输入图像描述

Another out-of-the-box option out there is the h3 polyfill function.另一个开箱即用的选项是 h3 polyfill 函数。 Basically any repeating structure would work (triangle, square, hex), but Uber's library uses hexes so you're stuck with that unless you write a module to do the same thing with one of the other shapes.基本上任何重复结构都可以工作(三角形、正方形、十六进制),但 Uber 的库使用十六进制,所以除非你编写一个模块来对其他形状之一做同样的事情,否则你会被困住。 You still have the issue with "n" not being specified directly though (only indirectly through the discrete zoom level options).但是,您仍然存在未直接指定“n”的问题(仅通过离散缩放级别选项间接指定)。

polyfill填充物

Just combining the response and basic polyfill docs provided by @user3496060 (very helpful for me, thank you), here's a simple function.只需结合 @user3496060 提供的响应和基本 polyfill 文档(对我很有帮助,谢谢),这是一个简单的功能。

And here's a great notebook from the h3 repo.这是来自 h3 repo 的一个很棒的笔记本 Check out the "Census Polygon to Hex" section for how they use polyfill() .查看“人口普查多边形到十六进制”部分,了解他们如何使用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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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