凸包(Convex Hull)
引言
欢迎光临本网页。在这个网页中,你可以学习到计算几何(Computational Geometry)中的「凸包」(Convex Hull)概念,以及求凸包的基本原理。你亦可试用本人编写的用来求凸包的应用程序。
甚么是凸包?
在了解凸包之前,须先认识何谓「凸多边形」(Convex Polygon)。从直观上说,一个凸多边形就是没有任何凹陷位的多边形。我们在低年级数学所学习的三角形、正方形、长方形、平行四边形、正五边形、正六边形等等,都是凸多边形的例子。但是以下这个「凸」字形却并非凸多边形,因为箭头指着的地方实际是一个凹陷位。
可是上述这一定义很不严密,究竟何谓「凹陷位」?实在难以说清楚。因此在数学上,凸多边形有另一个严格的定义。假设我们在一个多边形上(包括多边形的边界及边界围封的范围)任意取两点并以一条线段连结该两点,如果线段上的每一点均在该多边形上,那么我们便说这个多边形是凸的。根据以上定义,我们便可判断「凸」字形的确不是凸的。例如,在下图中,连结A、B两点的线段有一部分并不在该多边形上。
认识了凸多边形后,我们便可了解何谓凸包。给定平面上的一个(有限)点集(即一组点),这个点集的凸包就是包含点集中所有点的最小面积的凸多边形。例如,下图的点集共包含9个点,图中的六边形便是该点集的凸包。其中构成六边形的6个点称为「凸包上的点」(Hull Point),其余3个点则并非「凸包上的点」。请注意上述定义中「最小面积」这个限制条件,因为除了凸包以外,还有无限多个包含点集中所有点的凸多边形。例如,只要画一个面积足够大的四边形,便可包围任意给定的点集。因此假如没有这个限制条件,求凸包就变成非常容易但却没有唯一解的运算。
求凸包的应用程序
本人编写了三个求凸包的应用程序,包括一个Visual Basic版和两个Flash版。Visual Basic版为EXE档,请点击下列连结,下载有关档案(该EXE档连同其它必要档案已压缩在一个ZIP档案中,下载后必须解压缩),然后便可在你的计算机上执行。两个Flash版分别为SWF和EXE档,你只需点击下列有关连结,便可执行程序。上述程序都包含「使用说明」或"Instructions",浏览者只需依照说明上的指示便可使用该程序,请选择适合你计算机的程式。
连结:
求凸包的基本原理
本程序采用循序渐进的方式求取给定点集的凸包,首先把使用者最初输入的3个不共线(Non-collinear)的点按逆时针方向构成一个三角形(注1),这就是这3点的凸包。接着程序便会考察第4点,看看这个点是否位于前述三角形之内或三角形的边上。若是,则这第4点并非凸包上的点,前述三角形保持不变。若否,则把这前述的三角形扩大为一个四边形,并把不适用的边擦去。这个四边形便是这首4点的凸包。接着程序又会考察第5点,如此类推,直至所有点均已被考察为止。使用者在使用本程序时可以清楚看到上述从最初的三角形逐步扩大为最终的凸包的过程。
这里涉及到判断一点是否被包围在某一多边形内的问题,人类凭肉眼很容易便能作出此一判断。可是计算机没有眼睛,它所具备的信息只有给定点的坐标,我们应如何「教」计算机作出上述判断呢?其实方法并不太复杂。且来看看一个简单的例子。
在上图中,A、B、C是最初输入的三点,这三点按逆时针方向构成了一个三角形。接着让我们考察第4个点D。这一点有甚么特点?假如我们循着逆时针方向在三角形的边上走一周,我们便会发现D点总是位于我们的左方。事实上,在三角形范围内的任何一点都具有此一特点。
接着让我们来考察第5点E,这一点的情况跟D点很不一样。假如我们循着逆时针方向在三角形的边上走一周,我们便会发现E点有时出现在我们的左边,有时出现在右边。事实上,在三角形范围外的任何一点都具有此一特点。而且,上述方向改变还可帮助我们判断应把哪一点连到E点以及应擦去哪一条线。例如,当我们从CA线走到AB 在线时,E点的位置从我们的左边变为右边(注2),此一转向告诉我们应把A点连向E点。同样,当我们从AB线走到BC在线时,E点的位置从我们的右边变为左边,此一转向告诉我们应把B点连向E点。此外,在上述分析中,E 点总是位于AB线的右边,因此AB线必不能包住E点,因此应将AB线擦去。最后,当我们从BC线走到CA在线时,E 点总是位于我们的左边,因此我们无须把C点连向E点。经过上述分析后,我们便得一个新的四边形AEBC,这个四边形就是图中5点的凸包。
看到这里,读者不禁要问,计算机如何判断某一点是位于某条直线的左边还是右边呢?其实只要看看上图,我们容易发现,左转相当于逆时针方向,右转则相当于顺时针方向。因此我们可以利用逆时针和顺时针这一组概念来代替左、右这两个概念。这里我们可以用向量代数中一条有关平面三角形面积的公式。给定平面上3点 P1、P2、P3的坐标(x1, y1)、(x2, y2)和(x3, y3),这3点所构成三角形的面积可表达为一个名为Area的函数:
Area(P1, P2, P3)=
此一公式使用行列式(Determinant)来定义三角形面积,可以展开并化简为:
Area(P1, P2, P3) = (x1y2 - x1y3 - x2y1 + x3y1 + x2y3 - x3y2) / 2
但请注意,上式并非单纯计算三角形的面积,而是「有向面积」(Signed Area),它不仅告诉我们给定3点所构成三角形的大小,而且告诉我们这3点的相对方向。当Area(P1, P2, P3) 的值是负数时,这代表P1->P2->P3的走向是逆时针方向。反之,若 Area(P1, P2, P3)的值是正数,则代表这3点的走向是顺时针方向。若 Area(P1, P2, P3)为零,则代表这3点共线。因此Area这个函数在求凸包的运算中有极大的用途,可用来判断哪些点是凸包上的点,以及应用直线连结哪些点。事实上,本程序亦广泛运用这个函数。
注1:如果有3点在同一条直线上,我们就称该3点共线(Collinear)。若果3点共线,便不能构成一个三角形。至于为何要按逆时针方向构成这个三角形,看看下文便会明白。
注2:我们说「当我们在CA在线时E点位于我们的左边」,是指当我们把CA线无限延长并且面向着A点时,E点位于这条无限延长线的左边。
源文档