[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());
相关文章
|
编译器 索引
[Eigen中文文档] 块操作
本文介绍了块操作。块是matrix或array的部分矩形元素。块表达式既可以用作右值也可以用作左值。与Eigen表达式一样,如果让编译器进行优化,则块操作的运行时间成本为零。
343 0
|
存储 算法 NoSQL
[Eigen中文文档] 存储顺序
矩阵和二维数组有两种不同的存储顺序:列优先和行优先。本节解释了这些存储顺序以及如何指定应该使用哪一种。
380 0
|
存储 编译器 C语言
[Eigen中文文档] 对未对齐数组断言的解释
本文将解释程序因断言失败而终止的问题。
323 0
|
并行计算 算法 测试技术
[Eigen中文文档] 稠密分解方法目录
本文介绍了 Eigen 提供的处理稠密矩阵分解方法的目录。
244 0
|
存储 并行计算 算法
[Eigen中文文档] 概述(总目录)
Eigen是基于线性代数的C ++模板库,主要用于矩阵,向量,数值求解器和相关算法。常用的Ceres、G2O等项目均是基于Eigen库。 本系列文章将通过官方文档带你了解Eigen。
2471 1
|
存储 NoSQL API
[Eigen中文文档] Matrix类
在Eigen中,所有矩阵和向量都是Matrix模板类的对象。向量只是行数或者列数为1的特殊矩阵。
740 1
|
安全 编译器 C++
[Eigen中文文档] 矩阵与向量运算
本文章旨在提供有关如何使用 Eigen 在矩阵、向量和标量之间执行算术操作的概述和一些详细信息。
767 0
[Eigen中文文档] 高级初始化
本文介绍了几种用于初始化矩阵的高级方法。提供了有关之前介绍的逗号初始化程序的更多详细信息。还解释了如何获得特殊矩阵,例如单位矩阵和零矩阵。
335 0
|
测试技术
[Eigen中文文档] Array类与元素操作
与Matrix类用于线性代数计算不同的是,Array类提供了通用目的数组。此外,Array类提供了一种执行按系数运算的简单方法,这可能没有线性代数意义,例如对每一个元素都加一个常数或按系数将两个数组相乘。
488 0
[Eigen中文文档] 求解线性最小二乘系统
本文介绍如何使用 Eigen 求解线性最小二乘系统。 本文讨论三种方法 SVD 分解、QR 分解和正规方程。其中,SVD 分解通常最准确但最慢,正规方程式最快但最不准确,QR 分解介于两者之间。
451 0