在本节中,将介绍几何模块提供的许多可能性,以处理2D和3D旋转以及射影或仿射变换。
Eigen的Geometry模块提供了两种不同的几何变换:
1 抽象的变换,例如旋转(轴角或四元数表示),平移,缩放。这些转换未表示为矩阵,但是仍然可以将它们与表达式中的矩阵和向量混合,并根据需要将它们转换为矩阵。
2 射影或仿射变换矩阵:请参见Transform类。这些确实是矩阵。注意, 如果要使用OpenGL 4x4矩阵,则需要Affine3f和Affine3d。
可以从抽象转换构造一个Transform:Transform t(AngleAxis(angle,axis));
或像这样:
Transform t;
t = AngleAxis(angle,axis);
但是注意,不幸的是,由于C ++的工作方式,不能这样做:Transform t = AngleAxis(angle,axis);
说明:在C ++语言中,这将要求Transform具有一个来自AngleAxis的非显式转换构造函数,但是我们真的不想在此允许隐式转换。
1)变换的类型
变换类型 | 典型的初始化代码 |
---|---|
2D旋转 | Rotation2D |
3D旋转的轴角方法 | AngleAxis |
3D旋转的四元数方法 | Quaternion |
N维缩放 | Scaling(sx, sy, sz) |
N维平移 | Translation |
N维仿射 | Transform |
N维线性变换 | Matrix |
关于旋转的注意事项
要变换多个矢量,首选旋转矩阵,而对于其他用法,四元数是紧凑,快速和稳定的首选表示形式。最后,Rotation2D和AngleAxis主要是创建其他旋转对象的便捷类型。
关于平移和缩放的注意事项
像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(..);
2)仿射变换
本部分介绍仿射变换,概念上,仿射变换是一个非奇异线性变换 linear()与一个平移变换t的复合,可能是因为x’ = linear()*x + t ;所以linear()是线性部分
将变换应用于点 | VectorNf p1, p2; p2 = t * p1; |
将变换应用于向量 | VectorNf vec1, vec2;vec2 = t.linear() * vec1; |
应用一个更一般的变换作用在normal vector | VectorNf n1, n2;MatrixNf normalMatrix = t.linear().inverse().transpose();n2 = (normalMatrix * n1).normalized(); |
将纯旋转变换作用在一个 normal vector | n2 = t.linear() * n1; |
OpenGL compatibility 3D | glLoadMatrixf(t.data()); |
OpenGL compatibility 2D | Affine3f aux([Affine3f::Identity]());aux.linear().topLeftCorner<2,2>() = t.linear();aux.translation().start<2>() = t.translation();glLoadMatrixf(aux.data()); |
3)欧拉角
Matrix3f m;
m = AngleAxisf(angle1, Vector3f::UnitZ())
* AngleAxisf(angle2, Vector3f::UnitY())
* AngleAxisf(angle3, Vector3f::UnitZ());
#include
#include
#include
#include
int main()
{
//------------1 声明旋转矩阵与向量并初始化-----------
Eigen::Matrix3d rotation_matrix = Eigen::Matrix3d::Identity();
std::cout << "rotation_matrix = \n" << rotation_matrix << std::endl;
Eigen::AngleAxisd rotation_vector(M_PI / 4, Eigen::Vector3d(0, 0, 1));
std::cout.precision(3); //输出三位有效数字
std::cout << "rotation_vector_matrix = \n" << rotation_vector.matrix() << std::endl;
rotation_matrix = rotation_vector.toRotationMatrix();
//-------------2 对v进行操作-------------
Eigen::Vector3d v(1, 0, 0);
Eigen::Vector3d v_rotated = rotation_vector * v;
std::cout << "(1, 0, 0) after rotation (by matrix) = \n" << v_rotated.transpose() << std::endl;
v_rotated = rotation_matrix * v;
std::cout << "(1, 0, 0) after rotation (by matrix) = \n" << v_rotated.transpose() << std::endl;
//-------------3 欧拉角------------------
Eigen::Vector3d euler_angle = rotation_matrix.eulerAngles(2, 1, 0);
std::cout << "yaw pitch roll = " << euler_angle.transpose() << std::endl;
//-------------4 欧氏变换----------------
Eigen::Isometry3d T = Eigen::Isometry3d::Identity();
T.rotate(rotation_vector);
T.pretranslate(Eigen::Vector3d(1, 3, 4));
std::cout << "Transform matrix = \n" << T.matrix() << std::endl;
//-------------5 坐标变换----------------
Eigen::Vector3d v_transformed = T * v;
std::cout << "v transformed = " << v_transformed.transpose() << std::endl;
//-------------6 四元数------------------
Eigen::Quaterniond q = Eigen::Quaterniond(rotation_vector);
std::cout << "quaterniond from rotation vector = " << q.coeffs().transpose() << std::endl;
q = Eigen::Quaterniond(rotation_matrix);
std::cout << "quaterniond from rotation matrix = " << q.coeffs().transpose() << std::endl;
v_rotated = q * v;
std::cout << "(1, 0, 0) after rotation = \n" << v_rotated.transpose() << std::endl;
std::cout << "should be equal to " << (q * Eigen::Quaterniond(0, 1, 0, 0) * q.inverse()).coeffs().transpose() << std::endl;
}