[Eigen中文文档] 空间变换

简介: 本页将介绍几何模块提供的多种处理 2D 和 3D 旋转以及射影或仿射变换的方法。

文档总目录

英文原文(Space transformations)

本页将介绍几何模块提供的多种处理 2D 和 3D 旋转以及射影或仿射变换的方法。

Eigen 的 Geometry 模块提供了两种不同类型的几何变换:

  • 抽象变换,例如旋转(由角度和轴或四元数表示),平移,缩放。这些变换不是表示为矩阵,但是仍然可以在表达式中与矩阵和向量混合使用,并在需要时将它们转换为矩阵。

  • 射影或仿射变换矩阵:请参阅 Transform 类。这些确实是矩阵。

注意:

如果你正在使用 OpenGL 4x4 矩阵,那么 Affine3fAffine3d 就是你想要的。由于 Eigen 默认采用列主存储,你可以直接使用 Transform::data() 方法将变换矩阵传递给 OpenGL

你可以从抽象转换构造一个 Transform,如下所示:

Transform t(AngleAxis(angle,axis));

或者,像这样:

Transform t;
t = AngleAxis(angle,axis);

但请注意,由于 C++ 的工作原理,你不能这样做:

Transform t = AngleAxis(angle,axis);

说明:

在 C++ 语言中,需要 Transform 具有来自 AngleAxis 的非显式转换构造函数,但 Eigen 不允许此处隐式转换。

变换类型

2D 旋转某个角度

Rotation2D<float> rot2(angle_in_radian);

沿某个轴 3D 旋转某个角度

AngleAxis<float> aa(angle_in_radian, Vector3f(ax,ay,az));

轴向量必须标准化。

使用四元数进行 3D 旋转

Quaternion<float> q;  q = AngleAxis<float>(angle_in_radian, axis);

N 维缩放

Scaling(sx, sy)
Scaling(sx, sy, sz)
Scaling(s)
Scaling(vecN)

N 维变换

Translation<float,2>(tx, ty)
Translation<float,3>(tx, ty, tz)
Translation<float,N>(s)
Translation<float,N>(vecN)

N 维仿射变换

Transform<float,N,Affine> t = concatenation_of_any_transformations;
Transform<float,3,Affine> t = Translation3f(p) * AngleAxisf(a,axis) * Scaling(s);

N 维线性变换

Matrix<float,N> t = concatenation_of_rotations_and_scalings;
Matrix<float,2> t = Rotation2Df(a) * Scaling(s);
Matrix<float,3> t = AngleAxisf(a,axis) * Scaling(s);

纯旋转, 缩放等

关于旋转的注意:

要变换多个向量,首选的表示方法是旋转矩阵,而对于其他用途,四元数是首选的表示方法,因为它们紧凑,快速且稳定。最后,Rotation2DAngleAxis 主要是用于创建其他旋转对象的便捷类型。

关于平移和缩放的注意:

AngleAxis 一样,这些类的设计目的是简化线性(Matrix)和仿射(Transform)变换的创建和初始化过程。然而,与 AngleAxis 不同的是,这些类效率不高,但仍然可能有其他通用且高效的算法,以输入任何类型的变换。

上述任何转换类型都可以转换为具有相同性质的任何其他类型,或更通用的类型。以下是一些其他示例:

Rotation2Df r;  r  = Matrix2f(..);       // assumes a pure rotation matrix
AngleAxisf aa;  aa = Quaternionf(..);
AngleAxisf aa;  aa = Matrix3f(..);       // assumes a pure rotation matrix
Matrix2f m;     m  = Rotation2Df(..);
Matrix3f m;     m  = Quaternionf(..);       Matrix3f m;   m = Scaling(..);
Affine3f m;     m  = AngleAxis3f(..);       Affine3f m;   m = Scaling(..);
Affine3f m;     m  = Translation3f(..);     Affine3f m;   m = Matrix3f(..);

跨变换类型的通用 API

在某种程度上,Eigen 的几何模块允许编写适用于任何变换类型的通用算法:

描述 代码
两个变换的串联 gen1 * gen2;
将变换应用于向量 vec2 = gen1 * vec1;
获取变换的逆变换 gen2 = gen1.inverse();
球面插补(仅限Rotation2DQuaternion rot3 = rot1.slerp(alpha,rot2);

仿射变换

通用仿射变换由Transform类表示,其内部实际上是一个 $(Dim+1)^2$ 矩阵。在Eigen中不区分点和向量,因此所有点实际上都由从原点的位移向量表示($p≡p−0$)。考虑到这一点,当应用变换时,真实点和向量是有区别的。

将变换应用于点

VectorNf p1, p2;
p2 = t * p1;

将变换应用于向量

VectorNf vec1, vec2;
vec2 = t.linear() * vec1;

将一般变换应用到法向量

VectorNf n1, n2;
MatrixNf normalMatrix = t.linear().inverse().transpose();
n2 = (normalMatrix * n1).normalized();

将纯旋转变换应用到法向量(无缩放,无剪切)

n2 = t.linear() * n1;

OpenGL 3D 兼容性

glLoadMatrixf(t.data());

OpenGL 2D 兼容性

Affine3f aux(Affine3f::Identity());
aux.linear().topLeftCorner<2,2>() = t.linear();
aux.translation().start<2>() = t.translation();
glLoadMatrixf(aux.data());

组件访问器

对内部矩阵的完全读写访问

t.matrix() = matN1xN1;    // N1 means N+1
matN1xN1 = t.matrix();

访问系数

t(i,j) = scalar;   <=>   t.matrix()(i,j) = scalar;
scalar = t(i,j);   <=>   scalar = t.matrix()(i,j);

变换部分

t.translation() = vecN;
vecN = t.translation();

线性部分

t.linear() = matNxN;
matNxN = t.linear();

提取旋转矩阵

matNxN = t.rotation();

创建变换

虽然可以通过连接基本变换来创建和更新变换对象,但 Transform 类还具有过程式 API:

Translation

// 过程式API
t.translate(Vector_(tx,ty,..));
t.pretranslate(Vector_(tx,ty,..));
// 等效的自然API
t *= Translation_(tx,ty,..);
t = Translation_(tx,ty,..) * t;

Rotation

在 2D 和过程式 API 中,any_rotation 也可以是一个以弧度表示的角

// 过程式API
t.rotate(any_rotation);
t.prerotate(any_rotation);
// 等效的自然API
t *= any_rotation;
t = any_rotation * t;

Scaling

// 过程式API
t.scale(Vector_(sx,sy,..));
t.scale(s);
t.prescale(Vector_(sx,sy,..));
t.prescale(s);
// 等效的自然API
t *= Scaling(sx,sy,..);
t *= Scaling(s);
t = Scaling(sx,sy,..) * t;
t = Scaling(s) * t;

Shear transformation(剪切变换)

仅限于 2D

// 过程式API
t.shear(sx,sy);
t.preshear(sx,sy);

请注意,在这些 API 中,任意多个变换都可以连接在单个表达式中,如以下两个等效示例所示:

t.pretranslate(..).rotate(..).translate(..).scale(..);
t = Translation_(..) * t * RotationType(..) * Translation_(..) * Scaling(..);

欧拉角

欧拉角是创建旋转对象的方便工具。由于存在24种不同的惯例,它们使用起来非常令人困惑。本例演示如何按照2-1-2惯例创建旋转矩阵。

这里官方文档没给出更多信息,如你有相关更多信息,欢迎留言。

Matrix3f m;
m = AngleAxisf(angle1, Vector3f::UnitZ())
    * AngleAxisf(angle2, Vector3f::UnitY())
    * AngleAxisf(angle3, Vector3f::UnitZ());
相关文章
|
8月前
|
缓存 测试技术 编译器
[Eigen中文文档] 稠密矩阵分解函数对比
本文介绍了 Eigen 为各种方阵和过约束问题提供的稠密矩阵分解的速度比较。
64 0
|
8月前
|
并行计算 算法 测试技术
[Eigen中文文档] 稠密分解方法目录
本文介绍了 Eigen 提供的处理稠密矩阵分解方法的目录。
76 0
|
8月前
|
XML 并行计算 算法
[Eigen中文文档] 求解稀疏线性系统
在Eigen中,有多种方法可用于求解稀疏系数矩阵的线性系统。由于此类矩阵的特殊表示,必须特别小心以获得良好的性能。本文列出了Eigen中可用的稀疏求解器。还介绍了所有这些线性求解器共同的主要步骤。根据矩阵的属性、所需的准确度,最终用户可以调整这些步骤以提高其代码的性能。请注意,并不需要深入了解这些步骤背后的内容:最后一节介绍了一个基础例程,可轻松使用以获取所有可用求解器的性能洞察。
155 0
|
8月前
|
编译器 索引
[Eigen中文文档] 块操作
本文介绍了块操作。块是matrix或array的部分矩形元素。块表达式既可以用作右值也可以用作左值。与Eigen表达式一样,如果让编译器进行优化,则块操作的运行时间成本为零。
65 0
|
8月前
|
存储 算法 NoSQL
[Eigen中文文档] 存储顺序
矩阵和二维数组有两种不同的存储顺序:列优先和行优先。本节解释了这些存储顺序以及如何指定应该使用哪一种。
75 0
|
8月前
|
存储 算法 NoSQL
[Eigen中文文档] 稀疏矩阵操作
在许多应用中(例如,有限元方法),通常要处理非常大的矩阵,其中只有少数系数不为零。在这种情况下,可以通过使用仅存储非零系数的特殊表示来减少内存消耗并提高性能。这样的矩阵称为稀疏矩阵。
222 0
|
8月前
|
存储
[Eigen中文文档] 就地矩阵分解
从 Eigen 3.3 开始,LU、Cholesky 和 QR 分解可以就地操作,即直接在给定的输入矩阵内操作。当处理大矩阵时,或者当可用内存非常有限(嵌入式系统)时,此功能特别有用。
48 0
|
8月前
|
存储 C语言 C++
|
8月前
|
存储 编译器
|
8月前
[Eigen中文文档] 固定大小的可向量化Eigen对象
本文主要解释 固定大小可向量化 的含义。
52 0