Python科学计算(第2版)
上QQ阅读APP看书,第一时间看更新

3.10.2 凸包

所谓凸包是指N维空间中的一个区域,该区域中任意两点之间的线段都完全被包含在该区域之中,二维平面上的凸多边形就是典型的凸包。ConvexHull可以快速计算包含N维空间中点的集合的最小凸包。下面先看一个二维的例子:points2d是一组二维平面上的随机点,ch2d是这些点的凸包对象。ConvexHull.simplices是凸包的每条边线的两个顶点在points2d中的下标,由于它的形状为(5, 2),因此凸包由5条线段构成。对于二维的情况,ConvexHull.vertices是凸多边形的每个顶点在points2d中的下标,按逆时针方向的顺序排列。

    np.random.seed(42)
    points2d = np.random.rand(10, 2)
    ch2d = spatial.ConvexHull(points2d)
    ch2d.simplices   ch2d.vertices
    --------------  ---------------
    [[2, 5],        [5, 2, 6, 1, 0]
     [2, 6],
     [0, 5],
     [1, 6],
     [1, 0]]

使用matplotlib中的Polygon对象可以绘制如图3-59所示的多边形。

图3-59 二维平面上的凸包

    poly = pl.Polygon(points2d[ch2d.vertices], fill=None, lw=2, color="r", alpha=0.5)
    ax = pl.subplot(aspect="equal")
    pl.plot(points2d[:, 0], points2d[:, 1], "go")
    for i, pos in enumerate(points2d):
        pl.text(pos[0], pos[1], str(i), color="blue")
    ax.add_artist(poly)

三维空间中的凸包是一个凸多面体,每个面都是一个三角形。在下面的例子中,由simplices的形状可知,所得到的凸包由38个三角形面构成:

    np.random.seed(42)
    points3d = np.random.rand(40, 3)
    ch3d = spatial.ConvexHull(points3d)
    ch3d.simplices.shape
    (38, 3)

下面的程序用TVTK直观地显示凸包,图3-60中所有的绿色圆球表示points3d中的点,由红色线段构成的三角形面表示凸多面体上的面。没有和红色线段相连的点就是凸包之内的点:

图3-60 三维空间中的凸包

    from scpy2 import vtk_convexhull, vtk_scene, vtk_scene_to_array
    actors = vtk_convexhull(ch3d)
    scene = vtk_scene(actors, viewangle=22)
    %array_image vtk_scene_to_array(scene)
    scene.close()

如果读者希望采用三维交互界面,可以在Notebook中执行如下代码:

    %gui qt
    from scpy2 import ivtk_scene
    ivtk_scene(actors)