以下文字摘自互动百科:
Voronoi图,又叫泰森多边形或 Dirichlet图,它是由一组由连接两邻点直线的垂直平分线组成的连续多边形组成。 N个在平面上有区别的点,按照最邻近原则划分平面,每个点与它的最近邻区域相关联。 Delaunay三角形是由与相邻 Voronoi多边形共享一条边的相关点连接而成的三角形。 Delaunay三角形的外接圆圆心是与三角形相关的 Voronoi多边形的一个顶点。 Delaunay三角形是 Voronoi图的偶图。
对于给定的初始点集 P,有多种三角剖分方式,其中 Delaunay三角剖分具有以下特征:
实现内容: 本次作业主要实现了平面点集的Delaunay三角剖分。为了验证Delaunay三角剖分的正确性,系统提供了“圆测试”的功能,供用户对生成的三角形进行测试验证;为了验证DCEL数据结构的正确性,系统提供了“DCEL测试”的功能,用户输入任意一条测试线,系统将先后显示出测试线贯穿过的三角形;为了形象显示三角剖分的分治过程,系统提供了动态显示分治剖分过程。
报告组成: 首先对算法依赖的数据结构DCEL进行说明,然后对基于DCEL的分治算法进行介绍,接着介绍DCEL测试和圆测试的相关细节,最后是对作品操作进行介绍,以及展示和分析实验结果。
Guibas等[1]在文章中提出了一种Quad-Edge结构,使得Delaunay三角剖分的操作过程变得比较简单,并且由于这种结构保存了边的对偶信息,因此Delaunay三角与Voronoi diagrams之间的相互转换也非常容易。
此次实验要求使用DCEL(Doubly-Connected Edge List)结构,该结构比Quad-Edge简单,并未保存边的对偶信息。下面的两幅图显示了两种数据结构在信息存储上的区别。
Quad-Edge中的next为以origin为起点,逆时针找到的e[0]的下一条边。
虽然DCEL没有存储Quad-Edge中的对偶边e[1]和e[3],可能对从Delaunay三角转化为Voronoi图有所不便,但是对于实现Delaunay三角剖分来说DCEL已经足够用了,用Quad-Edge可以找得到的与e[0]相关联的边,使用DCEL结构也可以很轻易的找到,下面给出这些关联边的图示。
1.void splice(Edge* a, Edge* b)
该函数的功能为:若a和b的起点是一个点,那么 a和 b将会被分成两条不相干的边;若 a和 b原本是两条不相干的边,那么这两条边的起点就会被连起来。下面是 Guibas文章的中一张对 splice进行解释的图:
DCEL中 splice的具体实现与 Quad-Edge略有不同,只要掌握了 splice具有上述功能的本质原因,就能很容易的实现了。具体实现请参考源码 dtriangulation。
2.Edge* connect(Edge* a, Edge* b)
该函数的功能为:把 a的终点与 b的起点连起来。
3.void swap(Edge* e)
该函数的功能为:在 inCircle*测试失败后(意味着与 e相邻的两个三角不是 Delaunay三角),从 e的起点、终点沿四边形内部逆时针找到下两个点作为新的起点、终点,添加边 e‘,并删除边 e。如图所示:
*inCircle(a,b,c,d)函数测试点d是否在点a、b、c构成的三角形的外接圆内部。
判定一个点是否在一个圆内,我们马上想到得算法是求出该点到圆心的距离,然后与圆的半径大小做比较,但是假设圆心事先不知道,只提供了该圆上的三个顶点,然后同过这三个顶点来求得圆心的位置,我们马上想到的办法也可能是求出两条连线垂直平分线的交点就是圆心,但是这种算法在三点共线的情况下,两条连线的垂直平分线的交点在无穷远处,计算机是无法记录该圆心坐标,因此这种算法不鲁棒。 文献 [1]中提到的 InCircle方法是把平面上的点(x,y,0)投影到z=x 2+y 2的抛物面上,得到相应的投影坐标为(x, y, x 2+y 2),如下图所示:
判定原则如下:
4.Edge* locate(const Point2d& p, Edge* startEdge)
该函数的功能是给定一个点p,从startEdge出发,找到该点所落在的Delaunay三角剖分面片,返回该三角面片的按ccw方向的一条边。
主要步骤如下(见下图):
当平面上的点集划分到数目 N 小于4时(显然只会出现节点为2和3的情况,不会出现为1的情况),直接两两点互连就是Delaunay三角剖分,递归划分结束(具体情况见下图)。
由于 DCEL结构的特性,可以使得剖分完成后的所有边都可以通过任意边抵达,本递归算法返回结果是两条边,分别是:以最左点为始点的逆时针方向的边和以最右点为始点顺时针方向的边(见下图)。保存这两条特殊的边的目的:
两个子凸包的下公切线查找使用的是 Zig-Zag算法,具体的细节可参考 [1]或是邓俊辉老师计算几何课件。
分治法的Divide的时间复杂度为O(1),Merge的过程时间复杂度为O(n),设总的时间复杂度为T(n),则T(n)=2T(n/2)+O(n),根据主定理可以推出该分治法的时间复杂度T(n)为O(nlogn)
DCEL测试是通过在Delaunay三角剖分中连接一条直线 l ,然后按顺序找到并记录该边穿过的三角面片。主要是为了验证DCEL数据结构的正确性和点定位 locate算法的效率(见下图)。
Delaunay三角剖分具有如下性质:任一三角形外接圆内部不会出现第四个点。
为了直观地检测该程序对平面点集进行Delaunay三角剖分的正确性,我们为该程序添加了圆测试功能。在三角剖分之后,点击“操作”->“外接圆测试”,点中屏幕中任意一个三角形,程序将会绘制出该三角形的外接圆(左图),如果有第四个点“仿佛”落在该圆内,可以使用放大镜功能将该区域局部放大(中图),可以很明显地看出该点不在圆内(右图)。
遇到的问题:刚开始使用垂直平分线交点的方法求解三角形外接圆,后来发现忘记判断三角形的边是否水平或者竖直,导致在某些情况下无法计算得出外接圆。之后偶然发现一种更好的求解外接圆的方法[4],该方法简化了表达式,不需要繁琐的判别,就可求出结果,因此我们也采用该方法求解外接圆。具体实现请参考源码dtriangulation。
下面左图是1k个点的显示,右图是100k个点的显示。
下面两个剖分结果是分别对应上面两组输入的点集。
下面四组图是对剖分三角形进行DCEL测试的结果图。动态演示过程请见下面的视频demo。
系统提供了对剖分三角形进行圆测试,验证剖分得到的三角形是否正确。圆测试结果如下。
在输入的点集数目达到10k以上,比较难分辨出点和线的细节信息,此时可以通过选择放大显示来观察相关细节部分情况。如下图所示,左边是整体的显示,右边显示左边被框住区域的细节。
系统支持对分治过程的中间结果进行演示,由于程序在演示过程中无法进行截屏,演示过程见下面的视频demo。
下面的视频对以上涉及的相关操作都有一个简单的演示过程。具体情况可以下载并观看此视频。
http://cgprojects09.googlecode.com/files/demo.avi
点集数目 | 100 | 500 | 1,000 | 5,000 | 10,000 | 50,000 | 100,000 | 500,000 | 1,000,000 | 2,000,000 | 3,000,000 | 4,000,000 | 5,000,000 |
算法耗时(us) | 184 | 1,293 | 2,922 | 18,153 | 39,334 | 228,714 | 485,895 | 2,723,544 | 5,777,429 | 12,061,211 | 18,188,295 | 24,803,120 | 32,020,173 |
用上述实验数据进行曲线拟合,可以得到下面一条曲线,满足O( n log( n ))的性质。
点集数目 | 100 | 500 | 1,000 | 5,000 | 10,000 | 50,000 | 100,000 | 500,000 | 1,000,000 | 2,000,000 | 3,000,000 | 4,000,000 | 5,000,000 |
内存消耗(M) | 5 | 6 | 12 | 13 | 14 | 20 | 27 | 90 | 168 | 334 | 482 | 638 | 850 |
使用上述数据进行曲线拟合,大致可以看出,在点集数目为0.5M - 5M之间,曲线大致是线性变化的(点集数目较小时不能说明问题,因为算法使用的数据结构所占内存基本不占主要成分)。
以上测试实验的环境为:Intel Core 2 Duo CPU 2.2GHz, 2.00GB RAM。
[1]L. Guibas and J. Stolfi, Primitives for the manipulation of general subdivisions and the computation of Voronoi diagrams, ACM Transactions on Graphics, 4(2):75-123, 1985.
[2]R. A. Dwyer, A faster divide-and conquer algorithm for constructing Delaunay triangulations algorithmica, 2:137-151, 1987.
[3]D. Lischinski, Incremental Delaunay triangulation, Graphics gems IV, 47-59. 1994.
[4]段小武,巧求外接圆圆心,电脑开发与应用,第15卷,第08期,2002年。
数据文件格式:
5 # 第一行数字为点集个数
0.1 0.2 # 第二行以下是点集的信息,x坐标和y坐标
0.3 0.5
0.4 0.9
1.0 2.0
6.0 2.0