在 OpenCASCADE 中,从世界坐标系(WCS)到用户自定义坐标系(UDCS)的变换矩阵,本质上是一个 仿射变换矩阵,包含 旋转和平移 两个部分。这个矩阵描述了如何将一个点从世界坐标系变换到用户坐标系中。
🧮 一、数学基础
1. 三维坐标系变换的本质
三维空间中,坐标系变换由以下两个部分组成:
- 旋转(Rotation):描述用户坐标系相对于世界坐标系的朝向。
- 平移(Translation):描述用户坐标系的原点在世界坐标系中的位置。
因此,最终的变换矩阵是一个 4x4 的仿射变换矩阵,形式如下:
[R11R12R13TxR21R22R23TyR31R32R33Tz0001] \begin{bmatrix} R_{11} & R_{12} & R_{13} & T_x \\ R_{21} & R_{22} & R_{23} & T_y \\ R_{31} & R_{32} & R_{33} & T_z \\ 0 & 0 & 0 & 1 \end{bmatrix} R11R21R310R12R22R320R13R23R330TxTyTz1
其中:
- $ R $ 是一个 3x3 的旋转矩阵,表示坐标系的旋转。
- $ T $ 是一个 3D 平移向量,表示用户坐标系的原点在 WCS 中的位置。
🧭 二、用户自定义坐标系的定义
在 OpenCASCADE 中,使用 gp_Ax3
类定义一个三维坐标系,它包含以下三个关键元素:
- 原点(Location):
gp_Pnt
,表示坐标系的原点位置。 - Z 轴方向(Direction):
gp_Dir
,表示坐标系的主方向(通常为 Z 轴)。 - X 轴方向(XDirection):
gp_Dir
,表示坐标系的参考方向(通常为 X 轴)。
通过这三个元素,我们可以构造出完整的正交基:
- Z 轴:用户指定的
ZDirection
- X 轴:用户指定的
XDirection
- Y 轴:通过叉积计算:
Y = Z × X
🧮 三、变换矩阵的构建步骤
步骤 1:构造正交基向量
设:
- $ \vec{X} $:X 轴方向(单位向量)
- $ \vec{Y} $:Y 轴方向(单位向量)= $ \vec{Z} \times \vec{X} $
- $ \vec{Z} $:Z 轴方向(单位向量)
这些向量构成用户坐标系的三个正交基。
步骤 2:构造旋转矩阵
旋转矩阵 $ R $ 由这三个基向量构成:
R=[XxYxZxXyYyZyXzYzZz] R = \begin{bmatrix} X_x & Y_x & Z_x \\ X_y & Y_y & Z_y \\ X_z & Y_z & Z_z \end{bmatrix} R=XxXyXzYxYyYzZxZyZz
其中 $ X_x, X_y, X_z $ 是 $ \vec{X} $ 的三个分量,依此类推。
步骤 3:构造平移向量
平移向量 $ T $ 是用户坐标系的原点在世界坐标系中的坐标:
T=[x0y0z0] T = \begin{bmatrix} x_0 \\ y_0 \\ z_0 \end{bmatrix} T=x0y0z0
步骤 4:组合成仿射变换矩阵
将旋转和平移组合成 4x4 的仿射变换矩阵:
M=[XxYxZxx0XyYyZyy0XzYzZzz00001] M = \begin{bmatrix} X_x & Y_x & Z_x & x_0 \\ X_y & Y_y & Z_y & y_0 \\ X_z & Y_z & Z_z & z_0 \\ 0 & 0 & 0 & 1 \end{bmatrix} M=XxXyXz0YxYyYz0ZxZyZz0x0y0z01
🧪 四、代码实现(手动构建变换矩阵)
#include <gp_Ax3.hxx>
#include <gp_Mat.hxx>
#include <gp_XYZ.hxx>
#include <iostream>
int main()
{
// 1. 定义用户坐标系
gp_Pnt origin(10.0, 20.0, 30.0); // 原点
gp_Dir zAxis(0.0, 0.0, 1.0); // Z轴方向
gp_Dir xAxis(1.0, 0.0, 0.0); // X轴方向
gp_Ax3 userCS(origin, zAxis, xAxis); // 构造坐标系
// 2. 获取基向量
gp_Dir X = userCS.XDirection(); // X 轴
gp_Dir Y = userCS.YDirection(); // Y 轴(自动计算)
gp_Dir Z = userCS.Direction(); // Z 轴
// 3. 构造旋转矩阵
gp_Mat R(
X.X(), Y.X(), Z.X(),
X.Y(), Y.Y(), Z.Y(),
X.Z(), Y.Z(), Z.Z()
);
// 4. 构造平移向量
gp_XYZ T(origin.X(), origin.Y(), origin.Z());
// 5. 构造 4x4 仿射变换矩阵(手动)
double matrix[16] = {
X.X(), Y.X(), Z.X(), T.X(),
X.Y(), Y.Y(), Z.Y(), T.Y(),
X.Z(), Y.Z(), Z.Z(), T.Z(),
0.0, 0.0, 0.0, 1.0
};
// 6. 打印矩阵
std::cout << "手动构造的变换矩阵:" << std::endl;
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
std::cout << matrix[i * 4 + j] << " ";
}
std::cout << std::endl;
}
return 0;
}
📌 五、关键点总结
项目 | 说明 |
---|---|
变换矩阵构成 | 4x4 仿射矩阵,包含旋转和平移 |
旋转矩阵构造 | 由用户坐标系的三个正交基向量构成 |
平移向量 | 用户坐标系的原点在世界坐标系中的坐标 |
基向量顺序 | 通常为 X、Y、Z,其中 Y 由 Z × X 得到 |
OpenCASCADE 支持 | gp_Ax3::Transformation() 可直接获取变换矩阵 |
手动构建适用场景 | 需要深入理解变换原理、调试、或与第三方库交互 |
🧠 六、扩展理解:变换矩阵的逆
如果你需要 从用户坐标系变换回世界坐标系,可以使用 逆变换矩阵,即:
M−1=[RT−RT⋅T01] M^{-1} = \begin{bmatrix} R^T & -R^T \cdot T \\ 0 & 1 \end{bmatrix} M−1=[RT0−RT⋅T1]
在 OpenCASCADE 中,可以通过 gp_Trsf::Inverted()
获取逆变换。
📌 七、总结
问题 | 解答 |
---|---|
如何手动构造 WCS 到 UDCS 的变换矩阵? | 构造旋转矩阵(由用户坐标系的三个正交基向量构成)和平移向量(原点) |
变换矩阵的数学形式是什么? | 4x4 仿射矩阵,包含旋转和平移 |
如何获取逆变换? | 使用 gp_Trsf::Inverted() 或手动计算逆矩阵 |
如何验证变换是否正确? | 将原点变换到用户坐标系中,应得到 (0, 0, 0) |
为什么需要手动构造变换矩阵? | 理解底层原理、调试、与第三方库交互、自定义变换逻辑 |