coding随笔 | 点绕向量旋转

205 阅读4分钟

之所以会写这个东西,是因为我在半个月前coding的时候遇到了我难以解决的问题,直接要我复习了高中的数学知识,也记录下这难忘的一刻。

1 点绕向量旋转的分类

看来点绕向量旋转一般分为两类,第一是点在坐标原点绕x y z轴旋转,第二种是点绕任意向量旋转。 这两种的难度依次增加,下面我会介绍这两种情况的具体解法。下面我都会右手坐标作为讲解。

2 点绕坐标轴旋转

其实绕着x轴旋转,就是把视野中的坐标系降维到二维YOZ,然后绕着原点旋转相应的角度。所以由此得出以下的公式。

2.1 点绕x轴旋转a角

在这里插入图片描述

C++代码实现:

void codeRotateByX(double y, double z, double thetax, double& outy, double& outz)

{

    double y1 = y;//将变量拷贝一次,保证&y == &y这种情况下也能计算正确

    double z1 = z;

    double rx = thetax * CV_PI / 180;

    outy = cos(rx) * y1 - sin(rx) * z1;

    outz = cos(rx) * z1 + sin(rx) * y1;

}

2.2点绕y轴旋转β角

在这里插入图片描述

C++代码实现:

void codeRotateByY(double x, double z, double thetay, double& outx, double& outz)

{

    double x1 = x;

    double z1 = z;

    double ry = thetay * CV_PI / 180;

    outx = cos(ry) * x1 + sin(ry) * z1;

    outz = cos(ry) * z1 - sin(ry) * x1;

}

2.3点绕z轴旋转γ角

在这里插入图片描述

C++代码实现:

void codeRotateByZ(double x, double y, double thetaz, double& outx, double& outy)

{

    double x1 = x;//将变量拷贝一次,保证&x == &outx这种情况下也能计算正确

    double y1 = y;

    double rz = thetaz * CV_PI / 180;

    outx = cos(rz) * x1 - sin(rz) * y1;

    outy = sin(rz) * x1 + cos(rz) * y1;

 

}

3 点绕任意向量旋转

为了方便使用右手坐标系,v1,v2为旋转轴,θ表示旋转角度。

在这里插入图片描述

第一步 :将v1v2平移到原点,对应矩阵:

在这里插入图片描述 在这里插入图片描述

步骤2是一个旋转操作,将p(p = v2 -v1)旋转至XOZ平面,步骤3也是一个旋转操作,将p旋转至与Z轴重合,这两个操作对应的图如下。 在这里插入图片描述

做点p在平面YOZ上的投影点q。再过q做Z轴垂线,则r是p绕X轴旋转所得,且旋转角度为α,且 在这里插入图片描述 ,
在这里插入图片描述

于是旋转矩阵为 在这里插入图片描述

现在将r绕Y轴旋转至与Z轴重合,旋转的角度为-beta(方向为顺时针),且 在这里插入图片描述 , 在这里插入图片描述

于是得到旋转矩阵为 在这里插入图片描述

最后是绕Z轴旋转,对应的矩阵如下 在这里插入图片描述

然后把中间五个矩阵连乘起来,再转置一下,得到下面的绕任意轴旋转的矩阵 在这里插入图片描述

在这里插入图片描述

而在我coding的情景是已经将v1v2组成的旋转轴简化成旋转轴v,我只要把旋转轴单位化后,单位向量是只有方向意义,所以可以认为它在坐标原点。 点p为需要旋转的点(一个double类型,长度为3的数组),origin原来的坐标原点,z_axis为旋转轴,alpha为旋转角度。

int Pdgm_trans_point(ads_point p, ads_point origin, ads_point z_axis, ads_real alpha)
{

	double a0 = origin[X];
	double b0 = origin[Y];
	double c0 = origin[Z];
	double x = p[X];
	double y = p[Y];
	double z = p[Z];
	
	P3Normalize(z_axis);//向量单位化


	double u = z_axis[X]; 
    double v = z_axis[Y];
    double w = z_axis[Z];       //方向向量(u,v,w)需为单位向量!!!


	ads_point xyz;
    double SinA = sin(alpha * GM_PI / 180);
	double CosA = cos(alpha * GM_PI / 180);

    double uu = u * u;
	double vv = v * v;
    double ww = w * w;
    double uv = u * v;
    double uw = u * w;
    double vw = v * w;

    float t00 = uu + (vv + ww) * CosA;
    float t10 = uv * (1 - CosA) + w * SinA;
    float t20 = uw * (1 - CosA) - v * SinA;
    float t30 = 0;

    float t01 = uv * (1 - CosA) - w * SinA;
    float t11 = vv + (uu + ww) * CosA;
    float t21 = vw * (1 - CosA) + u * SinA;
    float t31 = 0;

    float t02 = uw * (1 - CosA) + v * SinA;
    float t12 = vw * (1 - CosA) - u * SinA;
    float t22 = ww + (uu + vv) * CosA;
    float t32 = 0;

    float t03 = (a0 * (vv + ww) - u * (b0 * v + c0 * w)) * (1 - CosA) + (b0 * w - c0 * v) * SinA;
    float t13 = (b0 * (uu + ww) - v * (a0 * u + c0 * w)) * (1 - CosA) + (c0 * u - a0 * w) * SinA; 
	float t23 = (c0 * (uu + vv) - w * (a0 * u + b0 * v)) * (1 - CosA) + (a0 * v - b0 * u) * SinA;
    float t33 = 1;

	p[0] = t00 * x + t01 * y + t02 * z + t03;
	p[1] = t10 * x + t11 * y + t12 * z + t13;
	p[2] = t20 * x + t21 * y + t22 * z + t23;


	return GM_OK;
}

后记

嘶,感觉这东西挺麻烦的,搞了我差不多两个星期(单纯的工作时间比较少)。其实解决这个问题还可以调库,想CAD的,OSG的,OpenGL的这些都有相对应的旋转库,再按照上面的步骤就可以实现了。 ps:数学底子不好,有写错的地方多多包涵。