用Python计算并绘制有界(封闭)的Voronoi图


介绍

scipy.spatial.Voronoiscipy.spatial.voronoi_plot_2d是用于使用Python计算和绘制Voronoi图的库示例。
有关这些的详细信息,请参见以下站点。

  • scipy.spatial.Voronoi的正式文档
  • scipy.spatial.voronoi_plot_2d的官方文档
  • 西皮·沃罗诺伊

但是,由于这些库创建的Voronoi图是在无边界(无边界)空间中计算的,因此无法在Voronoi外侧或Voronoi区域(多边形)上获取信息。
因此,这一次,我将介绍一种将封闭区域划分为Voronoi图的方法。

实作

在提到Voronoi地区受限的部分时,我提到了这篇文章。
总体流程如下。

  • 添加三个虚拟的母点以使所有Voronoi区域有界。
  • scipy.spatial.Voronoi计算Voronoi图。

  • shapely计算要划分的区域与每个Voronoi区域的交集。
  • 绘制在3中获得的多边形。
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.collections import PolyCollection
    from scipy.spatial import Voronoi, voronoi_plot_2d
    from shapely.geometry import Polygon

    def bounded_voronoi(bnd, pnts):
        """
        有界なボロノイ図を計算?描画する関数.
        """

        # すべての母点のボロノイ領域を有界にするために,ダミー母点を3個追加
        gn_pnts = np.concatenate([pnts, np.array([[100, 100], [100, -100], [-100, 0]])])

        # ボロノイ図の計算
        vor = Voronoi(gn_pnts)

        # 分割する領域をPolygonに
        bnd_poly = Polygon(bnd)

        # 各ボロノイ領域をしまうリスト
        vor_polys = []

        # ダミー以外の母点についての繰り返し
        for i in range(len(gn_pnts) - 3):

            # 閉空間を考慮しないボロノイ領域
            vor_poly = [vor.vertices[v] for v in vor.regions[vor.point_region[i]]]
            # 分割する領域をボロノイ領域の共通部分を計算
            i_cell = bnd_poly.intersection(Polygon(vor_poly))

            # 閉空間を考慮したボロノイ領域の頂点座標を格納
            vor_polys.append(list(i_cell.exterior.coords[:-1]))


        # ボロノイ図の描画
        fig = plt.figure(figsize=(7, 6))
        ax = fig.add_subplot(111)

        # 母点
        ax.scatter(pnts[:,0], pnts[:,1])

        # ボロノイ領域
        poly_vor = PolyCollection(vor_polys, edgecolor="black",
                                  facecolors="None", linewidth = 1.0)
        ax.add_collection(poly_vor)

        xmin = np.min(bnd[:,0])
        xmax = np.max(bnd[:,0])
        ymin = np.min(bnd[:,1])
        ymax = np.max(bnd[:,1])

        ax.set_xlim(xmin-0.1, xmax+0.1)
        ax.set_ylim(ymin-0.1, ymax+0.1)
        ax.set_aspect('equal')

        plt.show()

        return vor_polys

    划分单位平方

    使用上述功能划分单位平方给出以下内容。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # ボロノイ分割する領域
    bnd = np.array([[0, 0], [1, 0], [1, 1], [0, 1]])

    # 母点の個数
    n = 30
    # 母点座標
    pnts = np.random.rand(n, 2)

    # ボロノイ図の計算?描画
    vor_polys = bounded_voronoi(bnd, pnts)

    voronoi_sq.png

    划分一般的凸多边形

    不是正方形的一般凸多边形可以用相同的方式划分。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    from scipy.spatial import ConvexHull

    def points_in_convex_polygon(bnd, n):
        """
        凸多角形の内部にn個の点をランダムに発生させる関数.
        """

        #領域の境界を表す行列の作成
        bndhull = ConvexHull(bnd)
        bndTmp = bndhull.equations
        bndMat = np.matrix(bndTmp)
        Abnd = np.array(bndMat[:,0:2])
        bbnd = np.array(bndMat[:,2])

        # 領域を囲む長方形
        xmin = np.min(bnd[:,0])
        xmax = np.max(bnd[:,0])
        ymin = np.min(bnd[:,1])
        ymax = np.max(bnd[:,1])

        # 繰り返し用
        i = 0
        pnts = []

        while i < n:

            # 点を生成
            pnt = np.random.rand(2)
            pnt[0] = xmin + (xmax - xmin) * pnt[0]
            pnt[1] = ymin + (ymax - ymin) * pnt[1]

            # 点が凸多角形内にあれば
            if (np.round(np.dot(Abnd,pnt.transpose()),7) <= np.round(-bbnd.transpose(),7)).all():

                pnts.append(pnt.tolist())
                i += 1

        return np.array(pnts)


    # ボロノイ分割する領域
    bnd = np.array([[0.1,0.4],[0.3,0.2],[0.8,0.3],[0.9,0.6],[0.7,0.7],[0.4,0.7],[0.2,0.6]])

    # 母点の個数
    n = 10
    # 母点座標
    pnts = points_in_convex_polygon(bnd, n)

    # ボロノイ図の計算?描画
    vor_polys = bounded_voronoi(bnd, pnts)

    voronoi.png