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 提供了一個(gè)類BRepTools,其中有許多static函數(shù),主要用來(lái)對(duì)BRep表示的拓樸形狀的數(shù)據(jù)進(jìn)行讀寫(xiě),也提供了查找一個(gè)面中外環(huán)(Outer Wire)的函數(shù)。因?yàn)镺penCASCADE中的邊界表示法BRep的數(shù)據(jù)結(jié)構(gòu)如下圖1.1所示:
Figure 1.1 BRep Data Structure of OpenCASCADE
因?yàn)镺penCASCADE中拓樸結(jié)構(gòu)采用了包含關(guān)系,當(dāng)需要將TopoDS_Shape數(shù)據(jù)保存到文件時(shí),如何保持TopoDS_Shape中的關(guān)系,以便于從文件讀取這些數(shù)據(jù)時(shí),可以重構(gòu)出TopoDS_Shape中的各種關(guān)系?
參 考o(jì)pennurbs中的BRep表示時(shí)數(shù)據(jù)的存儲(chǔ)方式,可知直接在BRep中保存拓樸及幾何數(shù)據(jù)的索引,這樣對(duì)數(shù)據(jù)的存儲(chǔ)及讀取時(shí)重構(gòu)拓樸結(jié)構(gòu)還是很方 便的。而在OpenCASCADE中拓樸數(shù)據(jù)是以Handle來(lái)保存的,且為組合關(guān)系,即一個(gè)父結(jié)構(gòu)中有一個(gè)列表 (TopoDS_ListOfShape)給包含了子結(jié)構(gòu)數(shù)據(jù)。對(duì)于沒(méi)有索引的OpenCASCADE的拓樸結(jié)構(gòu),如何進(jìn)行讀寫(xiě)操作呢?
本文結(jié)合類BRepTools中的函數(shù),對(duì)OpenCASCADE中TopoDS_Shape數(shù)據(jù)的保存和讀取功能的代碼進(jìn)行分析,從而對(duì)ModelingData中的BRep數(shù)據(jù)做進(jìn)一步的理解。
2.Topology Shape Serialization
OpenCASCADE的類BRepTools中提供了如下函數(shù),可以TopoDS_Shape中的數(shù)據(jù)進(jìn)行導(dǎo)入導(dǎo)出:
v BRepTools::Dump();
v BRepTools::Read();
v BRepTools::Write();
這 幾個(gè)函數(shù)比較常用,因?yàn)榭梢苑奖愕貙opoDS_Shape導(dǎo)出,或?qū)氲絆penCASCADE的Draw Test Harness中,來(lái)對(duì)程序一些算法進(jìn)行驗(yàn)證。對(duì)于使用了組合關(guān)系的TopoDS_Shape如何確保數(shù)據(jù)的保存及讀取后,能夠維持這些關(guān)系?帶著這個(gè)問(wèn) 題去看BRep文件讀寫(xiě)的功能,應(yīng)該更為清晰。
還是看看代碼,如下所示為輸出TopoDS_Shape的函數(shù),在程序Debug時(shí)比較常用:
//
=======================================================================
//
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函數(shù)如下:
//
=======================================================================
//
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;
}
這是一個(gè)遞歸函數(shù),通過(guò)AddGeometry函數(shù),將TopoDS_Shape中的幾何信息都保存到相應(yīng)的集合Set中,Set中使用了Map,即給每個(gè)幾何信息一個(gè)唯一的編號(hào)與之對(duì)應(yīng)。
//
=======================================================================
//
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());
}
}
}
}
通過(guò)先將幾何數(shù)據(jù)收集到相應(yīng)的集合(映射)中,再在拓樸結(jié)構(gòu)對(duì)應(yīng)的地方以索引號(hào)的方式輸出,這樣就便于從文件讀取數(shù)據(jù)時(shí),以類似的方式來(lái)重構(gòu)BRep邊界表示的拓樸Shape的結(jié)構(gòu)。即讀取文件重構(gòu)拓樸結(jié)構(gòu)數(shù)據(jù)是輸出的逆過(guò)程。
在實(shí)現(xiàn)從文件讀取BRep表示的數(shù)據(jù)時(shí),先將幾何信息讀取到對(duì)應(yīng)的集合中,再讀取拓樸結(jié)構(gòu)數(shù)據(jù)時(shí),若拓樸結(jié)構(gòu)中包含幾何信息,則以索引的方式,找到對(duì)應(yīng)的幾何數(shù)據(jù)即可。詳細(xì)實(shí)現(xiàn)可參考源程序。
3. For Debugging
由 于BRepTools為T(mén)oolkit TKBRep中的類,所以依賴的動(dòng)態(tài)庫(kù)較少,所以在編程時(shí),若要驗(yàn)證一些算法的正確性時(shí),經(jīng)常需要將TopoDS_Shape的數(shù)據(jù)導(dǎo)出,甚至可以直接先 在Draw Test Harness中使用相關(guān)命令來(lái)將導(dǎo)出的數(shù)據(jù)導(dǎo)入來(lái)查看結(jié)果。
4. Conclusion
通 過(guò)BRepTools中對(duì)TopoDS_Shape數(shù)據(jù)的輸出及導(dǎo)入的代碼分析可知,對(duì)于只有組合關(guān)系的數(shù)據(jù),若想維持這種關(guān)系,就需要引入集合映射的類 來(lái)產(chǎn)生索引,進(jìn)而在讀取數(shù)據(jù)時(shí),可以根據(jù)索引來(lái)重構(gòu)拓樸關(guān)系。由于opennurbs中的BRep在內(nèi)存中本來(lái)就是索引的方式,所以在數(shù)據(jù)存取時(shí),實(shí)現(xiàn)要 簡(jiǎn)單很多。
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
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

