Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从Voronoi单元获取有界多边形坐标_Python_Computational Geometry_Polygons_Voronoi - Fatal编程技术网

Python 从Voronoi单元获取有界多边形坐标

Python 从Voronoi单元获取有界多边形坐标,python,computational-geometry,polygons,voronoi,Python,Computational Geometry,Polygons,Voronoi,我有点(例如,细胞塔位置的lat、lon对),我需要得到它们形成的Voronoi细胞的多边形 from scipy.spatial import Voronoi tower = [[ 24.686 , 46.7081], [ 24.686 , 46.7081], [ 24.686 , 46.7081]] c = Voronoi(towers) 现在,我需要得到每个单元的多边形边界(以及多边形围绕的质心)。我需要这个Voronoi也有界。这意味着边界不是无限

我有点(例如,细胞塔位置的lat、lon对),我需要得到它们形成的Voronoi细胞的多边形

from scipy.spatial import Voronoi

tower = [[ 24.686 ,  46.7081],
       [ 24.686 ,  46.7081],
       [ 24.686 ,  46.7081]]

c = Voronoi(towers)

现在,我需要得到每个单元的多边形边界(以及多边形围绕的质心)。我需要这个Voronoi也有界。这意味着边界不是无限大的,而是在一个边界框内。

给定一个矩形边界框,我的第一个想法是在这个边界框和所生成的Voronoï图之间定义一种相交操作。这个想法并不一定伟大,因为这需要编写大量计算几何的基本函数

# Generates a bounded vornoi diagram with finite regions in the bounding box
def bounded_voronoi(towers, bounding_box):
    # Select towers inside the bounding box
    i = in_box(towers, bounding_box)

    # Mirror points left, right, above, and under to provide finite regions for the
    # edge regions of the bounding box
    points_center = towers[i, :]

    points_left = np.copy(points_center)
    points_left[:, 0] = bounding_box[0] - (points_left[:, 0] - bounding_box[0])

    points_right = np.copy(points_center)
    points_right[:, 0] = bounding_box[1] + (bounding_box[1] - points_right[:, 0])

    points_down = np.copy(points_center)
    points_down[:, 1] = bounding_box[2] - (points_down[:, 1] - bounding_box[2])

    points_up = np.copy(points_center)
    points_up[:, 1] = bounding_box[3] + (bounding_box[3] - points_up[:, 1])

    points = np.append(points_center,
                       np.append(np.append(points_left,
                                           points_right,
                                           axis=0),
                                 np.append(points_down,
                                           points_up,
                                           axis=0),
                                 axis=0),
                       axis=0)
def generate_CVD(points, iterations, bounding_box):
    p = copy.copy(points)

    for i in range(iterations):
        vor = bounded_voronoi(p, bounding_box)
        centroids = []

        for region in vor.filtered_regions:
            # grabs vertices for the region and adds a duplicate
            # of the first one to the end
            vertices = vor.vertices[region + [region[0]], :] 
            centroid = centroid_region(vertices)
            centroids.append(list(centroid[0, :]))

        p = np.array(centroids)

    return bounded_voronoi(p, bounding_box)
然而,我想到了第二个想法(hack?):计算平面上一组
n
点的Voronoï图的算法的时间复杂度为
O(n ln(n))
。如何添加点以约束初始点的Voronoïcells位于边界框中

有界Voronoï图的解 一幅画抵得上一场精彩的演讲:

我在这里做了什么?这很简单!初始点(蓝色)位于
[0.0,1.0]x[0.0,1.0]
中。然后,我根据
x=0.0
(边界框的左边缘)通过反射对称获得左侧的点(蓝色)(即
[-1.0,0.0]x[0.0,1.0]
)。根据
x=1.0
y=0.0
y=1.0
(边界框的其他边缘)的反射对称性,我得到了完成此项工作所需的所有点(蓝色)

然后运行
scipy.spatial.Voronoi
。前面的图像描述了生成的Voronoï图(我使用)

下一步怎么办?仅根据边界框过滤点、边或面。并根据已知的计算公式得到每个面的质心。以下是结果的图像(质心为红色):

在显示代码之前先做一些有趣的事情 太好了!它似乎起作用了。如果在一次迭代后,我尝试在质心(红色)而不是初始点(蓝色)上重新运行算法会怎么样?如果我一次又一次地尝试呢

步骤2

步骤10

步骤25

酷!Voronoï细胞倾向于最小化其能量

这是密码
将matplotlib.pyplot导入为pl
将numpy作为np导入
将scipy作为sp导入
导入scipy.spatial
导入系统
eps=sys.float\u info.epsilon
n_塔=100
塔楼=np.random.rand(n_塔楼,2)
边界盒=np.数组([0,1,0,1.])#[x_最小,x_最大,y_最小,y_最大]
def输入框(塔、边界框):

返回np.logical\u and(np.logical\u and)(边界框[0]我在使用scipy的voronoi函数和创建CVD时遇到了很多困难,因此这些精彩的帖子和评论帮助很大。作为一名编程新手,我试图理解Flabetvvibes answer中的代码,我将与Energya和我自己的修改分享我对其工作原理的解释。我还发布了我的v答案底部的代码完整版本

import matplotlib.pyplot as pl
import numpy as np
import scipy as sp
import scipy.spatial
import sys
import copy

eps = sys.float_info.epsilon

# Returns a new np.array of towers that within the bounding_box
def in_box(towers, bounding_box):
    return np.logical_and(np.logical_and(bounding_box[0] <= towers[:, 0],
                                         towers[:, 0] <= bounding_box[1]),
                          np.logical_and(bounding_box[2] <= towers[:, 1],
                                         towers[:, 1] <= bounding_box[3]))
Flabetvvibes镜像点以允许沿边界框内边缘的区域是有限的。对于未定义的顶点,Scipy的voronoi方法返回-1,因此镜像点允许边界框内的所有区域是有限的,并且所有无限区域位于边界框外的镜像区域中至少在以后会被丢弃

# Compute Voronoi
vor = sp.spatial.Voronoi(points)

# creates a new attibute for points that form the diagram within the region
vor.filtered_points = points_center 
# grabs the first fifth of the regions, which are the original regions
vor.filtered_regions = np.array(vor.regions)[vor.point_region[:vor.npoints//5]]

return vor
bounded_voronoi方法的最后一位调用了scipy的voronoi函数,并为边界框内的过滤点和区域添加了新属性。Energya建议删除Flabetvvibe的代码,该代码使用一个线性函数手动查找边界框内的所有有限区域,该线性函数获取区域的前五分之一,这将是原始输入以及构成边界框的点

# Generates a bounded vornoi diagram with finite regions in the bounding box
def bounded_voronoi(towers, bounding_box):
    # Select towers inside the bounding box
    i = in_box(towers, bounding_box)

    # Mirror points left, right, above, and under to provide finite regions for the
    # edge regions of the bounding box
    points_center = towers[i, :]

    points_left = np.copy(points_center)
    points_left[:, 0] = bounding_box[0] - (points_left[:, 0] - bounding_box[0])

    points_right = np.copy(points_center)
    points_right[:, 0] = bounding_box[1] + (bounding_box[1] - points_right[:, 0])

    points_down = np.copy(points_center)
    points_down[:, 1] = bounding_box[2] - (points_down[:, 1] - bounding_box[2])

    points_up = np.copy(points_center)
    points_up[:, 1] = bounding_box[3] + (bounding_box[3] - points_up[:, 1])

    points = np.append(points_center,
                       np.append(np.append(points_left,
                                           points_right,
                                           axis=0),
                                 np.append(points_down,
                                           points_up,
                                           axis=0),
                                 axis=0),
                       axis=0)
def generate_CVD(points, iterations, bounding_box):
    p = copy.copy(points)

    for i in range(iterations):
        vor = bounded_voronoi(p, bounding_box)
        centroids = []

        for region in vor.filtered_regions:
            # grabs vertices for the region and adds a duplicate
            # of the first one to the end
            vertices = vor.vertices[region + [region[0]], :] 
            centroid = centroid_region(vertices)
            centroids.append(list(centroid[0, :]))

        p = np.array(centroids)

    return bounded_voronoi(p, bounding_box)
我使用Flabetvvibe的代码执行loyd算法的迭代,并将其形成一种易于使用的方法。对于每次迭代,调用先前的有界函数,然后为每个单元找到质心,它们成为下一次迭代的新点集。
顶点=vor.顶点[region+[region[0]],:]
只需抓取当前区域的所有顶点,并将第一个顶点复制到末端,以便第一个和最后一个顶点在计算质心时相同

感谢Flabetvvibes和Energya。您的帖子/答案教会了我如何更好地使用scipy的voronoi方法,而不是its文档。我还将代码作为一个单独的主体发布到任何其他正在寻找副本/粘贴的人的下方

import matplotlib.pyplot as pl
import numpy as np
import scipy as sp
import scipy.spatial
import sys
import copy

eps = sys.float_info.epsilon

# Returns a new np.array of towers that within the bounding_box
def in_box(towers, bounding_box):
    return np.logical_and(np.logical_and(bounding_box[0] <= towers[:, 0],
                                         towers[:, 0] <= bounding_box[1]),
                          np.logical_and(bounding_box[2] <= towers[:, 1],
                                         towers[:, 1] <= bounding_box[3]))


# Generates a bounded vornoi diagram with finite regions
def bounded_voronoi(towers, bounding_box):
    # Select towers inside the bounding box
    i = in_box(towers, bounding_box)

    # Mirror points left, right, above, and under to provide finite regions for the edge regions of the bounding box
    points_center = towers[i, :]

    points_left = np.copy(points_center)
    points_left[:, 0] = bounding_box[0] - (points_left[:, 0] - bounding_box[0])

    points_right = np.copy(points_center)
    points_right[:, 0] = bounding_box[1] + (bounding_box[1] - points_right[:, 0])

    points_down = np.copy(points_center)
    points_down[:, 1] = bounding_box[2] - (points_down[:, 1] - bounding_box[2])

    points_up = np.copy(points_center)
    points_up[:, 1] = bounding_box[3] + (bounding_box[3] - points_up[:, 1])

    points = np.append(points_center,
                       np.append(np.append(points_left,
                                           points_right,
                                           axis=0),
                                 np.append(points_down,
                                           points_up,
                                           axis=0),
                                 axis=0),
                       axis=0)

    # Compute Voronoi
    vor = sp.spatial.Voronoi(points)

    vor.filtered_points = points_center # creates a new attibute for points that form the diagram within the region
    vor.filtered_regions = np.array(vor.regions)[vor.point_region[:vor.npoints//5]] # grabs the first fifth of the regions, which are the original regions

    return vor


# Finds the centroid of a region. First and last point should be the same.
def centroid_region(vertices):
    # Polygon's signed area
    A = 0
    # Centroid's x
    C_x = 0
    # Centroid's y
    C_y = 0
    for i in range(0, len(vertices) - 1):
        s = (vertices[i, 0] * vertices[i + 1, 1] - vertices[i + 1, 0] * vertices[i, 1])
        A = A + s
        C_x = C_x + (vertices[i, 0] + vertices[i + 1, 0]) * s
        C_y = C_y + (vertices[i, 1] + vertices[i + 1, 1]) * s
    A = 0.5 * A
    C_x = (1.0 / (6.0 * A)) * C_x
    C_y = (1.0 / (6.0 * A)) * C_y
    return np.array([[C_x, C_y]])


# Performs x iterations of loyd's algorithm to calculate a centroidal vornoi diagram
def generate_CVD(points, iterations, bounding_box):
    p = copy.copy(points)

    for i in range(iterations):
        vor = bounded_voronoi(p, bounding_box)
        centroids = []

        for region in vor.filtered_regions:
            vertices = vor.vertices[region + [region[0]], :] # grabs vertices for the region and adds a duplicate of the first one to the end
            centroid = centroid_region(vertices)
            centroids.append(list(centroid[0, :]))

        p = np.array(centroids)

    return bounded_voronoi(p, bounding_box)


# returns a pyplot of given voronoi data
def plot_vornoi_diagram(vor, bounding_box, show_figure):
    # Initializes pyplot stuff
    fig = pl.figure()
    ax = fig.gca()

    # Plot initial points
    ax.plot(vor.filtered_points[:, 0], vor.filtered_points[:, 1], 'b.')

    # Plot ridges points
    for region in vor.filtered_regions:
        vertices = vor.vertices[region, :]
        ax.plot(vertices[:, 0], vertices[:, 1], 'go')

    # Plot ridges
    for region in vor.filtered_regions:
        vertices = vor.vertices[region + [region[0]], :]
        ax.plot(vertices[:, 0], vertices[:, 1], 'k-')

    # stores references to numbers for setting axes limits
    margin_percent = .1
    width = bounding_box[1]-bounding_box[0]
    height = bounding_box[3]-bounding_box[2]

    ax.set_xlim([bounding_box[0]-width*margin_percent, bounding_box[1]+width*margin_percent])
    ax.set_ylim([bounding_box[2]-height*margin_percent, bounding_box[3]+height*margin_percent])

    if show_figure:
        pl.show()
    return fig
将matplotlib.pyplot导入为pl
将numpy作为np导入
将scipy作为sp导入
导入scipy.spatial
导入系统
导入副本
eps=sys.float\u info.epsilon
#返回位于边界框内的塔的新np.array
def输入框(塔、边界框):

返回np.logical\u and(np.logical\u and)(边界框[0]为什么在检查点是否在边界框内时要减去epsilon?为了确保浮点舍入错误不会使点在边界框内时出现在边界框外?另外,为什么在获取质心坐标时要将A乘以6.0?如果您能在这些问题上提供任何帮助,我们将不胜感激!啊,这回答了我的第二个问题:回答你的第一个问题:是的,这个减法只用于处理浮点舍入错误。如果我记得很清楚,我开始时没有减法,但无法得到预期的结果。如果你尝试不使用减法的代码,请告诉我它是否正常工作。非常感谢这段代码&insigh不过,我对您的过程有一个改进:通过构造,您要保留的区域属于您为
scipy.space.Voronoi()
指定的点的前1/5。这意味着您可以使用
Voronoi.po