OpenCASCADE BRepTools

简介: OpenCASCADE BRepTools eryar@163.com Abstract. OpenCASCADE BRepTools provides utilities for BRep data structure.

OpenCASCADE BRepTools

eryar@163.com

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所示:

wps_clip_image-4070

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());
  }
}

由上述代码可知,Edge中的几何信息较多,Face中的几何信息最少,只是几何曲面或其用于显示的网格数据。在将拓朴数据输出时,拓朴面、边及顶点中包含的几何信息都是前面几何数据的编号,即相当于索引号的形式输出,代码如下所示:


// =======================================================================
// 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- 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- Curve on surf
         else
          OS 
<<   " " ;                              //  -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- 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- 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- Polygon on triangulation
           else
            OS 
<<   " " ;                             //  -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

http://www.cppblog.com/eryar/archive/2013/09/12/203199.html

目录
相关文章
|
算法框架/工具 图形学
OpenCASCADE Quaternion
OpenCASCADE Quaternion eryar@163.com Abstract. The quaternions are members of a noncommutative division algebra first invented by William Rowan Hamilton.
1452 0
|
算法 Windows
|
C++ 算法
OpenCASCADE BRep Projection
OpenCASCADE BRep Projection eryar@163.com 一网友发邮件问我下图所示的效果如何在OpenCASCADE中实现,我的想法是先构造出螺旋线,再将螺旋线投影到面上。
1676 0
|
算法
OpenCASCADE Interpolations and Approximations
OpenCASCADE Interpolations and Approximations eryar@163.com Abstract. In modeling, it is often required to approximate or interpolate points to curves and surfaces.
1400 0
|
算法
OpenCASCADE Interpolation - Lagrange
OpenCASCADE Interpolation - Lagrange eryar@163.com Abstract. Power basis polynomial is the most simple polynomial function.
1330 0
|
C++ 算法 Windows
OpenNURBS to OpenCASCADE
OpenNURBS to OpenCASCADE eryar@163.com Abstract. The OpenNURBS initiative provides CAD/CAM/CAE and computer graphics software developers the tools...
1691 0
|
算法 图形学 数据安全/隐私保护
OpenCASCADE BRep vs. OpenNURBS BRep
OpenCASCADE BRep vs. OpenNURBS BRep eryar@163.com Abstract. BRep short for Boundary Representation.
1660 0
|
算法
OpenCASCADE Conic to BSpline Curves-Hyperbola
OpenCASCADE Conic to BSpline Curves-Hyperbola eryar@163.com Abstract. Rational Bezier Curve can represent conic curves such as circle, ellipse, hyperbola, .
1090 0
|
C语言 Windows 开发工具
OpenCASCADE Conic to BSpline Curves-Parabola
OpenCASCADE Conic to BSpline Curves-Parabola eryar@163.com Abstract. Rational Bezier Curve can represent conic curves such as circle, ellipse, hyperbola, .
1007 0
OpenCascade 6.7.1 and Qt 5
OpenCascade 6.7.1 and Qt 5 eryar@163.com   Keywords: OpenCascade 6.7.1, Qt5, Demo   从OpenCascade6.
1113 0