计算几何实验报告.docx
- 文档编号:4065855
- 上传时间:2022-11-27
- 格式:DOCX
- 页数:15
- 大小:303.64KB
计算几何实验报告.docx
《计算几何实验报告.docx》由会员分享,可在线阅读,更多相关《计算几何实验报告.docx(15页珍藏版)》请在冰豆网上搜索。
计算几何实验报告
1.计算几何实验报告
2.实验目的
用VC语言实现任意多边形的Delaunay完全三角剖分算法。
3.实验内容
在计算机三维曲面造型,有限元计算和模式识别等领域里,经常要解决平面多边形的三角剖分问题。
一方面三角剖分解决了几何数据存储的一致性;另一方面三角形是平面域的单纯形,具有许多特性和优点,是解决许多问题的基础,处理上也比较简单,例如可以很好的拟合复杂边界等。
Delaunay三角剖分具有三角剖分最小内角为最大”的性质,能够进行任意多连通域有限网格的自动生成。
令P={P1,P2,⋯,PN}为平面域(R2)上N个离散点的集合,尽管有多种方法实现点集P的三角剖分,但是俄国科学家Delaunay在1934年证明:
必定存在且仅存在一种三角剖分(一般称为Delaunay三角剖分)算法,使得所有三角形的最小内角之和最大。
因此,Delaunay三角剖分能够尽可能地避免病态三角形的出现。
一般情况下,一个完整的Voronoi图有多个Voronoi多边形组成,第i个Voronoi多边形的数学表达形式如下:
Vi={x∈R2:
‖x-Pi‖≤‖x-Pi‖,j=1,⋯,n;j≠i}
(1)
式中,i=1,2,⋯,N,‖x-Pi‖表示平面域上点x和节点Pi之间的欧式距离。
从
(1)式可知,Voronoi多边形Vi内任意点x到节点Pi的距离比到点集P中任何其他节点的距离更近,因此Vi由节点Pi和每个相邻节点的垂直平分线所形成的开式半平面的交集组成,故Vi必为凸多边形。
一般情况下,Voronoi图的一个顶点同时属于三个Voronoi多边形,每个Voronoi多边形内有且仅有
一个节点。
连接三个共点的Voronoi多边形分别对应的三个节点则形成一个Delaunay三角形,所有这样的三角形的集合就是著名的Delaunay三角剖分。
图l给出了8个节点的Delaunay三角剖分及其对偶的Voronoi图。
Delaunay三角剖分的一个重要性质就是所谓的“空圆盘”性质:
对于任意的Delaunay三角形,其开式圆盘(即该三角形外接圆的内部区域)不包含其他任何节点,所有Delaunay三角形互不重叠,且完整地覆盖整个问题域。
4.算法原理
在实际问题中,任何二维图形总是有一个外环和若干个内环组成,并且任意两个环之间不会重叠。
对于自相交多边形或者有重叠的非自相交多边形,均可以将它们分解成若干个无重叠多边形。
整个算法如F:
令多边形的边数为N,第K条边的起点序号为LKl,终点序号为LK2,此时不再有内环和外环的概念的区分。
(1)若N=3,则该多边形本身是一个三角形,剖分结束;否则令K=1,转入
(1);
(2)令K=K+1,若LK2不在有向线段L1lLl2之左,转入
(2);否则转入(3);
(3)判断当前多边形其余各边是否与线段Ll1LK2或Ll2LK2相交,若是,转入
(2);否则,转入(4);
(4)保存节电LK2至候选节电列表中,若K=N,转入(5);否则转入
(2);
(5)首先,从候选节点列表中求出与节点Ll1,Ll2形成的外接圆最小的节点LO2,则节点L1l,Ll2和LO2必然构成一个有效的Delaunay三角形;其次,判断由节点L1l,Ll2和LO2构成的Delaunay三角形中是否有候选节点存在。
如果有候选节点存在,则保存到新的候选节点列表,然后再从新的候选节点列表中重新选取与节点L1l和L12构成的Delaunay三角形的外接圆最小的节点LO2,然后在对当前多边形作如下的修正。
如果没有候选节点存在,则直接对当前多边形作如下的修正。
①若线段L1lLO2及L12LO2均不是当前多边形的边界线段,则令N=N+1,LN1=LO2,LN2=L12,
L12=LO2,转入
(1):
②若线段L11LO2或(L12LO2)是当前多边形的第m条边界线段,而线段L12LO2(或L11=LO2)不
是当前多边形的边,则令L11=LO2(或L12=LO2),Lm1=LN1,Lm2=LN2,N=N-1,转入
(1);
③若线L11LO2及L12=LO2分别是当前多边形的第m条和第n条边界线段,则将线段L11L12,第m条和第n条边从当前的多边形中删除,N=N一3,转入
(1)。
5.程序实现
4.1数据结构
为了便于对多边形和剖分后形成的三角形的管理,本文采用MFC的CObList类设计和管理链表。
本文设计了2个单向链表其中点链表(CObList*mpNodeList)负责管理多边形的节点,链上的每个结点记录多边形节点的索引号和平面坐标值。
三角形链表(CObList*mpTriList)负责管理剖分后的三角形,链上的每个结点记录了生成的三角形的索引号和构成该三角形的三个顶点的索引号。
点链表和三角形链表结点类的设计如下:
点链表的结点类:
//点链表的结点类
classCNode:
publicCObject
{
public:
intindex;//点索引号
intx,y;//x,y坐标值
boolout;//内外环
intNO_in;//内环编号,外环为0,内环从1开始
boolhead;//是否环头
booltail;//是否环尾
public:
CNode()
{
index=0;
x=0;
y=0;
out=TRUE;
NO_in=0;
head=FALSE;
tail=FALSE;
}//零初始化
CNode(CNode*temp)
{
index=temp->index;
x=temp->x;
y=temp->y;
out=temp->out;
NO_in=temp->NO_in;
head=temp->head;
tail=temp->tail;
}
CNode(CNode&n)
{
index=n.index;
x=n.x;
y=n.y;
out=n.out;
NO_in=n.NO_in;
head=n.head;
tail=n.tail;
}
CNode&operator=(CNoden)
{
index=n.index;
x=n.x;
y=n.y;
out=n.out;
NO_in=n.NO_in;
head=n.head;
tail=n.tail;
return*this;
}
#ifdef_DEBUG
voidDump(CDumpContext&dc)const
{
//CObject:
:
Dump(dc);
dc< } #endif }; 三角形链结点类: classCTriange: publicCObject { public: intindex;//点索引号 intL1,L2,L3;//三角形的三个点的索引号 public: CTriange() { index=0; L1=0; L2=0; L3=0; }//零初始化 CTriange(CTriange*temp) { index=temp->index; L1=temp->L1; L2=temp->L2; L3=temp->L3; } CTriange(CTriange&t) { index=t.index; L1=t.L1; L2=t.L2; L3=t.L3; } CTriange&operator=(CTrianget) { index=t.index; L1=t.L1; L2=t.L1; L3=t.L3; return*this; } }; 同时整个算法的操作对象是多边形的边,为了使算法容易实现,设计了边链表类表示多边形的边,所有多边形的边都存储在边链表(CObList*mpEdgeList)中。 算法中对边的查找、插入、删除都是针对边链表的操作。 //边链表的边类 classCEdge: publicCObject { public: intindex;//边索引号 intL1,L2;//边的两个点的索引号 public: CEdge() { index=0; L1=0; L2=0; }//零初始化 CEdge(CEdge*temp) { index=temp->index; L1=temp->L1; L2=temp->L2; } CEdge(CEdge&t) { index=t.index; L1=t.L1; L2=t.L2; } CEdge&operator=(CEdget) { index=t.index; L1=t.L1; L2=t.L2; return*this; } #ifdef_DEBUG voidDump(CDumpContext&dc)const { //CObject: : Dump(dc); dc< "< } #endif }; 为了便于Windows对话框窗口在窗口重绘时完成对GUI的重绘,设计了便于完成图形重绘的边链表类。 储存对话框上现存的每一条边的颜色和位置信息。 而点的位置信息储存在(CObList*mpNodeList)中。 //用来画图的边链表的边类 classCEdge2: publicCObject { public: intcolor;//边索引号 intx1,y1,x2,y2;//边的两个点的坐标 public: CEdge2() { color=1; x1=0; y1=0; x2=0; y2=0; }//零初始化 CEdge2(CEdge2*temp) { color=temp->color; x1=temp->x1; y1=temp->y1; x2=temp->x2; y2=temp->y2; } CEdge2(CEdge2&t) { color=t.color; x1=t.x1; y1=t.y1; x2=t.x2; y2=t.y2; } CEdge2&operator=(CEdge2t) { color=t.color; x1=t.x1; y1=t.y1; x2=t.x2; y2=t.y2; return*this; } #ifdef_DEBUG voidDump(CDumpContext&dc)const { //CObject: : Dump(dc); dc< "< } #endif }; 程序中再求外接圆半径时会用到直线的斜截式方程,设计直线类如下: //直线方程结构 classCLine { public: doublek;//斜率 doubleb;//截距 }; 4.2GUI设计 本程序用vc6.0设计了基于对话框的绘图界面,使用GDI进行绘图操作,同时对用户各种不合法的输入进行了提示。 4.3程序结构 程序中使用的全局变量和宏如下: #defineBLACK1; #defineRED2; //常数 boolbcandraw=true;//能否绘图 doubleconstpai=3.1415926535897932384626; CWnd*pWnd;//当前窗口指针 CObList*mpNodeList,*mpTriList,*mpCandidateNode,*mpCandidateNode2,*mpEdgeList; //节点链,三角形链,候选节点链,新的候选节点链,边链 CObList*mpAllNode,*mpAllEdge;//界面上所有的点和边 intcurrentnode;//总结点数 intwaihuan;//外环节点数 intneihuan;//内环节点数 intend_in;//外环节点数,内环节点数,目前已完成处理的内环节点数 intcurhuan;//当前环数 boolwai;//是否外环 intcurrentedge=0;//总边数 inttri_index=0;//三角形索引 boolin_start;//内环开始输入的状态 intN;//当前多边形边数 intk;//当前处理边数 intdraw;//重绘次数 CNode*pL11,*pL12,*pLk1,*pLk2,*pLo1,*pLo2,*pLm1,*pLm2,*pLn1,*pLn2;//各边的始终点 CEdge*pLk,*pL1,*pLo,*pLm,*pLn;//各边 程序中用到的主要函数: boolisEdge(CNode*,CNode*,int&);//判断某两点是否多边形的边,如果是,是那条边 intWhichSide(CNode*,CNode*,CNode*);//点在直线哪侧 doublewaixin(CNode*,CNode*,CNode*);//求外接圆半径 intArea2(CNode*,CNode*,CNode*);//由三点坐标求三角形面积 boolToLeft(CNode*,CNode*,CNode*);//判断某点是否在一条直线的左侧 voidfindnode(CEdge*,CNode*&,CNode*&);//找到某边的始终点 voidfindedge(int,CEdge*&);//有索引找到某条边 boolsamep(CNode*,CNode*);//判断两点是否相同 CNodemidpoint(CNode*,CNode*);//求两点的中点 CLineline2p(CNode*,CNode*);//求两点确定的直线 boolisatline(CLine,CNode*);//判断某点是否在直线上 CLinelinepoint(CNode,double,double);//过某点直线方程 CNodecrosspoint(CLine,CLine);//求两直线交点 doubledist(CNode&,CNode&);//求两点距离 算法步骤函数: voidfun5(int&); voidfun4(int&); voidfun3(int&); voidfun2(int&); voidfun1(); 6.运行结果 总的来说,实验运行结果较好,能实现对大多数多边形的三角剖分。 也能对不合理的输入进行提示。 非法的点输入: 不合理的多边形: 简单凸多边形的的三角剖分: 简单凹多边形的三角剖分: 带一个洞的多边形的三角剖分: 带多个洞的多边形的三角剖分: 比较复杂的图形的剖分: “猫脸”图的剖分: 齿形图的剖分: 碰到超复杂的图也会出现一些问题,应当是算法本身的局限性(要求外圈按逆时针输入)导致的: 7.根据答辩意见所做的修改和补充 原论文中对于所谓“任意多边形的Delaunay完全三角剖分”定义不明确,我们的理解是剖分所得的三角形要满足DT规则,即三角形网络中三角形最小内角为最大,也即是所有三角形都尽量接近于等边三角形,而且任意一个三角形的外接圆不包含其他候选顶点(而不是其他顶点)。 8.实验总结 通过读别人的论文,可以学到有经验的学者是怎样解决一个问题的。 无论是算法设计,还是编程时数据结构的设计。 通过编程,也可以体会到怎样把论文中的算法变成程序,编程过程中总会遇到各种各样的问题,在解决这些问题的过程中锻炼了自己的编程能力,调试能力,结构设计能力,也能够发现自己编程方面的不足之处,以便以后学习弥补。 编程过程中小组成员之间的分工合作也很重要,完成这个作业要完成很多工作,找论文、读论文、理解算法、编程实现、调试、完善、优化、总结,相互的沟通与协调等。 小组中不同的人的长处是不同的,有的数学好,有的编程好,有的调试好,有的组织协调好,有的创意好,有的表达总结好,只有把资源放到作最适合最需要的地方才能取得最高的劳动生产率,这也是经济学原理的一点心得。 可以说这是编了一个有用的程序,也对理解计算几何课的内容比较有帮助。 当时学计算几何时感觉比较难,尤其是各种算法。 通过做这个实验,我们查阅了计算几何相关领域的论文,知道了计算几何的重要作用。 其实读十遍书都不如亲自做一个实验对算法的理解有帮助。 实验的结果也很有趣。 如果说有什么改进或建议的话,我觉得应该更多一点反馈的过程,没有反馈,系统就不能演化不能成熟完善。 在我们有一天能提出自己的点子之前,可能要了解理解大量的别人的工作,学习有经验的人的创意和思考方式,这是一段必须经历的过程。 最后,感谢邓老师提供这样一个宝贵的实验学习机会。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算 几何 实验 报告