简介
网格补洞操作,里面有有奖征集答案,欢迎大家踊跃回答。第一个留言为有效留言那个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.1415926using namespace std;
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;int main() {MyMesh mesh;map<MyMesh::HalfedgeHandle, int>holeHalfedgeHandle;// 半边 对应的 intvector<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.1415926using namespace std;
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;int main() {MyMesh mesh;map<MyMesh::HalfedgeHandle, int>holeHalfedgeHandle;// 半边 对应的 intvector<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;// 重写了寻找孔洞的代码,但是有bugdo {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;
}