是有一个现有的算法用于转换四元表示的一个转到一个欧拉角度表示的?旋转为欧拉表示已知并可以任意的六个排列(即xyz,xzy,yxz,yzx,zxy,z-y-x).我已经看到的算法为固定的旋转了(通常为美国航天局的标题下,银行,滚《公约》),但不是任意转顺序。

此外,由于有多个欧拉角度表示一个单一的方向,这种结果将是不明确的。这是可以接受的(因为取向仍然是 有效的, 它只是可能不是一个用户期望看到),然而它甚至会更好,如果有一个算法,它采取了旋转的限制(即数量度的自由,并限制每个自由的程度)考虑和取得最明智的'欧拉表示鉴于这些制约因素。

我有一种感觉,这个问题(或类似的东西)可能存在的IK或刚体动力学领域。


解决: 我只是意识到它可能不够清楚,我解决了这个问题由以下的肯Shoemake的算法从图形宝石。我没有回答我自己的问题的时候,但是它发生对我来说可能不够清楚,我这样做。看到答案,下面更详细的说明。


只是为了澄清我知道如何将从四元所谓的'泰特-布莱恩'表示什么我打电话的'美国航天局'公约》。这是一个旋转的顺序(假设《公约》中的'Z'轴线上)的zxy.我需要一个算法 所有 旋转的订单。

可能的解决方案,然后,是采取zxy秩序的转换并从中获得其他五个转换为其他转订单。我猜我希望有一个更加总体性'的解决方案。在任何情况下,我很惊讶我还没有能够找到现有的解决方案。

此外,这也许应该是一个单独的问题完全,任何转换(假定已知的旋转秩序的课程)是要去选择 一个 欧拉表示,但实际上有许多。例如,给定一个旋转为yxz,这两个表(0,0,180)和(180,180,0)是相等的(而且会产生相同的四元).有没有一种方法来限制溶液的使用限度的自由吗?像你这样的IK和刚体动力?即在上面的例子,如果只有一个自由度有关Z轴然后第二代表性可以被忽视。


我已经找到了一个文件,这可能是一个算法 这pdf 但我必须承认,我发现的逻辑和数学有点难以遵循。肯定还有其他的解决方案了吗?是任意转为真的如此罕见?当然,每个主要3D包,允许骨骼动画连同四元的插值(即玛雅,马、搅拌器、等等)必须具有完全解决这个问题?

有帮助吗?

解决方案

这看起来像旧技术的经典案例被忽略了 - 我设法从车库中挖掘出一个图形宝石IV的副本,看起来Ken Shoemake不仅有一个算法从随意的欧拉角转换轮换顺序,但也回答了我关于这个主题的大部分其他问题。万岁书籍。如果我能够对Shoemake先生的回答进行投票,并以声望点奖励他。

我想建议任何使用Euler角度的人都应该从他们的本地库中获取Graphics Gems IV的副本并阅读从第222页开始的部分。它必须是我所读过的问题的最清晰,最简洁的解释。


以下是我发现的有用链接 - http://www.cgafaq.info/wiki/Euler_angles_from_matrix - 这与Shoemake的系统相同;旋转顺序的24种不同排列被编码为四个独立的参数 - 内轴,奇偶校验,重复和帧 - 然后允许您将算法从24个减少到2个。可能是一个有用的维基 - 我还没有来之前穿过它。

提供的旧链接似乎已被破坏此处是从旋转矩阵计算欧拉角的另一个副本 "

其他提示

在Z轴向上的右手笛卡尔坐标系中,执行以下操作:

struct Quaternion
{
    double w, x, y, z;
};

void GetEulerAngles(Quaternion q, double& yaw, double& pitch, double& roll)
{
    const double w2 = q.w*q.w;
    const double x2 = q.x*q.x;
    const double y2 = q.y*q.y;
    const double z2 = q.z*q.z;
    const double unitLength = w2 + x2 + y2 + z2;    // Normalised == 1, otherwise correction divisor.
    const double abcd = q.w*q.x + q.y*q.z;
    const double eps = 1e-7;    // TODO: pick from your math lib instead of hardcoding.
    const double pi = 3.14159265358979323846;   // TODO: pick from your math lib instead of hardcoding.
    if (abcd > (0.5-eps)*unitLength)
    {
        yaw = 2 * atan2(q.y, q.w);
        pitch = pi;
        roll = 0;
    }
    else if (abcd < (-0.5+eps)*unitLength)
    {
        yaw = -2 * ::atan2(q.y, q.w);
        pitch = -pi;
        roll = 0;
    }
    else
    {
        const double adbc = q.w*q.z - q.x*q.y;
        const double acbd = q.w*q.y - q.x*q.z;
        yaw = ::atan2(2*adbc, 1 - 2*(z2+x2));
        pitch = ::asin(2*abcd/unitLength);
        roll = ::atan2(2*acbd, 1 - 2*(y2+x2));
    }
}

我一直在寻找类似解决方案的几天,我终于遇到了这个网站,它有一个将四元数转换为任意Euler和Tait-Bryan旋转的算法!

以下链接: http://bediyap.com/programming/convert -quaternion到欧拉 - 转/

这是代码:

///////////////////////////////
// Quaternion to Euler
///////////////////////////////
enum RotSeq{zyx, zyz, zxy, zxz, yxz, yxy, yzx, yzy, xyz, xyx, xzy,xzx};

void twoaxisrot(double r11, double r12, double r21, double r31, double r32, double res[]){
  res[0] = atan2( r11, r12 );
  res[1] = acos ( r21 );
  res[2] = atan2( r31, r32 );
}

void threeaxisrot(double r11, double r12, double r21, double r31, double r32, double res[]){
  res[0] = atan2( r31, r32 );
  res[1] = asin ( r21 );
  res[2] = atan2( r11, r12 );
}

void quaternion2Euler(const Quaternion& q, double res[], RotSeq rotSeq)
{
    switch(rotSeq){
    case zyx:
      threeaxisrot( 2*(q.x*q.y + q.w*q.z),
                     q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                    -2*(q.x*q.z - q.w*q.y),
                     2*(q.y*q.z + q.w*q.x),
                     q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                     res);
      break;

    case zyz:
      twoaxisrot( 2*(q.y*q.z - q.w*q.x),
                   2*(q.x*q.z + q.w*q.y),
                   q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                   2*(q.y*q.z + q.w*q.x),
                  -2*(q.x*q.z - q.w*q.y),
                  res);
      break;

    case zxy:
      threeaxisrot( -2*(q.x*q.y - q.w*q.z),
                      q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                      2*(q.y*q.z + q.w*q.x),
                     -2*(q.x*q.z - q.w*q.y),
                      q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                      res);
      break;

    case zxz:
      twoaxisrot( 2*(q.x*q.z + q.w*q.y),
                  -2*(q.y*q.z - q.w*q.x),
                   q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                   2*(q.x*q.z - q.w*q.y),
                   2*(q.y*q.z + q.w*q.x),
                   res);
      break;

    case yxz:
      threeaxisrot( 2*(q.x*q.z + q.w*q.y),
                     q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                    -2*(q.y*q.z - q.w*q.x),
                     2*(q.x*q.y + q.w*q.z),
                     q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                     res);
      break;

    case yxy:
      twoaxisrot( 2*(q.x*q.y - q.w*q.z),
                   2*(q.y*q.z + q.w*q.x),
                   q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                   2*(q.x*q.y + q.w*q.z),
                  -2*(q.y*q.z - q.w*q.x),
                  res);
      break;

    case yzx:
      threeaxisrot( -2*(q.x*q.z - q.w*q.y),
                      q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                      2*(q.x*q.y + q.w*q.z),
                     -2*(q.y*q.z - q.w*q.x),
                      q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                      res);
      break;

    case yzy:
      twoaxisrot( 2*(q.y*q.z + q.w*q.x),
                  -2*(q.x*q.y - q.w*q.z),
                   q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                   2*(q.y*q.z - q.w*q.x),
                   2*(q.x*q.y + q.w*q.z),
                   res);
      break;

    case xyz:
      threeaxisrot( -2*(q.y*q.z - q.w*q.x),
                    q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                    2*(q.x*q.z + q.w*q.y),
                   -2*(q.x*q.y - q.w*q.z),
                    q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                    res);
      break;

    case xyx:
      twoaxisrot( 2*(q.x*q.y + q.w*q.z),
                  -2*(q.x*q.z - q.w*q.y),
                   q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                   2*(q.x*q.y - q.w*q.z),
                   2*(q.x*q.z + q.w*q.y),
                   res);
      break;

    case xzy:
      threeaxisrot( 2*(q.y*q.z + q.w*q.x),
                     q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                    -2*(q.x*q.y - q.w*q.z),
                     2*(q.x*q.z + q.w*q.y),
                     q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                     res);
      break;

    case xzx:
      twoaxisrot( 2*(q.x*q.z - q.w*q.y),
                   2*(q.x*q.y + q.w*q.z),
                   q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                   2*(q.x*q.z + q.w*q.y),
                  -2*(q.x*q.y - q.w*q.z),
                  res);
      break;
    default:
      std::cout << "Unknown rotation sequence" << std::endl;
      break;
   }
}

我已经发表了题为“使用几何方法对任意旋转序列进行欧拉角转换的四元数”的论文。在我的网站noelhughes.net上。我也有算法将任何一组欧拉角转换为四元数和四元数到/从方向余弦矩阵转换,我将在本周末发布。这些也在Martin Bakers网站上,虽然有点难以找到。 Google我的名字,Noel Hughes和四元数,你应该找到它。

我这样解决:

第1步:确定您想要的Euler旋转的约定,例如 zyx

第2步:计算旋转的分析旋转矩阵。 例如,如果您想要R( zyx ),

** R *** zyx * = ** R *** x *( phi )* ** R *** y *( theta )* ** R *** z *( psi ),元素变为

R11 =  cos(theta)*cos(psi)
R12 = -cos(theta)*sin(psi)
R13 =  sin(theta)
R21 =  sin(psi)*cos(phi) + sin(theta)*cos(psi)*sin(phi)
R22 =  cos(psi)*cos(phi) - sin(theta)*sin(psi)*sin(phi)
R23 = -cos(theta)*sin(phi)
R31 =  sin(psi)*sin(phi) - sin(theta)*cos(psi)*cos(phi)
R32 =  cos(psi)sin(phi) + sin(theta)*sin(psi)*cos(phi)
R33 =  cos(theta)*cos(phi) 

第3步:通过检查,您可以使用上述元素找到三个角度的sin或tan。在这个例子中,

tan(phi) = -R23/R33

sin(theta) = -R13

tan(psi) = -R12/R11

第4步:计算四元数中的旋转矩阵(参见维基百科),用于计算上述角度所需的元素。

可以使用相同的程序计算其他约定。

这是我写的关于将四元数转换为欧拉角的论文。

Link 1

我还在这个位置放了一些文件,讨论了四元数,欧拉角和旋转矩阵(DCM)的各个方面。

Link 2

对那些偶然发现这一页,同时搜索,我最近找到的衍生于这些转换所有12个内在泰特-布莱恩(1-2-3,3-2-1,等等。) 和适当的欧拉(1-2-1的,3-1-3,等等。) 旋转序列在下面的两个参考文献:

谢谢来 frodo2975 第二链接。

维基百科展示了如何使用四元数的各个部分并计算欧拉角。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top