- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我遇到的问题是,我需要将 XYZ 固定轴旋转转换为关于 Z 的欧拉旋转,然后是 X',然后是 Z''。
这里是相关的矩阵:
X:
是:
Z:
结合起来,作为 Rz(psi) Ry(phi) Rx(theta) = Rxyz(theta,phi,psi);他们给予:
Rxyz:
以及我想要的特定欧拉角约定的旋转矩阵;这是:
欧拉:
所以我最初的计划是比较矩阵元素,然后提取我想要的角度;我想出了这个(最后的实际当前代码):
但这在某些情况下不起作用。最明显的是当 Cos(theta)Cos(phi) == 1 时;从那时起 Cos(beta) = 1,因此 Sin[beta] = 0。代码中 Sin(beta) 是 s2。这仅在 Cos(theta) 和 cos(phi) = +/- 1 时发生。
所以我可以马上排除可能的情况;
当 theta 或 phi = 0, 180, 360, 540, ... 时,则 Cos(theta) 和 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(γ)};
}
其中 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);
}
eq 只是为了比较测试的数字,r 是为了防止浮点错误将数字推到 Math.acos/Math.asin 的范围之外并给我 NaN 结果;
(即时不时地我会以 Math.acos(1.000000000000000004) 或其他东西结束。)
其中考虑了 4 种围绕 x 和 y 旋转且 c2==1 的情况。
但是现在就是问题所在了;
我上面所做的一切对我来说都很有意义,但它没有给出正确的角度;
这是一些输出,在每一对中,第一对是 theta phi psi 角,每对的第二对是相应的 alpha beta gamma 线。忽略舍入误差,它似乎让一些角度偏离了大约
[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]
我认为这是由于 Math.acos 和 Math.asin 的工作方式所致,有人能想出解决方案吗?
编辑:math.asin 和 math.acos 分别返回 -pi/2 和 pi/2 以及 0 和 pi 之间的值。这不是模棱两可的,所以我认为问题不在这里。好像我可能在某个地方有数学错误,但我看不出我的推理有漏洞......
EDIT2:对于任何不知道欧拉旋转如何工作的人来说,它是这样的:
也就是说,绕Z旋转,然后绕新的X轴(X')然后绕新的Z' ' 轴。
最佳答案
我还没有完全弄清楚这一点,但我确实注意到一件事:你使用 arccos/arcsin 函数就好像 cos/sin 是双射的,只是取它们的倒数。但是,在使用 arccos 时,请考虑 general solutions到弧函数。例如,当 cos y = x
时,有两种(好吧,无限多)解:
y = arccos x + 2kPI
,其中 k 元素 Z
y = 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
)
这立即适用于您的代码。语句 γ = Math.acos(r(c3));
必须以某种方式考虑符号。我对此很纠结,必须有一个标准来找出“不正确”的解决方案。
关于java - 从 Euler ZXZ 旋转转换为固定轴 XYZ 旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9774958/
我遇到的问题是,我需要将 XYZ 固定轴旋转转换为关于 Z 的欧拉旋转,然后是 X',然后是 Z''。 这里是相关的矩阵: X: 是: Z: 结合起来,作为 Rz(psi) Ry(phi) Rx(th
我是一名优秀的程序员,十分优秀!