原文出处:http://openmesh.org/Documentation/OpenMesh-Doc-Latest/mesh_iterators.html
迭代器
Mesh提供线性迭代(枚举定点,halfedge,边和面)。这些功能提供更加便捷的网格导航。每一个迭代器XYZIter迭代也存在常数型的迭代ConstXYZIter。
所有的迭代器在名字空间OpenMesh::Iterators中定义。迭代器接收网格作为模板参数。你应该使用网格自己提供的迭代器,比如 MyMesh::VertexIter而不是OpenMesh::Iterators::VertexIterT<MyMesh>。
迭代器是这样用的:
MyMesh mesh;
// iterate over all vertices
for (MyMesh::VertexIter v_it=mesh.vertices_begin(); v_it!=mesh.vertices_end(); ++v_it)
...; // do something with *v_it, v_it->, or v_it.handle()
// iterate over all halfedges
for (MyMesh::HalfedgeIter h_it=mesh.halfedges_begin(); h_it!=mesh.halfedges_end(); ++h_it)
...; // do something with *h_it, h_it->, or h_it.handle()
// iterate over all edges
for (MyMesh::EdgeIter e_it=mesh.edges_begin(); e_it!=mesh.edges_end(); ++e_it)
...; // do something with *e_it, e_it->, or e_it.handle()
// iterator over all faces
for (MyMesh::FaceIter f_it=mesh.faces_begin(); f_it!=mesh.faces_end(); ++f_it)
...; // do something with *f_it, f_it->, or f_it.handle()
对应的常量部分:
- ConstVertexIter,
- ConstHalfedgeIter,
- ConstEdgeIter,
- ConstFaceIter
线性迭代器几乎与STL迭代器一致。对于接口的定义:OpenMesh::Concepts::IteratorT。
因为性能的原因,操作符++(int)(后递增)和操作符-(int)(后递增)都没有实现。因此,当我们使用迭代器的时,使用前递增操作符(++it)。另外,对于标准操作符,每一个线性迭代器提供一个方法 handle(),返回该项被迭代器引用的句柄。
因为性能的原因,操作符++(int)(后递增)和操作符-(int)(后递增)都没有实现。因此,当我们使用迭代器的时,使用前递增操作符(++it)。另外,对于标准操作符,每一个线性迭代器提供一个方法 handle(),返回该项被迭代器引用的句柄。
删除元素
如果网格中没有元素被标记为已删除,idx()中提供的指数将会是连续的数字从0到元素数-1(元素为顶点的时候就会是0到n_vertices()-1)。然而,当元素被标记被已删除而OpenMesh::ArrayKernel::garbage_collection()还没有被调用,情况就不一样。
当garbage_collection()被调用的时候,元素会被重新组织,这些元素的迭代器和句柄会确保是连续的整数。
注意:
- 如果你删除网格中的数据,这些数据任然会被标准迭代器枚举。为了跳过已删除的元素,使用Skipping Iterators。
- 一个项目的迭代器通常比项目的句柄占用更多的内存。为了存储许多的项目引用,最好使用句柄。
如何在OpenMesh中使用迭代器
这个例子演示了如何使用迭代器遍历所有的面:
MyMesh mesh;
for(MyMesh::FaceIter f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
std::cout << "The face's valence is " << mesh.valence( f_it.handle() ) << std::endl;
}
跳过迭代器(Skipping Iterators)
所有的迭代器都能够有相对应的跳过迭代器(Skipping Iterators)。如果元素在网格中被删除了,标准的迭代器会遍历所有的元素,甚至是已经删除的(直到垃圾回收完成之后才不能够访问到)。跳过迭代器忽视这些元素。
你可以使用下列的函数重新获得这些跳过迭代器:
- vertices_sbegin(),
- edges_sbegin(),
- halfedges_sbegin(),
- faces_sbegin()
循环器
OpenMesh也提供了循环器(Circulators),循环器提供了枚举其他邻接的相同或者不同类型项目。比如,一个VertexVertexIter允许枚举邻接的所有的顶点(比如,它允许枚举中心顶点的1-ring)。近似地,一个FaceHalfedgeIter枚举所有该面所有的halfedge。通常的,(CenterItem_AuxiliaryInformation_TargetItem_Iter)(擦!这名字起的)指派一个循环器枚举围绕中心项目所有的目标项目。循环器的构造器是形式为Circulator(MeshType mesh, TargetHandle center_handle),比如,获取一个项目的网格和句柄后循环之。
关于顶点的循环器:
- VertexVertexIter: iterate over all neighboring vertices.
- VertexIHalfedgeIter: iterate over all incoming halfedges.
- VertexOHalfedgeIter: iterate over all outgoing halfedges.
- VertexEdgeIter: iterate over all incident edges.
- VertexFaceIter: iterate over all adjacent faces.
关于面的循环器:
- FaceVertexIter: iterate over the face's vertices.
- FaceHalfedgeIter: iterate over the face's halfedges.
- FaceEdgeIter: iterate over the face's edges.
- FaceFaceIter: iterate over all edge-neighboring faces.
更多的,循环器提供操作bool(),只要循环器没有到达队列的尾部,函数就会返回true。
OpenMesh提供下列的函数(定义在OpenMesh::PolyConnectivity)获得围绕某个特定项目的循环器:
注意:
- 每个循环器都存在他们对应的常量版本。为了使用这些常量循环器,只用在某个类型前加上前缀Const并加前缀"c"到返回循环器的函数上。
- 例子:
ConstVertexVertexIter cvvit = mesh.cvv_iter(some_vertex_handle);
注意:
- 当构建循环器的迭代器的时候,确保你没有创建一个已删除元素的循环器(比如已删除面的FaceVertexIter),则会导致不可预计的行为。使用跳过迭代器来遍历元素和创建循环器是安全的,因为这样不会包含已删除的元素。
如何在OpenMesh上使用循环器
展示了如何枚举1-ring顶点:
MyMesh mesh;
// (linearly) iterate over all vertices
for (MyMesh::VertexIter v_it=mesh.vertices_sbegin(); v_it!=mesh.vertices_end(); ++v_it)
{
// circulate around the current vertex
for (MyMesh::VertexVertexIter vv_it=mesh.vv_iter(v_it.handle()); vv_it; ++vv_it)
{
// do something with e.g. mesh.point(*vv_it)
}
}
枚举邻接面的所有halfedge():
MyMesh mesh;
...
// Assuming faceHandle contains the face handle of the target face
MyMesh::FaceHalfedgeIter fh_it = mesh.fh_iter(faceHandle);
for(; fh_it; ++fh_it) {
std::cout << "Halfedge has handle " << fh_it.handle() << std::endl;
}