packages feed

mini-1.6.4.0: src/Mini/Linear/Transform3D.hs

-- | Affine transform matrices for three-dimensional Euclidean space
module Mini.Linear.Transform3D (
  -- * Translation
  translate,

  -- * Scaling
  scale,

  -- * Shearing
  shearByX,
  shearByY,
  shearByZ,

  -- * Rotation
  yaw,
  pitch,
  roll,
  euler,
) where

import Mini.Linear.Matrix (
  diagonal,
  identity,
 )
import Mini.Linear.Space (
  V3 (V3),
  V4,
  w,
  x,
  xyz,
  y,
  z,
 )
import Mini.Optics.Lens (
  set,
 )
import Prelude (
  Floating,
  Num,
  cos,
  negate,
  sin,
  ($),
  (*),
  (+),
  (-),
  (.),
 )

-- Translation

-- | Translate each dimension by the corresponding components of a vector
translate :: (Num a) => V3 a -> V4 (V4 a)
translate v = set (w . xyz) v identity

-- Scaling

-- | Scale each dimension by the corresponding components of a vector
scale :: (Num a) => V3 a -> V4 (V4 a)
scale v = set (diagonal . xyz) v identity

-- Shearing

-- | Shear each dimension w.r.t. /x/ by the corresponding components of a vector
shearByX :: (Num a) => V3 a -> V4 (V4 a)
shearByX v = set (x . xyz) v identity

-- | Shear each dimension w.r.t. /y/ by the corresponding components of a vector
shearByY :: (Num a) => V3 a -> V4 (V4 a)
shearByY v = set (y . xyz) v identity

-- | Shear each dimension w.r.t. /z/ by the corresponding components of a vector
shearByZ :: (Num a) => V3 a -> V4 (V4 a)
shearByZ v = set (z . xyz) v identity

-- Rotation

-- | Rotate a number of radians around the /y/-axis
yaw :: (Floating a) => a -> V4 (V4 a)
yaw phi =
  set (x . x) (cos phi)
    . set (x . z) (negate $ sin phi)
    . set (z . x) (sin phi)
    . set (z . z) (cos phi)
    $ identity

-- | Rotate a number of radians around the /x/-axis
pitch :: (Floating a) => a -> V4 (V4 a)
pitch phi =
  set (y . y) (cos phi)
    . set (y . z) (sin phi)
    . set (z . y) (negate $ sin phi)
    . set (z . z) (cos phi)
    $ identity

-- | Rotate a number of radians around the /z/-axis
roll :: (Floating a) => a -> V4 (V4 a)
roll phi =
  set (x . x) (cos phi)
    . set (x . y) (sin phi)
    . set (y . x) (negate $ sin phi)
    . set (y . y) (cos phi)
    $ identity

-- | Rotate in order of 'yaw', 'pitch', 'roll' (/y, x, z/)
euler :: (Floating a) => V3 a -> V4 (V4 a)
euler (V3 p h r) =
  set (x . x) (cos r * cos h - sin r * sin p * sin h)
    . set (x . y) (sin r * cos h + cos r * sin p * sin h)
    . set (x . z) (negate $ cos p * sin h)
    . set (y . x) (negate $ sin r * cos p)
    . set (y . y) (cos r * cos p)
    . set (y . z) (sin p)
    . set (z . x) (cos r * sin h + sin r * sin p * cos h)
    . set (z . y) (sin r * sin h - cos r * sin p * cos h)
    . set (z . z) (cos p * cos h)
    $ identity