在3D中围绕任意轴旋转点

时间:2016-03-10 11:15:50

标签: c# rotation

我在一个球体(半径为1,以原点为中心)上有一个点(xi,yi,zi),我希望围绕指定的轴(xa,ya,za)旋转角度(ω)。然后,我想要恢复相对于原始点的方向,通过该角度指向旋转点。

换句话说,我想知道我是向上,向下,向左还是向右旋转这个点,以及左旋/右旋转多少与总旋转和上/下旋转相对于总旋转。 / p>

这需要在接近极点时起作用(z = +/- 1)。也就是说,我说我在北极附近旋转。我的原点可能是从新点开始的球体的另一面,但我仍然想要回归。

理想情况下,这应该返回0到2 pi之间的角度,其中0 =向右旋转,pi / 2 =向上旋转,pi =向左旋转等等。但是,我也可以使用具有相对幅度的2d向量水平和垂直方向的方向。

我希望有人已经为此建立了一个功能。但是,我似乎无法找到它。我建立了自己的...然而,它不起作用。朝向两极,当围绕z轴旋转时,它似乎会返回至少一个点的错误方向。但是,我不能很好地理解这个问题,以便预测它为什么是错误的,更不用说代码中的哪个元素是不正确的。

我能找到的每个答案都只是围绕z轴旋转,或者只是在两个维度上旋转。我能找到的最接近我的问题的线程是here但是这会返回新点,而不是旋转方向,我不能理解这个函数是否足以将它包含在我的函数中。

public double[] Rotate(double xi, double yi, double zi, double xa, double ya, double za, double omega)
{
    //xi,yi,zi is our pt
    //xa,ya,za is our axis
    //omega is our angle of rotation
    //Prepare output
    double[] output = new double[2];
    //Rotate our point
    double turnVar = (xi * xa + yi * ya + zi * za) * (1 - Math.Cos(omega));
    double xn = turnVar + xi * Math.Cos(omega) + (-za * yi + ya * zi) * Math.Sin(omega);
    double yn = turnVar + yi * Math.Cos(omega) + (za * xi - xa * zi) * Math.Sin(omega);
    double zn = turnVar + zi * Math.Cos(omega) + (-ya * xi + xa * yi) * Math.Sin(omega);
    //Calculate difference between our new point and our old point
    double xd = xn - xi;
    double yd = yn - yi;
    double zd = zn - zi;
    //Calculate radius(at a particular z) for all points
    double ri = Math.Sqrt(xi * xi + yi * yi);
    double rn = Math.Sqrt(xn * xn + yn * yn);
    double rd = Math.Sqrt(xd * xd + yd * yd);
    //Calculate magnitude of the rotation
    double td = Math.Sqrt(rd * rd + zd * zd);
    //If our rotation is in the left direction
    if (Math.Atan2(yn, xn) < Math.Atan2(yi, xi))
    {
        //Return negative as the direction and the fraction of the rotation in the horizontal
        output[0] = -1 * rd / td;
    }
    else
    //So it should be toward the right direction
    {
        //Return positive as the direction and the fraction of the rotation in the horizontal
        output[0] = rd / td;
    }
    //But if the rotation is large, the two points are probably much closer in the opposite direction
    //ie 0.9 pi ==> 1.1 pi is right, but atan will return this as 0.9 pi ==> -0.9 pi which is left
    if (Math.Atan2(yn, xn) - Math.Atan2(yi, xi) > 0.5 * Math.PI)
    {
        //Adjust the output for this border issue
        output[0] = output[0] * -1;
    }
    //If we are near the poles
    //Using omega/2 as the range for the poles...
    if (Math.Abs(Math.Atan2(zn, rn)) > (Math.PI / 2) - 0.5 * omega || Math.Abs(Math.Atan2(zi, ri)) > (Math.PI / 2) - 0.5 * omega)
    {
        //If we are rotating over the top, the signs for x/y shouldn't swap
        if (Math.Sign(xi) == Math.Sign(xn) && Math.Sign(yi) == Math.Sign(yn))
        {
            //If we are going up
            if (Math.Atan2(zn, rn) < Math.Atan2(zi, ri))
            {
                //Return negative as the direction and the fraction of the rotation in the vertical
                output[1] = -1 * zd / td;
            }
            else
            //We should be goind down
            {
                //Return positive as the direction and the fraction of the rotation in the vertical
                output[1] = zd / td;
            }
        }
        else
        //So we are rotating over the top of the poles
        {
            //Are we on the top pole?
            if (Math.Atan2(zn, rn) < 0)
            {
                //Return negative as the direction and the fraction of the rotation in the vertical
                output[1] = -1 * zd / td;
            }
            else
            //So we are on the bottom pole?
            {
                //Return positive as the direction and the fraction of the rotation in the vertical
                output[1] = zd / td;
            }
        }
    }
    else
    {
        //If we are going up
        if (Math.Atan2(zn, rn) < Math.Atan2(zi, ri))
        {
            //Return negative as the direction and the fraction of the rotation in the vertical
            output[1] = -1 * zd / td;
        }
        else
        //We should be goind down
        {
            //Return positive as the direction and the fraction of the rotation in the vertical
            output[1] = zd / td;
        }
    }
    //Return output
    return output;
}

0 个答案:

没有答案