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中做一些顯示。
 
發佈了27 篇原創文章 · 獲贊 70 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章