Skip to content

数学基础

1. 点、向量与方向

在笛卡尔坐标系中,三维的点、向量和方向都可以用三元数表示,如(x,y,z)。在显示引擎中,一般用Vector3表示点、向量和方向。但在几何造型引擎中,点、向量和方向代表不同的含义,故使用不同的类来表示。

三维空间定义:

含义备注内置常量
GPnt三维空间位置原点: GP.Origin()
GVec向量具有大小和方向的三维量-
GDir方向只代表三维方向,长度为1的向量X方向:GP.DX(); Y方向: GP.DY(); Z方向: GP.DZ()
GXYZ三维的XYZ三元数-

在二维空间中的定义:

含义备注内置常量
GPnt2d二维空间位置原点: GP.Origin2d()
GVec2d向量具有大小和方向的量-
GDir2d方向只代表方向,长度为1的向量X方向:GP.DX2d(); Y方向: GP.DY2d();
csharp
[TestMethod]
public void 构造基本的点向量和方向()
{
    // 1. 点
    // 构造两个点
    var pt1 = new GPnt(10, 10, 0);
    var pt2 = new GPnt(10, 10, 10);

    // 2 向量
    // 两个点构造向量:从pt1指向pt2,即 pt2 - pt1
    var vec1 = new GVec(pt1, pt2);

    Assert.IsTrue(vec1.IsEqual(new GVec(0,0,10), 0, 0));

    // GPnt、GVec、GDir都可以通过其XYZ()方法得到GXYZ值
    // 通过GXYZ值构造向量
    var vec2 = new GVec(pt1.XYZ());

    Assert.IsTrue(vec2.XYZ().IsEqual(pt1.XYZ(), 0));

    // 叉乘
    GVec cross = vec1.Crossed(vec2);
    // 点乘
    double dot = vec1.Dot(vec2);
    // 向量夹角
    double angle = vec1.Angle(vec2);
    // 模,长度
    double mod = vec1.Magnitude();

    // 3 方向
    // 通过向量构造方向
    var dir1 = new GDir(vec1);
    // 方向变成单位向量
    Assert.IsTrue(dir1.IsEqual(new GDir(0, 0, 1), 0));

}

显示引擎中点、向量、方向的定义:

含义内置常量
Vector2二维float2-
Vector3三维float3Vector3.Zero, Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z
Vector3d三维double3Vector3d.Zero, Vector3d.UNIT_X, Vector3d.UNIT_Y, Vector3d.UNIT_Z

注:与GPnt/GVec/GDir相比,Vector3d更加灵活,支持直接的加减操作。

  • Vector3d的使用
csharp
var v1 = new Vector3d(10, 10, 0);
var v2 = new Vector3d(10, 10, 10);

// 相减
var v3 = v2 - v1;
// 相加
var v4 = v2 + v1;
// 叉乘
var v5 = v1.cross(v2);
// 点乘
var dot = v1.dot(v3);
// 夹角,弧度
var angle = v1.angleTo(v4);

// 单位化
var d1 = v1.normalized();
  • Vector3d支持GPnt/GVec/GDir互相转换:
csharp
var v1 = new Vector3d(10, 10, 0);

// Vector3d转换成GPnt/GVec/GDir
var pt = new GPnt(v1);
var v2 = new GVec(v1);
var v3 = v1.normalized();
var d1 = new GDir(v3);
var xyz = new GXYZ(v1);

// GPnt/GVec/GDir转换成Vector3d
var w1 = new Vector3d(pt);
var w2 = new Vector3d(v2);
var w3 = new Vector3d(d1);
var w4 = new Vector3d(xyz);

2. 坐标轴/坐标系

含义备注内置常量
GAx1三维空间的一个轴由一个点和方向确定的坐标轴GP.OX(); GP.OY(); GP.OZ()
GAx2三维右手坐标系只能是右手坐标系GP.XOY(); GP.YOZ(); GP.ZOX()
GAx3三维坐标系可以是右手也可以是左手坐标系-
GAx2d二维坐标系二维空间中的点和方向确定的坐标系GP.OX2d(); GP.OY2d(); GP.OZ2d()
csharp
//构造一个在指定位置和方向的轴
var ax1 = new GAx1(new GPnt(10,10,0), new GDir(1,0,0));

// 构造右手坐标系,指定Z和X方向
var ax2 = new GAx2(new GPnt(10, 10, 0), new GDir(0, 0, 1), new GDir(1, 0, 0));

// 使用右手坐标系来构造GAx3坐标系
var ax3 = new GAx3(ax2);

// 绕着ax1转45度
ax3.Rotate(ax1, System.Math.PI / 4);
// 沿着X方向移动10个单位
ax3.Translate(new GVec(10, 0, 0));

// 转换成变换
var trsf = GTrsf.From(ax3);

3. 矩阵变换

图形学中常用的矩阵变换有平移矩阵(Translation)、旋转矩阵(Rotation)、缩放矩阵(Scale)、镜像矩阵(Mirror)等。组合使用基本的矩阵变换可以用来实现装配零件、模拟物体运动等功能。

AnyCAD中有两种表示矩阵变换的方法GTrsf和Matrix4d,其中GTrsf主要用于几何变换,Matrix4主要用于显示对象变换。GTrsf和Matrix4可以互相转换。

3.2 GTrsf

  • GTrsf 用来表示平移、等比缩放、旋转、镜像等矩阵变换
变换GTrsf构造方法
平移SetTranslation
仅设置平移部分SetTranslationPart
旋转SetRotation
仅设置旋转部分SetRotationPart
缩放SetScale
镜像SetMirror
矩阵相乘Multiply

四元数可以与欧拉角进行互相转换。欧拉角比GQuaternion更具可读性,在界面上展示更加直观。

若对四元数和欧拉角不熟悉,可暂忽略,不影响简单的应用场景。

  • 示例:
csharp
var trsf = new GTrsf();
// 构造一个平移变换,x轴平移10个单位
trsf.SetTranslation(new GVec(10,0,0));

var rot = new GTrsf();
// 绕着Z轴旋转90度
trsf.SetRotation(new GAx1(new GPnt(0, 0, 0), new GDir(0, 0, 1)), 90.0 / 180.0 * System.Math.PI);

// 变换累加
// trsf * rot
var m = trsf.Multiplied(rot);

// 使用四元数表示的旋转变换
GQuaternion rotation = trsf.GetRotation();

// 从四元数中提取欧拉角
double u = 0, v = 0, w = 0;
rotation.GetEulerAngles(GEulerSequence.gp_Extrinsic_XYX, ref u, ref v, ref w);

3.3 Matrix4

Matrix4 可以表示任意矩阵变换

Matrix4提供了静态方法用于构造基本的变换矩阵:

变换Matrix4方法
平移Matrix4 makeTranslation(Vector3 v)
缩放Matrix4 makeScale(float x, float y, float z)
旋转Matrix4 makeRotationAxis(Vector3 axis, float angle)

Matrix4d 是Matrix4的双精度版本

csharp
// 构造平移矩阵,沿着x轴移动10个单位
var trans = Matrix4.makeTranslation(10,0,0);

// 构造旋转矩阵,从一个方向变换到另外个方向的旋转矩阵
var rot = Matrix4.makeRotation(new Vector3(1,0,0), new Vector3(1,1,1).normalized());

// 绕着Z轴转45度
var rot2 = Matrix4.makeRotationAxis(new Vector3(0, 0, 1), 45.0f / 180.0f * System.MathF.PI);

// 先旋转,在平移
var mat = trans * rot2;

3.4 矩阵相乘

矩阵相乘不符合交换律,即M1和M2以下的相乘结果不一定相等:

M2 = M1 * M2
M3 = M2 * M1

在对物体进行组合变换的时候需要考虑变换的顺序,

M1 = T * S * R   // 先旋转、再缩放、最后平移
M2 = R * S * T   // 先平移、再缩放、最后旋转

3.5 矩阵变换的应用

  • 点、向量、方向空间变换

GPnt/GVec/GDir可以直接与GTrsf相乘,以实现空间变换

csharp
var trsf = new GTrsf();
// 构造一个平移变换,x轴平移10个单位
trsf.SetTranslation(new GVec(10, 0, 0));

var pt = new GPnt();

// 点沿着X轴平移了10个单位
pt.Transform(trsf);
Assert.IsTrue(pt.IsEqual(new GPnt(10, 0, 0), 0));

var vec = new GVec(0, 0, 1);
// 向量沿着X轴平移了10个单位,大小不变
vec.Transform(trsf);
Assert.IsTrue(vec.IsEqual(new GVec(0, 0, 1), 0, 0));


var dir = new GDir(0, 0, 1);
// 方向沿着X轴平移N个单位,没有变化
dir.Transform(trsf);
Assert.IsTrue(dir.IsEqual(new GDir(0, 0, 1), 0));
  • 使用TransformTool对TopoShape进行矩阵变换:
变换TransformTool方法
平移TopoShape Translate(TopoShape pShape, GVec vec)
旋转TopoShape Rotation(TopoShape pShape, GAx1 axis, double angle)
缩放TopoShape Scale(TopoShape pShape, GPnt center, double scale)
镜像TopoShape Mirror(TopoShape shape, GAx1 axis)
组合变换TopoShape Transform(TopoShape pShape, GTrsf trf)
csharp
var trsf = new GTrsf();
trsf.SetTranslation(new GVec(10,0,0));
var shape = ShapeBuilder.MakeBox(new GAx2(), 10, 10, 10);

// x轴平移10个单位
var newShape = TransformTool.Transform(shape, trsf);
  • 显示对象矩阵变换

例,对SceneNode平移后再旋转:

csharp
    var matrixR = Matrix4.makeRotationAxis(new Vector3(0, 0, 1), Math.PI);
    var matrixT = Matrix4.makeTranslation(-50, 0, 0);
    ConeNode1.SetTransform(matrixR * matrixT);

    renderView.RequstUpdate();

几何变换是对TopoShape变换,显示变换时对场景节点SceneNode变换。对SceneNode变换不会影响TopoShape。

相比几何变换,显示变换更加轻量,即速度更快(快的不是一点点)。

4. 小结

矩阵变换是图形学里面基本的概念,对于几何对象和显示对象有着不同的应用场景。

在动画模拟的过程中,一般对显示对象进行变换即可;在需要进行几何对象操作的,比如布尔运算的情况下,则需要对几何对象进行矩阵变换。

矩阵变换是建模和显示最基本的技能,一定需要掌握

5. 思考问题

  • 如何实现绕着某个点旋转?
  • 如何使用矩阵变换实现自传和公转?
  • 几何对象和显示对象进行矩阵变换的应用场景分别是什么?
  • 对模型旋转何缩放的时候,模型的最终位置与模型的局部坐标系的原点有关系吗?

6. 深入阅读


上海图无形科技有限公司旗下产品
Copyright © 2013-2024 AnyCAD