Vector 由四元数旋转的3D中两个3D向量之间的角度

Vector 由四元数旋转的3D中两个3D向量之间的角度,vector,3d,angle,quaternions,euler-angles,Vector,3d,Angle,Quaternions,Euler Angles,我有一个三维单位四元数={w,x,y,z}来自一个传感器设备。我想得到X,Y和Z轴的角度(ax,ay,az)的数量(但是角度应该是独立的,一个不应该随着另一个的改变而改变)。我遇到了,四元数到欧拉角度转换,它们有万向节锁问题&它们是相互依赖的。 所以我想采取不同的方法 取三维向量x=[1,0,0],y=[0,1,0]和z=[0,0,1]。如果我用四元数旋转这些向量x,y和z,我们得到3个向量xx,yy和zz。然后计算x,xx矢量之间的角度。类似地,y,yy和z,zz之间的角度。这似乎也不起作用。

我有一个三维单位四元数={w,x,y,z}来自一个传感器设备。我想得到X,Y和Z轴的角度(ax,ay,az)的数量(但是角度应该是独立的,一个不应该随着另一个的改变而改变)。我遇到了,四元数欧拉角度转换,它们有万向节锁问题&它们是相互依赖的。 所以我想采取不同的方法

取三维向量x=[1,0,0],y=[0,1,0]和z=[0,0,1]。如果我用四元数旋转这些向量x,y和z,我们得到3个向量xx,yy和zz。然后计算x,xx矢量之间的角度。类似地,y,yy和z,zz之间的角度。这似乎也不起作用。 下面是我写的C代码。角度范围应为-180至180或0至360度acos不是首选,因为它存在精度问题

如何做到这一点?是否有标准方法?如何将三维四元数分解为单个X、Y和Z轴的3个四元数

Vector3D rotVecX = QuatVecRotation(Quaternion, new Vector3D(1,0,0));
Vector3D rotVecY = QuatVecRotation(Quaternion, new Vector3D(0,1,0));
Vector3D rotVecZ = QuatVecRotation(Quaternion, new Vector3D(0,0,1));                
float aX = (float)GetXangle(new Vector3D(1, 0, 0), rotVec1);
float aY = (float)GetYangle(new Vector3D(0, 1, 0), rotVec2);
float aZ = (float)GetZangle(new Vector3D(0, 0, 1), rotVec3); 

Vector3D四元旋转(四元数四元,Vector3D矢量)
{            
四元数Qvec=新的四元数(0,向量X,向量Y,向量Z);
四元数QvecR=四元数乘法(quat,Qvec);
四元数Qinv=新的四元数(四元数W、-四元数X、-四元数Y、-四元数Z);//共轭或逆
四元数Qr=四元数乘法(QvecR,Qinv);
Vector3D结果向量=新的Vector3D(Qr.X,Qr.Y,Qr.Z);
resultVec.Normalize();
返回结果vec;
}
公共双GetXangle(Vector3D vec1、Vector3D vec2)
{            
Vector3D轴=Vector3D.叉积(vec1,vec2);
双角度=Rad2Deg((浮点)数学Atan2(轴长度,向量3D.DotProduct(向量1,向量2));
double dir=Vector3D.DotProduct(Vector3D.CrossProduct(axis,vec1),新的Vector3D(0,1,1));
如果(dir使用点积:

x·xx=|x | xx | cos(角度)

因此:


angle=acos(x·xx/(|x | | | xx |))

如果从四元数获得的欧拉角变大,那么如果它们变小(在两个连续四元数之间),我们将遇到万向节锁问题,那么应该没有问题。我们可以将当前角度添加到之前的角度中,这样就可以使它们处于所需的范围内。

我建议先计算罗德里格斯旋转。这非常简单

考虑到有两个向量ab

旋转轴将由它们的叉积N=axb定义

旋转角度将由其标准化点积定义 cos(θ)=a*b/(|a| | | |b|

要在Rodriguez旋转与其四元数之间转换的公式为

Vector3D QuatVecRotation(Quaternion quat, Vector3D vec)
    {            
        Quaternion Qvec = new Quaternion(0,vec.X,vec.Y,vec.Z);              
        Quaternion QvecR = Quaternion.Multiply(quat, Qvec);
        Quaternion Qinv = new Quaternion( quat.W, -quat.X, -quat.Y, -quat.Z); // conjugate or Inverse
        Quaternion Qr = Quaternion.Multiply(QvecR, Qinv);
        Vector3D resultVec = new Vector3D(Qr.X, Qr.Y, Qr.Z);
        resultVec.Normalize();
        return resultVec;
    }
    public double GetXangle(Vector3D vec1, Vector3D vec2)
    {            
        Vector3D axis = Vector3D.CrossProduct(vec1, vec2);
        double angle = Rad2Deg((float)Math.Atan2(axis.Length, Vector3D.DotProduct(vec1, vec2)));            
        double dir = Vector3D.DotProduct(Vector3D.CrossProduct(axis, vec1), new Vector3D(0, 1, 1));
        if(dir<0)
            angle = angle * Math.Sign(dir);            
        return angle;
    }