wil*_*ill 6 java math trigonometry rotation rotational-matrices
我遇到的问题是,我需要从XYZ固定轴旋转转换为关于Z的欧拉旋转,然后是X',然后是Z''.
以下是相关的矩阵:
X: 
Y: 
Z: 
结合,如Rz(psi)Ry(phi)Rx(theta)= Rxyz(theta,phi,psi); 他们给:
Rxyz: 
和我想要的欧拉角特定惯例的旋转矩阵; 这是:
欧拉: 
所以我最初的计划是比较矩阵元素,并提取我想要的角度; 我想出了这个(最后的实际当前代码):

但这在几种情况下不起作用.当Cos(theta)Cos(phi)== 1时最明显的是; 从那以后,Cos(beta)= 1,因此Sinβ= 0.其中Sin(beta)是代码中的s2.只有当Cos(theta)和cos(phi)= +/- 1时才会发生这种情况.
所以我马上就可以排除可能出现的情况;
当theta或phi = 0,180,360,540,...时,则Cos(θ)和Cos(phi)为+/- 1;
所以我只需要对这些案件做不同的事情;
我最终得到了这段代码:
public static double[] ZXZtoEuler(double ?, double ?, double ?){
? *= Math.PI/180.0;
? *= Math.PI/180.0;
? *= Math.PI/180.0;
double ? = -1;
double ? = -1;
double ? = -1;
double c2 = Math.cos(?) * Math.cos(?);
? = Math.acos(r(c2));
if(eq(c2,1) || eq(c2,-1)){
if(eq(Math.cos(?),1)){
if(eq(Math.cos(?),1)){
? = 0.0;
? = ?;
}else if(eq(Math.cos(?),-1)){
? = 0.0;
? = Math.PI - ?;
}
}else if(eq(Math.cos(?),-1)){
if(eq(Math.cos(?),1)){
? = 0.0;
? = -?;
}else if(eq(Math.cos(?),-1)){
? = 0.0;
? = ? + Math.PI;
}
}
}else{
//original way
double s2 = Math.sin(?);
double c3 = ( Math.sin(?) * Math.cos(?) )/ s2;
double s1 = ( Math.sin(?) * Math.sin(?) + Math.cos(?) * Math.sin(?) * Math.cos(?) )/s2;
? = Math.acos(r(c3));
? = Math.asin(r(s1));
}
? *= 180/Math.PI;
? *= 180/Math.PI;
? *= 180/Math.PI;
return new double[] {r(?), r(?), r(?)};
}
Run Code Online (Sandbox Code Playgroud)
其中r和eq只是两个简单的函数;
public static double r(double a){
double prec = 1000000000.0;
return Math.round(a*prec)/prec;
}
static double thresh = 1E-4;
public static boolean eq(double a, double b){
return (Math.abs(a-b) < thresh);
}
Run Code Online (Sandbox Code Playgroud)
eq只是比较测试的数字,而r是为了防止浮点错误推动数字超出Math.acos/Math.asin的范围并给我NaN结果;
(即偶尔我会以Math.acos(1.000000000000000004)或其他东西结束.)
其中考虑了围绕x和y旋转的4种情况,其中c2 == 1.
但现在问题出现了;
我上面所做的一切对我来说都是有道理的,但它没有给出正确的角度;
这是一些输出,在每对中,第一个是theta phi psi角度,每对中的第二个是相应的alpha beta伽马线.忽略舍入误差,它似乎是通过约一些角度
[0.0, 0.0, 0.0] - correct!
[0.0, 0.0, 0.0]
[0.0, 0.0, 45.0] - correct!
[0.0, 0.0, 45.0]
[0.0, 0.0, 90.0] - correct!
[0.0, 0.0, 90.0]
[0.0, 0.0, 135.0] - correct!
[0.0, 0.0, 135.0]
[0.0, 0.0, 180.0] - correct
[0.0, 0.0, 180.0]
[0.0, 0.0, 225.0] - correct
[0.0, 0.0, 225.0]
[0.0, 0.0, 270.0] - correct
[0.0, 0.0, 270.0]
[0.0, 0.0, 315.0] - correct
[0.0, 0.0, 315.0]
[0.0, 45.0, 0.0] - incorrect: should be [90, 45, -90]
[90.0, 44.999982, 90.0]
[0.0, 45.0, 45.0]
[45.000018, 44.999982, 90.0]
[0.0, 45.0, 90.0]
[0.0, 44.999982, 90.0]
[0.0, 45.0, 135.0]
[-45.000018, 44.999982, 90.0]
[0.0, 45.0, 180.0]
[-90.0, 44.999982, 90.0]
[0.0, 45.0, 225.0]
[-45.000018, 44.999982, 90.0]
[0.0, 45.0, 270.0]
[0.0, 44.999982, 90.0]
[0.0, 45.0, 315.0]
[45.000018, 44.999982, 90.0]
[0.0, 90.0, 0.0]
[90.0, 90.0, 90.0]
[0.0, 90.0, 45.0]
[45.000018, 90.0, 90.0]
[0.0, 90.0, 90.0]
[0.0, 90.0, 90.0]
[0.0, 90.0, 135.0]
[-45.000018, 90.0, 90.0]
[0.0, 90.0, 180.0]
[-90.0, 90.0, 90.0]
[0.0, 90.0, 225.0]
[-45.000018, 90.0, 90.0]
Run Code Online (Sandbox Code Playgroud)
我认为这是由于Math.acos和Math.asin的工作方式,有人能想到一个解决方案吗?
编辑:math.asin和math.acos分别在-pi/2和pi/2以及0和pi之间返回值.这不是含糊不清的,所以我认为问题不在这里.好像我可能在某个地方有数学错误,但我在理论上看不到一个漏洞......
编辑2:对于任何人如何不知道欧拉旋转如何工作,它是这样的:

也就是说,围绕Z旋转,然后绕新的X轴(X')旋转,然后绕新的Z'轴旋转.
我还没有完全弄清楚这一点,但我确实注意到一件事:您使用 arccos/arcsin 函数,就好像 cos/sin 是双射的一样,只是取它们的倒数。但是,在计算 arccos 时,请考虑arc 函数的通解。例如,当 时cos y = x,则有两个(好吧,无限多个)解决方案:
y = arccos x + 2kPI, 在哪里k element Zy = 2PI - arccos x + 2kPI, k 如上有了k=-1,最后一个方程就简化为
y = -arccos x所以总共,y = +- arccos x. cos这本质上可以归结为轴对称于 的事实x=0。类似的论证适用于arcsin,导致y = PI - asin x(k=0在 的通解中sin y = x)
这立即适用于您的代码。该声明\xce\xb3 = Math.acos(r(c3));必须以某种方式考虑到该符号。我在这个问题上挣扎,必须有一个标准来找出“不正确”的解决方案。