shapes-demo-0.1.0.0: src/Physics/Draw/Transform.hs
{-# Language MultiParamTypeClasses #-}
{-# Language FlexibleInstances #-}
{-# Language FlexibleContexts #-}
module Physics.Draw.Transform where
import Linear.Affine
import Linear.Matrix
import Linear.V2
import Utils.Utils
import Physics.Draw.Linear
type WorldTransform a = (M33 a, M33 a)
toTransform :: (Floating a) => Diff V2 a -> a -> WorldTransform a
toTransform pos ori = joinTransforms (translateTransform pos) (rotateTransform ori)
scaleTransform :: (Floating a) => V2 a -> WorldTransform a
scaleTransform s@(V2 x y) = (afscale33 s, afscale33 s')
where s' = V2 (1/x) (1/y)
rotateTransform :: (Floating a) => a -> WorldTransform a
rotateTransform ori = (rot, rot')
where rot = afrotate33 ori
rot' = afrotate33 (-ori)
translateTransform :: (Floating a) => Diff V2 a -> WorldTransform a
translateTransform pos = (transl, transl')
where transl = aftranslate33 pos
transl' = aftranslate33 (-pos)
idTransform :: (Num a) => WorldTransform a
idTransform = (identity, identity)
joinTransforms :: (Num a) => WorldTransform a -> WorldTransform a -> WorldTransform a
joinTransforms (outer, outer') (inner, inner') = (outer !*! inner, inner' !*! outer')
joinTransforms' :: (Num a) => [WorldTransform a] -> WorldTransform a
joinTransforms' = foldl1 joinTransforms
invertTransform :: WorldTransform a -> WorldTransform a
invertTransform (f, g) = (g, f)
-- TODO: add another type variable to track values that originated in the same local space
-- see lap, Geometry.overlap
data LocalT a b = LocalT !(WorldTransform a) !b deriving (Show, Eq)
type LV2 a = LocalT a (V2 a)
type LP2 a = LocalT a (P2 a)
data WorldT a = WorldT !a deriving (Show, Eq)
type WV2 a = WorldT (V2 a)
type WP2 a = WorldT (Point V2 a)
iExtract :: WorldT a -> a
iExtract (WorldT x) = x
iInject :: a -> WorldT a
iInject = WorldT
iInject_ :: Num a => b -> LocalT a b
iInject_ = LocalT idTransform
instance Functor (LocalT a) where
fmap f (LocalT t v) = LocalT t (f v)
instance Functor WorldT where
fmap f (WorldT v) = WorldT (f v)
-- wExtract and wInject don't change the transform - they only move between types
class WorldTransformable t a where
-- TODO: deduplicate - these are just opposite sides of a tuple
transform :: WorldTransform a -> t -> t
untransform :: WorldTransform a -> t -> t
wExtract :: LocalT a t -> WorldT t
wExtract (LocalT t v) = WorldT (transform t v)
wExtract_ :: LocalT a t -> t
wExtract_ = iExtract . wExtract
wInject :: WorldTransform a -> WorldT t -> LocalT a t
wInject t v = LocalT t (untransform t (iExtract v))
wInject_ :: WorldTransform a -> t -> t -- same as wInject, but throws away type information
wInject_ = untransform
instance (Floating a) => WorldTransformable (P2 a) a where
transform (trans, _) = afmul trans
untransform (_, untrans) = afmul untrans
instance (Floating a) => WorldTransformable (V2 a) a where
transform (trans, _) = afmul trans
untransform (_, untrans) = afmul untrans
instance (WorldTransformable t a) => WorldTransformable (WorldT t) a where
transform t = WorldT . transform t . iExtract
untransform t = WorldT . untransform t . iExtract
instance (Num a) => WorldTransformable (LocalT a b) a where
transform t' (LocalT t v) = LocalT (joinTransforms t' t) v
untransform t' (LocalT t v) = LocalT (joinTransforms (invertTransform t') t) v
wInject _ = LocalT idTransform . iExtract
instance (WorldTransformable b a) => WorldTransformable (b, b) a where
transform t = pairMap (transform t)
untransform t = pairMap (untransform t)
instance (WorldTransformable b a) => WorldTransformable [b] a where
transform t = map (transform t)
untransform t = map (untransform t)
instance (WorldTransformable b a) => WorldTransformable (Maybe b) a where
transform t = fmap (transform t)
untransform t = fmap (untransform t)
data WaL w a l = WaL { _wlW :: !(WorldT w)
, _wlL :: !(LocalT a l)
} deriving (Show, Eq)
type WaL' a t = WaL t a t
instance (Num a, WorldTransformable w a, WorldTransformable l a) => WorldTransformable (WaL w a l) a where
transform t (WaL w l) =
WaL (transform t w) (transform t l)
untransform t (WaL w l) =
WaL (untransform t w) (untransform t l)
wfmap :: (Functor t) => (a -> t b) -> WorldT a -> t (WorldT b)
wfmap f (WorldT v) = fmap WorldT (f v)
wflip :: (Functor t) => WorldT (t a) -> t (WorldT a)
wflip (WorldT v) = fmap WorldT v
wmap :: (a -> b) -> WorldT a -> WorldT b
wmap = fmap
wlift2 :: (a -> b -> c) -> WorldT a -> WorldT b -> WorldT c
wlift2 f x = wap (wmap f x)
wlift2_ :: (a -> b -> c) -> WorldT a -> WorldT b -> c
wlift2_ f x y = iExtract (wlift2 f x y)
wap :: WorldT (a -> b) -> WorldT a -> WorldT b
wap (WorldT f) = wmap f
wlap :: (WorldTransformable a n) => WorldT (a -> b) -> LocalT n a -> WorldT b
wlap f = wap f . wExtract
lwap :: (WorldTransformable a n) => LocalT n (a -> b) -> WorldT a -> LocalT n b
lwap (LocalT t f) x = lmap f (wInject t x)
lap :: (WorldTransformable a n) => LocalT n (a -> b) -> LocalT n a -> LocalT n b
lap f x = lwap f (wExtract x)
lmap :: (a -> b) -> LocalT n a -> LocalT n b
lmap = fmap
lfmap :: (Functor t) => (a -> t b) -> LocalT n a -> t (LocalT n b)
lfmap f (LocalT t v) = fmap (LocalT t) (f v)
lunsafe_ :: (a -> b) -> LocalT n a -> b
lunsafe_ f (LocalT _ v) = f v
wlens :: (Functor f) => (a -> f a) -> WorldT a -> f (WorldT a)
wlens f = fmap WorldT . f . iExtract