CGAL:Surface mesh

User Manual 用戶手冊

該類Surface_mesh是半邊數(shù)據(jù)結(jié)構(gòu)的實現(xiàn)予权,可用于表示多面體表面扫腺。它是CGAL包Halfedge Data Structure3D Polyhedral Surface的替代方案。主要區(qū)別在于它是基于索引的攒至,而不是基于指針的迫吐。此外账忘,將信息添加到頂點鳖擒,半邊蒋荚,邊和面的機制要簡單得多,并且可以在運行時(runtime)完成惊奇,而不必在編譯時完成颂郎。

因為數(shù)據(jù)結(jié)構(gòu)使用整數(shù)索引作為頂點容为,半邊,邊和面的描述符房维,所以它的內(nèi)存占用空間比基于64位指針的版本要低咙俩。由于索引是連續(xù)的湿故,因此它們可以用作存儲屬性的向量的索引坛猪。

當元素被刪除時墅茉,它們僅被標記為已刪除,并且必須調(diào)用垃圾回收函數(shù)才能真正刪除它們悍募。

1 用法(usage)

主類Surface_mesh提供了四個嵌套類坠宴,它們表示半邊數(shù)據(jù)結(jié)構(gòu)的基本元素:

這些class是基本圖元個體的封裝喜鼓,這樣做的目的是為了保證類型安全衔肢。它們默認是可構(gòu)造的膀懈,因此可能會產(chǎn)生一些無效的元素谨垃。新的元素可以通過一系列不包括連通性的低級函數(shù)向surface mesh這個類添加或者刪除刘陶。一個例外是Surface_mesh::add_face()匙隔,它嘗試向網(wǎng)格(由一系列頂點定義)中添加一個新面,如果操作在拓撲上無效撼短,則失敗挺勿。

typedef Surface_mesh<Point> Mesh;
Mesh m;
Mesh::Vertex_index u = m.add_vertex(Point(0,1,0));
Mesh::Vertex_index v = m.add_vertex(Point(0,0,0));
Mesh::Vertex_index w = m.add_vertex(Point(1,0,0));
m.add_face(u, v, w);

正如Surface_mesh是基于索引的(index based)不瓶,Vertex_indexHalfedge_index蚊丐,Edge_indexFace_index沒有成員函數(shù)來訪問連接性或?qū)傩晕醪巍?a target="_blank">Surface_mesh中創(chuàng)建的函數(shù)必須有獲取這些信息的功能。

2 連通性(connectivity)

surface mesh是一種能夠保持頂點麦备,邊和面的入射信息的孽椰,以邊為核心的數(shù)據(jù)結(jié)構(gòu)。
每個邊由兩個方向相反的半邊表示泥兰,每個半邊均存儲對入射面和入射頂點的引用弄屡,此外,它還存儲對入射面的下一個和上一個入射半邊的引用鞋诗。
其實說白了,surface mesh有一個半邊結(jié)構(gòu)的表達方式:對于一個半邊h它有以下這樣幾個導航的表達方式:Surface_mesh::opposite()削彬,Surface_mesh::next()全庸,Surface_mesh::prev()Surface_mesh::target()融痛,和Surface_mesh::face()和半邊數(shù)據(jù)結(jié)構(gòu)是差不多的壶笼。

3 范圍和迭代器(range and iterators)

Surface_mesh提供迭代器范圍以枚舉所有頂點,半邊雁刷,邊和面覆劈。它提供的成員函數(shù)返回與Boost.Range庫兼容的元素范圍。

來自官方文檔的示例,演示如何從范圍中獲取迭代器類型沛励,獲得begin和end迭代器的替代方法以及基于范圍(range for c++11)的循環(huán)的替代方法责语。

#include <vector>

#include <boost/foreach.hpp>

#include <CGAL/Simple_cartesian.h>

#include <CGAL/Surface_mesh.h>

typedef CGAL::Simple_cartesian<double> K;

typedef CGAL::Surface_mesh<K::Point_3> Mesh;

typedef Mesh::Vertex_index vertex_descriptor;

typedef Mesh::Face_index face_descriptor;

int main()

{

Mesh m;

// u                x
// +------------+
// |            |
// |      f     |
// |            |
// +------------+
// v                w

// Add the points as vertices

vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));

vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));

vertex_descriptor w = m.add_vertex(K::Point_3(1,0,0));

vertex_descriptor x = m.add_vertex(K::Point_3(1,1,0));

/* face_descriptor f = */ m.add_face(u,v,w,x);

{

std::cout << "all vertices " << std::endl;

// The vertex iterator type is a nested type of the Vertex_range

Mesh::Vertex_range::iterator vb, ve;

Mesh::Vertex_range r = m.vertices();

// The iterators can be accessed through the C++ range API

vb = r.begin();

ve = r.end();

// or the boost Range API

vb = boost::begin(r);

ve = boost::end(r);

// or with boost::tie, as the CGAL range derives from std::pair

for(boost::tie(vb, ve) = m.vertices(); vb != ve; ++vb){

std::cout << *vb << std::endl;

}

// Instead of the classical for loop one can use

// the boost macro for a range

BOOST_FOREACH(vertex_descriptor vd, m.vertices()){

std::cout << vd << std::endl;

}

// or the C++11 for loop. Note that there is a ':' and not a ',' as in BOOST_FOREACH

#ifndef CGAL_CFG_NO_CPP0X_RANGE_BASED_FOR

for(vertex_descriptor vd : m.vertices()){

std::cout << vd << std::endl;

}

#endif

}

return 0;

}

4 循環(huán)器(circulators)

CGAL和Boost Graph Library中提供了圍繞面和頂點的循環(huán)器作為模板類。

圍繞面的循環(huán)器基本上會進行調(diào)用Surface_mesh::next()目派,以從該面的逆時針方向從半邊變?yōu)榘脒吚ず颍⑶胰∠脮r返回半邊或入射頂點或相對面。

圍繞目標邊的頂點的循環(huán)器基本上會進行調(diào)用Surface_mesh::opposite(Surface_mesh::next())企蹭,以使圍繞同一目標點的順時針方向從半邊變?yōu)榘脒叀?/p>

example:

下面的示例演示如何枚舉給定半邊目標周圍的頂點白筹。第二個循環(huán)表明智末,每種循環(huán)器類型都帶有一個等效的迭代器和一個用于創(chuàng)建迭代器范圍的自由函數(shù)

#include <vector>
#include <boost/foreach.hpp>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;
int main()
{
  Mesh m;
  // u            x
  // +------------+
  // |            |
  // |            |
  // |      f     |
  // |            |
  // |            |
  // +------------+
  // v            w
  // Add the points as vertices
  vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
  vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
  vertex_descriptor w = m.add_vertex(K::Point_3(1,0,0));
  vertex_descriptor x = m.add_vertex(K::Point_3(1,1,0));
  face_descriptor f = m.add_face(u,v,w,x);
 
  {
    std::cout << "vertices around vertex " << v << std::endl;
    CGAL::Vertex_around_target_circulator<Mesh> vbegin(m.halfedge(v),m), done(vbegin);
    do {
      std::cout << *vbegin++ << std::endl;
    } while(vbegin != done);
  }
   
  { 
    std::cout << "vertices around face " << f << std::endl;
    CGAL::Vertex_around_face_iterator<Mesh> vbegin, vend;
    for(boost::tie(vbegin, vend) = vertices_around_face(m.halfedge(f), m);
        vbegin != vend; 
        ++vbegin){
      std::cout << *vbegin << std::endl;
    }
  }
  // or the same again, but directly with a range based loop
  BOOST_FOREACH(vertex_descriptor vd,vertices_around_face(m.halfedge(f), m)){
    std::cout << vd << std::endl;
  } 
    
  return 0;
}

5 屬性(properties)

Surface_mesh提供一種實時為頂點,半邊徒河,邊和面指定新屬性的機制系馆。給定屬性的所有值都存儲為連續(xù)的內(nèi)存塊。每當將鍵類型的新元素添加到數(shù)據(jù)結(jié)構(gòu)中或Surface_mesh::collect_garbage()執(zhí)行功能時虚青,對屬性的引用都將無效它呀。元素的屬性在刪除后將繼續(xù)存在。嘗試通過無效的元素訪問屬性將導致未定義的行為棒厘。
默認情況下纵穿,會維護一個屬性"v:point"。通過將新點添加到數(shù)據(jù)結(jié)構(gòu)時奢人,必須提供此屬性的值Surface_mesh::add_vertex()谓媒。可以使用Surface_mesh::points()或直接訪問該屬性`Surface_mesh::point(Surface_mesh::Vertex_index v)何乎。

當元素被刪除時句惯,它僅被標記為已刪除,并且在Surface_mesh::collect_garbage()被調(diào)用時被真正刪除支救。垃圾回收也確實會刪除這些元素的屬性抢野。

連接性也存儲在屬性中,即名為“ v:connectivity”各墨,“ h:connectivity”和“ f:connectivity”的屬性指孤。對于已刪除元素的標記,它非常相似贬堵,其中有“ v:removed”恃轩,“ e:removed”和“ f:removed”。

example:

#include <string>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <boost/foreach.hpp>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;
int main()
{
  Mesh m;
  vertex_descriptor v0 = m.add_vertex(K::Point_3(0,2,0));
  vertex_descriptor v1 = m.add_vertex(K::Point_3(2,2,0));
  vertex_descriptor v2 = m.add_vertex(K::Point_3(0,0,0));
  vertex_descriptor v3 = m.add_vertex(K::Point_3(2,0,0));
  vertex_descriptor v4 = m.add_vertex(K::Point_3(1,1,0));
  m.add_face(v3, v1, v4);
  m.add_face(v0, v4, v1);
  m.add_face(v0, v2, v4);
  m.add_face(v2, v3, v4);
  // give each vertex a name, the default is empty
  Mesh::Property_map<vertex_descriptor,std::string> name;
  bool created;
  boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","");
  assert(created);
  // add some names to the vertices
  name[v0] = "hello";
  name[v2] = "world";
  {
    // You get an existing property, and created will be false
    Mesh::Property_map<vertex_descriptor,std::string> name;
    bool created;
    boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name", "");
    assert(! created);
  }
  //  You can't get a property that does not exist
  Mesh::Property_map<face_descriptor,std::string> gnus;
  bool found;
  boost::tie(gnus, found) = m.property_map<face_descriptor,std::string>("v:gnus");
  assert(! found);
  // retrieve the point property for which exists a convenience function
  Mesh::Property_map<vertex_descriptor, K::Point_3> location = m.points();
  BOOST_FOREACH( vertex_descriptor vd, m.vertices()) { 
    std::cout << name[vd] << " @ " << location[vd] << std::endl;
  }
  std::vector<std::string> props = m.properties<vertex_descriptor>();
  BOOST_FOREACH(std::string p, props){
    std::cout << p << std::endl;
  }
  
  // delete the string property again
  m.remove_property_map(name);
  return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黎做,一起剝皮案震驚了整個濱河市叉跛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒸殿,老刑警劉巖筷厘,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宏所,居然都是意外死亡酥艳,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門楣铁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玖雁,“玉大人更扁,你說我怎么就攤上這事盖腕『斩” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵溃列,是天一觀的道長劲厌。 經(jīng)常有香客問我,道長听隐,這世上最難降的妖魔是什么补鼻? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮雅任,結(jié)果婚禮上风范,老公的妹妹穿的比我還像新娘。我一直安慰自己沪么,他們只是感情好硼婿,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著禽车,像睡著了一般寇漫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上殉摔,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天州胳,我揣著相機與錄音,去河邊找鬼逸月。 笑死栓撞,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的彻采。 我是一名探鬼主播腐缤,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肛响!你這毒婦竟也來了岭粤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤特笋,失蹤者是張志新(化名)和其女友劉穎剃浇,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猎物,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡虎囚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔫磨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淘讥。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖堤如,靈堂內(nèi)的尸體忽然破棺而出蒲列,到底是詐尸還是另有隱情窒朋,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布蝗岖,位于F島的核電站侥猩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏抵赢。R本人自食惡果不足惜欺劳,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铅鲤。 院中可真熱鬧划提,春花似錦、人聲如沸邢享。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驼仪。三九已至掸犬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绪爸,已是汗流浹背湾碎。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奠货,地道東北人介褥。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像递惋,于是被迫代替她去往敵國和親柔滔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容