All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.bixilon.kotlinglm.gtc.gtc_Quaternion.kt Maven / Gradle / Ivy

There is a newer version: 0.9.9.1-12
Show newest version
package de.bixilon.kotlinglm.gtc

import de.bixilon.kotlinglm.detail.GLM_COORDINATE_SYSTEM
import de.bixilon.kotlinglm.detail.GlmCoordinateSystem
import de.bixilon.kotlinglm.GLM.sqrt
import de.bixilon.kotlinglm.mat3x3.Mat3
import de.bixilon.kotlinglm.mat3x3.Mat3d
import de.bixilon.kotlinglm.mat4x4.Mat4
import de.bixilon.kotlinglm.mat4x4.Mat4d
import de.bixilon.kotlinglm.quaternion.Quat
import de.bixilon.kotlinglm.quaternion.QuatD
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.kotlinglm.vec3.Vec3d
import de.bixilon.kotlinglm.vec4.Vec4bool

/**
 * Created by GBarbieri on 14.12.2016.
 */

interface gtc_Quaternion {


    /** Converts a quaternion to a 3 * 3 matrix.    */
    fun mat3_cast(q: Quat, res: Mat3): Mat3 {

        val qxx = q.x * q.x
        val qyy = q.y * q.y
        val qzz = q.z * q.z
        val qxz = q.x * q.z
        val qxy = q.x * q.y
        val qyz = q.y * q.z
        val qwx = q.w * q.x
        val qwy = q.w * q.y
        val qwz = q.w * q.z

        res[0, 0] = 1f - 2f * (qyy + qzz)
        res[0, 1] = 2f * (qxy + qwz)
        res[0, 2] = 2f * (qxz - qwy)

        res[1, 0] = 2f * (qxy - qwz)
        res[1, 1] = 1f - 2f * (qxx + qzz)
        res[1, 2] = 2f * (qyz + qwx)

        res[2, 0] = 2f * (qxz + qwy)
        res[2, 1] = 2f * (qyz - qwx)
        res[2, 2] = 1f - 2f * (qxx + qyy)

        return res
    }

    fun mat3_cast(q: Quat) = mat3_cast(q, Mat3())

    /** Converts a quaternion to a 3 * 3 matrix.    */
    fun mat3d_cast(q: QuatD, m: Mat3): Mat3 {

        TODO()
//        val qxx = q.x * q.x
//        val qyy = q.y * q.y
//        val qzz = q.z * q.z
//        val qxz = q.x * q.z
//        val qxy = q.x * q.y
//        val qyz = q.y * q.z
//        val qwx = q.w * q.x
//        val qwy = q.w * q.y
//        val qwz = q.w * q.z
//
//        res[0, 0] = 1f - 2f * (qyy + qzz)
//        res[0, 1] = 2f * (qxy + qwz)
//        res[0, 2] = 2f * (qxz - qwy)
//
//        res[1, 0] = 2f * (qxy - qwz)
//        res[1, 1] = 1f - 2f * (qxx + qzz)
//        res[1, 2] = 2f * (qyz + qwx)
//
//        res[2, 0] = 2f * (qxz + qwy)
//        res[2, 1] = 2f * (qyz - qwx)
//        res[2, 2] = 1f - 2f * (qxx + qyy)
//
//        return res
    }

    /** Converts a quaternion to a 4 * 4 matrix.    */
    fun mat4_cast(q: Quat, res: Mat4): Mat4 {

        val qxx = q.x * q.x
        val qyy = q.y * q.y
        val qzz = q.z * q.z
        val qxz = q.x * q.z
        val qxy = q.x * q.y
        val qyz = q.y * q.z
        val qwx = q.w * q.x
        val qwy = q.w * q.y
        val qwz = q.w * q.z

        res[0, 0] = 1f - 2f * (qyy + qzz)
        res[0, 1] = 2f * (qxy + qwz)
        res[0, 2] = 2f * (qxz - qwy)

        res[1, 0] = 2f * (qxy - qwz)
        res[1, 1] = 1f - 2f * (qxx + qzz)
        res[1, 2] = 2f * (qyz + qwx)

        res[2, 0] = 2f * (qxz + qwy)
        res[2, 1] = 2f * (qyz - qwx)
        res[2, 2] = 1f - 2f * (qxx + qyy)

        return res
    }

    fun mat4_cast(q: Quat) = mat4_cast(q, Mat4())


    fun mat4d_cast(res: Mat4, q: QuatD): Mat4 = TODO()


    /** Converts a pure rotation 3 * 3 matrix to a quaternion.    */
    fun quat_cast(m: Mat3, res: Quat): Quat =
            quat_cast(m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2], res)

    fun quatD_cast(m: Mat3d, res: QuatD): QuatD =
            quatD_cast(m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2], res)

    fun quat_cast(m: Mat3): Quat =
            quat_cast(m, Quat())

    fun quatD_cast(m: Mat3d): QuatD =
            quatD_cast(m, QuatD())

    /** Converts a pure rotation 4 * 4 matrix to a quaternion.    */
    fun quat_cast(m: Mat4, res: Quat): Quat =
            quat_cast(m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2], res)

    fun quatD_cast(m: Mat4d, res: QuatD): QuatD =
            quatD_cast(m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2], res)

    fun quat_cast(m: Mat4): Quat =
            quat_cast(m, Quat())

    fun quatD_cast(m: Mat4d): QuatD =
            quatD_cast(m, QuatD())


    fun quat_cast(
            m00: Float, m01: Float, m02: Float,
            m10: Float, m11: Float, m12: Float,
            m20: Float, m21: Float, m22: Float,
            res: Quat): Quat {

        val fourXSquaredMinus1 = m00 - m11 - m22
        val fourYSquaredMinus1 = m11 - m00 - m22
        val fourZSquaredMinus1 = m22 - m00 - m11
        val fourWSquaredMinus1 = m00 + m11 + m22

        var biggestIndex = 0
        var fourBiggestSquaredMinus1 = fourWSquaredMinus1
        if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) {
            fourBiggestSquaredMinus1 = fourXSquaredMinus1
            biggestIndex = 1
        }
        if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) {
            fourBiggestSquaredMinus1 = fourYSquaredMinus1
            biggestIndex = 2
        }
        if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) {
            fourBiggestSquaredMinus1 = fourZSquaredMinus1
            biggestIndex = 3
        }

        val biggestVal = sqrt(fourBiggestSquaredMinus1 + 1f) * 0.5f
        val mult = 0.25f / biggestVal

        return when (biggestIndex) {
            0 -> res.put(biggestVal, (m12 - m21) * mult, (m20 - m02) * mult, (m01 - m10) * mult)
            1 -> res.put((m12 - m21) * mult, biggestVal, (m01 + m10) * mult, (m20 + m02) * mult)
            2 -> res.put((m20 - m02) * mult, (m01 + m10) * mult, biggestVal, (m12 + m21) * mult)
            3 -> res.put((m01 - m10) * mult, (m20 + m02) * mult, (m12 + m21) * mult, biggestVal)
            // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity.
            else -> {
                assert(false)
                res.put(1f, 0f, 0f, 0f)
            }
        }
    }

    fun quat_cast(
            m00: Float, m01: Float, m02: Float,
            m10: Float, m11: Float, m12: Float,
            m20: Float, m21: Float, m22: Float) = quat_cast(m00, m01, m02, m10, m11, m12, m20, m21, m22, Quat())


    fun quatD_cast(
            m00: Double, m01: Double, m02: Double,
            m10: Double, m11: Double, m12: Double,
            m20: Double, m21: Double, m22: Double,
            res: QuatD): QuatD {

        val fourXSquaredMinus1 = m00 - m11 - m22
        val fourYSquaredMinus1 = m11 - m00 - m22
        val fourZSquaredMinus1 = m22 - m00 - m11
        val fourWSquaredMinus1 = m00 + m11 + m22

        var biggestIndex = 0
        var fourBiggestSquaredMinus1 = fourWSquaredMinus1
        if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) {
            fourBiggestSquaredMinus1 = fourXSquaredMinus1
            biggestIndex = 1
        }
        if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) {
            fourBiggestSquaredMinus1 = fourYSquaredMinus1
            biggestIndex = 2
        }
        if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) {
            fourBiggestSquaredMinus1 = fourZSquaredMinus1
            biggestIndex = 3
        }

        val biggestVal = sqrt(fourBiggestSquaredMinus1 + 1.0) * 0.5
        val mult = 0.25 / biggestVal

        when (biggestIndex) {
            0 -> {
                res.w = biggestVal
                res.x = (m12 - m21) * mult
                res.y = (m20 - m02) * mult
                res.z = (m01 - m10) * mult
            }
            1 -> {
                res.w = (m12 - m21) * mult
                res.x = biggestVal
                res.y = (m01 + m10) * mult
                res.z = (m20 + m02) * mult
            }
            2 -> {
                res.w = (m20 - m02) * mult
                res.x = (m01 + m10) * mult
                res.y = biggestVal
                res.z = (m12 + m21) * mult
            }
            3 -> {
                res.w = (m01 - m10) * mult
                res.x = (m20 + m02) * mult
                res.y = (m12 + m21) * mult
                res.z = biggestVal
            }

            // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity.
            else -> assert(false)
        }
        return res
    }

    fun quatD_cast(
            m00: Double, m01: Double, m02: Double,
            m10: Double, m11: Double, m12: Double,
            m20: Double, m21: Double, m22: Double) = quatD_cast(m00, m01, m02, m10, m11, m12, m20, m21, m22, QuatD())


    //TODO move res in front, default arg on classes
    /** Returns the component-wise comparison result of x < y.  */
    fun lessThan(a: Quat, b: Quat, res: Vec4bool): Vec4bool {
        res.x = a.x < b.x
        res.y = a.y < b.y
        res.z = a.z < b.z
        res.w = a.w < b.w
        return res
    }

    fun lessThan(a: Quat, b: Quat) = lessThan(a, b, Vec4bool())

    /** Returns the component-wise comparison result of x <= y.  */
    fun lessThanEqual(a: Quat, b: Quat, res: Vec4bool): Vec4bool {
        res.x = a.x <= b.x
        res.y = a.y <= b.y
        res.z = a.z <= b.z
        res.w = a.w <= b.w
        return res
    }

    fun lessThanEqual(a: Quat, b: Quat) = lessThanEqual(a, b, Vec4bool())

    /** Returns the component-wise comparison result of x > y.  */
    fun greater(a: Quat, b: Quat, res: Vec4bool): Vec4bool {
        res.x = a.x > b.x
        res.y = a.y > b.y
        res.z = a.z > b.z
        res.w = a.w > b.w
        return res
    }

    fun greater(a: Quat, b: Quat) = greater(a, b, Vec4bool())

    /** Returns the component-wise comparison result of x >= y.  */
    fun greaterThan(a: Quat, b: Quat, res: Vec4bool): Vec4bool {
        res.x = a.x >= b.x
        res.y = a.y >= b.y
        res.z = a.z >= b.z
        res.w = a.w >= b.w
        return res
    }

    fun greaterThan(a: Quat, b: Quat) = greaterThan(a, b, Vec4bool())


    /** Returns the component-wise comparison of result x == y. */
    fun equal(a: Quat, b: Quat, res: Vec4bool): Vec4bool {
        res.x = a.x.equals(b.x)// TODO https://youtrack.jetbrains.com/issue/KT-48648
        res.y = a.y.equals(b.y)
        res.z = a.z.equals(b.z)
        res.w = a.w.equals(b.w)
        return res
    }

    fun equal(a: Quat, b: Quat) = equal(a, b, Vec4bool())


    /** Returns the component-wise comparison of result x != y. */
    fun notEqual(a: Quat, b: Quat, res: Vec4bool): Vec4bool {
        res.x = !a.x.equals(b.x)// TODO https://youtrack.jetbrains.com/issue/KT-48648
        res.y = !a.y.equals(b.y)
        res.z = !a.z.equals(b.z)
        res.w = !a.w.equals(b.w)
        return res
    }

    fun notEqual(a: Quat, b: Quat) = notEqual(a, b, Vec4bool())


    /** Returns true if x holds a NaN (not a number).   */
    fun isNan(q: Quat, res: Vec4bool): Vec4bool {
        res.x = q.x.isNaN()
        res.y = q.y.isNaN()
        res.z = q.z.isNaN()
        res.w = q.w.isNaN()
        return res
    }

    fun isNan(q: Quat) = isNan(q, Vec4bool())


    /** Returns true if x holds a positive infinity main.or negative infinity.   */
    fun isInf(q: Quat, res: Vec4bool): Vec4bool {
        res.x = q.x.isInfinite()
        res.y = q.y.isInfinite()
        res.z = q.z.isInfinite()
        res.w = q.w.isInfinite()
        return res
    }

    fun isInf(q: Quat) = isInf(q, Vec4bool())


    /** Build a look at quaternion based on the default handedness.
     *  @param direction Desired forward direction. Needs to be normalized.
     *  @param up Up vector, how the camera is oriented. Typically (0, 1, 0). */
    fun quatLookAt(direction: Vec3, up: Vec3): Quat = when (GLM_COORDINATE_SYSTEM) {
        GlmCoordinateSystem.LEFT_HANDED -> quatLookAtLH(direction, up)
        else -> quatLookAtRH(direction, up)
    }

    /** Build a right-handed look at quaternion.
     *  @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized.
     *  @param up Up vector, how the camera is oriented. Typically (0, 1, 0).   */
    fun quatLookAtRH(direction: Vec3, up: Vec3): Quat {
        val result = Mat3()

        result[2] = -direction
        result[0] = (up cross result[2]).normalizeAssign()
        result[1] = result[2] cross result[0]

        return result.toQuat()
    }

    /** Build a left-handed look at quaternion.
     *  @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized.
     *  @param up Up vector, how the camera is oriented. Typically (0, 1, 0). */
    fun quatLookAtLH(direction: Vec3, up: Vec3): Quat {
        val result = Mat3()

        result[2] = direction
        result[0] = (up cross result[2]).normalizeAssign()
        result[1] = result[2] cross result[0]

        return result.toQuat()
    }

    // ------------------------------ QuatD ------------------------------

    /** Build a look at quaternion based on the default handedness.
     *  @param direction Desired forward direction. Needs to be normalized.
     *  @param up Up vector, how the camera is oriented. Typically (0, 1, 0). */
    fun quatLookAt(direction: Vec3d, up: Vec3d): QuatD = when (GLM_COORDINATE_SYSTEM) {
        GlmCoordinateSystem.LEFT_HANDED -> quatLookAtLH(direction, up)
        else -> quatLookAtRH(direction, up)
    }

    /** Build a right-handed look at quaternion.
     *  @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized.
     *  @param up Up vector, how the camera is oriented. Typically (0, 1, 0).   */
    fun quatLookAtRH(direction: Vec3d, up: Vec3d): QuatD {
        val result = Mat3d()

        result[2] = -direction
        result[0] = (up cross result[2]).normalizeAssign()
        result[1] = result[2] cross result[0]

        return result.toQuatD()
    }

    /** Build a left-handed look at quaternion.
     *  @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized.
     *  @param up Up vector, how the camera is oriented. Typically (0, 1, 0). */
    fun quatLookAtLH(direction: Vec3d, up: Vec3d): QuatD {
        val result = Mat3d()

        result[2] = direction
        result[0] = (up cross result[2]).normalizeAssign()
        result[1] = result[2] cross result[0]

        return result.toQuatD()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy