Java 的四元数、欧拉角、轴-角表示、旋转向量之间的相互转化

因为项目需要刚接触的 ARCore,新的方向有很多新的坑,空间中的旋转很是让人头疼,SceneForm 框架提供的 API 其实已经很强大了,还是会有一些漏网的小鱼,没有对应的 API,根据网上的资料和自己的总结,提供以下几个 Java 版本的接口,希望对大家有帮助。

1、四元数转欧拉角
Quaternion(四元数)是 SceneForm 提供且建议使用的表示旋转的方式,四元数可以避免欧拉角方式的万向节死锁。

    /**
     * 四元数转欧拉角
     * @param quaternion 四元数
     * @return 欧拉角
     */
    public Vector3 quaternion2Eular(Quaternion quaternion) {
        double epsilon = 0.0009765625f;
        double threshold = 0.5f - epsilon;
        Vector3 euler = new Vector3();
        double tag = quaternion.w * quaternion.y - quaternion.x * quaternion.z;

        // 奇异姿态,俯仰角为 ±90 度
        if (tag < -threshold || tag > threshold) {
            int sign = sign(tag);
            euler.z = -2 * sign * (float) Math.atan2(quaternion.x, quaternion.w); // yaw
            euler.y = sign * (float)(Math.PI / 2.0); // pitch
            euler.x = 0; // roll

        } else {
            euler.x = (float) Math.atan2(
                    2 * (quaternion.y * quaternion.z + quaternion.w * quaternion.x),
                    quaternion.w * quaternion.w - quaternion.x * quaternion.x - quaternion.y * quaternion.y + quaternion.z * quaternion.z);
            euler.y = (float) Math.asin(-2 * (quaternion.x * quaternion.z - quaternion.w * quaternion.y));
            euler.z = (float) Math.atan2(2 * (quaternion.x * quaternion.y + quaternion.w * quaternion.z),
                    quaternion.w * quaternion.w + quaternion.x * quaternion.x - quaternion.y * quaternion.y - quaternion.z * quaternion.z);
        }

        float scale = (float)( 180 / Math.PI);
        //弧度转换角度
        euler.x = euler.x * scale;
        euler.y = euler.y * scale;
        euler.z = euler.z * scale;
        return euler;
    }

    private int sign(double param) {
        if (param > 0) {
            return 1;
        } else if (param == 0){
            return 0;
        } else {
            return -1;
        }
    }

2、旋转向量转对应的轴-角表示方式
旋转向量表示物体在三维空间的旋转,向量(x,y,z)表示三维空间中旋转的方向,向量的模表示旋转的角度(弧度)。

    public static class AxisAngle {
        Vector3 Axis;
        float angle;
    }

    /**
     *
     * 旋转向量转对应的轴-角表示方式
     * @param rotationVector 旋转向量
     * @return 轴-角
     */
    public AxisAngle rotationVector2AxisAngle(Vector3 rotationVector) {

        //旋转向量的模(弧度)
        float mo = (float) Math.sqrt(
                rotationVector.x * rotationVector.x + rotationVector.y * rotationVector.y + rotationVector.z * rotationVector.z);
        float angle =  (float) (mo * ( 180 / Math.PI));
        //生成轴方向的单位向量
        rotationVector.x = rotationVector.x / mo;
        rotationVector.y = rotationVector.y / mo;
        rotationVector.z = rotationVector.z / mo;

        AxisAngle axisAngle = new AxisAngle();
        axisAngle.Axis = rotationVector;
        axisAngle.angle = angle;
        return axisAngle;
    }

3、将旋转向量转换为对应的四元数

    /**
     *
     * 将旋转向量转换为对应的四元数
     * @param rotationVector 旋转向量
     * @return 四元数
     */
    public Quaternion rotationVector2Quaternion(Vector3 rotationVector) {

        //旋转向量转对应的轴-角表示方式
        AxisAngle axisAngle = rotationVector2AxisAngle(rotationVector);
        if (axisAngle != null) {
            //轴-角表示方式转四元数
            Quaternion qu = Quaternion.axisAngle(axisAngle.Axis, axisAngle.angle);
            return qu;
        }
        return null;
    }
发布了23 篇原创文章 · 获赞 22 · 访问量 3897

猜你喜欢

转载自blog.csdn.net/qq_19154605/article/details/103080176