点集的三角剖分(Triangulation),对数值分析(比如有限元分析)以及图形学来说,都是极为重要的一项预处理技术。
尤其是Delaunay三角剖分,由于其独特性,关于点集的很多种几何图都和Delaunay三角剖分相关,如Voronoi图,EMST树,Gabriel图等。
Delaunay剖分所具备的优异特性:
1.最接近:以最近的三点形成三角形,且各线段(三角形的边)皆不相交。
2.唯一性:不论从区域何处开始构建,最终都将得到一致的结果。
3.最优性:任意两个相邻三角形形成的凸四边形的对角线如果可以互换的话,那么两个三角形六个内角中最小的角度不会变大。
4.最规则:如果将三角网中的每个三角形的最小角进行升序排列,则Delaunay三角网的排列得到的数值最大。
5.区域性:新增、删除、移动某一个顶点时只会影响临近的三角形。
6.具有凸多边形的外壳:三角网最外层的边界形成一个凸多边形的外壳。
概念及定义
二维实数域(二维平面)上的三角剖分
定义1:假设V是二维实数域上的有限点集,边e是由点集中的点作为端点构成的封闭线段, E为e的集合。
那么该点集V的一个三角剖分T=(V,E)是一个平面图G,该平面图满足条件:
1.除了端点,平面图中的边不包含点集中的任何点。
2.没有相交边。
3.平面图中所有的面都是三角面,且所有三角面的合集就是点集V的凸包。
那什么是Delaunay三角剖分呢?不过是一种特殊的三角剖分罢了。从Delaunay边说起。
Delaunay边
定义2:假设E中的一条边e(两个端点为a,b),e若满足下列条件,则称之为Delaunay边:
存在一个圆经过a,b两点,圆内不含点集V中任何的点,这一特性又称空圆特性。
Delaunay三角剖分
定义3:如果点集V的一个三角剖分T只包含Delaunay边,那么该三角剖分称为Delaunay三角剖分。
定义4:假设T为V的任一三角剖分,则T是V的一个Delaunay三角剖分,当前仅当T中的每个三角形的外接圆的内部不包含V中任何的点。
定义5:V的Voronoi图是由多边形区域的集合(有些区域可能不是闭合的),该区域仅含点集中的一个点v,区域中的任何位置到v的距离都比该位置到点集中其它所有点的距离短。
由Voronoi图和Delaunay三角剖分的关系,可以引出另一个Delaunay三角剖分的定义:
定义6:将Voronoi图相邻区域(共边的区域)中的点连接起来构成的图,称为Delaunay三角剖分。
如下图:
概念部分到此,下面看看怎么求Delaunay三角剖分。
计算Delaunay三角剖分
问题1:计算二维Delaunay三角剖分
问题输入:二维实数域上的点集V
问题输出:Delaunay三角剖分DT = (V, E).
算法
由不同的定义对应有不同的算法。用得较多的是基于定义3或4的算法。
目前常用的算法又分为好几种,被不同的家伙发现。什么扫描线法(Sweepline),随机增量法(Incremental),分治法(Divide and Conquer)
c++实现:(转载)
-
-
-
- #include "StdAfx.h"
- #include <cv.h>
- #include <highgui.h>
- void draw_subdiv_edge( IplImage* img, CvSubdiv2DEdge edge, CvScalar color );
-
-
-
-
- CvSubdiv2D* init_delaunay( CvMemStorage* storage,
- CvRect rect )
- {
- CvSubdiv2D* subdiv;
-
- subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*subdiv),
- sizeof(CvSubdiv2DPoint),
- sizeof(CvQuadEdge2D),
- storage );
- cvInitSubdivDelaunay2D( subdiv, rect );
-
- return subdiv;
- }
-
-
- void draw_subdiv_point( IplImage* img, CvPoint2D32f fp, CvScalar color )
- {
- cvCircle( img, cvPoint(cvRound(fp.x), cvRound(fp.y)), 5, color, CV_FILLED, 8, 0 );
- }
-
-
- void locate_point( CvSubdiv2D* subdiv, CvPoint2D32f fp, IplImage* img,
- CvScalar active_color )
- {
- CvSubdiv2DEdge e;
- CvSubdiv2DEdge e0 = 0;
- CvSubdiv2DPoint* p = 0;
-
- cvSubdiv2DLocate( subdiv, fp, &e0, &p );
-
- if( e0 )
- {
- e = e0;
- do
- {
- draw_subdiv_edge( img, e, active_color );
- e = cvSubdiv2DGetEdge(e,CV_NEXT_AROUND_LEFT);
- }
- while( e != e0 );
- }
-
- draw_subdiv_point( img, fp, active_color );
- }
-
-
-
-
-
-
- void draw_subdiv_edge( IplImage* img, CvSubdiv2DEdge edge, CvScalar color )
- {
- CvSubdiv2DPoint* org_pt;
- CvSubdiv2DPoint* dst_pt;
- CvPoint2D32f org;
- CvPoint2D32f dst;
- CvPoint iorg, idst;
-
- org_pt = cvSubdiv2DEdgeOrg(edge);
- dst_pt = cvSubdiv2DEdgeDst(edge);
-
- if( org_pt && dst_pt )
- {
- org = org_pt->pt;
- dst = dst_pt->pt;
-
- iorg = cvPoint( cvRound( org.x ), cvRound( org.y ));
- idst = cvPoint( cvRound( dst.x ), cvRound( dst.y ));
-
- cvLine( img, iorg, idst, color, 1, CV_AA, 0 );
- }
- }
-
-
- void draw_subdiv( IplImage* img, CvSubdiv2D* subdiv,
- CvScalar delaunay_color, CvScalar voronoi_color )
- {
- CvSeqReader reader;
- int i, total = subdiv->edges->total;
- int elem_size = subdiv->edges->elem_size;
-
- cvStartReadSeq( (CvSeq*)(subdiv->edges), &reader, 0 );
-
- for( i = 0; i < total; i++ )
- {
- CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);
-
- if( CV_IS_SET_ELEM( edge ))
- {
- draw_subdiv_edge( img, (CvSubdiv2DEdge)edge + 1, voronoi_color );
-
-
-
-
- draw_subdiv_edge( img, (CvSubdiv2DEdge)edge, delaunay_color );
- }
-
- CV_NEXT_SEQ_ELEM( elem_size, reader );
- }
- }
-
-
-
-
-
- void draw_subdiv_facet( IplImage* img, CvSubdiv2DEdge edge )
- {
- CvSubdiv2DEdge t = edge;
- int i, count = 0;
- CvPoint* buf = 0;
-
-
- do
- {
- count++;
- t = cvSubdiv2DGetEdge( t, CV_NEXT_AROUND_LEFT );
- } while (t != edge );
-
- buf = (CvPoint*)malloc( count * sizeof(buf[0]));
-
-
- t = edge;
- for( i = 0; i < count; i++ )
- {
- CvSubdiv2DPoint* pt = cvSubdiv2DEdgeOrg( t );
- if( !pt ) break;
- buf[i] = cvPoint( cvRound(pt->pt.x), cvRound(pt->pt.y));
- t = cvSubdiv2DGetEdge( t, CV_NEXT_AROUND_LEFT );
- }
-
- if( i == count )
- {
- CvSubdiv2DPoint* pt = cvSubdiv2DEdgeDst( cvSubdiv2DRotateEdge( edge, 1 ));
- cvFillConvexPoly( img, buf, count, CV_RGB(rand()&255,rand()&255,rand()&255), CV_AA, 0 );
- cvPolyLine( img, &buf, &count, 1, 1, CV_RGB(0,0,0), 1, CV_AA, 0);
- draw_subdiv_point( img, pt->pt, CV_RGB(0,0,0));
- }
- free( buf );
- }
-
- void paint_voronoi( CvSubdiv2D* subdiv, IplImage* img )
- {
- CvSeqReader reader;
- int i, total = subdiv->edges->total;
- int elem_size = subdiv->edges->elem_size;
-
- cvCalcSubdivVoronoi2D( subdiv );
-
- cvStartReadSeq( (CvSeq*)(subdiv->edges), &reader, 0 );
-
- for( i = 0; i < total; i++ )
- {
- CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);
-
- if( CV_IS_SET_ELEM( edge ))
- {
- CvSubdiv2DEdge e = (CvSubdiv2DEdge)edge;
-
- draw_subdiv_facet( img, cvSubdiv2DRotateEdge( e, 1 ));
-
-
- draw_subdiv_facet( img, cvSubdiv2DRotateEdge( e, 3 ));
- }
-
- CV_NEXT_SEQ_ELEM( elem_size, reader );
- }
- }
-
-
- void run(void)
- {
- char win[] = "source";
- int i;
- CvRect rect = { 0, 0, 600, 600 };
- CvMemStorage* storage;
- CvSubdiv2D* subdiv;
- IplImage* img;
- CvScalar active_facet_color, delaunay_color, voronoi_color, bkgnd_color;
-
- active_facet_color = CV_RGB( 255, 0, 0 );
- delaunay_color = CV_RGB( 0,0,0);
- voronoi_color = CV_RGB(0, 180, 0);
- bkgnd_color = CV_RGB(255,255,255);
-
- img = cvCreateImage( cvSize(rect.width,rect.height), 8, 3 );
- cvSet( img, bkgnd_color, 0 );
-
- cvNamedWindow( win, 1 );
-
- storage = cvCreateMemStorage(0);
- subdiv = init_delaunay( storage, rect );
-
- printf("Delaunay triangulation will be build now interactively.\n"
- "To stop the process, press any key\n\n");
-
- for( i = 0; i < 20; i++ )
- {
- CvPoint2D32f fp = cvPoint2D32f( (float)(rand()%(rect.width-10)+5),
- (float)(rand()%(rect.height-10)+5));
-
- locate_point( subdiv, fp, img, active_facet_color );
- cvShowImage( win, img );
-
- if( cvWaitKey( 100 ) >= 0 )
- break;
-
- cvSubdivDelaunay2DInsert( subdiv, fp );
- cvCalcSubdivVoronoi2D( subdiv );
- cvSet( img, bkgnd_color, 0 );
- draw_subdiv( img, subdiv, delaunay_color, voronoi_color );
- cvShowImage( win, img );
-
- if( cvWaitKey(100) >= 0 )
- break;
- }
-
- cvSet( img, bkgnd_color, 0 );
- paint_voronoi( subdiv, img );
- cvShowImage( win, img );
-
- cvWaitKey(0);
-
- cvReleaseMemStorage( &storage );
- cvReleaseImage(&img);
- cvDestroyWindow( win );
- }
-
- int main( int argc, char** argv )
- {
- run();
- return 0;
- }
原文地址:
http://blog.csdn.net/kuikuijia/article/details/46282959