GAMES 101 pa0

### `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;
}
```

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值