匯東網


2D 旋转,3D 旋转和矩阵变换简要记录

[編輯] [转简体]
|
作者:huidong | 分類:【算法】2D、3D 相關算法
[ 21 瀏覽 0 評論 5 贊 7 踩 ]

概要

正文

2D 旋转推导

只要你学过一点三角函数,2D 旋转一定难不倒你,接下来我将推导 2D 旋转公式。

如图,如果我们知道一点 P(x, y),那么我们就可以求得它与原点的距离 OP:

r = √(x^2 + y^2)

那么 OP 与 x 轴的夹角即为

α = asin(y / r)

据此,如果我们要将 P 点逆时针旋转 β,只需要根据以下公式就可以得到新的坐标:

x' = r * (cos(α + β))

y' = r * (sin(α + β))

在 C++ 中可以表示为:

struct dPOINT
{
    double x;
    double y;
};

dPOINT rotate2D(dPOINT p, double radian)
{
    double r = sqrt(p.x * p.x + p.y * p.y);
    double _radian = asin(p.y / r);
    return dPOINT{ r * (cos(radian + _radian)),r * (sin(radian + _radian)) };
}

此外,还可以将其推导为矩阵形式。如果我们把点 P 看作是一个向量,那么他就是 x 倍 x 轴方向的单位向量,和 y 倍 y 轴方向的单位向量复合产生的向量。

在这种情况下,旋转点 P 相当于将 x 轴和 y 轴的单位向量进行了旋转,我们暂称旋转后的两个单位向量为 <x> 和 <y>。

用这两个旋转后的单位向量再次以原先比例复合,得到的也就是旋转后的点 P。

而计算 P 点在 xOy 下的坐标,就只需要将 <x> 和 <y> 在 xOy 上的分量找出,也就是把 <x> 和 <y> 投影到 x 轴和 y 轴上。投影后

要得到新的 P 点坐标,只需要将其和此矩阵相乘:

x' = x * cos(β) - y * sin(β)

y' = x * sin(β) + y * cos(β)


如果你看不懂矩阵,其实这也就是向量,<x> 和 <y> 可以写为坐标:

<x> = ( cos(β), sin(β) )

<y> = ( -sin(β), cos(β) )

旋转后的点 P 可表示为

P = x * <x> + y * <y> = x * ( cos(β), sin(β) ) + y * ( -sin(β), cos(β) ) = ( x * cos(β) - y * sin(β), x * sin(β) + y * cos(β) )

即可求得 P 点坐标。

这个算法的好处就在于:不需要计算 OP 和点 P 与 x 轴的夹角。

在 C++ 中:

struct dPOINT
{
    double x;
    double y;
};

dPOINT rotate2D_2(dPOINT p, double radian)
{
    return dPOINT{ p.x * cos(radian) - p.y * sin(radian),p.x * sin(radian) + p.y * cos(radian) };
}


3D 旋转

3D 旋转其实是绕 x, y, z 轴的旋转。首先需要模仿上面的 2D 旋转矩阵写出 3D 的绕一个轴的旋转矩阵,然后再将三个轴的旋转复合。注意,三个轴的旋转是有先后次序的,不同的旋转次序会产生不同的结果。通常采用 z - y - x 的旋转顺序。


最终的复合矩阵如下:

在 C++ 中:

struct dCPOINT3D
{
    double x, y, z;
    COLORREF c;
};

dCPOINT3D rotate3D(dCPOINT3D p, double Z, double Y, double X)
{
    return {
        p.x * (cos(Y) * cos(Z)) +
        p.y * (-(cos(X) * sin(Z)) + (sin(X) * sin(Y) * cos(Z))) +
        p.z * ((sin(X) * sin(Z)) + (cos(X) * sin(Y) * cos(Z))),

        p.x * (cos(Y) * sin(Z)) +
        p.y * ((cos(X) * cos(Z)) + (sin(X) * sin(Y) * sin(Z))) +
        p.z * ((-sin(X) * cos(Z)) + (cos(X) * sin(Y) * sin(Z))),

        p.x * (-sin(Y)) +
        p.y * (sin(X) * cos(Y)) +
        p.z * (cos(X) * cos(Y)),

        p.c
    };
}


[ 5] [ 7]


 評論區  0 條評論

+ 添加評論