{-# LANGUAGE CPP #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Algebra.Quaternion where
import safe Data.Algebra
import safe Data.Distributive
import safe Data.Fixed
import safe Data.Functor.Rep
import safe Data.Semifield
import safe Data.Semigroup.Foldable
import safe Data.Semimodule
import safe Data.Semimodule.Vector
import safe Data.Semiring
import safe GHC.Generics hiding (Rep)
import safe Prelude hiding (Num(..), Fractional(..), sum, product)
type QuatF = Quaternion Float
type QuatD = Quaternion Double
type QuatR = Quaternion Rational
type QuatM = Quaternion Micro
type QuatN = Quaternion Nano
type QuatP = Quaternion Pico
data Quaternion a = Quaternion !a {-# UNPACK #-}! (V3 a) deriving (Eq, Ord, Show, Generic, Generic1)
quat :: a -> a -> a -> a -> Quaternion a
quat r x y z = Quaternion r (V3 x y z)
scal :: Quaternion a -> a
scal (Quaternion r _) = r
vect :: Quaternion a -> V3 a
vect (Quaternion _ v) = v
rotate :: Ring a => Quaternion a -> V3 a -> V3 a
rotate q v = v' where Quaternion _ v' = q * Quaternion zero v * conj q
normalize :: QuatD -> QuatD
normalize q = 1.0 / (sqrt $ norm q) *. q
qe :: Semiring a => Quaternion a
qe = idx Nothing
qi :: Semiring a => Quaternion a
qi = idx (Just I31)
qj :: Semiring a => Quaternion a
qj = idx (Just I32)
qk :: Semiring a => Quaternion a
qk = idx (Just I33)
instance (Additive-Semigroup) a => Semigroup (Quaternion a) where
(<>) = mzipWithRep (+)
instance (Additive-Monoid) a => Monoid (Quaternion a) where
mempty = pureRep zero
instance (Additive-Group) a => Magma (Quaternion a) where
(<<) = mzipWithRep (-)
instance (Additive-Group) a => Quasigroup (Quaternion a)
instance (Additive-Group) a => Loop (Quaternion a)
instance (Additive-Group) a => Group (Quaternion a)
instance (Additive-Group) a => Magma (Additive (Quaternion a)) where
(<<) = mzipWithRep (<<)
instance (Additive-Group) a => Quasigroup (Additive (Quaternion a))
instance (Additive-Group) a => Loop (Additive (Quaternion a))
instance (Additive-Group) a => Group (Additive (Quaternion a))
instance Semiring a => Semimodule a (Quaternion a) where
(*.) = multl
instance (Additive-Semigroup) a => Semigroup (Additive (Quaternion a)) where
(<>) = mzipWithRep (<>)
instance (Additive-Monoid) a => Monoid (Additive (Quaternion a)) where
mempty = pure mempty
instance Ring a => Semigroup (Multiplicative (Quaternion a)) where
(<>) = mzipWithRep (><)
instance Ring a => Monoid (Multiplicative (Quaternion a)) where
mempty = pure unit
instance Ring a => Presemiring (Quaternion a)
instance Ring a => Semiring (Quaternion a)
instance Ring a => Ring (Quaternion a)
instance Functor Quaternion where
fmap f (Quaternion r v) = Quaternion (f r) (fmap f v)
{-# INLINE fmap #-}
a <$ _ = Quaternion a (V3 a a a)
{-# INLINE (<$) #-}
instance Foldable Quaternion where
foldMap f (Quaternion e v) = f e <> foldMap f v
{-# INLINE foldMap #-}
foldr f z (Quaternion e v) = f e (foldr f z v)
{-# INLINE foldr #-}
null _ = False
length _ = 4
instance Foldable1 Quaternion where
foldMap1 f (Quaternion r v) = f r <> foldMap1 f v
{-# INLINE foldMap1 #-}
instance Distributive Quaternion where
distribute f = Quaternion (fmap (\(Quaternion x _) -> x) f) $ V3
(fmap (\(Quaternion _ (V3 y _ _)) -> y) f)
(fmap (\(Quaternion _ (V3 _ z _)) -> z) f)
(fmap (\(Quaternion _ (V3 _ _ w)) -> w) f)
{-# INLINE distribute #-}
instance Representable Quaternion where
type Rep Quaternion = Maybe I3
tabulate f = Quaternion (f Nothing) (V3 (f $ Just I31) (f $ Just I32) (f $ Just I33))
{-# INLINE tabulate #-}
index (Quaternion r v) = maybe r (index v)
{-# INLINE index #-}