TopoDS_Shape對象的子對象,作為一個鏈表保存在TopoDS_TShape對象中,如下:
class TopoDS_TShape : public Standard_Transient { ... private: ... TopoDS_ListOfShape myShapes; Standard_Integer myFlags; };
這里,myShapes是一個TopoDS_Shape對象的列表。
首先,該列表放在BopoDS_TShape中,即放在共享對象中,是因為對一些共享對象的子對象,通常也是需要被共享的。例如:一個Face的Wire對象,如果Face是被共享,Wire對象也是隨之共享的。
其次,使用TopoDS_Shape對象,而不是TopoDS_TShape對象,因為子對象也可以具有方向、位置等信息,或者說子對象也可以是被多處共享的對象。例如:Edge的Vertex對象,會把匯集到該Vertex的多條Edge共享,但對每個Edge來說,該Vertex的方向可能是不同的。
這里,父子關系是一個單向的關系,即每個對象記錄了各自的子對象列表,非常簡單。反過來的引用關系,沒有記錄,例如:wire所在的face是誰,沒有記錄。這個應當由如下原因:
A) 由於OCCT的對象共享基於句柄機制,使用了基於引用計數的技術。如果記錄了反向拓撲對象的信息,則可能引起循環依賴。例如:Face記錄了Edge的共享對象,而Edge又反向記錄了Face對象,則會形成循環依賴,當對象自動釋放時,可能兩者都釋放不了,這個是引用計數計數的一個問題。
B)出於共享的考慮。因為,可能一個Wire對象既可能是一個Face的外環,也可以是另一個Face的內環(例如:孔的情況)。特別是由於OCCT支持non-manifold情形,一個Wire可能被多個Face所共享,因此記錄反向關系,管理起來會比較復雜,特別是模型頻繁改變的情況下。
如此一來,要獲取子對象所在的父對象,通常需要建表機制,通過遍歷父對象的子對象,建立子對象和父對象對應關系的表,例如:遍歷Face的Edge,建立Edge和face間的表,從而獲得Edge鄰接的Face對象列表。這個主要是TopExp包中的類TopExp提供了對應的建表方法,這個方法在OCCT的拓撲算法中是主要的方式,這個也導致OCCT的一些處理效率比較慢。
相對Parasolid中的簡潔記錄,例如:
struct LOOP_s // Loop
{
int node_id; // $d
union ATTRIB_GROUP_u attributes_groups; // $p
struct FIN_s *fin; // $p
struct FACE_s *face; // $p
struct LOOP_s *next; // $p
};
參見《Parasolid XT Format Reference》
Loop直接記錄了所在的face,OCCT的方式顯然是低效的。
對拓撲對象的子對象進行遍歷,是不能直接遍歷上述列表的,通常借助兩個類:
TopoDS_Iterator類:遍歷拓撲對象的直屬子對象,例如:遍歷Face的子對象Wire對象。
TopExp_Explorer類:可以遍歷拓撲對象的任意子對象,例如:遍歷Face的Edge對象。
兩個類都考慮了子對象對父對象的方向的繼承(復合),這個是很關鍵的一步,決定了獲取子對象的最終方向是否正確。
如下是典型的代碼:
// Explore face to find all boundaries for (TopoDS_Iterator aIw(face); aIw.More(); aIw.Next()) { if(aIw.Value().ShapeType() != TopAbs_WIRE) continue; for (TopoDS_Iterator aIIe(aIw.Value()); aIIe.More(); aIIe.Next()) { const TopoDS_Shape& edge = aIIe.Value();
這里是依次遍歷Face的裁剪環對象Wire,進而遍歷Wire的Edge子對象。
TopExp_Explorer anIt (theFace, TopAbs_EDGE); for ( ; anIt.More(); anIt.Next()) { TopoDS_Edge aCurEdge = TopoDS::Edge (anIt.Current());
這里是直接遍歷Face的Edge對象,對每個對象進行處理。