玩玩 spatial 模組


在 Scipy 的模組中,我個人最有興趣的,應該是 spatial 模組了吧!特別是其中的 Delaunay 三角分割,以及建立 Voronoi 圖的部份,畢竟我用 OpenSCAD 創作了許多 3D 模型,而其中有不少就是基於 Delaunay 或 Voronoi。

如果你想知道怎麼實作出 Delaunay 或 Voronoi,可以參考〈玩轉 p5.js〉中相關的文件,而在先前的〈圖片三角分割〉中,也曾透過 Matplotlib 的 mtri.Triangulation 來建立 Delaunay 三角分割。

Scipy 的 spatial 模組中,也有個 Delaunay 類別,來看看如何建立三角分割:

import numpy as np
from scipy import spatial
import matplotlib.pyplot as plt

n = 20

points = np.random.rand(n, 2)
xs = points[:,0]
ys = points[:,1]

tri = spatial.Delaunay(points)

# 換為 spatial.delaunay_plot_2d(tri) 也可以
plt.triplot(xs, ys, tri.simplices, marker = 'o')

plt.show()

simplices 是每個三角形,每個三角形的元素是最初指定點的索引,若只是要畫出三角分割,spatial 提供了 delaunay_plot_2d 函式可以直接使用,其底層基於 Matplotlib,來看看執行結果:

玩玩 spatial 模組

如果你看過〈玩轉 p5.js〉中 Delaunay 與 Voronoi 的文件,就會知道 Delaunay 與 Voronoi 是可以互轉的,如果你要建立 Voronoi,在 spatial 模組中有個 Voronoi 類別:

import numpy as np
from scipy import spatial
import matplotlib.pyplot as plt

n = 20
points = np.random.rand(n, 2)

vor = spatial.Voronoi(points)
spatial.voronoi_plot_2d(vor)
plt.show()

同樣地,spatial 提供了 voronoi_plot_2d 函式可以直接畫 Voronoi 圖,來看看畫出來的結果:

玩玩 spatial 模組

將兩個圖合在一起:

import numpy as np
from scipy import spatial
import matplotlib.pyplot as plt

n = 20
points = np.random.rand(n, 2)

vor = spatial.Voronoi(points)
spatial.voronoi_plot_2d(vor, show_vertices = False)

tri = spatial.Delaunay(points)
xs = points[:,0]
ys = points[:,1]

plt.triplot(xs, ys, tri.simplices, marker = 'o')

plt.show()

在執行結果中,Voronoi 圖就像是細胞,綠點是細胞核:

玩玩 spatial 模組

spatial 模組還有計算各種距離、凸包等的函式,有興趣可以看看〈Spatial data structures and algorithms〉,如果對空間計算方面有興趣,透過 spatial 模組可以省不少的功夫,例如在〈建立 Convex hull〉中,就有基於 ConvexHull 建立凸包模型的範例,另外,在〈Voronoi 2D/3D〉中,有建立 3D 版本的 Voronoi 範例,可以參考一下。