我在一个球体(半径为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;
}