Triangulate.cpp
资源名称:08.zip [点击查看]
上传用户:ynjin1970
上传日期:2014-10-13
资源大小:6438k
文件大小:16k
源码类别:
中间件编程
开发平台:
Visual C++
- // GenerateTri1.cpp: implementation of the CTriangulate class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- //#include "ct.h"
- #include "Triangulate.h"
- #include "globalfunctions.h"
- #include <math.h>
- #include <strstrea.h>
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- CTriangulate::CTriangulate()
- {
- nv_ = 0;
- ntri_ = 0;
- }
- CTriangulate::~CTriangulate()
- {
- delete []pv_;
- delete ptri_;
- }
- /*******************************************************************
- Triangulation subroutine
- Takes as input NV vertices in array pxyz
- Returned is a list of ntri triangular faces in the array v
- These triangles are arranged in a consistent clockwise order.
- The triangle array 'v' should be malloced to 3 * nv
- The vertex array pxyz must be big enough to hold 3 more points
- The vertex array must be sorted in increasing x values say
- qsort(p,nv,sizeof(XYZ),XYZCompare);
- :
- int XYZCompare(void *v1,void *v2)
- {
- XYZ *p1,*p2;
- p1 = v1;
- p2 = v2;
- if (p1->x < p2->x)
- return(-1);
- else if (p1->x > p2->x)
- return(1);
- else
- return(0);
- }
- ******************************************************************/
- int CTriangulate::Triangulate(int nv, XYZ *pxyz, int *ntri, TRIANGLE *v)
- // nv为存储在顶点数组pxyz中的顶点的个数
- // 返回存储在V中的三角形,其个数由ntri指定
- {
- int *complete = NULL; //在点已按x轴排序的情况下表示三角形是否需要处理
- IEDGE *edges = NULL;
- int nedge = 0;
- int trimax; // 三角形的最多个数
- int emax = 200; //边缓冲区的最大长度,会自然增长。与edges关联
- int status = 0; //非0表示错误
- int inside;
- int i,j,k;
- double xp,yp,x1,y1,x2,y2,x3,y3,xc,yc,r; //判断点是否在外接圆内
- double xmin,xmax,ymin,ymax,xmid,ymid,dx, dy, dmax; //超级三角形
- /* Allocate memory for the completeness list, flag for each triangle */
- trimax = 4 * nv;
- if ((complete = (int *) malloc(trimax*sizeof(int))) == NULL) {
- status = 1;
- goto skip;
- }
- /* Allocate memory for the edge list */
- if ((edges = (IEDGE *) malloc(emax*(long)sizeof(IEDGE))) == NULL) {
- status = 2;
- goto skip;
- }
- /*
- Find the maximum and minimum vertex bounds.
- This is to allow calculation of the bounding triangle
- */
- xmin = pxyz[0].x;
- ymin = pxyz[0].y;
- xmax = xmin;
- ymax = ymin;
- for (i=1;i<nv;i++) {
- if (pxyz[i].x < xmin) xmin = pxyz[i].x;
- if (pxyz[i].x > xmax) xmax = pxyz[i].x;
- if (pxyz[i].y < ymin) ymin = pxyz[i].y;
- if (pxyz[i].y > ymax) ymax = pxyz[i].y;
- }
- dx = xmax - xmin;
- dy = ymax - ymin;
- dmax = (dx > dy) ? dx : dy;
- xmid = (xmax + xmin) / 2.0;
- ymid = (ymax + ymin) / 2.0;
- /*
- Set up the supertriangle
- This is a triangle which encompasses all the sample points.
- The supertriangle coordinates are added to the end of the
- vertex list. The supertriangle is the first triangle in
- the triangle list.
- */
- pxyz[nv+0].x = xmid - 20 * dmax;
- pxyz[nv+0].y = ymid - dmax;
- pxyz[nv+0].z = 0.0;
- pxyz[nv+1].x = xmid;
- pxyz[nv+1].y = ymid + 20 * dmax;
- pxyz[nv+1].z = 0.0;
- pxyz[nv+2].x = xmid + 20 * dmax;
- pxyz[nv+2].y = ymid - dmax;
- pxyz[nv+2].z = 0.0;
- v[0].p1 = nv;
- v[0].p2 = nv+1;
- v[0].p3 = nv+2;
- complete[0] = FALSE;
- *ntri = 1;
- /*
- Include each point one at a time into the existing mesh
- */
- for (i=0;i<nv;i++) {
- xp = pxyz[i].x;
- yp = pxyz[i].y;
- nedge = 0;
- /*
- Set up the edge buffer.
- If the point (xp,yp) lies inside the circumcircle then the
- three edges of that triangle are added to the edge buffer
- and that triangle is removed.
- */
- for (j=0;j<(*ntri);j++) {
- if (complete[j])
- continue;
- x1 = pxyz[v[j].p1].x;
- y1 = pxyz[v[j].p1].y;
- x2 = pxyz[v[j].p2].x;
- y2 = pxyz[v[j].p2].y;
- x3 = pxyz[v[j].p3].x;
- y3 = pxyz[v[j].p3].y;
- inside = CircumCircle(xp,yp,x1,y1,x2,y2,x3,y3,&xc,&yc,&r);
- if (xc + r < xp)
- complete[j] = TRUE;
- if (inside) {
- /* Check that we haven't exceeded the edge list size */
- if (nedge+3 >= emax) {
- emax += 100;
- if ((edges = (IEDGE *) realloc(edges,emax*(long)sizeof(IEDGE))) == NULL) {
- status = 3;
- goto skip;
- }
- }
- edges[nedge+0].p1 = v[j].p1;
- edges[nedge+0].p2 = v[j].p2;
- edges[nedge+1].p1 = v[j].p2;
- edges[nedge+1].p2 = v[j].p3;
- edges[nedge+2].p1 = v[j].p3;
- edges[nedge+2].p2 = v[j].p1;
- nedge += 3;
- v[j] = v[(*ntri)-1];
- complete[j] = complete[(*ntri)-1];
- (*ntri)--;
- j--;
- }
- }
- /*
- Tag multiple edges
- Note: if all triangles are specified anticlockwise then all
- interior edges are opposite pointing in direction.
- */
- for (j=0;j<nedge-1;j++) {
- for (k=j+1;k<nedge;k++) {
- if ((edges[j].p1 == edges[k].p2) && (edges[j].p2 == edges[k].p1)) {
- edges[j].p1 = -1;
- edges[j].p2 = -1;
- edges[k].p1 = -1;
- edges[k].p2 = -1;
- }
- /* Shouldn't need the following, see note above */
- if ((edges[j].p1 == edges[k].p1) && (edges[j].p2 == edges[k].p2)) {
- edges[j].p1 = -1;
- edges[j].p2 = -1;
- edges[k].p1 = -1;
- edges[k].p2 = -1;
- }
- }
- }
- /*
- Form new triangles for the current point
- Skipping over any tagged edges.
- All edges are arranged in clockwise order.
- */
- for (j=0;j<nedge;j++) {
- if (edges[j].p1 < 0 || edges[j].p2 < 0)
- continue;
- if ((*ntri) >= trimax) {
- status = 4;
- goto skip;
- }
- v[*ntri].p1 = edges[j].p1;
- v[*ntri].p2 = edges[j].p2;
- v[*ntri].p3 = i;
- complete[*ntri] = FALSE;
- (*ntri)++;
- }
- }
- /*
- Remove triangles with supertriangle vertices
- These are triangles which have a vertex number greater than nv
- */
- for (i=0;i<(*ntri);i++) {
- if (v[i].p1 >= nv || v[i].p2 >= nv || v[i].p3 >= nv) {
- v[i] = v[(*ntri)-1];
- (*ntri)--;
- i--;
- }
- }
- skip:
- free(edges);
- free(complete);
- return(status);
- }
- /////////////////////////////////////////////////////////////////////
- /*
- Return TRUE if a point (xp,yp) is inside the circumcircle made up
- of the points (x1,y1), (x2,y2), (x3,y3)
- The circumcircle centre is returned in (xc,yc) and the radius r
- NOTE: A point on the edge is inside the circumcircle
- */
- int CTriangulate::CircumCircle(double xp,double yp,
- double x1,double y1,double x2,double y2,double x3,double y3,
- double *xc,double *yc,double *r)
- {
- double m1,m2,mx1,mx2,my1,my2;
- double dx,dy,rsqr,drsqr;
- double EPSILON = 0.000001;
- /* Check for coincident points */
- if (fabs(y1-y2) < EPSILON && fabs(y2-y3) < EPSILON)
- return(FALSE);
- if (fabs(y2-y1) < EPSILON) {
- m2 = - (x3-x2) / (y3-y2);
- mx2 = (x2 + x3) / 2.0;
- my2 = (y2 + y3) / 2.0;
- *xc = (x2 + x1) / 2.0;
- *yc = m2 * (*xc - mx2) + my2;
- } else if (fabs(y3-y2) < EPSILON) {
- m1 = - (x2-x1) / (y2-y1);
- mx1 = (x1 + x2) / 2.0;
- my1 = (y1 + y2) / 2.0;
- *xc = (x3 + x2) / 2.0;
- *yc = m1 * (*xc - mx1) + my1;
- } else {
- m1 = - (x2-x1) / (y2-y1);
- m2 = - (x3-x2) / (y3-y2);
- mx1 = (x1 + x2) / 2.0;
- mx2 = (x2 + x3) / 2.0;
- my1 = (y1 + y2) / 2.0;
- my2 = (y2 + y3) / 2.0;
- *xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
- *yc = m1 * (*xc - mx1) + my1;
- }
- dx = x2 - *xc;
- dy = y2 - *yc;
- rsqr = dx*dx + dy*dy;
- *r = sqrt(rsqr);
- dx = xp - *xc;
- dy = yp - *yc;
- drsqr = dx*dx + dy*dy;
- return((drsqr <= rsqr) ? TRUE : FALSE);
- }
- void CTriangulate::QSortVertexByX() //X增大排序
- {
- qsort((void *)pv_, (size_t)nv_, sizeof(XYZ), compare);
- }
- ///////////////////////////////////////////////////////////////////////
- /*
- 用成员变量m_szFileName指定的文件初始化pv_和nv_.
- 成功返回true,否则返回false
- */
- bool CTriangulate::Initial(char *szFileName)
- {
- strcpy(szFileName_, szFileName); // 初始化成员变量,该文件保存了顶点信息
- char *buf = NULL;
- if ( this->szFileName_ == NULL ) return false;
- // 使用内存映像文件来读取文件数据
- HANDLE hFile = CreateFile( szFileName_,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL, //security attributes
- OPEN_EXISTING,
- FILE_FLAG_SEQUENTIAL_SCAN,
- NULL); //template file
- if ( hFile == INVALID_HANDLE_VALUE) return false; //因错误返回
- HANDLE hFileMapping = CreateFileMapping(hFile,
- NULL, // Security attributes
- PAGE_READONLY,
- 0, //内存映射的最大大小,这位64位中的高位
- 0, //64位中的低位,0为匹配文件的实际长度
- NULL); //给内存映射命名
- if ( hFileMapping == NULL ) return false;
- LPVOID pMem = MapViewOfFile(hFileMapping,
- FILE_MAP_READ,
- 0, //视图在映射文件的起始位置,64位中的高位
- 0, // 64位中的低位,这是从文件头开始映射
- 0); //映射长度
- if (pMem == NULL) return false;
- buf = (char *)pMem;
- ////////////////////////////////////////////////////////////////
- // TODO: Add your process in here
- //
- char linebuf[1024];
- char *pos;
- XYZ *pTemp;
- long MAXVERTEX = 1000;
- //pv_ = (XYZ *)malloc( MAXVERTEX * sizeof(XYZ) );
- if ((pv_ = new XYZ[MAXVERTEX]) == NULL ) return false;
- istrstream is(buf, GetFileSize(hFile, NULL));
- while ( ! is.eof() )
- {
- is.getline(linebuf, 1024);
- pos = strchr(linebuf, '#'); // 符号#后为注释
- if ( pos != NULL ) *pos = ' '; //remove comment
- if ( sscanf(linebuf, "%le %le %le", &pv_[nv_].x, &pv_[nv_].y, &pv_[nv_].z ) != 3)
- continue; // error! continue to read next line
- else
- {
- nv_++;
- if ( nv_ >= MAXVERTEX)
- {
- if ((pTemp = new XYZ[MAXVERTEX + 1000]) == NULL ) return false;
- memcpy(pTemp, pv_, sizeof(XYZ) * MAXVERTEX);
- delete []pv_;
- pv_ = pTemp;
- MAXVERTEX += 1000;
- }
- }
- }
- //
- // end your process
- //////////////////////////////////////////////////////////////////
- CloseHandle(hFile);
- CloseHandle(hFileMapping);
- UnmapViewOfFile(pMem);
- // set RBvertex_ and LTvertex_
- LTvertex_ = pv_[0];
- RBvertex_ = LTvertex_;
- for ( int i = 1; i < nv_; i++ )
- {
- if ( pv_[i].x > LTvertex_.x ) LTvertex_.x = pv_[i].x;
- if ( pv_[i].x < RBvertex_.x ) RBvertex_.x = pv_[i].x;
- if ( pv_[i].y > LTvertex_.y ) LTvertex_.y = pv_[i].y;
- if ( pv_[i].y < RBvertex_.y ) RBvertex_.y = pv_[i].y;
- if ( pv_[i].z > LTvertex_.z ) LTvertex_.z = pv_[i].z;
- if ( pv_[i].z < RBvertex_.z ) RBvertex_.z = pv_[i].z;
- }
- return true; //正常返回为0
- }
- //////////////////////////////////////////////////////////////////////
- /*
- 根据nv_和pv_创建三角形,创建的三角形保存在ptri_中
- 三角形的个数保存在ntri_中;
- 其中需要调用三角形的剖分算法Triangulate()
- 注意:
- 有很多种三角剖分算法,Triangulate()是一种增量算法。
- */
- bool CTriangulate::CreateTriangle()
- {
- SortAndRemoveRepeatPoints(); // 根据x的大小对pv_进行排序,并且删掉重复的点
- // Triangulate()函数需要已经排序过的pv_
- AfxMessageBox("排序和删除重复点结束。",0,0);
- if ((ptri_ = new TRIANGLE[4 * nv_]) == NULL)
- return false; //三角形的最多个数是顶点个数的4倍
- Triangulate(nv_, pv_, &ntri_, ptri_);
- AfxMessageBox("三角剖分结束。",0,0);
- MeshedTris();
- AfxMessageBox("建立三角形之间的关系结束。",0,0);
- return true;
- }
- XYZ CTriangulate::GetLTvertex() // 获得散点的xyz的最大值
- {
- return LTvertex_;
- }
- XYZ CTriangulate::GetRBvertex() // 获得散点的xyz的最小值
- {
- return RBvertex_;
- }
- // 为TRIANGLE的T1,T2,T3设定值。即建立三角形的邻接关系
- void CTriangulate::MeshedTris() //对各个独立的三角形建立网络联系
- {
- int i, j;
- for (i = 0; i < ntri_; i++) // remove 不规范的点, need it?
- {
- if (ptri_[i].p1 == ptri_[i].p2 || ptri_[i].p1 == ptri_[i].p3 || ptri_[i].p2 == ptri_[i].p3 )
- {
- ptri_[i] = ptri_[ntri_ - 1];
- ntri_--;
- }
- }
- for (i = 0; i < ntri_; i++)
- {
- if (ptri_[i].t3 == NEIGHBOR_UNKNOWN)
- for ( j = i + 1; j < ntri_; j++)
- {
- if ( (ptri_[i].p1 == ptri_[j].p1 || ptri_[i].p1 == ptri_[j].p2 || ptri_[i].p1 == ptri_[j].p3 )
- && (ptri_[i].p2 == ptri_[j].p1 || ptri_[i].p2 == ptri_[j].p2 || ptri_[i].p2 == ptri_[j].p3 ) )
- {
- ptri_[i].t3 = j; // 设置第i个三角形的边p1p2的邻接三角形
- // 由于两个邻接三角形是相互邻接的,所以同时设置“邻接三角形j”的邻接三角形为i
- if ( ptri_[j].p1 + ptri_[j].p2 == ptri_[i].p1 + ptri_[i].p2 )
- ptri_[j].t3 = i;
- else if ( ptri_[j].p1 + ptri_[j].p3 == ptri_[i].p1 + ptri_[i].p2 )
- ptri_[j].t2 = i;
- else //( ptri_[j].p3 + ptri_[j].p2 == ptri_[i].p1 + ptri_[i].p2 )
- ptri_[j].t1 = i;
- break;
- }
- }
- if (ptri_[i].t2 == NEIGHBOR_UNKNOWN)
- for ( j = i + 1; j < ntri_; j++)
- {
- if ( (ptri_[i].p1 == ptri_[j].p1 || ptri_[i].p1 == ptri_[j].p2 || ptri_[i].p1 == ptri_[j].p3 )
- && (ptri_[i].p3 == ptri_[j].p1 || ptri_[i].p3 == ptri_[j].p2 || ptri_[i].p3 == ptri_[j].p3 ) )
- {
- ptri_[i].t2 = j; // 设置第i个三角形的边p1p2的邻接三角形
- // 由于两个邻接三角形是相互邻接的,所以同时设置“邻接三角形j”的邻接三角形为i
- if ( ptri_[j].p1 + ptri_[j].p2 == ptri_[i].p1 + ptri_[i].p3 )
- ptri_[j].t3 = i;
- else if ( ptri_[j].p1 + ptri_[j].p3 == ptri_[i].p1 + ptri_[i].p3 )
- ptri_[j].t2 = i;
- else //if ( ptri_[j].p3 + ptri_[j].p2 == ptri_[i].p1 + ptri_[i].p3 )
- ptri_[j].t1 = i;
- break;
- }
- }
- if (ptri_[i].t1 == NEIGHBOR_UNKNOWN)
- for ( j = i + 1; j < ntri_; j++)
- {
- if ( (ptri_[i].p3 == ptri_[j].p1 || ptri_[i].p3 == ptri_[j].p2 || ptri_[i].p3 == ptri_[j].p3 )
- && (ptri_[i].p2 == ptri_[j].p1 || ptri_[i].p2 == ptri_[j].p2 || ptri_[i].p2 == ptri_[j].p3 ) )
- {
- ptri_[i].t1 = j; // 设置第i个三角形的边p1p2的邻接三角形
- // 由于两个邻接三角形是相互邻接的,所以同时设置“邻接三角形j”的邻接三角形为i
- if ( ptri_[j].p1 + ptri_[j].p2 == ptri_[i].p3 + ptri_[i].p2 )
- ptri_[j].t3 = i;
- else if ( ptri_[j].p1 + ptri_[j].p3 == ptri_[i].p3 + ptri_[i].p2 )
- ptri_[j].t2 = i;
- else //if ( ptri_[j].p3 + ptri_[j].p2 == ptri_[i].p3 + ptri_[i].p2 )
- ptri_[j].t1 = i;
- break;
- }
- }
- } // end i
- }
- void CTriangulate::SortAndRemoveRepeatPoints()
- {
- int i, j;
- int pos(0), pos2(0);
- int readpos(0), writepos(0);
- QSortVertexByX(); // 按X增大排序
- bool *flagkilled = new bool[nv_];
- for ( i = 0; i < nv_; i++)
- flagkilled[i] = false;
- while( pos < nv_)
- {
- while( pv_[++pos2].x == pv_[pos].x );
- for(i = pos; i < pos2; i++)
- {
- if(flagkilled[i]) continue;
- for (j = i + 1; j < pos2; j++)
- if(pv_[j].y == pv_[i].y)
- flagkilled[j] = true;
- }
- pos = pos2;
- }
- while(readpos < nv_)
- {
- while(flagkilled[readpos]) // skip killed points
- readpos++;
- if (writepos != readpos)
- pv_[writepos] = pv_[readpos];
- writepos++;
- readpos++;
- }
- nv_ = writepos;
- delete []flagkilled;
- //TRACE("output norepeat points: nv=%dn", nv_);
- //for (i=0; i<nv_; i++)
- // TRACE("%lf %lf %lfn", pv_[i].x, pv_[i].y, pv_[i].z);
- //TRACE("End outputn");
- }