0.前言
本文将从HalfEdge简介、数据结构的定义、mesh的建立、顶点的顶点邻居查询、顶点的面邻居查询、边的邻居查询、网格数据结构的输入与输出、测试结果八个方面。因作者水平有限,文中难免会有错误之处,希望读者批评指正。
1.HalfEdge简介
HalfEdge(半边)是一种用于表示多边形网格(Polygon Mesh)的一种常用方法,它能够表示任意的多边形网格(必须是流形)。HalfEdge将每条无向边分裂为两条有向边。每一条HalfEdge都以逆时针的方式围绕一个面, 因此每一条边界(boundary)可以被看做围绕着一个空面。
HalfEdge优点:即使包含了点、边、面的邻接信息,该数据结构的大小依然是固定的,没有使用动态数组。
HalfEdge的缺点:只能表示流形结构,无法表示非流形结构。
2.数据结构的定义
基本的数据结构有点、边和面
namespace trimesh_type { //命名空间三角网格
typedef long index_t;
struct point_t { //顶点
index_t index; //顶点的索引
float x, y, z; //顶点的坐标
};
struct edge_t { //三角网格中的边
index_t v[2]; //存储两个顶点
index_t& start() {
return v[0];
}
index_t& end() {
return v[1];
}
edge_t() {
v[0] = v[1] = -1; //初始化两个顶点的索引
}
};
struct triangle_t { //三角形
point_t v[3]; //三角形三个顶点
const point_t& i() const {
return v[0];
}
const point_t& j() const {
return v[1];
}
const point_t& k() const {
return v[2];
}
};
}
半边结构:
struct halfedge_t {
index_t toVertex; //半边所指向的顶点
index_t face; //半边所存储的面(若为边界,存储的面为空)
index_t edge; //所在的无向边
index_t prev; //前一个半边
index_t oppositeHe; //与自己方向相反的半边
index_t nextHe; //下一条半边(逆时针方向)
halfedge_t() :toVertex(-1),
face(-1),
edge(-1),
oppositeHe(-1),
nextHe(-1) {}
};
mesh中包含维护的变量有:
private:
vector<point_t> mPoints; //点集
vector<triangle_t> mTriangles; //三角形网格集合
vector<halfedge_t> mHalfEdges; //半边集合
vector<index_t > mVertexHalfEdges; //根据顶点索引获取半边索引
vector<index_t > mFaceHalfEdges; //根据面的索引获取半边索引
vector<index_t > mEdgeHalfEdges; //根据无向边的索引获取半边的索引
typedef map<pair<index_t, index_t>, index_t > directedEdge2indexMap_t;
directedEdge2indexMap_t mDirectedEdge2heIndex; //根据有向边获取半边索引
};
3.Mesh的建立
输入:想要构建模型的点集以及三角形网格的信息
输出:一个完整的mesh数据结构
但是为了方便地构建出HalfEdge的数据结构,我们还应该提供边的集合,边的集合可以通过点以及三角形网格的信息获取
/**
* 根据三角形网格的信息输出边的集合
* 没有准备边集信息时调用此函数
* @param triangles 三角形网格信息
* @param edgesOut 输出的边集
* @return
*/
int unorderedEdgesFromTriangles(const vector<triangle_t> &triangles, vector<edge_t> &edgesOut) {
typedef set<pair<index_t , index_t > > edgeSet_t; //边集,防止重复建边
edgeSet_t edges;
for (index_t t = 0; t < triangles.size(); ++t) {
edges.insert(make_pair(min(triangles[t].i().index, triangles[t].j().index), max(triangles[t].i().index, triangles[t].j().index)));
edges.insert(make_pair(min(triangles[t].j().index, triangles[t].k().index), max(triangles[t]