首页 > 解决方案 > 旋转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#mathgeometry

解决方案


你的-标志错了,它应该在另一个窦......我没有用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)。它只是将您的点转换为极坐标添加增量角度并转换回笛卡尔。


推荐阅读