packages feed

geomancy-0.4.0.0: test/Support/Reference/Mat4.hs

{-# LANGUAGE RecordWildCards #-}

module Support.Reference.Mat4
  ( rowMajor
  , colMajor
  , identity
  , compose
  , apply
  , det
  , inverse
  ) where

import Data.Foldable (toList)
import Linear (M44, V4(..), transpose)

import Support.Ball (Ball, sumAnyOrder)

rowMajor
  :: a -> a -> a -> a
  -> a -> a -> a -> a
  -> a -> a -> a -> a
  -> a -> a -> a -> a
  -> M44 a
rowMajor
  m00 m01 m02 m03
  m10 m11 m12 m13
  m20 m21 m22 m23
  m30 m31 m32 m33 =
    V4
      (V4 m00 m01 m02 m03)
      (V4 m10 m11 m12 m13)
      (V4 m20 m21 m22 m23)
      (V4 m30 m31 m32 m33)

colMajor
  :: a -> a -> a -> a
  -> a -> a -> a -> a
  -> a -> a -> a -> a
  -> a -> a -> a -> a
  -> M44 a
colMajor
  m00 m01 m02 m03
  m10 m11 m12 m13
  m20 m21 m22 m23
  m30 m31 m32 m33 =
    transpose $ rowMajor
      m00 m01 m02 m03
      m10 m11 m12 m13
      m20 m21 m22 m23
      m30 m31 m32 m33

identity :: Num a => M44 a
identity = rowMajor
  1 0 0 0
  0 1 0 0
  0 0 1 0
  0 0 0 1

compose :: RealFloat p => M44 (Ball p) -> M44 (Ball p) -> M44 (Ball p)
compose a b = fmap (\row -> fmap (dotAnyOrder row) (transpose a)) b

apply :: RealFloat p => M44 (Ball p) -> V4 (Ball p) -> V4 (Ball p)
apply m v = fmap (dotAnyOrder v) (transpose m)

dotAnyOrder :: RealFloat p => V4 (Ball p) -> V4 (Ball p) -> Ball p
dotAnyOrder a b = sumAnyOrder $ zipWith (*) (toList a) (toList b)

det :: Num a => M44 a -> a
det m =
    s0 * c5
  - s1 * c4
  + s2 * c3
  + s3 * c2
  - s4 * c1
  + s5 * c0
  where
    Cofactors{..} = cofactors m

inverse :: Fractional a => M44 a -> M44 a
inverse m@(V4
  (V4 m00 m01 m02 m03)
  (V4 m10 m11 m12 m13)
  (V4 m20 m21 m22 m23)
  (V4 m30 m31 m32 m33)) =
    rowMajor
      i00 i01 i02 i03
      i10 i11 i12 i13
      i20 i21 i22 i23
      i30 i31 i32 i33
  where
    Cofactors{..} = cofactors m

    invDet = recip (det m)

    i00 = ( m11 * c5 - m12 * c4 + m13 * c3) * invDet
    i01 = (-m01 * c5 + m02 * c4 - m03 * c3) * invDet
    i02 = ( m31 * s5 - m32 * s4 + m33 * s3) * invDet
    i03 = (-m21 * s5 + m22 * s4 - m23 * s3) * invDet

    i10 = (-m10 * c5 + m12 * c2 - m13 * c1) * invDet
    i11 = ( m00 * c5 - m02 * c2 + m03 * c1) * invDet
    i12 = (-m30 * s5 + m32 * s2 - m33 * s1) * invDet
    i13 = ( m20 * s5 - m22 * s2 + m23 * s1) * invDet

    i20 = ( m10 * c4 - m11 * c2 + m13 * c0) * invDet
    i21 = (-m00 * c4 + m01 * c2 - m03 * c0) * invDet
    i22 = ( m30 * s4 - m31 * s2 + m33 * s0) * invDet
    i23 = (-m20 * s4 + m21 * s2 - m23 * s0) * invDet

    i30 = (-m10 * c3 + m11 * c1 - m12 * c0) * invDet
    i31 = ( m00 * c3 - m01 * c1 + m02 * c0) * invDet
    i32 = (-m30 * s3 + m31 * s1 - m32 * s0) * invDet
    i33 = ( m20 * s3 - m21 * s1 + m22 * s0) * invDet

data Cofactors a = Cofactors
  { s0, s1, s2, s3, s4, s5 :: a
  , c0, c1, c2, c3, c4, c5 :: a
  }

cofactors :: Num a => M44 a -> Cofactors a
cofactors (V4
  (V4 m00 m01 m02 m03)
  (V4 m10 m11 m12 m13)
  (V4 m20 m21 m22 m23)
  (V4 m30 m31 m32 m33)) =
    Cofactors
      { s0 = m00 * m11 - m10 * m01
      , s1 = m00 * m12 - m10 * m02
      , s2 = m00 * m13 - m10 * m03
      , s3 = m01 * m12 - m11 * m02
      , s4 = m01 * m13 - m11 * m03
      , s5 = m02 * m13 - m12 * m03

      , c5 = m22 * m33 - m32 * m23
      , c4 = m21 * m33 - m31 * m23
      , c3 = m21 * m32 - m31 * m22
      , c2 = m20 * m33 - m30 * m23
      , c1 = m20 * m32 - m30 * m22
      , c0 = m20 * m31 - m30 * m21
      }