java - 从 Euler ZXZ 旋转转换为固定轴 XYZ 旋转

原文 标签 java math rotation trigonometry rotational-matrices

我遇到的问题是,我需要从 XYZ 固定轴旋转转换为围绕 Z 的欧拉旋转,然后是 X',然后是 Z''。

以下是相关矩阵:

X:X

是:Y

Z:Z

结合起来,如 Rz(psi) Ry(phi) Rx(theta) = Rxyz(theta,phi,psi);他们给:

Rxyz:Rxyz

以及我想要的特定欧拉角约定的旋转矩阵;这是:

欧拉:Euler

所以我最初的计划是比较矩阵元素,并以这种方式提取我想要的角度;我想出了这个(最后的实际当前代码):

Code

但这在几种情况下不起作用。最明显的是 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.0000000000000000004) 或其他东西。)

这考虑了围绕 x 和 y 旋转的 4 种情况,其中 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:对于不知道欧拉旋转如何工作的人来说,它是这样的:

Euler Angles Gif

也就是说,先围绕 Z 旋转,然后围绕新的 X 轴 (X') 再围绕新的 Z'' 轴旋转。

最佳答案

我还没有完全弄清楚这一点,但我确实注意到了一件事情:你使用 arccos/arcsin 函数就好像 cos/sin 是双射的一样,只是取它们的倒数。但是,在使用 arccos 时,请考虑 general solutions到弧函数。例如,当 cos y = x ,那么有两个(好吧,无穷多个)解决方案:

  • y = arccos x + 2kPI ,其中 k element Z
  • y = 2PI - arccos x + 2kPI , k 如上

  • k=-1 ,最后一个方程简化为
  • y = -arccos x

  • 所以总共,y = +- arccos x .这基本上归结为 cos轴对称于 x=0 .类似的论点适用于 arcsin ,导致 y = PI - asin x (与 k=0sin y = x 的一般解决方案中)

    这立即适用于您的代码。声明γ = Math.acos(r(c3));以某种方式必须考虑到标志。我在这个问题上挣扎,必须有一个标准来梳理“不正确”的解决方案。

    关于java - 从 Euler ZXZ 旋转转换为固定轴 XYZ 旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9774958/

    相关文章:

    java - Main如何上课?

    algorithm - 旅行商(TSP):与找到的路线的顶点数和长度有什么关系?

    c++ - 绕轴旋转坐标

    java - 旋转图像时背景为黑色

    java - 覆盖类泛型类型

    c# - 单元测试方法的独立性

    java - 获取第一个具有400个以上除数的Triangle号

    c++ - 我的方形 tetrimino 一直在奇怪地旋转,但我的其他 tetrimonos 旋转正常?

    java - 输入流为空

    c++ - 如何从总测量执行时间中删除时钟所花费的时间?