1. 程式人生 > >半邊數據結構(The_Half-Edge_Data_Structure)

半邊數據結構(The_Half-Edge_Data_Structure)

註意 CA rom 方案 至少 程序 code 常用 course

文章轉載自:https://blog.csdn.net/lafengxiaoyu/article/details/51524361

介紹

表示多邊形網格(polygon mesh)的一個常用方式就是使用共享的頂點列表和面的列表(裏面包含面所含的頂點)。這樣的表示方法在許多情況下都非常方便和高效,但是在某些特定的領域,反而會效率比較低。

舉例來說,網格簡化(mesh simplification)通常需要把一條邊退化成一個頂點。這個操作需要刪除與這條邊鄰接的面並且更新面中存儲的與這條邊相關的頂點數據。這種多邊形“手術”需要我們了解網格的組成部分的鄰接關系,例如面和頂點。雖然我們肯定可以用之前提及的網格表示方法來實現網格簡化,但是代價會比較高。許多情況下需要遍歷面或者點的列表,或者二者都有。

在一個多邊形網格上其他類型的的臨近查詢包括:

  • 哪條邊用到了這個點
  • 哪條邊用到這個點
  • 哪個面臨近這條邊
  • 哪條邊臨近這個面
  • 哪個面臨近這個面

為了使得這些類型的臨近查詢更加有效,發展出更加精細的邊界表示方案(b-reps),更加明確地建模表示點、邊和面,並且也臨近信息也相應地儲存進去了。

這些表示類型中最常見的其中一種是“翼邊數據結構”(winged-edge)。其中每條邊包含了指向其兩個頂點,兩個鄰接面的指針以及指向從其終點延伸出去的四條邊的指針。這種結構可以讓我們在常數時間內判斷哪些點與面與該邊連接,但是面對其他類型的查詢,這種結構會帶來更大的開銷。

半邊(half-edge)數據結構是一種略微復雜的邊表示方法(b-reps)並且在其上做之前提到的所有操作都可以在常數時間完成(*)。更優秀的是,即使包含了面、頂點和邊的鄰接信息,數據結構的大小是固定的(沒有使用動態數組)且緊湊的。

這些特性是的半邊數據結構成為了許多應用的最佳選擇,但是其只能表示流形表面(manifold surfaces),而在某些情況下被證明是不可用的(流形的數學定義指的是曲面上的每一點都有一個小鄰域,小鄰域有一個圓盤的拓撲結構)。。對於多邊形網格來說,這意味著每條邊是且只能是兩個面的邊,T-型接合(t-junctions)和內部多邊形(internal polygons)和網格中的空缺時,不能使用半邊結構。

(*)更確切地說,每個片段信息的常數時間集中。比如,當查詢一個頂點周圍所有的臨近邊時,在臨近頂點的邊的操作上與數量是線性的,但是每條邊是常數時間。

結構

之所以稱為半邊數據結構,是因為在這個結構中並不會存儲網格的邊的信息,取而代之的是半邊(half-edges)。半邊這麽叫,就是因為它其實是一條邊的一半,等於是把一條邊保持長度不變,形式上分為兩條半邊(因為按照定義邊沒有寬度或者至少是單位寬度,這就是一個假象劃分)。這兩條半邊組合在一起稱為一條邊,也就是一條邊等於一對半邊。半邊是有方向的,並且一條邊的一對半邊有相反的方向。
下圖展示了三角形網格的一小部分的半邊描述。藍色是頂點,橙色是半邊,其中的箭頭表示指針(為了不畫得太亂,省略了一些)

技術分享圖片

可以很清楚地看到圍繞一個面的三條邊形成了一個環(circular linked list)。這個鏈表既可以順時針也可以逆時針,只要在使用中保持一致就好。環中的每半邊存儲一個指向以其為邊的面的指針(圖中沒有畫出來)、指向半邊終點的指針(同樣沒畫出來)和指向它的另一條半邊(就是合起來組成一條邊的那個半邊)的指針。在C語言中,結構如下:

struct HE_edge  
   {  
  
       HE_vert* vert;   // vertex at the end of the half-edge  
       HE_edge* pair;   // oppositely oriented adjacent half-edge   
       HE_face* face;   // face the half-edge borders  
       HE_edge* next;   // next half-edge around the face  
     
   };  

  在半邊數據結構中的點儲存著x,y,z的位置和以其為起始點的半邊的指針。在任意給定的點上存在超過一條我們可以選擇的半邊
,但是我們只需要選擇其中一條並且是哪一條沒關系,在下面的查詢方法中我們會看到解釋。在C中點數據結構如下

struct HE_vert  
    {  
  
        float x;  
        float y;  
        float z;  
  
        HE_edge* edge;  // one of the half-edges emantating from the vertex  
      
    };  

  對於一個半邊數據結構的簡單形式,一個面僅僅需要儲存一個圍繞它的邊的指針,在一些特定場合可能要求我們儲存比如材質和法向一類的信息。和上面一樣,雖然有很多邊圍繞著面,我們只需要儲存其中一條,而無所謂是哪一條。下面是在C中面的數據結構

struct HE_face  
    {  
  
        HE_edge* edge;  // one of the half-edges bordering the face  
  
    };  

  

鄰近查詢

關於鄰近查詢的大多數答案就儲存在邊、點和面的數據結構裏。比如,圍繞著半邊的面或者點可以輕易地找出

HE_vert* vert1 = edge->vert;  
HE_vert* vert2 = edge->pair->vert;  
  
HE_face* face1 = edge->face;  
HE_face* face2 = edge->pair->face; 

  稍微復雜一點的例子,找到圍繞著面的所有半邊。因為圍繞著面的所有半邊形成了一個環狀列表,並且面結構中儲存了其中一個半邊的指針,因此我們可以

HE_edge* edge = face->edge;  
  
     do {  
  
        // do something with edge  
        edge = edge->next;  
       
     } while (edge != face->edge);  
   

  類似地,我們可能對圍繞著特定點的邊或者是面感興趣。參照之前的圖解,指針組成了圍繞點的一個圈,叠代程序類似,如下:

HE_edge* edge = vert->edge;  
  
     do {  
  
          // do something with edge, edge->pair or edge->face  
          edge = edge->pair->next;  
  
     } while (edge != vert->edge);  
   

  值得註意的是所有的例子中都沒有檢查空指針,這是因為流形曲面的限制。為此要求,所有的指針都必須是有效的。

其他鄰近關系都可以通過下面的這些例子被迅速找到。

附註

哈佛圖形檔案網格實驗室有一套完整的半邊數據結構實現代碼,可以參看http://www.cs.deas.harvard.edu/~xgu/mesh/

之前提到半邊數據結構在某型情況下不能用。但是翼邊數據結構可以。更多的信息可以查看"Computer Graphics: Principles and Practice"

半邊數據結構(The_Half-Edge_Data_Structure)