1 标准对象的集合容器
在处理现实问题时,经常将问题抽象成一个数学模型,接着对模型求解, 然后将解提取出来以解决现实问题。 其实在 CAD 软件中, 主要解决的就是数学模型。因此,本节将描述 OCC 的数学基本类型和数学算法。它们包括向量和矩阵类、基本几何类型和常用数学算法。
1.1 向量和矩阵类
向量和矩阵组件为向量和矩阵提供了 C++实现。 这个组件通常用来定义更复杂的数据结构。向量和矩阵类支持由实数组成的向量和矩阵的标准操作,如加、乘、转置、求逆等。向量和矩阵的范围是任意的, 但必须在声明的时候就定义好, 并且定义后不能更改,如例 3.18 所示。
例 3.18:
math_Vector v(1, 3);
//一个三维向量,索引区间为(1,3)。
math_Matrix m(0, 2, 0, 2);
//一个 3x3 的矩阵,行区间和列区间都为(0,2)。
math_Vector v(N1, N2);
//一个(N2-N1+1)维的向量,索引区间为(N1,N2)。
向量和矩阵对象遵循语意值,即它们不能被共享,也不能通过赋值来拷贝,如例 3.19 所示。
例 3.19:
math_Vector v1(1, 3), v2(0, 2);
v2 = v1;
// 将 v1 的值拷贝给 v2;对 v1 的改变不会影响 v2。
可以使用索引(必须在定义的范围内) 来初始化或包含向量和矩阵值, 如例3.20 所示。
例 3.20:
math_Vector v(1, 3);
math_Matrix m(1, 3, 1, 3);
Standard_Real value;
v(2) = 1.0;
value = v(1);
m(1, 3) = 1.0;
value = m(2, 2);
在向量和矩阵对象上的有些操作可能是不合法的。 这种情况下, 系统会产生异常,如例 3.21 所示。可能用到的两种标准异常有:
(1) Standard_DimensionError 异常。当两个矩阵或者向量的维数不同时,系统产生 Standard_DimensionError 异常。
(2) Standard_RangeError 异常。如果向量或矩阵的索引在定义的范围外,系统将产生 Standard_RangeError 异常。
例 3.21:
math_Vector v1(1, 3), v2(1, 2), v3(0, 2);
v1 = v2;
//错误,将产生 Standard_DimensionError 异常。
v1 = v3;
//可以,尽管索引区间不相等,但维数是一样的。
v1(0) = 2.0;
//错误,将产生 Standard_RangeError 异常。
1.2 基本几何类型
在创建一个几何对象前,必须知道这个对象是 2D 的还是 3D 的,以及将如何使用这个对象。
gp 包为二维和三维对象提供了一些通过值处理的类。它定义了一些基本的非持久几何实体;这些实体在二维和三维的代数计算和基本几何结构分析中用到。 它也提供一些基本的几何转换, 如等价、 旋转、 平移、 镜像、 缩放、 复合变换等。
注意: gp 包中的实体是通过值处理的。gp 包中可实现的几何实体有:二维和三维直角坐标(x, y, z)、矩阵、笛卡尔点、 向量、 方向、 轴、 直线、 圆、 椭圆、 双曲线、 抛物线、 平面、 无穷圆柱曲面、球面、螺旋面和圆锥面。
在创建一个几何对象前, 必须知道它是二维的还是三维的, 以及将如何使用它。 如果需要的不是某种基本几何类型的单个实例, 而是某种几何类型的一系列实例,那么 TColgp 包能够处理这样的集合容器,并且提供一些必要的功能。特别地, 这个包为通用类中那些标准的和经常使用的实例化提供几何对象。 TColgp包为 TCollection 类的实例化提供类(来自 gp 包, 如 XY、 XYZ、 Pnt、 Pnt2d、Vec、 Vec2d、 Lin、 Lin2d、 Circ、 Circ2d 等; 这些类是非持久的)。
1.3 常用数学算法
常用数学算法组件为一些经常使用的数学算法提供 C++实现。它们包括:
(1)求解线性方程组的算法;
(2) 寻找一元或多元函数最小值的算法;
(3)求解非线性方程或非线性方程组的算法;
(4)寻找矩阵特征值和特征向量的算法。
所有的数学算法都是采用相同的规则来实现的。这些规则包括:
(1)构造函数。在给定合适的参数后,构造函数完成算法需要实现的所有
或者大部分算法。 所有相关信息存储在构造的对象中。 因此后发计算或后发问题将以最有效的方式解决。
(2) IsDone 函数。如果计算成功, IsDone 函数将返回布尔真值。
(3)对每一种算法的都提供了一套函数;每套函数能够包含多个结果。只有 IsDone 函数返回真值时, 才可以调用函数。 否则将产生 StdFail_NotDone 异常。
例 3.22 说明了 Gauss 类(用来实现线性方程组的高斯解法)的用法。例中的声明是从 math_Gauss 类的头文件中提取出来的。
例 3.22:
class Gauss
{
public:
Gauss (const math_Matrix& A);
Standard_Boolean IsDone() const;
void Solve (const math_Vector& B,
math_Vector& X) const;
};
假设要用高斯类解方程 ax1=b1 和 ax2=b2, 那么程序实现如例 3.23 所示。
例 3.23:
#include <math_Vector.hxx>
#include <math_Matrix.hxx>
main ()
{
math_ Matrix a(1, 3, 1, 3);
math_Vector b1(1, 3), b2(1, 3);
math_Vector x1(1, 3), x2(1, 3);
// a, b1 和 b2 设有相应的值。
math_Gauss sol(a);
//计算系数矩阵 A 的 LU 分解。
if(sol.IsDone())
{ //是否分解成功?
sol.Solve(b1, x1);
//分解成功,则计算第一组解 x1。
sol.Solve(b2, x2);
//接着计算第二组解 x2。
...
}
else
{ //分解不成功。
//分析错误原因。
sol.Solve(b1, x1);
//错误,产生 StdFail_NotDone 异常。}
}
}
例 3.24 说明了 BissecNewton 类(实现了 Newton 和 Bissection 算法的结合,用来解一个具有指定边界的函数)的用法。
例 3.24:
class BissecNewton
{
public:
BissecNewton (math_FunctionWithDerivative& f,
const Standard_Real bound1,
const Standard_Real bound2,
const Standard_Real tolx);
Standard_Boolean IsDone() const;
Standard_Real Root();
};
抽象类 math_FunctionWithDerivative 描述了这样一些服务,这些服务在BissecNewton 算法用到的 f 函数中必须被实现。例 3.25 中的声明来自抽象类math_FunctionWithDerivative 的头文件。
例 3.25:
class math_FunctionWithDerivative
{
public:
virtual Standard_Boolean Value (const Standard_Real x, Standard_Real& f) = 0;
virtual Standard_Boolean Derivative (const Standard_Real x,
Standard_Real& d) = 0;
virtual Standard_Boolean Values (const Standard_Real x,
Standard_Real& f,
Standard_Real& d) = 0;
};
下面的测试例子(例 3.26)用 BissecNewton 类来解方程 f(x)=x**2-4,其中x 在区间[1.5, 2.5]取值。这个待解函数在 myFunction 类中实现,而 myFunc- tion类是 math_FunctionWithDerivative 的派生类。 Main 函数将找到所需的根。
例 3.26:
#include <math_BissecNewton.hxx>
#include <math_FunctionWithDerivative.hxx>
class myFunction : public math_FunctionWithDerivative
{
Standard_Real coefa, coefb, coefc;
public:myFunction (const Standard_Real a, const Standard_Real b,
const Standard_Real c) : coefa(a), coefb(b), coefc(c)
{}
virtual Standard_Boolean Value (const Standard_Real x,
Standard_Real& f)
{
f = coefa * x * x + coefb * x + coefc;
}
virtual Standard_Boolean Derivative (const Standard_Real x,
Standard_Real& d)
{
d = coefa * x * 2.0 + coefb;
}
virtual Standard_Boolean Values (const Standard_Real x,
Standard_Real& f, Standard_Real& d)
{
f = coefa * x * x + coefb * x + coefc;
d = coefa * x * 2.0 + coefb;
}
};
main()
{
myFunction f(1.0, 0.0, 4.0);
math_BissecNewton sol(F, 1.5, 2.5, 0.000001);
if(Sol.IsDone())
{ //条件是否为真?
Standard_Real x = sol.Root();
//条件为真则执行该语句。
}
else
{ //条件是假的。
//这里需要一些代码,用来尝试别的方法或者产生异常。
}
. . .
}