### `pa0`
1. 弧度制转为角度制
①一弧度的定义为弧长等于半径所对应的角度,即`1rad = l/r(l为弧长,r为半径)`
②那么一个圆周为$360^o$,对应的弧度为$2 \pi$
③那么一个1度对应的弧度为$2\pi/360=\pi/180$
④角度转为弧度使用公式$\frac{x}{180}*\pi(其中x为角度制)$
⑤反之,弧度转为角度为$\frac{180}{\pi}*y(其中y为弧度制)$
2. 在C++中反三角运算得到的是弧度制的表示,如果需要转换为角度制表示需要进行上述的转换
3. 同理的C++比如求解$sin30^o$,输入不能是角度值,必须是弧度制,因此需要将角度值转为弧度制,对于$\pi$的常量,可以使用$<cmath>中的M_{PI}$常量
#### `Eigen`库的使用
Eigen库提供有Matrix和Array两种模板类。它们定义如下:
```C++
typedef Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options> MyMatrixType;
typedef Array<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options> MyArrayType;
```
其中,通常我们会根据需要设置前三个参数,其它为默认值即可。
- Scalar:指定元素类型,比如,float, double, bool, int 等。
- RowsAtCompileTime:指定行数或者设置成动态(Dynamic);
- ColsAtCompileTime:指定列数或者设置成动态(Dynamic);
- Options:标志位,可以是ColMajor或RowMajor,默认是ColMajor;
从上面可以看出,行数和列数是允许固定大小,也允许动态大小的,所以下面的几种类型是可以的。
```C++
Matrix<double, 10, 5>
Matrix<double, 10, Dynamic>
Matrix<double, Dynamic, 5>
Matrix<double, Dynamic, Dynamic>
Array<float ,Dynamic,1>
Array<float ,10,3>
```
另外,我们还可以使用Eigen库已经重定义的类型,下面是一些简单的例子可参考。
![img](https://pic3.zhimg.com/80/v2-7edb7fff98bdc3843feca7f4998e9c56_720w.webp)
**矩阵的基本运算**
学习了矩阵的定义,那我们下面来看一下几个基本的矩阵运算。Matrix重载了+,+=,-,-+,×,×=,/,/=这几个基本的四则运算。
对于加减运算,需要注意一下几点:
- 左右矩阵的行列对应相等;
- 数据的类型也要相同,因为矩阵运算不支持隐式类型转换;
- 不支持和标量进行加减运算。
#### `Cross-product`
`Eigen`库中的叉积满足右手定则,叉积的运算公式为:
a向量的坐标为(1,2,3),b向量的坐标为(2,3,4),根据右手系叉积公式得到的新向量为
$(y_1z_2-z_1y_2,z_1x_2-x_1z_2,x_1y_2-y_1x_2)$
那么就是
$(2*4-3*3,3*2-1*4,1*3-2*2)$
那么就是
$(-1,2,-1)$
看`cross-product的结果是满足的`
#### `pa0`要求
给定一个点 P=(2,1), 将该点绕原点先逆时针旋转 45◦,再平移 (1,2), 计算出 变换后点的坐标(要求用齐次坐标进行计算)。
首先需要定义一个二维平面中的点(使用齐次坐标定义)
$2D的point定义为$`Vector3d p(2,1,1)`
将该点绕原点逆时针旋转 45◦
即在p点的坐标上左乘一个旋转矩阵,旋转矩阵为:
```C++
R(45°)=(
(cos(45.0/180.0 * M_PI),-sin(45.0/180.0 * M_PI), 0),
(sin(45.0/180.0 * M_PI),cos(45.0/180.0 * M_PI), 0),
(0 ,0, 1)
)
```
再平移(1,2)
即再次左乘一个平移矩阵
平移矩阵为
```C++
T(1,2)=(
(1, 0, 1),
(0, 1, 2),
(0, 0, 1),
)
```
编写C++程序
```C++
Eigen::Vector3f p(2,1,1);
// 定义旋转矩阵R
Eigen::Matrix3f R;
R << std::cos(45.0 / 180.0 * M_PI) , - std::sin(45.0 / 180.0 * M_PI) , 0, std::sin(45.0 / 180.0 * M_PI), std::cos(45.0 / 180.0 * M_PI), 0, 0, 0, 1;
// 定义平移矩阵T
Eigen::Matrix3f T;
T << 1,0,1,0,1,2,0,0,1;
// 输出结果
std::cout << "原始的点为" << std::endl << p << std::endl;
std::cout << "旋转后的结果" << std::endl << R * p << std::endl;
std::cout << "旋转并平移后的结果" << std::endl << T * R * p << std::endl;
```
#### `Vector3d`和`Vector3f`的区别
`Vector3d`和`Vector3f`都是Eigen库中的向量类型,它们的区别在于数据类型和精度:
1. `Vector3d`:这是Eigen库中的`double`精度浮点数向量类型。它用于表示具有双精度浮点数(64位)元素的三维向量。通常在需要高精度计算或处理双精度浮点数数据的情况下使用。
2. `Vector3f`:这是Eigen库中的`float`精度浮点数向量类型。它用于表示具有单精度浮点数(32位)元素的三维向量。通常在需要低内存占用和较快计算速度的情况下使用,但可能会牺牲一些数值精度。
选择使用哪种类型取决于你的应用需求。如果你需要高精度的数值计算并且可以容忍较高的内存消耗,那么使用`Vector3d`是合适的。如果你的应用对内存消耗有限,且不需要双精度精度,那么使用`Vector3f`可以提供更高的计算性能。
#### 最终结果包括了Eigen库的一些学习
```C++
#include<cmath>
#include<eigen3/Eigen/Core>
#include<eigen3/Eigen/Dense>
#include<iostream>
const double PI = 1.0/4.0 * std::acos(-1);
int main(){
// Basic Example of cpp
std::cout << "Example of cpp \n";
float a = 1.0, b = 2.0;
std::cout << a << std::endl;
std::cout << a/b << std::endl;
std::cout << std::sqrt(b) << std::endl;
// c++ 中输出的是pai的数值,需要转化成弧度制
std::cout << std::acos(-1) << std::endl;
double radians = std::acos(-1);
double degrees = radians * (180.0 / M_PI);
std::cout << "Angle in degrees " << degrees << std::endl;
std::cout << std::sin(30.0/180.0*acos(-1)) << std::endl;
std::cout << "use M_PI " << std::sin(30.0/180.0 * M_PI) << std::endl;
std::cout << "---***---" << std::endl;
// 矩阵的定义和初始化
std::cout << "矩阵的定义和初始化" << std::endl;
Eigen::MatrixXf matrix1(3,4); // 定义了矩阵的大小,但是没有初始化
Eigen::Vector3f vector1;
matrix1 = Eigen::MatrixXf::Zero(3,4);
vector1 = Eigen::Vector3f::Ones();
std::cout << "---matrix1---" << std::endl << matrix1 << std::endl;
std::cout << "---vector1---" << std::endl << vector1 << std::endl;
std::cout << "也可以给确定矩阵大小的矩阵赋值" << std::endl;
matrix1 << 1,2,3,4,5,6,7,8,9,10,11,12;
vector1 << 1,2,3;
std::cout << "---matrix1---" << std::endl << matrix1 << std::endl;
std::cout << "---vector1---" << std::endl << vector1 << std::endl;
std::cout << "可以使用()对某个元素进行访问,元素是可读可写的" << std::endl;
matrix1(1, 3) = 100;
vector1(1) = 200;
std::cout << "---matrix1---" << std::endl << matrix1 << std::endl;
std::cout << "---vector1---" << std::endl << vector1 << std::endl;
// 矩阵的基本运算
// 不允许重定义一个矩阵,不是python允许重定义
Eigen::MatrixXf matrix2(2, 3);
Eigen::MatrixXf matrix3(2, 3);
matrix2 << 1,2,3,4,5,6;
matrix3 << 2,3,4,5,6,7;
std::cout << "---matrix2---" << std::endl << matrix2 << std::endl;
std::cout << "---matrix3---" << std::endl << matrix3 << std::endl;
std::cout << "---matrix2 + matrix3---" << std::endl << matrix2 + matrix3 << std::endl;
// 关于乘除法运算,矩阵支持矩阵和标量之间的乘除法运算,标量和矩阵中的每个运算相运算
Eigen::MatrixXf matrix4(2, 3);
matrix4 << 4,5,6,7,8,9;
std::cout << "---matrix4---" << std::endl << matrix3 << std::endl;
std::cout << "---matrix4 * 2 ---" << std::endl << matrix4 * 2 << std::endl;
std::cout << "---matrix4 / 2 ---" << std::endl << matrix4 / 2 << std::endl;
// Eigen库直接重载了 * 运算符,可以直接进行矩阵的相乘
Eigen::MatrixXf matrix5(3, 2);
matrix5 << 1,2,3,4,5,6;
std::cout << "---matrix5---" << std::endl << matrix5 << std::endl;
std::cout << "---matrix4 * matrix5---" << std::endl << matrix4 * matrix5 << std::endl;
// Eigen库还包括了矩阵的转置,共轭,共轭转置等矩阵运算,分别由transpose(),conjugate(),adjoint()
std::cout << "---matrix5---" << std::endl << matrix5 << std::endl;
std::cout << "---matrix5 transpose---" << std::endl << matrix5.transpose() << std::endl;
std::cout << "---matrix5 conjugate---" << std::endl << matrix5.conjugate() << std::endl;
std::cout << "---matrix5 adjoint---" << std::endl << matrix5.adjoint() << std::endl;
// Eigen库不直接支持虚数的表示,需要自己定义虚数
// 为什么要特别区别Matrix和Array呢:因为对于Arrany没有矩阵的运算,只有元素级别的运算
// 至此大概了解了eigen库中元素的表示
// Example of vector
std::cout << "Example of vector \n";
// vector definition(定义向量v和w)
Eigen::Vector3f v(1.0f,2.0f,3.0f);
Eigen::Vector3f w(1.0f,0.0f,0.0f);
// vector output
std::cout << "Example of output \n";
std::cout << v << std::endl;
// vector add
std::cout << "Example of add \n";
std::cout << v + w << std::endl;
// vector scalar multiply
std::cout << "Example of scalar multiply \n";
std::cout << v * 3.0f << std::endl;
std::cout << 2.0f * v << std::endl;
// 矩阵和矩阵的乘法
// 定义了一个矩阵6
Eigen::Matrix2d matrix6;
matrix6 << 1,2,3,4;
// 定义了两个二维的列向量
Eigen::Vector2d u1(-1,1), v1(2,0);
std::cout << "---matrix6 * u1---" << std::endl << matrix6 * u1 << std::endl;
std::cout << "---u1^T * matrix6---" << std::endl << u1.transpose() * matrix6 << std::endl;
std::cout << "---u1^T * v1" << std::endl << u1.transpose() * v1 << std::endl;
std::cout << "---u1 * v1^T" << std::endl << u1 * v1.transpose() << std::endl;
std::cout << "---matrix6 * matrix6---" << std::endl << matrix6 * matrix6 << std::endl;
// Dot-product(向量的点积)和Cross-product
Eigen::Vector3d v2(1,2,3);
Eigen::Vector3d w2(2,3,4);
std::cout << "v2" << std::endl << v2 << std::endl;
std::cout << "w2" << std::endl << w2 << std::endl;
std::cout << "Dot-product" << std::endl << v2.dot(w2) << std::endl;
std::cout << "Dor-product though matrix product" << std::endl << v2.adjoint() * w2 << std::endl;
std::cout << "Cross-product" << std::endl << v2.cross(w2) << std::endl ;
// Example of matrix
std::cout << "Example of matrix \n";
// matrix definition
Eigen::Matrix3f i,j;
i << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0;
j << 2.0, 3.0, 1.0, 4.0, 6.0, 5.0, 9.0, 7.0, 8.0;
// matrix output
std::cout << "Example of output \n";
std::cout << i << std::endl;
// matrix add i + j
// matrix scalar multiply i * 2.0
// matrix multiply i * j
// matrix multiply vector i * v
// 本次作业的要求:
// 先定义齐次坐标下的点
// 请保证点的类型和相乘的矩阵类型是一致的
Eigen::Vector3f p(2,1,1);
// 定义旋转矩阵R
Eigen::Matrix3f R;
R << std::cos(45.0 / 180.0 * M_PI) , - std::sin(45.0 / 180.0 * M_PI) , 0, std::sin(45.0 / 180.0 * M_PI), std::cos(45.0 / 180.0 * M_PI), 0, 0, 0, 1;
// 定义平移矩阵T
Eigen::Matrix3f T;
T << 1,0,1,0,1,2,0,0,1;
// 输出结果
std::cout << "原始的点为" << std::endl << p << std::endl;
std::cout << "旋转后的结果" << std::endl << R * p << std::endl;
std::cout << "旋转并平移后的结果" << std::endl << T * R * p << std::endl;
std::cout << "---CSDN结果---" << std::endl;
// P(1, 2) Rotation counterclockwise 45 + T(1 , 2)
std::cout << "P(2,1) Transformation" << std::endl;
Eigen::Vector3f P2(2.0f, 1.0f, 1.0f);
Eigen::Matrix3f R2, T2;
R2 << cos(PI), -sin(PI), 0.0, sin(PI), cos(PI), 0.0, 0.0, 0.0, 1.0;
T2 << 1.0, 0.0, 1.0, 0.0, 1.0, 2.0, 0.0, 0.0, 1.0;
std::cout << P2 << '\n' << R2 << '\n' << T2 << std::endl;
// Transformation
std::cout << T2 * R2 * P2 << std::endl;
return 0;
}
```