2019-4-9 Delaunay三角剖分-逐点插入法
一:理解delaunay三角剖分原理
关键点在于三角形生成的规则及其实现过程。生成初始三角形,将初始三角形放入临时三角形中,判断三角形是否满足delaunay三角形规则,只有满足规则三角形才会被加入Delaunay三角形链表中。否则插入新的点,生成新的临时三角形,在对新三角形进行delaunay规则判断,继续进行分割,知道满足条件,将三角形加入Delaunay三角形链表中,直到遍历所有点,完成三角剖分。
1:delaunay三角形空圆特性: 构建空间三角片的关键依据
2:delaunay三角形最大化最小角; 对构建完成的三角片进行局部优化的依据
3:具有凸多边形外壳,就是所谓凸包 n个点生成的三角形大于n个的一种理解
耗时的地方:1:如何建立超级三角形,将所有的点包围
2:需要搜索临时三角形列表,确定插入点所在的三角形,进而更新插入三角形临时边
二:结合需求搭建程序函数结构
input:已排序的顶点列表(vertices)
output:划分完成的三角剖分结果(triangles)
//若顶点未排序,则先进行排序 ,排序规则可利用先x大小后y大小的方法。排序的目的是什么?
初始化超级三角形,将所有点包含其中 //如何划分超级三角形?
初始化临时三角形列表(temp triangles),将超级三角形加入其中 //三角形,顶点,边的结构体如何建立
初始化结果三角形列表(triangles),将超级三角形加入其中
遍历已排序的所有点,进行delaunay三角剖分操作。按照排序索引进行遍历
初始化三角形边缓存数组(edge buffer) //若插入点不满足delaunay规则,则需将插入点与原三角形的三个顶点连接, // 生成三个新的三角形,保存新的三个边与原三角形的边
遍历临时三角形列表中的所有三角形
计算三角形圆心和半径 // 三角形外接圆的表达,圆心及半径
如果该点在外接圆的右侧 //如何判断这个结果
则该三角形为delaunay三角形,保存到triangles中,跳过
如果该点三角形在外接圆的外侧,不在右侧的情况
定为不确定三角形
如果该点在外接圆内部
该点不为delaunay三角形,删除temp中的三角形
连接原三角形三个顶点,生成三条边加入edge buffer中
遍历完临时三角形,对edge的边进行去重 // 去重的操作方法
将edge buffer中生成的新边,与原三角形三个顶点生成新的三角形,加入temp triangles 列表中
遍历完所有点后,合并triangles与temp triangles
删除超级三角形有关的三角形
end
定义数据结构及函数功能
// 点结构体
struct Point_
{
float x;
float y;
float z;
}
Point_* pts = new Point_[p_num];
// 建立点云列表,利用索引的方式获取每个点,创建边和三角面结构体,
// 一方面 减少点复制而避免内存浪费
// 另一方面可将三角化后的点直接用于GLSL进行表面重构
// 边结构体
struct Edge_
{
int e1;
int e2;
}
// 三角形结构体
struct Triangle_
{
int p1;
int p2;
int p3;
}
//创建点云
bool createPoints(const int n_point, PointXY* &pxy);
// 排序函数,对点集进行排序
void xySort(const void *v1,const void *v2);
// 构建超级三角形
// 利用排序后最左边和最右边的点进行构建
Triangle_ superTriangle(const float* &vertices);
// 输入三角形(三个顶点),计算外接圆的圆心及半径
int circumCircle(Triangle_ triangle, float&xc, float&yc, float&r)
// 实现delaunay三角剖分
void DT(int nv, PointXY p[],Triangle_ temp_tri[], int &ntri)
int xySort(const void *v1,const void *v2)
{
PointXY* p1 = (PointXY*)v1;
PointXY* p2 = (PointXY*)v2;
if(p1->x < p2->x)
return (-1);
else if(p1->x > p2->x)
return (1);
return (0);
}
2019-4-10
三:实现具体函数功能
bool createPoints(const int n_point, PointXY* &pxy)
{
//初始化
double x, y;
bool b_Ok = false;
//注意添加这个函数,根据时间创建随机数,比较合理
srand((time_t) time(NULL));
int pn = 0;
while(pn != n_point)
{
//生成新的点,并检查是否有重复的点
do{
b_Ok = true;
x = rand()%500;
y = rand()%500;
for (int n_cp = 0; n_cp <= pn; n_cp++)
{
if((x == pxy[n_cp].x) && (y == pxy[n_cp].y)) b_Ok = false;
}
}while (!b_Ok);
pxy[pn].x = x * 1.0;
pxy[pn].y = y * 1.0;
pn++;
}
if(pn != n_point )
return false;
else
return true;
}
四:调试修改代码
异常:三个点时,结果出现异常,不能正确保存结果。
异常位置在哪?
1:边参数设置位置错误,需要在进行遍历每个临时三角形前就初始化为0,nedge = 0
2:输入n个点,生成的三角形一般都大于n,因此在设置临时三角形为3倍
3:删除临时三角形貌似出现异常了,暂时没找到
参考文献:[1]https://www.cnblogs.com/zhiyishou/p/4430017.html
[2]https://blog.csdn.net/qq_34719188/article/details/83216527
[3]https://blog.csdn.net/newthinker_wei/article/details/45598769