简介
网格补洞操作,里面有有奖征集答案,欢迎大家踊跃回答。第一个留言为有效留言
那个horse.off请到
github下载
算法描述
找到网格的所有的边界半边。
for循环选定一个孔洞的关键点
以来点来遍历整个孔洞
补洞
代码
// 网格 补洞的操作
#include <iostream>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <cmath>
#include <vector>
#include <map>
#define pi 3.1415926
using namespace std;
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;
int main() {
MyMesh mesh;
map<MyMesh::HalfedgeHandle, int>holeHalfedgeHandle;// 半边 对应的 int
vector<MyMesh::HalfedgeHandle> halfedgeHandle;//选定的孔洞集合
MyMesh::VertexHandle vertexHandle;
if (!OpenMesh::IO::read_mesh(mesh, "horse.off")) {
std::cerr << "Cannot read mesh to file ' horse.off ' " << std::endl;
return 1;
}
for (auto he_it = mesh.halfedges_begin(); he_it != mesh.halfedges_end(); ++he_it) {
if (mesh.is_boundary(*he_it)) {
holeHalfedgeHandle.insert(make_pair(*he_it, 0));// 在有边界半边加入到集合中
}
}
for (map<MyMesh::HalfedgeHandle, int>::iterator mh_it = holeHalfedgeHandle.begin(); mh_it != holeHalfedgeHandle.end(); ++mh_it) {
if (mh_it->second == 0) {//将这个集合中还没处理过的边界点
halfedgeHandle.clear();// 临时处理的半边钩子清空
halfedgeHandle.push_back(mh_it->first);// 将边界的半边钩子放入其中
holeHalfedgeHandle[mh_it->first] = 1;// 将边界的半边钩子设定为已经处理
vertexHandle = mesh.from_vertex_handle(mh_it->first);//把正在处理的半边的来点找到
//选定孔洞
for (map<MyMesh::HalfedgeHandle, int>::iterator mit = holeHalfedgeHandle.begin(); mit != holeHalfedgeHandle.end(); ++mit) {
//再次遍历整个边界集 是对应 上一层的for循环的选定的孔洞。
if (mesh.to_vertex_handle(mit->first) == vertexHandle) {// 如果这个边界集合中的某个点的去点是这个关键点
halfedgeHandle.push_back(mit->first);// 将这个去点关键点加入半边集合中
holeHalfedgeHandle[mit->first] = 1;// 将整个半边集合中去掉求点关键点所在的半边
vertexHandle = mesh.from_vertex_handle(mit->first);// 将这个去点作为来点成为一个钩子关键点
if (mesh.from_vertex_handle(mit->first) == mesh.to_vertex_handle(mh_it->first))// 当遍历这个孔洞
// 如果上一层选定的孔洞的半边的去点 等于 此时的选定的半边的来点 说明整个孔洞已经遍历完毕了
break;
mit = holeHalfedgeHandle.begin();// 感觉效率有点低,如果找到了这个关键点,可能要重新遍历所有空洞元素
}
else {
continue;
}
}
vector<MyMesh::VertexHandle>ver;
vector<MyMesh::VertexHandle>face;
// 将这个孔洞的边界点都加入的数组ver中
for (vector<MyMesh::HalfedgeHandle>::iterator halfe = halfedgeHandle.begin(); halfe != halfedgeHandle.end(); ++halfe) {
vertexHandle = mesh.from_vertex_handle(*halfe);
ver.push_back(vertexHandle);
}
// 设定第一个点为角点(ver.end() - 1),然后构成一个平面
for (vector<MyMesh::VertexHandle>::iterator v_it = ver.begin() + 1; v_it != ver.end() - 1; ++v_it) {
face.clear();
face.push_back(*(ver.end() - 1));
face.push_back(*(v_it));
face.push_back(*(v_it - 1));
mesh.add_face(face);
}
}
}
// 将生成的新网格输出
if (!OpenMesh::IO::write_mesh(mesh, "rocker_result.off")) {
std::cerr << "Cannot write mesh to file ' rocker_result.off ' " << std::endl;
return 1;
}
return 0;
}
代码二
采用下一条半边来构建整个模型,但是有bug,为了应对bug不得已加了一些代码,大的孔洞已经填补,但是小得多孔洞没有填补,不知道为什么?
任何人找到我的bug,解决我的bug,留下支付宝号(在留言中),本人将会转1元人民币。
// 网格 补洞的操作
#include <iostream>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <cmath>
#include <vector>
#include <map>
#define pi 3.1415926
using namespace std;
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;
int main() {
MyMesh mesh;
map<MyMesh::HalfedgeHandle, int>holeHalfedgeHandle;// 半边 对应的 int
vector<MyMesh::HalfedgeHandle> halfedgeHandle;//选定的孔洞集合
MyMesh::VertexHandle vertexHandle;
if (!OpenMesh::IO::read_mesh(mesh, "horse.off")) {
std::cerr << "Cannot read mesh to file ' horse.off ' " << std::endl;
return 1;
}
for (auto he_it = mesh.halfedges_begin(); he_it != mesh.halfedges_end(); ++he_it) {
if (mesh.is_boundary(*he_it)) {
holeHalfedgeHandle.insert(make_pair(*he_it, 0));// 在有边界半边加入到集合中
}
}
for (map<MyMesh::HalfedgeHandle, int>::iterator mh_it = holeHalfedgeHandle.begin(); mh_it != holeHalfedgeHandle.end(); ++mh_it) {
if (mh_it->second == 0) {//将这个集合中还没处理过的边界点
halfedgeHandle.clear();// 临时处理的半边钩子清空
halfedgeHandle.push_back(mh_it->first);// 将边界的半边钩子放入其中
holeHalfedgeHandle[mh_it->first] = 1;// 将边界的半边钩子设定为已经处理
vertexHandle = mesh.to_vertex_handle(mh_it->first);//把正在处理的半边的来点找到
OpenMesh::ArrayKernel::VertexHandle to_v;
//选定孔洞
bool check = false;
// 重写了寻找孔洞的代码,但是有bug
do {
for (auto vh_it = mesh.voh_begin(vertexHandle); vh_it != mesh.voh_end(vertexHandle); ++vh_it) // 半边迭代器
{
OpenMesh::ArrayKernel::HalfedgeHandle h = mesh.next_halfedge_handle(*vh_it);// 这个顶点的下一条半边
if (mesh.is_boundary(h)) {
if (holeHalfedgeHandle[h] == 1) {
check = true;
break;
}
halfedgeHandle.push_back(h);
holeHalfedgeHandle[h] = 1;
vertexHandle = mesh.to_vertex_handle(h);// 下一条半边的来点(handle)
break;
}
else {
continue;
}
// 如果下一条半边的来点等于最初选定点的去点,那么整个孔洞已经遍历完毕
++vh_it;
if (vh_it == mesh.voh_end(vertexHandle))
check = true;
}
if (check == true) {
break;
}
} while (vertexHandle != mesh.to_vertex_handle(mh_it->first));// 如果上一层选定的孔洞的半边的去点 等于 此时的选定的半边的来点 说明整个孔洞已经遍历完毕了
vector<MyMesh::VertexHandle>ver;
vector<MyMesh::VertexHandle>face;
// 将这个孔洞的边界点都加入的数组ver中
for (vector<MyMesh::HalfedgeHandle>::iterator halfe = halfedgeHandle.begin(); halfe != halfedgeHandle.end(); ++halfe) {
vertexHandle = mesh.from_vertex_handle(*halfe);
ver.push_back(vertexHandle);
}
// 设定第一个点为角点(ver.end() - 1),然后构成一个平面
if (ver.size() <= 3) {
break;
}
for (vector<MyMesh::VertexHandle>::iterator v_it = ver.begin() + 1; v_it != ver.end() - 1; ++v_it) {
face.clear();
face.push_back(*(ver.end() - 1));
face.push_back(*(v_it - 1));
face.push_back(*(v_it));
mesh.add_face(face);
}
}
}
// 将生成的新网格输出
if (!OpenMesh::IO::write_mesh(mesh, "rocker_result.off")) {
std::cerr << "Cannot write mesh to file ' rocker_result.off ' " << std::endl;
return 1;
}
return 0;
}