OpenMesh学习笔记4 迭代器和循环器

迭代器和循环器

迭代器

    OpenMesh提供了遍历网格元素(点,半边,边,面)的迭代器。
    所有的迭代器都定义在命名空间OpenMesh::Iterators中的模板类,需要一个具体的网格对象(即已经初始化或者从文件读取的网格对象)作为模板参数。定义迭代器时,需要使用网格对象提供的类型,如MyMesh::VertexIter而不是OpenMesh::Iterators::VertexIterT<MyMesh>。(这样的定义方式,感觉跟模板类的模板参数传递不太一样,自己适应一下就好了。)
    下面是各种网格元素迭代器的使用方式:
MyMesh mesh;
   ...; // specify the mesh data
// 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

// 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

// 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

// 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
    为了效率考虑,建议使用前置递增运算符(++it)。

删除元素

    如果一个网格对象中没有元素被标记为已删除,对应元素的序号(idx())是从0到num-1的连续整数(其中num是元素个数),例如点的序号就是从0到n_vertices()-1。
    但是相反,如果有元素被标记为已删除,且OpenMesh::ArrayKernel::garbage_collection()没有被调用,这种连续的序号就不成立了,当然,如果调用了garbage_collection()函数,结果就跟上面一样了。原因就是OpenMesh采用了一种”懒“的元素删除方案,用于避免不必要的数据结构更新。当然,半边数据结构会在删除元素的过程中立即更新,以保证以下算法的正确执行:
  • 如果你删除了一个面,那么这个面会仍然存在,但留下的洞的半边会立即更新(应该是删除掉这个面上的所有半边,比如如果是三角形面,就会删除三条逆时针方向的首尾相连的半边),这就意味着,邻接顶点的循环器(看下面的内容了解循环器),不会再列出这个面;
  • 如果删除了一条边,那么相邻的面也会被移除(即把他们标记为已删除并更新周围的半边),同样的,循环器就不回再”看到“这些已经删除的元素了;
  • 如果删除一个点,那么与之相连的边和相应的面也都会被标记为已删除,和上面的方案一样。
    迭代器在遍历元素的过程中,仍然会遍历到所有的元素,包括已经标记为已删除元素。除非使用一种特殊的跳跃迭代器(skipping iterators),遍历过程中会跳过已经标记为删除的元素。而循环器总是只遍历没有被删除的元素。

在OpenMesh中如何使用迭代器

    迭代一个网格对象中所有的面的示例如下:
MyMesh mesh;
   ...; // specify the mesh data
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 ) << std::endl;
}

跳跃迭代器

    跳跃迭代器和普通的迭代器一样,只是在初始化迭代器时,不在使用<element>_begin()函数,而是用<element>_sbegin(),多了一个s而已,列举如下:
  • vertices_sbegin(),
  • edges_sbegin(),
  • halfedges_sbegin(),
  • faces_sbegin()

循环器

    循环器是用来遍历与某一个元素相邻的所有另一种元素。如列出与一个点相邻的所有点(其实就是1-ring领域了),列出一个面上的所有点,或者一个面相邻的所有的面等。具体的有下面这些,就不一一介绍了,比较好理解的。
    
一个点的循环器:
  • 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.

    其他循环器

  • HalfedgeLoopIter: iterate over a sequence of Halfedges. (all Halfedges over a face or a hole)
OpenMesh通过以下函数得到一个特定对象的循环器:
/**************************************************
 * Vertex circulators
 **************************************************/

// Get the vertex-vertex circulator (1-ring) of vertex _vh
VertexVertexIter OpenMesh::PolyConnectivity::vv_iter (VertexHandle _vh);

// Get the vertex-incoming halfedges circulator of vertex _vh
VertexIHalfedgeIter OpenMesh::PolyConnectivity::vih_iter (VertexHandle _vh);

// Get the vertex-outgoing halfedges circulator of vertex _vh
VertexOHalfedgeIter OpenMesh::PolyConnectivity::voh_iter (VertexHandle _vh);

// Get the vertex-edge circulator of vertex _vh
VertexEdgeIter OpenMesh::PolyConnectivity::ve_iter (VertexHandle _vh);

// Get the vertex-face circulator of vertex _vh
VertexFaceIter OpenMesh::PolyConnectivity::vf_iter (VertexHandle _vh);

/**************************************************
 * Face circulators
 **************************************************/

// Get the face-vertex circulator of face _fh
FaceVertexIter OpenMesh::PolyConnectivity::fv_iter (FaceHandle _fh);

// Get the face-halfedge circulator of face _fh
FaceHalfedgeIter OpenMesh::PolyConnectivity::fh_iter (FaceHandle _fh);

// Get the face-edge circulator of face _fh
FaceEdgeIter OpenMesh::PolyConnectivity::fe_iter (FaceHandle _fh);

// Get the face-face circulator of face _fh
FaceFaceIter OpenMesh::PolyConnectivity::ff_iter (FaceHandle _fh);

  除了上述常规的迭代器之外,还有一些特定方向的循环器(顺时针和逆时针),在函数中插入“cw”和“ccw”用以得到对应的方向循环器(其实就是说,常规循环器列出的对象顺序是不固定的,可能是跳跃的)。例如:

VertexVertexIter vvit = mesh.vv_iter(some_vertex_handle);          // fastest (clock or counterclockwise)
VertexVertexCWIter vvcwit = mesh.vv_cwiter(some_vertex_handle);    // clockwise
VertexVertexCCWIter vvccwit = mesh.vv_ccwiter(some_vertex_handle); // counter-clockwise
  注意,ccw和cw迭代器必须保证OpenMesh::Attributes::PrevHalfedge是可用的(因为在半边结构中,为了节省空间,这个属性是可以关闭的)。

在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); vv_it.is_valid(); ++vv_it)
  {
    // do something with e.g. mesh.point(*vv_it)
  }
}
列出一个面上的所有内部半边的例子如下:
MyMesh mesh;

...

// Assuming faceHandle contains the face handle of the target face

MyMesh::FaceHalfedgeIter fh_it = mesh.fh_iter(faceHandle);

for(; fh_it.is_valid(); ++fh_it) {
    std::cout << "Halfedge has handle " << *fh_it << std::endl;
}

关于具体的例子,下一篇附上,介绍如何使用循环器和迭代器,并在OpenGL中做一些显示。

 

© 版权声明
THE END
喜欢就支持一下吧
点赞317 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容