网格的补洞操作

简介

网格补洞操作,里面有有奖征集答案,欢迎大家踊跃回答。第一个留言为有效留言
那个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;
}



Hope is a good thing,maybe the best of things,and no good thing ever dies.----------- Andy Dufresne
原文地址:https://www.cnblogs.com/eat-too-much/p/11177089.html