mischief-math-0.1.0.0: src/Mischief/Math/Quat.hs
module Mischief.Math.Quat where
import Data.Default (Default (def))
import Linear (M33, Quaternion (Quaternion), V3 (V3), axisAngle, fromQuaternion)
import Mischief.Math.Vec (Dir3 (Dir3))
import Mischief.Math.Vec.Orphans.FieldAccessors ()
newtype Quat = Quat (Quaternion Float) deriving newtype (Show, Eq, Ord, Num)
instance Default Quat where
def = identity
identity :: Quat
identity = Quat $ Quaternion 1 $ V3 0 0 0
fromAxisAngle :: Dir3 Float -> Float -> Quat
fromAxisAngle (Dir3 dir) angle = Quat $ axisAngle dir angle
fromXYZW :: (Float, Float, Float, Float) -> Quat
fromXYZW (x, y, z, w) = Quat $ Quaternion w (V3 x y z)
fromRotationX :: Float -> Quat
fromRotationX angle =
let (s, c) = (sin angle, cos angle)
in fromXYZW (s, 0, 0, c)
fromRotationY :: Float -> Quat
fromRotationY angle =
let (s, c) = (sin angle, cos angle)
in fromXYZW (0, s, 0, c)
fromRotationZ :: Float -> Quat
fromRotationZ angle =
let (s, c) = (sin angle, cos angle)
in fromXYZW (0, 0, s, c)
fromAngles :: V3 Float -> Quat
fromAngles vec3 = rotateX vec3.x $ rotateY vec3.y $ rotateZ vec3.z identity
fromEuler :: Euler -> Quat
fromEuler Euler {x, y, z} = fromAngles $ V3 x y z
rotateAxis :: Dir3 Float -> Float -> Quat -> Quat
rotateAxis dir angle quat = quat * fromAxisAngle dir angle
rotateX :: Float -> Quat -> Quat
rotateX angle quat = quat * fromRotationX angle
rotateY :: Float -> Quat -> Quat
rotateY angle quat = quat * fromRotationY angle
rotateZ :: Float -> Quat -> Quat
rotateZ angle quat = quat * fromRotationZ angle
toMat3 :: Quat -> M33 Float
toMat3 (Quat quat) = fromQuaternion quat
toEuler :: Quat -> Euler
toEuler = m33ToEuler . toMat3
data Euler = Euler {x :: Float, y :: Float, z :: Float} deriving (Show, Eq)
m33ToEuler :: M33 Float -> Euler
m33ToEuler (V3 (V3 m11 m12 m13) (V3 _ _ m23) (V3 _ _ m33)) =
Euler {x = atan2 (-m23) m33 * 0.5, y = asin m13 * 0.5, z = atan2 (-m12) m11 * 0.5}