OpenCASCADE BRepTools
Abstract. OpenCASCADE BRepTools provides utilities for BRep data structure. OuterWire method to find the outer wire of a face. Dump method to dump a BRep object. It also can be used as the data exchange for OpenCASCADE native shapes.?
Key Words. OpenCASCADE, BRepTools, BRep, Topology
1. Introduction
OpenCASCADE 提供了一個類BRepTools,其中有許多static函數,主要用來對BRep表示的拓樸形狀的數據進行讀寫,也提供了查找一個面中外環(Outer Wire)的函數。因為OpenCASCADE中的邊界表示法BRep的數據結構如下圖1.1所示:
Figure 1.1 BRep Data Structure of OpenCASCADE
因為OpenCASCADE中拓樸結構采用了包含關系,當需要將TopoDS_Shape數據保存到文件時,如何保持TopoDS_Shape中的關系,以便于從文件讀取這些數據時,可以重構出TopoDS_Shape中的各種關系?
參 考opennurbs中的BRep表示時數據的存儲方式,可知直接在BRep中保存拓樸及幾何數據的索引,這樣對數據的存儲及讀取時重構拓樸結構還是很方 便的。而在OpenCASCADE中拓樸數據是以Handle來保存的,且為組合關系,即一個父結構中有一個列表 (TopoDS_ListOfShape)給包含了子結構數據。對于沒有索引的OpenCASCADE的拓樸結構,如何進行讀寫操作呢?
本文結合類BRepTools中的函數,對OpenCASCADE中TopoDS_Shape數據的保存和讀取功能的代碼進行分析,從而對ModelingData中的BRep數據做進一步的理解。
2.Topology Shape Serialization
OpenCASCADE的類BRepTools中提供了如下函數,可以TopoDS_Shape中的數據進行導入導出:
v BRepTools::Dump();
v BRepTools::Read();
v BRepTools::Write();
這 幾個函數比較常用,因為可以方便地將TopoDS_Shape導出,或導入到OpenCASCADE的Draw Test Harness中,來對程序一些算法進行驗證。對于使用了組合關系的TopoDS_Shape如何確保數據的保存及讀取后,能夠維持這些關系?帶著這個問 題去看BRep文件讀寫的功能,應該更為清晰。
還是看看代碼,如下所示為輸出TopoDS_Shape的函數,在程序Debug時比較常用:
// ======================================================================= // function : Dump // purpose : // ======================================================================= void BRepTools::Dump( const TopoDS_Shape& Sh, Standard_OStream& S) { BRepTools_ShapeSet SS; SS.Add(Sh); SS.Dump(Sh,S); SS.Dump(S); }
其中使用了類BRepTools_ShapeSet,這里的Set的意思我理解為集合的意思,其Add函數如下:
// ======================================================================= // function : Add // purpose : // ======================================================================= Standard_Integer TopTools_ShapeSet::Add( const TopoDS_Shape& S) { if (S.IsNull()) return 0 ; myLocations.Add(S.Location()); TopoDS_Shape S2 = S; S2.Location(TopLoc_Location()); Standard_Integer index = myShapes.FindIndex(S2); if (index == 0 ) { AddGeometry(S2); for (TopoDS_Iterator its(S2,Standard_False,Standard_False); its.More(); its.Next()) Add(its.Value()); index = myShapes.Add(S2); } return index; }
這是一個遞歸函數,通過AddGeometry函數,將TopoDS_Shape中的幾何信息都保存到相應的集合Set中,Set中使用了Map,即給每個幾何信息一個唯一的編號與之對應。
// ======================================================================= // function : AddGeometry // purpose : // ======================================================================= void BRepTools_ShapeSet::AddGeometry( const TopoDS_Shape& S) { // Add the geometry if (S.ShapeType() == TopAbs_VERTEX) { Handle(BRep_TVertex) TV = Handle(BRep_TVertex)::DownCast(S.TShape()); BRep_ListIteratorOfListOfPointRepresentation itrp(TV -> Points()); while (itrp.More()) { const Handle(BRep_PointRepresentation)& PR = itrp.Value(); if (PR-> IsPointOnCurve()) { myCurves.Add(PR -> Curve()); } else if (PR-> IsPointOnCurveOnSurface()) { myCurves2d.Add(PR -> PCurve()); mySurfaces.Add(PR -> Surface()); } else if (PR-> IsPointOnSurface()) { mySurfaces.Add(PR -> Surface()); } ChangeLocations().Add(PR -> Location()); itrp.Next(); } } else if (S.ShapeType() == TopAbs_EDGE) { // Add the curve geometry Handle(BRep_TEdge) TE = Handle(BRep_TEdge)::DownCast(S.TShape()); BRep_ListIteratorOfListOfCurveRepresentation itrc(TE -> Curves()); while (itrc.More()) { const Handle(BRep_CurveRepresentation)& CR = itrc.Value(); if (CR-> IsCurve3D()) { if (!CR-> Curve3D().IsNull()) { myCurves.Add(CR -> Curve3D()); ChangeLocations().Add(CR -> Location()); } } else if (CR-> IsCurveOnSurface()) { mySurfaces.Add(CR -> Surface()); myCurves2d.Add(CR -> PCurve()); ChangeLocations().Add(CR -> Location()); if (CR-> IsCurveOnClosedSurface()) myCurves2d.Add(CR -> PCurve2()); } else if (CR-> IsRegularity()) { mySurfaces.Add(CR -> Surface()); ChangeLocations().Add(CR -> Location()); mySurfaces.Add(CR -> Surface2()); ChangeLocations().Add(CR -> Location2()); } else if (myWithTriangles) { // for XML Persistence if (CR-> IsPolygon3D()) { if (!CR-> Polygon3D().IsNull()) { myPolygons3D.Add(CR -> Polygon3D()); ChangeLocations().Add(CR -> Location()); } } else if (CR-> IsPolygonOnTriangulation()) { myTriangulations.Add(CR -> Triangulation()); myNodes.Add(CR -> PolygonOnTriangulation()); ChangeLocations().Add(CR -> Location()); if (CR-> IsPolygonOnClosedTriangulation()) myNodes.Add(CR -> PolygonOnTriangulation2()); } else if (CR-> IsPolygonOnSurface()) { mySurfaces.Add(CR -> Surface()); myPolygons2D.Add(CR -> Polygon()); ChangeLocations().Add(CR -> Location()); if (CR-> IsPolygonOnClosedSurface()) myPolygons2D.Add(CR -> Polygon2()); } } itrc.Next(); } } else if (S.ShapeType() == TopAbs_FACE) { // Add the surface geometry Handle(BRep_TFace) TF = Handle(BRep_TFace)::DownCast(S.TShape()); if (!TF->Surface().IsNull()) mySurfaces.Add(TF-> Surface()); if (myWithTriangles) { // for XML Persistence Handle(Poly_Triangulation) Tr = TF-> Triangulation(); if (! Tr.IsNull()) myTriangulations.Add(Tr); } ChangeLocations().Add(TF -> Location()); } }
// ======================================================================= // function : WriteGeometry // purpose : // ======================================================================= void BRepTools_ShapeSet::WriteGeometry( const TopoDS_Shape& S, Standard_OStream & OS) const { // Write the geometry if (S.ShapeType() == TopAbs_VERTEX) { // Write the point geometry TopoDS_Vertex V = TopoDS::Vertex(S); OS << BRep_Tool::Tolerance(V) << " \n " ; gp_Pnt p = BRep_Tool::Pnt(V); OS <<p.X()<< " " <<p.Y()<< " " <<p.Z()<< " \n " ; Handle(BRep_TVertex) TV = Handle(BRep_TVertex)::DownCast(S.TShape()); BRep_ListIteratorOfListOfPointRepresentation itrp(TV -> Points()); while (itrp.More()) { const Handle(BRep_PointRepresentation)& PR = itrp.Value(); OS << PR-> Parameter(); if (PR-> IsPointOnCurve()) { OS << " 1 " << myCurves.Index(PR-> Curve()); } else if (PR-> IsPointOnCurveOnSurface()) { OS << " 2 " << myCurves2d.Index(PR-> PCurve()); OS << " " << mySurfaces.Index(PR-> Surface()); } else if (PR-> IsPointOnSurface()) { OS << " 3 " << PR->Parameter2() << " " ; OS << mySurfaces.Index(PR-> Surface()); } OS << " " << Locations().Index(PR-> Location()); OS << " \n " ; itrp.Next(); } OS << " 0 0\n " ; // end representations } else if (S.ShapeType() == TopAbs_EDGE) { // Write the curve geometry Handle(BRep_TEdge) TE = Handle(BRep_TEdge)::DownCast(S.TShape()); OS << " " << TE->Tolerance() << " " ; OS << ((TE->SameParameter()) ? 1 : 0 ) << " " ; OS << ((TE->SameRange()) ? 1 : 0 ) << " " ; OS << ((TE->Degenerated()) ? 1 : 0 ) << " \n " ; Standard_Real first, last; BRep_ListIteratorOfListOfCurveRepresentation itrc = TE-> Curves(); while (itrc.More()) { const Handle(BRep_CurveRepresentation)& CR = itrc.Value(); if (CR-> IsCurve3D()) { if (!CR-> Curve3D().IsNull()) { Handle(BRep_GCurve) GC = Handle(BRep_GCurve)::DownCast(itrc.Value()); GC -> Range(first, last); OS << " 1 " ; // -1- Curve 3D OS << " " <<myCurves.Index(CR-> Curve3D()); OS << " " <<Locations().Index(CR-> Location()); OS << " " <<first<< " " << last; OS << " \n " ; } } else if (CR-> IsCurveOnSurface()) { Handle(BRep_GCurve) GC = Handle(BRep_GCurve)::DownCast(itrc.Value()); GC -> Range(first, last); if (!CR-> IsCurveOnClosedSurface()) OS << " 2 " ; // -2- Curve on surf else OS << " 3 " ; // -3- Curve on closed surf OS << " " <<myCurves2d.Index(CR-> PCurve()); if (CR-> IsCurveOnClosedSurface()) { OS << " " << myCurves2d.Index(CR-> PCurve2()); PrintRegularity(CR -> Continuity(),OS); } OS << " " << mySurfaces.Index(CR-> Surface()); OS << " " << Locations().Index(CR-> Location()); OS << " " <<first<< " " << last; OS << " \n " ; // Write UV Points // for XML Persistence higher performance if (FormatNb() == 2 ) { gp_Pnt2d Pf,Pl; if (CR-> IsCurveOnClosedSurface()) { Handle(BRep_CurveOnClosedSurface) COCS = Handle(BRep_CurveOnClosedSurface)::DownCast(CR); COCS -> UVPoints2(Pf,Pl); } else { Handle(BRep_CurveOnSurface) COS = Handle(BRep_CurveOnSurface)::DownCast(CR); COS -> UVPoints(Pf,Pl); } OS << Pf.X() << " " << Pf.Y() << " " << Pl.X() << " " << Pl.Y() << " \n " ; } } else if (CR-> IsRegularity()) { OS << " 4 " ; // -4- Regularity PrintRegularity(CR-> Continuity(),OS); OS << " " <<mySurfaces.Index(CR-> Surface()); OS << " " <<Locations().Index(CR-> Location()); OS << " " <<mySurfaces.Index(CR-> Surface2()); OS << " " <<Locations().Index(CR-> Location2()); OS << " \n " ; } else if (myWithTriangles) { // for XML Persistence if (CR-> IsPolygon3D()) { Handle(BRep_Polygon3D) GC = Handle(BRep_Polygon3D)::DownCast(itrc.Value()); if (!GC-> Polygon3D().IsNull()) { OS << " 5 " ; // -5- Polygon3D OS << " " <<myPolygons3D.FindIndex(CR-> Polygon3D()); OS << " " <<Locations().Index(CR-> Location()); OS << " \n " ; } } else if (CR-> IsPolygonOnTriangulation()) { Handle(BRep_PolygonOnTriangulation) PT = Handle(BRep_PolygonOnTriangulation)::DownCast(itrc.Value()); if (!CR-> IsPolygonOnClosedTriangulation()) OS << " 6 " ; // -6- Polygon on triangulation else OS << " 7 " ; // -7- Polygon on closed triangulation OS << " " << myNodes.FindIndex(PT-> PolygonOnTriangulation()); if (CR-> IsPolygonOnClosedTriangulation()) { OS << " " << myNodes.FindIndex(PT-> PolygonOnTriangulation2()); } OS << " " << myTriangulations.FindIndex(PT-> Triangulation()); OS << " " <<Locations().Index(CR-> Location()); OS << " \n " ; } } itrc.Next(); } OS << " 0\n " ; // end of the list of representations } else if (S.ShapeType() == TopAbs_FACE) { Handle(BRep_TFace) TF = Handle(BRep_TFace)::DownCast(S.TShape()); const TopoDS_Face& F = TopoDS::Face(S); if (!(TF-> Surface()).IsNull()) { OS << ((BRep_Tool::NaturalRestriction(F)) ? 1 : 0 ); OS << " " ; // Write the surface geometry OS << " " <<TF-> Tolerance(); OS << " " <<mySurfaces.Index(TF-> Surface()); OS << " " <<Locations().Index(TF-> Location()); OS << " \n " ; } else // For correct reading of null face { OS << 0 ; OS << " " ; OS << " " <<TF-> Tolerance(); OS << " " << 0 ; OS << " " << 0 ; OS << " \n " ; } if (myWithTriangles) { // for XML Persistence if (!(TF-> Triangulation()).IsNull()) { OS << 2 ; OS << " " ; // Write the triangulation OS << " " <<myTriangulations.FindIndex(TF-> Triangulation()); } } } }
通過先將幾何數據收集到相應的集合(映射)中,再在拓樸結構對應的地方以索引號的方式輸出,這樣就便于從文件讀取數據時,以類似的方式來重構BRep邊界表示的拓樸Shape的結構。即讀取文件重構拓樸結構數據是輸出的逆過程。
在實現從文件讀取BRep表示的數據時,先將幾何信息讀取到對應的集合中,再讀取拓樸結構數據時,若拓樸結構中包含幾何信息,則以索引的方式,找到對應的幾何數據即可。詳細實現可參考源程序。
3. For Debugging
由 于BRepTools為Toolkit TKBRep中的類,所以依賴的動態庫較少,所以在編程時,若要驗證一些算法的正確性時,經常需要將TopoDS_Shape的數據導出,甚至可以直接先 在Draw Test Harness中使用相關命令來將導出的數據導入來查看結果。
4. Conclusion
通 過BRepTools中對TopoDS_Shape數據的輸出及導入的代碼分析可知,對于只有組合關系的數據,若想維持這種關系,就需要引入集合映射的類 來產生索引,進而在讀取數據時,可以根據索引來重構拓樸關系。由于opennurbs中的BRep在內存中本來就是索引的方式,所以在數據存取時,實現要 簡單很多。
5. References
1. OpenCASCADE Team. BRep Format. 2014.12
2. Shing Liu. Topology and Geometry in OpenCascade-Topology.?
http://www.cppblog.com/eryar/archive/2013/09/21/203338.html
3. Shing Liu. Topology and Geometry in OpenCascade-Vertex
http://www.cppblog.com/eryar/archive/2013/08/20/202678.html
4. Shing Liu. Topology and Geometry in OpenCascade-Edge
http://www.cppblog.com/eryar/archive/2013/08/24/202739.html
5. Shing Liu. Topology and Geometry in OpenCascade-Face
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
