基于自适应区域增长(ARGS)算法的平面三角网格剖分

基于自适应区域增长(ARGS)算法的平面三角网格剖分

· 主要思路

1 首先建立活动边表存储链表activeList,用于记录ARGS算法中边的信息。

2 定义种子三角面片SeedT,以种子三角片为核心,不断向周围扩张,查找种子三角片的方法为:在点云中随机找一个点point,然后获取r领域中的所有点,并根据到领域点到point的距离排序,选取距离最小的两个点作为三角片中的点,筛选种子三角片的条件如下:
(1) 三个点不在一条直线上。
(2) 三个点所构成的三角片内部不包含点云中其他的点。
(3) 领域点集中的其他点都在种子三角片的同一侧,此项约束能够保证种子三角片能够保证种子三角片的选取在点云曲面的外表面上。

3 获取候选点集以及最佳点BestP,首先得到当前活动边,以当前活动边为终点为源点,查找r领域中的领域点,通过计算这些点与活动边构建的新三角片的法向量与活动边对应的法向量的y值乘积来选取乘积小于0的一侧的点作为候选点集,接着对候选点集中的点计算代价并排序,选取代价最小的点为最佳点。

4 记录最佳点BestP和当前活动边所构成的新三角片,将新生成的两条边加入到当前活动边的位置,并从活动边表中删除当前活动边。

5 当前活动边表为空时,搜寻结束。

注意:搜索领域点本程序采用的PCL中内置的搜索领域算法。

· 实现代码

// 网格重建
vector ARGS::ArgsAlgorithm()
{
Surface Orgin, a,c1;
boost::shared_ptrpcl::visualization::PCLVisualizer view(new pcl::visualization::PCLVisualizer(“test”));
pcl::PointXYZ bestpoint;

vector<CEdge> activelist;

list<CEdge>active;
vector<CEdge> currentlist;
CEdge fixededge, currentedge;
Orgin = SelectSurface();
//Orgin.ToString();
int i1 = 0;
int i = 0;

// 将种子三角面片的三条边加入到活动边表active中,并在surfacelist中存储每一条边对应的三角面片
view->addLine(Orgin.edge1.startNode, Orgin.edge1.endNode, std::to_string(i1));
i1++;
view->addLine(Orgin.edge2.startNode, Orgin.edge2.endNode, std::to_string(i1));
i1++;
view->addLine(Orgin.edge3.startNode, Orgin.edge3.endNode, std::to_string(i1));
i1++;
// 将种子三角面片的边添加到活动边表中
active.push_front(Orgin.edge3);
active.push_front(Orgin.edge2);
surfacelist1.push_back(Orgin);
active.push_front(Orgin.edge1);

activelist.push_back(Orgin.edge1);
surfacelist.push_back(Orgin);
activelist.push_back(Orgin.edge2);
surfacelist.push_back(Orgin);

activelist.push_back(Orgin.edge3);
surfacelist.push_back(Orgin);
currentedge = active.front();
currentlist.push_back(currentedge);
a = surfacelist.front();
fixededge = Orgin.edge3;
c1 = Orgin;
do
{
	surfacelist1.push_back(a);
	// 获取最佳点(通过代价和新构建三角片与当前活动边所对应的三角片的法向量来确定最佳点,将所得代价排序,选取最小的点为最佳点)
	bestpoint = GetCandidate(currentedge, a);
	// 没有找到最佳点,需要进行出栈,然后选取栈顶元素为当前活动边
	if (flag == 1)
	{
		flag = 0;
		if (active.size() != 0||surfacelist.size()!=0)
		{
			active.pop_front();
			surfacelist.pop_front();
			currentedge.startNode = active.front().endNode;
			currentedge.endNode = active.front().startNode;
			continue;
		}
		else
			break;
	}
	// 找到最佳点后,以当前活动边以及最佳点最为新的三角片,并将新的三角片中的新的两条边加入到活动边表中,并更新当前活动边。
	CEdge edge2(bestpoint, currentedge.endNode), edge1(currentedge.startNode,bestpoint);

	a.edge1 = edge1;
	a.edge2 = edge2;
	a.edge3 = currentedge;
	a.p0 = currentedge.startNode;
	a.p1 = bestpoint;
	a.p2 = currentedge.endNode;
	if(active.size()>0)
	{
	active.pop_front();
	surfacelist.pop_front();
	active.push_front(edge2);
	surfacelist.push_front(a);
	active.push_front(edge1);
	surfacelist.push_front(a);
	}
	else break;


	currentedge = active.front();
	// 判断新生成的当前活动边是否已经为访问过的活动边,若已经访问过则出栈。
	while (count(currentlist.begin(),currentlist.end(), currentedge)>0)
	{
		active.pop_front();
		surfacelist.pop_front();
		currentedge = active.front();
	}
	// 当前活动边所对应的三角片
	a = surfacelist.front();
	// 记录已经访问过的活动边
	currentlist.push_back(currentedge);

	i++;
	std::cout <<"序号:"<< i << std::endl;

	


} while (!active.empty());
i = 0;

// 显示三角网格剖分结果
for (auto it = surfacelist1.begin();it != surfacelist1.end();it++)
{
	Surface a = *it;
	view->addLine(a.edge1.startNode, a.edge1.endNode,1,0,0, std::to_string(i1));
	
	i1++;
	view->addLine(a.edge2.startNode, a.edge2.endNode, 0, 1, 0, std::to_string(i1));
	i1++;
	view->addLine(a.edge3.startNode, a.edge3.endNode, 0, 0, 1, std::to_string(i1));
	i1++;
}
return surfacelist1;

}

## ·运行结果
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190906155145243.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaWR1XzQwOTI0MjI1,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190906155157892.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaWR1XzQwOTI0MjI1,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190906155206754.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaWR1XzQwOTI0MjI1,size_16,color_FFFFFF,t_70)
## ·总结
这个任务有一定的难度,从配置vtk,pcl,qt到实现网格重建遇到了很多问题,但是都在同组小伙伴和我的不懈努力下得到了解决,虽然在这个过程中我们有很多意见分歧,但是都互相探讨,找出最优化的方案。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Delaunay三角剖分算法是一个将给定点集进行连边分割成不相交三角形的算法,其分割结果是基于三角形的最小内角,以此来保证分割结果的质量。在计算机图形学、离散数学和计算机视觉等领域中,Delaunay三角剖分算法都有广泛的应用。 C语言是一种常用的编程语言,在许多计算领域中都有着重要的应用。为了实现Delaunay三角剖分算法,我们可以使用C语言编写相关的源代码。该算法代码可分为以下几个步骤: 1. 首先确定点集的边界,以确定整个区域的边界。我们可以使用任意一个叶子点作为三角网格的起点。 2. 将所有的点按照x坐标排序,以方便后续计算。 3. 选取一个凸包三角形,它应该包含所有的点。根据这个凸包三角形来初始化我们的三角形列表。 4. 顺次遍历点集中的每一个点,判断其是否属于当前三角网格中的某个三角形。如果不属于,则根据Delaunay的定义找到该点能加入的新三角形,以及需要翻转的旧三角形。 5. 将每个新的三角形加入三角网格中,并将旧的三角形从网格中删去。 6. 重复以上步骤,直到所有点都被处理完毕。 7. 由于边缘的三角形可能不属于需要的结果,因此需要将这些边缘的三角形删除,从而得到最终的Delaunay三角剖分结果。 总的来说,实现Delaunay三角剖分算法需要进行多次计算和遍历,涉及到数据结构、算法设计等方面。在C语言中,我们可以使用数组、堆栈等数据结构来支持算法的实现。最终代码的实现需要根据具体的应用需求而定,可以根据相关的算法描述和设计思路来进行编写和调试。 ### 回答2: Delaunay三角剖分算法是一种广泛应用于计算机图形学和计算几何领域的算法。其主要作用是将一个点集按照一定的规则进行三角剖分,得到无重叠的三角形组合。这些三角形通常用于计算复杂的几何形状线段、点和区域之间的关系。 C语言是一种广泛应用于计算机程序设计和开发的高级编程语言。在Delaunay三角剖分算法的实现过程中,C语言是一种传统的编程语言选择。下面给出一个简单的Delaunay三角剖分算法C语言的实现,以供参考。 首先,我们需要定义一个包含点坐标值的结构体: typedef struct { double x; double y; } Point; 接着,我们需要定义一个包含边线信息的结构体: typedef struct { Point p1; Point p2; } Line; 定义一个检查是否为Delaunay三角形的函数: int isDelaunay(Point p1, Point p2, Point p3, Point test) { double edge1 = (p1.x - p2.x) * (test.y - p2.y) - (p1.y - p2.y) * (test.x - p2.x); double edge2 = (p2.x - p3.x) * (test.y - p3.y) - (p2.y - p3.y) * (test.x - p3.x); double edge3 = (p3.x - p1.x) * (test.y - p1.y) - (p3.y - p1.y) * (test.x - p1.x); if (edge1 > 0 && edge2 > 0 && edge3 > 0) { return 1; } else if (edge1 < 0 && edge2 < 0 && edge3 < 0) { return 1; } else { return 0; } } 定义一个进行三角剖分的函数: void DelaunayTriangulation(Point *points, int numPoints) { Line *lines = malloc(3 * (numPoints - 2) * sizeof(Line)); int numLines = 0; int i, j, k; for (i = 0; i < numPoints - 2; i++) { for (j = i + 1; j < numPoints - 1; j++) { for (k = j + 1; k < numPoints; k++) { int isTri = 1; int l; for (l = 0; l < numPoints; l++) { if (l != i && l != j && l != k) { if(isDelaunay(points[i], points[j], points[k], points[l])) { isTri = 0; break; } } } if (isTri) { lines[numLines].p1 = points[i]; lines[numLines].p2 = points[j]; numLines++; lines[numLines].p1 = points[j]; lines[numLines].p2 = points[k]; numLines++; lines[numLines].p1 = points[k]; lines[numLines].p2 = points[i]; numLines++; } } } } /* perform edge flipping to get a Delaunay triangulation */ int label = 0; for (i = 0; i < numLines; ) { int j; for (j = i+1; j < numLines; j++){ if ((lines[i].p1.x == lines[j].p2.x && lines[i].p1.y == lines[j].p2.y && lines[i].p2.x == lines[j].p1.x && lines[i].p2.y == lines[j].p1.y) || (lines[i].p1.x == lines[j].p1.x && lines[i].p1.y == lines[j].p1.y && lines[i].p2.x == lines[j].p2.x && lines[i].p2.y == lines[j].p2.y) || (lines[i].p1.x == lines[j].p2.x && lines[i].p1.y == lines[j].p2.y && lines[i].p2.x == lines[j].p1.x && lines[i].p2.y == lines[j].p1.y) || (lines[i].p1.x == lines[j].p1.x && lines[i].p1.y == lines[j].p2.y && lines[i].p2.x == lines[j].p2.x && lines[i].p2.y == lines[j].p1.y)){ Point newPt1, newPt2; newPt1 = lines[i].p1 == lines[j].p1 ? lines[i].p2 : lines[i].p1; newPt2 = lines[j].p1 == lines[i].p1 ? lines[j].p2 : lines[j].p1; lines[i].p2 = newPt1; lines[j].p2 = newPt2; i = 0; j = 0; continue; } } i++; } /* print out the completed Delaunay triangulation */ for (i = 0; i < numLines; i++) { printf(" %f,%f - %f,%f\n", lines[i].p1.x, lines[i].p1.y, lines[i].p2.x,lines[i].p2.y); } free(lines); } 最后,我们可以通过编写主函数(main)来测试该算法: int main(int argc, char *argv[]) { /* can be adapted to take in command line args */ Point points[] = {{0,0}, {1,0}, {0,1}, {1,1}, {0.5,0.5}}; int numPoints = sizeof(points) / sizeof(Point); DelaunayTriangulation(points, numPoints); return 0; } 通过以上的代码,我们实现了一个简单的Delaunay三角剖分算法,并通过一个包含5个点的点集进行了测试。在实际应用中,可以根据具体需求进行算法优化和性能调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值