Geometry Surface of OpenCascade BRep

eryar@163.com

摘要Abstract:几何曲面是参数表示的曲面 ,在边界表示中其数据存在于BRep_TFace中,BRep_TFace中不仅包括了几何曲线,还包含用于显示的离散几何信息,如三角剖分数据。本文主要对OpenCascade的BRep表示中几何曲面进行说明,将在后面分析Topology部分的读写程序时来说明包含几何数据的三种拓朴结构中分别包括哪些几何信息。

关键字Key Words:OpenCascade BRep, Geometry Surface, Topology

一、引言 Introduction

边界表示(Boundary Representation)也称为BRep表示,它是几何造型中最成熟、无二义的表示法。实体的边界通常是由面的并集来表示,而每个面又由它所在的曲面的定义加上其边界来表示,面的边界是边的并集,而边又是由点来表示的。

边界表示的一个重要特征是描述形体的信息包括几何信息(Geometry)和拓朴信息(Topology)两个方面。拓朴信息描述形体上的顶点、边、面的连接关系,它形成物体边界表示的“骨架”。形体的几何信息犹如附着在“骨架”上的肌肉。例如,形体的某个面位于某一个曲面上,定义这一曲面方程的数据就是几何信息。此外,边的形状、顶点在三维空间中的位置(点的坐标)等都是几何信息,一般来说,几何信息描述形体的大小、尺寸、位置和形状等。

OpenCascade中几何(Geometry)与拓朴(Topology)的关系也是按上述方式组织的。即几何信息在BRep中并不是单独存在的,而是依附于拓朴存在的。通过继承TopoDS包中的抽象的拓朴类实现了边界表示(BRep)模型。如下图所示:

Figure 1.1 Topology data structure in OpenCascade

从上面的类图可以看出只有三种拓朴对象有几何数据:顶点(vertex)、边(edge)、面(face),分别为BRep_TVertex、BRep_TEdge、BRep_TFace。BRep_TVertex中主要包含一个空间点(x, y, z)数据;几何曲线数据主要存在于BRep_TEdge中,BRep_TEdge中不仅包括了几何曲线,还包含其他类型的几何信息;BRep_TFace中主要包含几何曲面及其他的几何数据,如面的三角剖分等。本文主要对OpenCascade的BRep表示中几何曲面进行说明,将在后面分析Topology部分的读写程序时来说明这三种拓朴结构中分别包括哪些几何信息。

Draw Test Harness是OpenCascade提供的一种灵活和简便的测试与演示OCCT造型库的工具。他不仅可以使用交互的方式来创建、显示和修改曲线、曲面和拓朴形状,还可以以脚本(script)的方式来使用,OpenCascade就是用脚本的方式来对其造型内核进行自动化测试(Tests)。本文将示例程序的几何曲面在Draw Test Harness进行创建与显示,结合图形的直观显示便于对抽象概念的理解。

二、示例程序 Example Code

在OpenCascade提供的文档《BRep Format Description White Paper》对其BRep文件数据进行了说明。BRep文件的几何部分包含了参数曲面,根据文档中提供的数据,利用其提供的类来将示例数据进行输出,再调试其相关代码来分析其实现。示例程序如下所示:

/*
* Copyright (c) 2013 eryar All Rights Reserved.
*
* File : Main.cpp
* Author : eryar@163.com
* Date : 2013-12-01 12:18
* Version : 1.0v
*
* Description : Demonstrate the geometry surface section
* of the BRep file of OpenCascade.
* KeyWords : OpenCascade, BRep File, Geometry Surface
*
*/ // OpenCascade library.
#define WNT
#include <Geom_Plane.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_ConicalSurface.hxx>
#include <Geom_SphericalSurface.hxx>
#include <Geom_ToroidalSurface.hxx>
#include <Geom_SurfaceOfLinearExtrusion.hxx>
#include <Geom_SurfaceOfRevolution.hxx>
#include <Geom_BezierSurface.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_OffsetSurface.hxx> #include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx> #include <GeomTools.hxx>
#include <Geom_Circle.hxx> #pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")
#pragma comment(lib, "TKG3d.lib")
#pragma comment(lib, "TKGeomBase.lib") int main(void)
{
gp_Ax2 axis(gp_Pnt(, , ), gp::DZ());
std::ofstream dumpFile("geometrySurface.txt"); // Surface record 1 - Plane.
// Example: 1 0 0 3 0 0 1 1 0 -0 -0 1 0
Handle_Geom_Plane thePlane = new Geom_Plane(gp_Pnt(, , ), gp_Dir(, , ));
GeomTools::Write(thePlane, dumpFile);
GeomTools::Dump(thePlane, dumpFile);
GeomTools::Write(thePlane, std::cout);
GeomTools::Dump(thePlane, std::cout); // Surface record 2 - Cylinder.
// Example: 2 1 2 3 0 0 1 1 0 0 0 1 0 4
Handle_Geom_CylindricalSurface theCylinder = new Geom_CylindricalSurface(axis, 4.0);
GeomTools::Write(theCylinder, dumpFile);
GeomTools::Dump(theCylinder, dumpFile);
GeomTools::Write(theCylinder, std::cout);
GeomTools::Dump(theCylinder, std::cout); // Surface record 3 - Cone.
// Example: 3 1 2 3 0 0 1 1 0 0 0 1 0 4
// 0.75
Handle_Geom_ConicalSurface theCone = new Geom_ConicalSurface(axis, 0.75, 4.0);
GeomTools::Write(theCone, dumpFile);
GeomTools::Dump(theCone, dumpFile);
GeomTools::Write(theCone, std::cout);
GeomTools::Dump(theCone, std::cout); // Surface record 4 - Sphere.
// Example: 4 1 2 3 0 0 1 1 0 -0 -0 1 0 4
Handle_Geom_SphericalSurface theSphere = new Geom_SphericalSurface(axis, );
GeomTools::Write(theSphere, dumpFile);
GeomTools::Dump(theSphere, dumpFile);
GeomTools::Write(theSphere, std::cout);
GeomTools::Dump(theSphere, std::cout); // Surface record 5 - Torus.
// Example: 5 1 2 3 0 0 1 1 0 -0 -0 1 0 8 4
Handle_Geom_ToroidalSurface theTorus = new Geom_ToroidalSurface(axis, , );
GeomTools::Write(theTorus, dumpFile);
GeomTools::Dump(theTorus, dumpFile);
GeomTools::Write(theTorus, std::cout);
GeomTools::Dump(theTorus, std::cout); // Surface record 6 - Linear Extrusion.
// Example: 6 0 0.6 0.8
// 2 1 2 3 0 0 1 1 0 -0 -0 1 0 4
Handle_Geom_Circle baseCurve = new Geom_Circle(axis, 4.0);
Handle_Geom_SurfaceOfLinearExtrusion theExtrusion = new Geom_SurfaceOfLinearExtrusion(baseCurve, gp_Dir(, 0.6, 0.8));
GeomTools::Write(theExtrusion, dumpFile);
GeomTools::Dump(theExtrusion, dumpFile);
GeomTools::Write(theExtrusion, std::cout);
GeomTools::Dump(theExtrusion, std::cout); // Surface record 7 - Revolution Surface.
// Example: 7 -4 0 3 0 1 0
// 2 1 2 3 0 0 1 1 0 -0 -0 1 0 4
Handle_Geom_SurfaceOfRevolution theRevolution = new Geom_SurfaceOfRevolution(baseCurve, gp::OY());
theRevolution->SetLocation(gp_Pnt(-, , ));
GeomTools::Write(theRevolution, dumpFile);
GeomTools::Dump(theRevolution, dumpFile);
GeomTools::Write(theRevolution, std::cout);
GeomTools::Dump(theRevolution, std::cout); // Surface record 8 - Bezier Surface.
// Example: 8 1 1 2 1 0 0 1 7 1 0 -4 10
// 0 1 -2 8 1 1 5 11
// 0 2 3 9 1 2 6 12
TColgp_Array2OfPnt poles(, , , );
TColStd_Array2OfReal weights(, , , ); poles.SetValue(, , gp_Pnt(, , )); weights.SetValue(, , 7.0);
poles.SetValue(, , gp_Pnt(, , -)); weights.SetValue(, , 10.0); poles.SetValue(, , gp_Pnt(, , -)); weights.SetValue(, , 8.0);
poles.SetValue(, , gp_Pnt(, , )); weights.SetValue(, , 11.0); poles.SetValue(, , gp_Pnt(, , )); weights.SetValue(, , 9.0);
poles.SetValue(, , gp_Pnt(, , )); weights.SetValue(, , 12.0); Handle_Geom_BezierSurface theBezierSurface = new Geom_BezierSurface(poles, weights);
GeomTools::Write(theBezierSurface, dumpFile);
GeomTools::Dump(theBezierSurface, dumpFile);
GeomTools::Write(theBezierSurface, std::cout);
GeomTools::Dump(theBezierSurface, std::cout); // Surface record 9 - B-spline Surface.
// Example: 9 1 1 0 0 1 1 3 2 5 4 0 0 1 7 1 0 -4 10
// 0 1 -2 8 1 1 5 11
// 0 2 3 9 1 2 6 12
//
// 0 1
// 0.25 1
// 0.5 1
// 0.75 1
// 1 1
//
// 0 1
// 0.3 1
// 0.7 1
// 1 1
Standard_Integer uDegree = ;
Standard_Integer vDegree = ;
Standard_Boolean uPeriodic = Standard_False;
Standard_Boolean vPeriodic = Standard_False; TColStd_Array1OfReal uKnots(, );
TColStd_Array1OfReal vKnots(, );
TColStd_Array1OfInteger uMults(, );
TColStd_Array1OfInteger vMults(, ); uKnots.SetValue(, );
uKnots.SetValue(, 0.25);
uKnots.SetValue(, 0.5);
uKnots.SetValue(, 0.75);
uKnots.SetValue(, 1.0); vKnots.SetValue(, );
vKnots.SetValue(, 0.3);
vKnots.SetValue(, 0.7);
vKnots.SetValue(, 1.0); // Multiplicity of u and v are 1.
uMults.Init();
vMults.Init(); Handle_Geom_BSplineSurface theBSplineSurface = new Geom_BSplineSurface(poles, weights, uKnots, vKnots, uMults, vMults, uDegree, vDegree, uPeriodic, vPeriodic);
GeomTools::Write(theBSplineSurface, dumpFile);
GeomTools::Dump(theBSplineSurface, dumpFile);
GeomTools::Write(theBSplineSurface, std::cout);
GeomTools::Dump(theBSplineSurface, std::cout); // Surface record 10 - Rectangular Trim Surface.
// Example: 10 -1 2 -3 4
// 1 1 2 3 0 0 1 1 0 -0 -0 1 0
Handle_Geom_Plane baseSurface = new Geom_Plane(axis);
Handle_Geom_RectangularTrimmedSurface theTrimmedSurface = new Geom_RectangularTrimmedSurface(baseSurface, -1.0, 2.0, -3.0, 4.0);
GeomTools::Write(theTrimmedSurface, dumpFile);
GeomTools::Dump(theTrimmedSurface, dumpFile);
GeomTools::Write(theTrimmedSurface, std::cout);
GeomTools::Dump(theTrimmedSurface, std::cout); // Surface record 11 - Offset Surface.
// Example: 11 -2
// 1 1 2 3 0 0 1 1 0 -0 -0 1 0
Handle_Geom_OffsetSurface theOffsetSurface = new Geom_OffsetSurface(baseSurface, -2.0);
GeomTools::Write(theOffsetSurface, dumpFile);
GeomTools::Dump(theOffsetSurface, dumpFile);
GeomTools::Write(theOffsetSurface, std::cout);
GeomTools::Dump(theOffsetSurface, std::cout); return ;
  }

上述程序将《BRep Format Description White Paper》中的几何部分(Geometry Section)的参数曲面(Surfaces)示例数据分别使用类GeomTools的静态函数输出到屏幕和文件。

当使用GeomTools::Write()时输出的内容与BRep文件中一致,当使用GeomTools::Dump()时输出更易读的信息。为了便于对比理解,将两种形式都输出到文件geometrySurface.txt中,输出数据如下所示:

         - -
Plane
Origin :, ,
Axis :, ,
XAxis :, , -
YAxis :-, , - -
CylindricalSurface
Origin :, ,
Axis :, ,
XAxis :, , -
YAxis :-, ,
Radius : - -
0.75
ConicalSurface
Origin :, ,
Axis :, ,
XAxis :, , -
YAxis :-, ,
Radius : Angle :0.75 - -
SphericalSurface
Center :, ,
Axis :, ,
XAxis :, , -
YAxis :-, ,
Radius : - -
ToroidalSurface
Origin :, ,
Axis :, ,
XAxis :, , -
YAxis :-, ,
Radii : 0.6 0.8
- -
SurfaceOfLinearExtrusion
Direction :, 0.6, 0.8
Basis curve :
Circle
Center :, ,
Axis :, ,
XAxis :, , -
YAxis :-, ,
Radius : -
- -
SurfaceOfRevolution
Origin :-, ,
Direction :, ,
Basis curve :
Circle
Center :, ,
Axis :, ,
XAxis :, , -
YAxis :-, ,
Radius : -
- BezierSurface urational vrational
Degrees :
, : , ,
, : , , - , : , , -
, : , , , : , ,
, : , , -
- 0.25
0.5
0.75 0.3
0.7 BSplineSurface urational vrational
Degrees :
NbPoles :
NbKnots :
Poles : , : , ,
, : , , - , : , , -
, : , , , : , ,
, : , , UKnots : : : 0.25 : 0.5 : 0.75 : VKnots : : : 0.3 : 0.7 : - -
- -
RectangularTrimmedSurface
Parameters : - -
BasisSurface :
Plane
Origin :, ,
Axis :, ,
XAxis :, , -
YAxis :-, , -
- -
OffsetSurface
Offset : -
BasisSurface :
Plane
Origin :, ,
Axis :, ,
XAxis :, , -
YAxis :-, ,

三、程序说明 Example Description

3.1 平面 Plane

示例:

// Surface record 1 - Plane.
// Example: 1 0 0 3 0 0 1 1 0 -0 -0 1 0
Handle_Geom_Plane thePlane = new Geom_Plane(gp_Pnt(, , ), gp_Dir(, , ));
GeomTools::Write(thePlane, dumpFile);
GeomTools::Dump(thePlane, dumpFile);

<surface record 1>定义了平面。平面数据包含三维点P和三维正交坐标系N,Du,Dv。平面通过点P,且其法向量为N。其参数方程如下所示:

示例数据表示的平面为通过点P=(0,0,3),法向量N=(0,0,1),其参数方程如下所示:

在Draw Test Harness中创建并显示平面如下所示:

3.2 圆柱面 Cylinder

示例:

// Surface record 2 - Cylinder.
// Example: 2 1 2 3 0 0 1 1 0 0 0 1 0 4
Handle_Geom_CylindricalSurface theCylinder = new Geom_CylindricalSurface(axis, 4.0);
GeomTools::Write(theCylinder, dumpFile);
GeomTools::Dump(theCylinder, dumpFile);

<surface record 2>定义了圆柱面。圆柱面的数据包含三维点P,三维正交坐标系Dv,Dx,Dy和一个非负实数r。圆柱面的轴通过点P,方向为Dv,圆柱面的半径为r,其参数方程如下所示:

示例数据表示的圆柱面为轴通过点P=(1,2,3),轴的方向Dv=(0,0,1),方向Dx=(1,0,-0),Dy=(-0,1,0),半径r=4,其参数方程如下所示:

在Draw Test Harness中创建并显示圆柱面如下所示:

3.3 圆锥面 Cone

示例:

// Surface record 3 - Cone.
// Example: 3 1 2 3 0 0 1 1 0 0 0 1 0 4
// 0.75
Handle_Geom_ConicalSurface theCone = new Geom_ConicalSurface(axis, 0.75, 4.0);
GeomTools::Write(theCone, dumpFile);
GeomTools::Dump(theCone, dumpFile);

<surface record 3>定义了圆锥面。圆锥面的数据包含三维点P,正交坐标系Dz,Dx,Dy,非负实数r和实数ψ(范围为(-π/2, π/2))。圆锥面通过点P且轴的方向为Dz。过点P且与方向Dx,Dy平行的平面为圆锥面的参考平面(referenced plane)。参考平面截圆锥面为一个圆,其半径为r。其参数方程如下所示:

示例数据表示的圆锥面的轴通过点P=(1,2,3),方向Dz=(0,0,1)。圆锥面的其他数据是Dx=(1,0,-0),Dy=(-0,1,0),半径r=4,角度ψ=0.75。其参数方程如下所示:

在Draw Test Harness中创建并显示圆锥面如下所示:

3.4 球面 Sphere

示例:

// Surface record 4 - Sphere.
// Example: 4 1 2 3 0 0 1 1 0 -0 -0 1 0 4
Handle_Geom_SphericalSurface theSphere = new Geom_SphericalSurface(axis, );
GeomTools::Write(theSphere, dumpFile);
GeomTools::Dump(theSphere, dumpFile);

<surface record 4>定义了球面。球面的数据包含三维点P,三维正交坐标系Dz,Dx,Dy和非负实数r。即球面的球心为点P,半径为r,其参数方程如下所示:

示例数据表示的球面为球心过点P=(1,2,3),方向分别为Dz=(0,0,1),Dx=(1,0,-0),Dy=(-0,1,0),半径r=4。其参数方程如下所示:

在Draw Test Harness中创建并显示球面如下所示:

3.5 圆环面 Torus

示例:

// Surface record 5 - Torus.
// Example: 5 1 2 3 0 0 1 1 0 -0 -0 1 0 8 4
Handle_Geom_ToroidalSurface theTorus = new Geom_ToroidalSurface(axis, , );
GeomTools::Write(theTorus, dumpFile);
GeomTools::Dump(theTorus, dumpFile);

<surface record 5>定义了圆环面。圆环面的数据包含三维点P,三维正交坐标系Dz,Dx,Dy和非负实数r1,r2。圆环面的轴通过点P,方向为Dz,r1是从圆环面的圆的中心到点P的距离,圆环面的圆的半径为r2。圆环面的参数方程如下所示:

示例数据表示的圆环面的轴通过点P=(1,2,3),轴的方向为Dz=(0,0,1)。其它数据为Dx=(1,0,-0),Dy=(0,1,0),r1=8,r2=4,其参数方程如下所示:

在Draw Test Harness中创建并显示圆环面如下所示:

3.6 线性拉伸面 Linear Extrusion

示例:

// Surface record 6 - Linear Extrusion.
// Example: 6 0 0.6 0.8
// 2 1 2 3 0 0 1 1 0 -0 -0 1 0 4
Handle_Geom_Circle baseCurve = new Geom_Circle(axis, 4.0);
Handle_Geom_SurfaceOfLinearExtrusion theExtrusion = new Geom_SurfaceOfLinearExtrusion(baseCurve, gp_Dir(, 0.6, 0.8));
GeomTools::Write(theExtrusion, dumpFile);
GeomTools::Dump(theExtrusion, dumpFile);

<surface record 6>定义了线性拉伸面。线性拉伸面的数据包含三维方向Dv和三维曲线<3D curve record>。其参数方程如下所示:

示例数据表示的线性拉伸面的拉伸方向Dv=(0,0.6,0.8),拉伸曲线为圆。拉伸面的参数方程如下所示:

在Draw Test Harness中创建并显示线性拉伸面如下所示:

3.7 旋转面 Revolution Surface

示例:

// Surface record 7 - Revolution Surface.
// Example: 7 -4 0 3 0 1 0
// 2 1 2 3 0 0 1 1 0 -0 -0 1 0 4
Handle_Geom_SurfaceOfRevolution theRevolution = new Geom_SurfaceOfRevolution(baseCurve, gp::OY());
theRevolution->SetLocation(gp_Pnt(-, , ));
GeomTools::Write(theRevolution, dumpFile);
GeomTools::Dump(theRevolution, dumpFile);

<surface record 7>定义了旋转面。旋转面的数据包含三维点P,三维方向D和三维曲线。旋转曲面的轴通过点P且方向为D,旋转曲线为C与旋转轴共面。旋转曲面的参数方程如下所示:

示例数据表示的旋转曲面的旋转轴通过点P=(-4,0,3),方向D=(0,1,0),旋转曲线是一个圆。其参数方程如下所示:

在Draw Test Harness中创建并显示旋转面如下所示:

3.8 Bezier曲面 Bezier Surface

示例:

// Surface record 8 - Bezier Surface.
// Example: 8 1 1 2 1 0 0 1 7 1 0 -4 10
// 0 1 -2 8 1 1 5 11
// 0 2 3 9 1 2 6 12
TColgp_Array2OfPnt poles(, , , );
TColStd_Array2OfReal weights(, , , ); poles.SetValue(, , gp_Pnt(, , )); weights.SetValue(, , 7.0);
poles.SetValue(, , gp_Pnt(, , -)); weights.SetValue(, , 10.0); poles.SetValue(, , gp_Pnt(, , -)); weights.SetValue(, , 8.0);
poles.SetValue(, , gp_Pnt(, , )); weights.SetValue(, , 11.0); poles.SetValue(, , gp_Pnt(, , )); weights.SetValue(, , 9.0);
poles.SetValue(, , gp_Pnt(, , )); weights.SetValue(, , 12.0); Handle_Geom_BezierSurface theBezierSurface = new Geom_BezierSurface(poles, weights);
GeomTools::Write(theBezierSurface, dumpFile);
GeomTools::Dump(theBezierSurface, dumpFile);

<surface record 8>定义了Bezier曲面。曲面的数据包含u有理标志位ru,v有理标志位rv,曲面次数mu, mv,和weight poles。u,v的次数都不能大于25。

当ru+rv=0时,weight poles是(mu+1)(mv+1)个三维点Bi,j((i,j)∈{0,...,mu}x{0,...,mv}),hi,j=1((i,j)∈{0,...,mu}x{0,...,mv});

当ru+rv≠0时,weight poles是(mu+1)(mv+1)个带权控制点对Bi,j,hi,j。Bi,j是三维点,hi,j是权因子,正实数。

Bezier曲面的参数方程如下所示:

示例数据表示的Bezier曲面为:u有理标志位ru=1,v有理标志位rv=1,次数mu=2,mv=1,weight poles为:B0,0=(0,0,1),h0,0=7,B0,1=(1,0,-4),h0,1=10,B1,0=(0,1,-2),h1,0=8,B1,1=(1,1,5),h1,1=11,B2,0=(0,2,3),h2,0=9,B2,1=(1,2,6),h2,1=12。曲面的参数方程为:

在Draw Test Harness中创建并显示Bezier曲面如下所示:

3.9 B样条曲面 B-spline Surface

示例:

// Surface record 9 - B-spline Surface.
// Example: 9 1 1 0 0 1 1 3 2 5 4 0 0 1 7 1 0 -4 10
// 0 1 -2 8 1 1 5 11
// 0 2 3 9 1 2 6 12
//
// 0 1
// 0.25 1
// 0.5 1
// 0.75 1
// 1 1
//
// 0 1
// 0.3 1
// 0.7 1
// 1 1
Standard_Integer uDegree = ;
Standard_Integer vDegree = ;
Standard_Boolean uPeriodic = Standard_False;
Standard_Boolean vPeriodic = Standard_False; TColStd_Array1OfReal uKnots(, );
TColStd_Array1OfReal vKnots(, );
TColStd_Array1OfInteger uMults(, );
TColStd_Array1OfInteger vMults(, ); uKnots.SetValue(, );
uKnots.SetValue(, 0.25);
uKnots.SetValue(, 0.5);
uKnots.SetValue(, 0.75);
uKnots.SetValue(, 1.0); vKnots.SetValue(, );
vKnots.SetValue(, 0.3);
vKnots.SetValue(, 0.7);
vKnots.SetValue(, 1.0); // Multiplicity of u and v are 1.
uMults.Init();
vMults.Init(); Handle_Geom_BSplineSurface theBSplineSurface = new Geom_BSplineSurface(poles, weights, uKnots, vKnots, uMults, vMults, uDegree, vDegree, uPeriodic, vPeriodic);
GeomTools::Write(theBSplineSurface, dumpFile);
GeomTools::Dump(theBSplineSurface, dumpFile);

<surface record 9>定义了B-Spline曲面。B样条曲面数据包含u有理标志位ru,v有理标志位rv,u次数mu<=25;v次数mv<=25,u控制点数nu>=2,v控制点数nv>=2,u重节点数ku,v重节点数kn,weight poles,u重节点,v重节点。

当ru+rv=0时,weight poles是(mu+1)(mv+1)个三维点Bi,j((i,j)∈{0,...,mu}x{0,...,mv}),hi,j=1((i,j)∈{0,...,mu}x{0,...,mv});

当ru+rv≠0时,weight poles是(mu+1)(mv+1)个带权控制点对Bi,j,hi,j。Bi,j是三维点,hi,j是权因子,正实数。

u重节点及其重数有ku对:u1,q1,...,uku,qku。这里ui是重数为qi>=1的节点:

v重节点及其重数有kv对:u1,q1,...,ukv,qkv。这里vi是重数为qi>=1的节点:

B-Spline曲面的参数方程如下所示:

基函数Ni,j和Mi,j有如下的递归定义:

示例数据表示的B-Spline曲面为:u有理标志位ru=1,v有理标志位rv=1,u次数mu=1,v次数mv=1,u控制点数nu=3,v控制点数nv=2,u有重复度的节点数ku=5,v有重复度节点数kv=4,带权控制点B1,1=(0,0,1),h1,1=7,B1,2=(1,0,-4),h1,2=10,B2,1=(0,1,-2),h2,1=8,B2,2=(1,1,5),h2,2=11,B3,1=(0,2,3),h3,1=9,B3,2=(1,2,6),h3,2=12,u有重复度节点u1=0,q1=1,u2=0.25,q2=1,u3=0.5,q3=1,u4=0.75,q4=1,u5=1,q5=1,v有重度度节点v1=0,r1=1,v2=0.3,r2=1,v3=0.7,r3=1,v4=1,r4=1。B-Spline曲面的参数方程如下所示:

在Draw Test Harness中创建并显示B样条曲面如下所示:

3.10 矩形裁剪曲面 Rectangular Trim Surface

示例:

// Surface record 10 - Rectangular Trim Surface.
// Example: 10 -1 2 -3 4
// 1 1 2 3 0 0 1 1 0 -0 -0 1 0
Handle_Geom_Plane baseSurface = new Geom_Plane(axis);
Handle_Geom_RectangularTrimmedSurface theTrimmedSurface = new Geom_RectangularTrimmedSurface(baseSurface, -1.0, 2.0, -3.0, 4.0);
GeomTools::Write(theTrimmedSurface, dumpFile);
GeomTools::Dump(theTrimmedSurface, dumpFile);

<surface record 10>定义了矩形裁剪曲面。矩形裁剪曲面的数据包含实数umin,umax,vmin,vmax和一个曲面。矩形裁剪曲面是将曲面限制在矩形区域[umin,umax]x[vmin,vmax]内得到的曲面。曲面的参数方程如下所示:

示例数据表示的矩形裁剪曲面的矩形裁剪区域为[-1,2]x[-3,4],被裁剪曲面B(u,v)=(1,2,3)+u(1,0,0)+v(0,1,0)。其参数方程如下所示:

在Draw Test Harness中创建并显示矩形裁剪曲面如下所示:

3.11 偏移曲面 Offset Surface

示例:

// Surface record 11 - Offset Surface.
// Example: 11 -2
// 1 1 2 3 0 0 1 1 0 -0 -0 1 0
Handle_Geom_OffsetSurface theOffsetSurface = new Geom_OffsetSurface(baseSurface, -2.0);
GeomTools::Write(theOffsetSurface, dumpFile);
GeomTools::Dump(theOffsetSurface, dumpFile);

<surface record 11>定义了偏移曲面。偏移曲面的数据包含偏移距离d和曲面。偏移曲面的就将基准曲面B没曲面的法向N上偏移距离d得到的曲面。偏移曲面的参数方程如下所示:

示例数据表示的偏移曲面的偏移距离d=-2,基准曲面B(u,v)=(1,2,3)+u(1,0,0)+v(0,1,0)。其参数方程如下所示:

在Draw Test Harness中创建并显示偏移曲面如下所示:

注:当偏移-2时,效果不明显示,所以偏移了-20,这样看上去比较明显。

四、程序分析 Refactoring the Code

Figure 4.1 Class diagram of Geom_Surface

根据几何曲面的类图可知,几何曲面有个共同的基类Geom_Surface。而在对几何数据进行输出与读入时,用了很多条件判断。输出部分程序代码如下所示:

//=======================================================================
//function : PrintSurface
//purpose :
//=======================================================================
void GeomTools_SurfaceSet::PrintSurface(const Handle(Geom_Surface)& S,
Standard_OStream& OS,
const Standard_Boolean compact)
{
Handle(Standard_Type) TheType = S->DynamicType(); if ( TheType == STANDARD_TYPE(Geom_Plane)) {
Print(Handle(Geom_Plane)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_CylindricalSurface)) {
Print(Handle(Geom_CylindricalSurface)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_ConicalSurface)) {
Print(Handle(Geom_ConicalSurface)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_SphericalSurface)) {
Print(Handle(Geom_SphericalSurface)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_ToroidalSurface)) {
Print(Handle(Geom_ToroidalSurface)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion)) {
Print(Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_SurfaceOfRevolution)) {
Print(Handle(Geom_SurfaceOfRevolution)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_BezierSurface)) {
Print(Handle(Geom_BezierSurface)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_BSplineSurface)) {
Print(Handle(Geom_BSplineSurface)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
Print(Handle(Geom_RectangularTrimmedSurface)::DownCast(S),OS,compact);
}
else if ( TheType == STANDARD_TYPE(Geom_OffsetSurface)) {
Print(Handle(Geom_OffsetSurface)::DownCast(S),OS,compact);
}
else {
GeomTools::GetUndefinedTypeHandler()->PrintSurface(S,OS,compact);
//if (!compact)
// OS << "***** Unknown Surface ********\n";
//else
// cout << "***** Unknown Surface ********"<<endl;
}
}

读入部分的程序代码如下所示:

//=======================================================================
//function : ReadSurface
//purpose :
//=======================================================================
Standard_IStream& GeomTools_SurfaceSet::ReadSurface(Standard_IStream& IS,
Handle(Geom_Surface)& S)
{
Standard_Integer stype; try {
OCC_CATCH_SIGNALS
IS >> stype;
switch (stype) { case PLANE :
{
Handle(Geom_Plane) SS;
IS >> SS;
S = SS;
}
break; case CYLINDER :
{
Handle(Geom_CylindricalSurface) SS;
IS >> SS;
S = SS;
}
break; case CONE :
{
Handle(Geom_ConicalSurface) SS;
IS >> SS;
S = SS;
}
break; case SPHERE :
{
Handle(Geom_SphericalSurface) SS;
IS >> SS;
S = SS;
}
break; case TORUS :
{
Handle(Geom_ToroidalSurface) SS;
IS >> SS;
S = SS;
}
break; case LINEAREXTRUSION :
{
Handle(Geom_SurfaceOfLinearExtrusion) SS;
IS >> SS;
S = SS;
}
break; case REVOLUTION :
{
Handle(Geom_SurfaceOfRevolution) SS;
IS >> SS;
S = SS;
}
break; case BEZIER :
{
Handle(Geom_BezierSurface) SS;
IS >> SS;
S = SS;
}
break; case BSPLINE :
{
Handle(Geom_BSplineSurface) SS;
IS >> SS;
S = SS;
}
break; case RECTANGULAR :
{
Handle(Geom_RectangularTrimmedSurface) SS;
IS >> SS;
S = SS;
}
break; case OFFSET :
{
Handle(Geom_OffsetSurface) SS;
IS >> SS;
S = SS;
}
break; default :
{
Handle(Geom_Surface) SS;
GeomTools::GetUndefinedTypeHandler()->ReadSurface(stype,IS,SS);
S = SS;
}
break;
}
}
catch(Standard_Failure) {
#ifdef DEB
Handle(Standard_Failure) anExc = Standard_Failure::Caught();
cout <<"EXCEPTION in GeomTools_SurfaceSet::ReadSurface(..)!!!" << endl;
cout << anExc << endl;
#endif
S = NULL;
}
return IS;
}

正如《Refactoring-Improving the Design of Existing Code》书中以多态取代条件表达式(Replace Conditional with Polymorphism)所说,在面向对象术语中,听上去最高贵的词非“多态”莫属。多态最根本的好处就是如果你需要根据对象的不同类型而采取不同的行为,多态使你不必编写明显的条件表达式。正因为有了多态,所以你会发现“类型码的switch语句”以及“基于类型名称的if-then-else语句”在面向对象程序中很少出现。

多态能够带给你很多好处。如果同一组条件表达式在程序许多地方出现,那么使用多态的收益是最大的。使用条件表达式时,如果你想添加一种新类型,就必须查找并更新所有条件表达式。但如果改用多态,只需要一个新的子类,并在其中提供适当的函数就行了。类的用户不需要了解这个子类,这就大降低了系统各部分之间的依赖,使系统升级更容易。

OpenCascade的几何曲面已经有一个基类Geom_Surface了,可将输出做为虚函数,就不需要做判断了。在读入(创建)时引入工厂模式,对于UndefinedTypeHandler()可以引入Null对象。经过这样重构之后的程序可读性应该会更好吧!

五、结论 Conclusion

在边界表示BRep的形状中,参数表示的几何曲面并不会孤立存在,他总是依附于拓朴面中。在OpenCascade的BRep格式的文件中三维几何曲面共有十一种,通过将这十一种几何曲面输出,理解参数表示的几何曲面的数据结构。

通过查看其读写几何曲面的源程序,提出重构的方法。当在面向对象的程序中出现很条件表达式时,那么程序就有“坏味道”了,需要进行重构改进。

六、参考资料 References

1. OpenCascade. BRep Format Description White Paper

2. Martin Fowler. Refactoring:Improving the Design of Existing Code. Addison-Wesley

3. Les Piegl, Wayne Tiller. The NURBS Book. Springer-Verlag

Geometry Surface of OpenCascade BRep的更多相关文章

  1. Geometry Curve of OpenCascade BRep

    Geometry Curve of OpenCascade BRep eryar@163.com 摘要Abstract:几何曲线是参数表示的曲线 ,在边界表示中其数据存在于BRep_TEdge中,BR ...

  2. Representation Data in OpenCascade BRep

    Representation Data in OpenCascade BRep eryar@163.com 摘要Abstract:现在的显示器大多数是光栅显示器,即可以看做一个像素的矩阵.在光栅显示器 ...

  3. OpenCASCADE BRep vs. OpenNURBS BRep

    OpenCASCADE BRep vs. OpenNURBS BRep eryar@163.com Abstract. BRep short for Boundary Representation. ...

  4. Topology Shapes of OpenCascade BRep

    Topology Shapes of OpenCascade BRep eryar@163.com 摘要Abstract:通过对OpenCascade中的BRep数据的读写,理解边界表示法的概念及实现 ...

  5. OpenCASCADE BRep Projection

    OpenCASCADE BRep Projection eryar@163.com 一网友发邮件问我下图所示的效果如何在OpenCASCADE中实现,我的想法是先构造出螺旋线,再将螺旋线投影到面上. ...

  6. OpenCascade BRep Format Description

    OpenCascade BRep Format Description eryar@163.com 摘要Abstract:本文结合OpenCascade的BRep格式描述文档和源程序,对BRep格式进 ...

  7. Locations Section of OpenCascade BRep

    Locations Section of OpenCascade BRep eryar@163.com 摘要Abstract:本文结合OpenCascade的BRep格式描述文档和源程序,对BRep格 ...

  8. OpenCascade BRep Format Description (2)

    OpenCascade BRep Format Description eryar@163.com 摘要Abstract:本文结合OpenCascade的BRep格式描述文档和源程序,对BRep格式进 ...

  9. OpenCASCADE Linear Extrusion Surface

    OpenCASCADE Linear Extrusion Surface eryar@163.com Abstract. OpenCASCADE linear extrusion surface is ...

随机推荐

  1. Number of 1 Bits

    class Solution { public: int hammingWeight(uint32_t n) { string aaa = toBinary(n); ; ; i < sizeof ...

  2. C++多态(一)

    面试题目中关于多态的问题不少,例如重载.虚函数(覆盖).多态的概念等等,这里做一个梳理,包含如下内容: 一.多态的定义 (一)定义 能够呈现不同形态的特性或状态. (二)两种多态性 1.编译时的多态性 ...

  3. Top ShooterHDU2863&&继续xxx定律HDU3784

    继续xxx定律 HDU3784 先看这个题目:HDU3782 #include<iostream> #include<algorithm> #include<stdio. ...

  4. python-getattr

    getattr(object, name[, default]) Return the value of the named attribute of object.  name must be a ...

  5. 配置IP地址

    1.linux如果在一个路由器环境中,则可以使用dhclient命令获取IP地址. dhclient 2.手动配置 打开配置文件 vi /etc/sysconfig/network-scripts/i ...

  6. 安装RPM包或者安装源码包

    本系列的博客来自于:http://www.92csz.com/study/linux/ 在此,感谢原作者提供的入门知识 这个系列的博客的目的在于将比较常用的liunx命令从作者的文章中摘录下来,供自己 ...

  7. NativeScript 也能开发桌面应用 (nativescript-dotnet-runtime)

    自从看了NativeScript就甚是喜欢,心想要是也能开发桌面应用该多好.求人不如求己,开源组件很强大,差不多组装一下就行了,说干就干. Javascript 引擎用 Jint , 纯C#实现,集成 ...

  8. Linux计划任务crontab运行脚本不正确的问题

    问题的由来 写好的程序希望在崩溃之后能够自启动,于是利用linux的crontab功能,添加一个计划任务,每分钟执行一个脚本查看需要监控的进程是否还在,如果不在则启动之,否则不做任何事情.这么一个简单 ...

  9. 更高效地提高redis client多线程操作的并发吞吐设计

    Redis是一个非常高效的基于内存的NOSQL数据库,它提供非常高效的数据读写效能.在实际应用中往往是带宽和CLIENT库读写损耗过高导致无法更好地发挥出Redis更出色的能力.下面结合一些redis ...

  10. Linux下添加新硬盘,分区及挂载(转)

    挂载好新硬盘后输入fdisk -l命令看当前磁盘信息,卸载硬盘分区 umount /dev/sdb 可以看到除了当前的第一块硬盘外还有一块sdb的第二块硬盘,然后用fdisk /dev/sdb 进行分 ...