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;
    }
發佈了28 篇原創文章 · 獲贊 27 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章