<2x3>OpenMesh译稿:使用并理解OpenMesh-迭代器与循环器

                                    <2x3>OpenMesh译稿:使用并理解OpenMesh-迭代器与循环器_第1张图片

迭代器与循环器

迭代器

         OpenMesh提供一种线性迭代器(能够枚举顶点、半边、边以及面),能够轻易的遍历整个网格。

         所有的迭代器存在于命令空间OpenMesh::Iterators。他们是模版类,能够通过模版参数来指定一个网格。您应该使用网格本身所提供的迭代器类型,例如MyMesh::VertexIter,而不是OpenMesh::Iterators::VertexlterT

 迭代器的用法如下所示:

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

对应的常量型迭代器为:

ConstVertexIter,
ConstHalfedgeIter,
ConstEdgeIter,
ConstFaceIter.

        线性迭代器的使用与STL迭代器相同,有关其具体接口的说明请看:OpenMesh::Concepts::IteratorT。

        在使用迭代器时,使用(++it)可提高效率。

不推荐使用:

        虽然可以通过handle()来获取迭代器引用的句柄项,但并不建议这样做,可以通过取消引用来替代。

元素删除

         如果网格内没有元素被删除,则元素的编号下标为0至元素个数减1,为连续性的,例如,顶点的编号为0至n_vertices()-1。

         然而,应注意当元素标记为已删除,并且尚未调用OpenMesh::ArrayKernel::garbage_collection()时的情况。在调用了

garbage_collection()之后,元素重新编号,句柄和迭代器重新排序。

         OpenMesh使用延迟删除方案来避免对数据结构进行不必要的更新。 halfedge数据结构将始终保持更新状态,以确保正确的迭代器运算。

         如果您删除一个面,这个面实际上仍然存在,但逻辑上已经删除,即将会从半边结构中删除,意味着这个面上邻接的顶点循环器将不再链接这个面。

         如果删除一条边,则邻接的面也会被删除,将对应的边和面标记为已删除,同时更新邻接的半边结构。循环器也不会再访问已删除的面与边。

         对于顶点,将删除其相邻的边与面,并且将顶点也标记为已删除。

         对于迭代器,仍然会枚举出所有的顶点、边与面(包含已被删除的),除非您使用skipping iterators,这将会跳过原始的元素。而circulators总会列举出那些未被删除的元素。

         注意:

         1. 如果删除网格上的元素,仍然能通过标准迭代器搜索。如果想要忽略已删除的元素,请使用跳跃迭代器;

         2. 一个类型的迭代器往往比句柄占用更多的内存,如果要存储一个项目的许多引用,最好使用句柄。

在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 ) \<< std::endl;
}

         所有的迭代器都可用作跳跃迭代器。如果元素被删除后(在garbage_collection调用 前),标准迭代器仍然会遍历它。而跳

跃迭代器将忽略这些被删除的元素,您可以通过调用以下函数来获取跳跃迭代器:

vertices_sbegin(),
edges_sbegin(),
halfedges_sbegin(),
faces_sbegin()

 

        这些迭代器的与标准迭代器的结束相同,例如vertices_end()。

循环器

         OpenMesh同时提供循环器,用以提供访问与当前项相同或者其他类型的邻接对象方法。例如,VertexVertexIter用来枚举一个顶点的邻接点。类似的,FaceHalfedgeIter用来枚举面的所有半边。通常来说,CenterItem_AuxiliaryInformation_TargetItem_Iter用来枚举以当前项目为中心,其周围的所有邻接对象。

         顶点循环器可指向的对象:

  • VertexVertexIter:所有的邻接顶点;
  • VertexIHalfedgeIter:所有的进半边(incoming halfedge);
  • VertexOHalfedgeIter:所有的出半边(outgoing halfedge);
  • VertexEdgeIter:所有的邻接边;
  • VertexFaceIter:所有的邻接面。

面循环器可指向的对象:

  • FaceVertexIter:面的所有顶点;
  • FaceHalfedgeIter:面的所有半边;
  • FaceEdgeIter:面的所有边;
  • FaceFaceIter:所有的邻接面。

其它循环器:

  • HalfedgeLoopIter:访问一系列半边(围绕一个面或者孔洞)

所有循环器都提供CirculatorT 中所列出的接口,这些操作与迭代器功能基本相同。

注:

循环器类似于双向迭代器,它们具有bidirectional_iterator_tag。但是,双向遍历功能需要OpenMesh::Attributes::PrevHalfedge可用,否则只能沿一个方向遍历。

推荐:

当循环器没有达到序列的最后一个元素,可以使用操作符bool(),返回为true。否则请使用is_valid()。

OpenMesh提供以下功能(定义于OpenMesh::PolyConnectivity)以来获取围绕某个对象的循环器。

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

        也可以将cw循环器转换为ccw循环器,反之亦然。为此,每个循环器提供一个构造函数,将另一个循环器作为输入。如果转

换了一个cw循环器,ccw循环器与cw循环器指向同一个对象,但增量和减量的方向发生改变。

此仅能够对有效的循环器进行转换,对于无效循环器则仍然无效。例如:

VertexVertexCWIter vvcwit = mesh.vv_cwend(some_vertex_handle);
VertexVertexCCWIter vvccwit = VertexVertexCCWIter(vvcwit); //conversion of an invalid circulator
 --vvcwit;  //is valid now (if the range >= 1)
 ++vvccwit; //can still be invalid

        CW和CCW循环器功能需要OpenMesh :: Attributes :: PrevHalfedge属性可用。

注:

        每种循环器都存在const型,想要使用这些常量型循环器只需要在前面添加“Const”,并且在每个循环器的函数前添加前缀“c”,例如:

ConstVertexVertexIter cvvit = mesh.cvv_iter(some_vertex_handle);

注:

         注意使用迭代器来构造循环器时,确保不要使用已删除元素的迭代器(例如,已删除Face的迭代器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); 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;
}

 

译者说明:因科研需要,避免重复造轮子,近来借用OpenMesh,因其结构封装严谨,灵活可靠,且十分方便,故抽出时间对官网的说明做点翻译。英文水平不高,如翻译有误请多多包涵,也请您多多指正。

上一篇:使用并理解OpenMesh-半边数据结构

下一篇:使用并理解OpenMesh-网格的导航

英文原文地址:http://www.openmesh.org/Documentation/OpenMesh-Doc-Latest/index.html

--------------------- 
作者:feengg 
来源:CSDN 
原文:https://blog.csdn.net/feengg/article/details/86317079
版权声明:本文为博主原创文章,转载请附上博文链接!

<2x3>OpenMesh译稿:使用并理解OpenMesh-迭代器与循环器_第2张图片

 

 

 

你可能感兴趣的:(图形学,OpenMesh译稿,OpenMesh,图形学,翻译,教程,迭代器)