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

时间:2018-06-19 11:48:19

标签: c# math geometry

我需要绕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(像我五岁那样解释)

1 个答案:

答案 0 :(得分:3)

您弄错了-符号,它应该在另一个窦上...我没有在 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进入子结果的潜在危险)。只需将您的点转换为极坐标,再加上增量角,然后转换回笛卡尔坐标即可。