两种旋转3D点的方式,有什么区别



我需要绕 Y 轴旋转 3D 点

我不是数学家,所以我在互联网上搜索并找到了这个页面 https://www.siggraph.org/education/materials/HyperGraph/modeling/mod_tran/3drota.htm#Y-Axis%20Rotation

使用此代码

private void RotateAroundY_1()
{
double x = 40.46;
double y = 16.52;
double z = 56.5;
double b = -1* 64.77;       // rotation degree (mult with -1 to get the rotation counter clockwise
double B = DegreeToRadian(b);   // B

double X = x * Math.Cos(B) + z*Math.Sin(B);
double Y = y;
double Z = z*Math.Cos(B) - x*Math.Sin(B);
Console.WriteLine(string.Format("X: {0} Y: {1} Z: {2}",X,Y,Z));
}
private double DegreeToRadian(double b)
{
return (Math.PI / 180) * b;
}

我得到这个结果

X: -33,8639291270836 
Y: 16,52 
Z: 60,6835719455922

但是,旋转的坐标应该是(根据3D CAD程序及其用户(

X: 68.38
Y: 16,52 
Z: -12.5

如果我使用此代码

private void RotateAroundY_2()
{
double x = 40.46;
double y = 16.52;
double z = 56.5;
double b = -1* 64.77;   // rotation degree (mult with -1 to get the rotation counter clockwise
double curAng = Math.Atan2(z, x);
double X = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(z, 2));
double Y = Math.Cos(DegreeToRadian(b) + curAng) * hyp;
double Z = Math.Sin(DegreeToRadian(b) + curAng) * hyp;
Console.WriteLine(string.Format("X: {0} Y: {1} Z: {2}",X,Y,Z));
}
private double DegreeToRadian(double b)
{
return (Math.PI / 180) * b;
}

我得到这个结果

X: 68,3563218478633
Y: 16,52
Z: -12,5169830003609

所以我将使用RotateAroundY_2,但我希望我能理解区别是什么以及为什么我 应该使用第二个吗?

ELI5 (像我五岁一样解释(

你弄错了-符号,它应该在另一个窦上......我不用C#编码,所以所有代码块都在C++(需要移植它,但应该足够简单(。

void rotate_y(double &x,double &y,double &z,double ang)
{
double u=x,v=z;
ang*=M_PI/180.0;
x=+u*cos(ang)-v*sin(ang);
z=+u*sin(ang)+v*cos(ang);
}

像这样使用它:

double x=40.46,y=16.52,z=56.5,ang=-64.77;
mm_log->Lines->Add(AnsiString().sprintf("(%03.3f,%03.3f,%03.3f)",x,y,z));
rotate_y(x,y,z,ang);
mm_log->Lines->Add(AnsiString().sprintf("(%03.3f,%03.3f,%03.3f)",x,y,z));

结果为以下输出:

(40.460,16.520,56.500)
(68.356,16.520,-12.517)

当您在另一sin上得到减号时,您将以相反的方式旋转,因此将角度乘以-1也会导致您想要的结果。

void rotate_y(double &x,double &y,double &z,double ang)
{
double u=x,v=z;
ang*=-M_PI/180.0;       
x=+u*cos(ang)+v*sin(ang);
z=-u*sin(ang)+v*cos(ang);
}

喜欢这个:

(40.460,16.520,56.500)
(68.356,16.520,-12.517)

您还可以稍微优化旋转:

void rotate_y(double &x,double &y,double &z,double ang)
{
double u=x,v=z,c,s;
ang*=M_PI/180.0;
c=cos(ang);
s=sin(ang);
x=+u*c-v*s;
z=+u*s+v*c;
}

以避免多次sin,cos使用。

您获得的另一个旋转代码非常慢且不准确,因为它在atan2上中继(这也具有在子结果中NaN的潜在危险(。它只是将您的点转换为极坐标,加上增量角并转换回笛卡尔。

最新更新