将一个数据结构的模型OpenMesh进行分割,用区域增长的方式,来遍历所有,且此算法耗时比较短。
[TOC]
本文初发于 “偕臧的小站“,同步转载于此。
简述:
将一个数据结构的模型OpenMesh进行分割,用区域增长的方式,来遍历所有,且此算法耗时比较短。
编程环境:Win10 x64 专业版
编程软件: visual studio 2015
思路:
- 将所有的面进行标记为-1(表示没有属于那一块)和false(表示还没有遍历过)
- 选择一个种子面fhSeed,然后向它的周边相邻的(三个)面进行区域增长,也给做上标
- 对于这三个面,也把它作为一个新的面,然后向自己周边进行增长(然后辐射周边)
- 然后用一个小的容器储存,正在增长的面,每次增长结束,就把自己这个已经遍历过的面,从容器中删除,当容器值为0的时候,便是一块完整的被遍历出来了
- 重复以上2-3-4步骤
- 将已经遍历了的面,打上标记,已经标记了的,不在标记;当所有的面全部都遍历结束,也就分割开了(这样的话,一个物体的面,属于哪一块,都被标记出来了)。
代码:
假设其中的一个模型变量为 :RefineMesh refineMeshNew
;
OpenMesh::FPropHandleT<int> FPropTriMark; //属于那一块
OpenMesh::FPropHandleT<bool> FPropTriFlag; //是否遍历过
refineMeshNew.add_property(FPropTriMark, "FPropTriMark");
refineMeshNew.add_property(FPropTriFlag, "FPropTriFlag");
for (auto f_it = refineMeshNew.faces_begin(); f_it != refineMeshNew.faces_end(); f_it++)
{
refineMeshNew.property(FPropTriMark, *f_it) = -1;
refineMeshNew.property(FPropTriFlag, *f_it) = false;
}
int nMark = 0; //标记属于哪一块Mesh
//外层循环------------------------------------------------------------------------------
while (true)
{
//外层结束标志
OpenMesh::FaceHandle fhSeed;
for (auto f_itTemp = refineMeshNew.faces_begin(); f_itTemp != refineMeshNew.faces_end(); f_itTemp++)
{
if (!refineMeshNew.property(FPropTriFlag, *f_itTemp))
{
fhSeed = *f_itTemp;
break;
}
}
if (!fhSeed.is_valid())
break;
refineMeshNew.property(FPropTriFlag, fhSeed) = true;
refineMeshNew.property(FPropTriMark, fhSeed) = nMark;
vector<OpenMesh::FaceHandle> vecMarkFH;
vecMarkFH.push_back(fhSeed);
//内层循环------------------------------------------------------------------------------
while (true)
{
if (vecMarkFH.size() == 0)
break;
OpenMesh::FaceHandle fhTemp = vecMarkFH[0];
for (auto ff_it = refineMeshNew.ff_iter(fhTemp); ff_it != refineMeshNew.ff_end(fhTemp); ff_it++)
{
if (!refineMeshNew.property(FPropTriFlag, *ff_it))
{
refineMeshNew.property(FPropTriFlag, *ff_it) = true;
refineMeshNew.property(FPropTriMark, *ff_it) = nMark;
}
}
vecMarkFH.erase(vecMarkFH.begin());
}
nMark++;
}
//外层循环结束------------------------------------------------------------------------------
效率:
经过测试,用此算法,遍历一个有四千多万(40, 000, 000多)个面的数据模型,只需要耗费时间约6s
,比我自己先前写的一个思路,耗时效率要高得多
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
更新:
更新时间: 2019-7-9 17:35:43
更新内容: 增加有分割后的多个模型导出的代码分享
将下面的mesh
替换成分割之后的pMesh,分割成为多个的时候,建议使用Vector<pMesh> v
来存储,然后使用1行里面的代码替换掉mesh
为v[i]
即可;
提示: 因为上面代码已经将模型做了区分,然后使用for循环,直接按照标记所属于的,直接输出;亦可以即可将各自的点、面、半边、纹理等属性赋值给一个新的pMesh
即可;
if (!OpenMesh::IO::write_mesh(mesh, "output.off"))
std::cerr << "Cannot write mesh to file 'output.off'" << std::endl;
本博文同步到csdn博客: OpenMesh模型分割:区域增长实现