{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
module Diagrams.Core.Transform
(
(:-:)(..), (<->), linv, lapp
, Transformation(..)
, inv, transp, transl
, dropTransl
, apply
, papply
, fromLinear
, fromOrthogonal
, fromSymmetric
, basis
, dimension
, onBasis
, listRep
, matrixRep
, matrixHomRep
, determinant
, isReflection
, avgScale
, eye
, HasLinearMap
, HasBasis
, Transformable(..)
, TransInv(TransInv)
, translation, translate
, scaling, scale
) where
import Control.Lens (Rewrapped, Traversable, Wrapped (..),
iso, (&), (.~))
import qualified Data.Map as M
import Data.Semigroup
import qualified Data.Set as S
import Data.Monoid.Action
import Data.Monoid.Deletable
import Linear.Affine
import Linear.Vector
import Data.Foldable (Foldable, toList)
import Data.Functor.Rep
import Diagrams.Core.HasOrigin
import Diagrams.Core.Measure
import Diagrams.Core.Points ()
import Diagrams.Core.V
data (:-:) u v = (u -> v) :-: (v -> u)
infixr 7 :-:
(<->) :: (u -> v) -> (v -> u) -> (u :-: v)
f <-> g = f :-: g
instance Semigroup (a :-: a) where
(f :-: f') <> (g :-: g') = f . g :-: g' . f'
instance Monoid (v :-: v) where
mempty = id :-: id
mappend = (<>)
linv :: (u :-: v) -> (v :-: u)
linv (f :-: g) = g :-: f
lapp :: (u :-: v) -> u -> v
lapp (f :-: _) = f
data Transformation v n = Transformation (v n :-: v n) (v n :-: v n) (v n)
type instance V (Transformation v n) = v
type instance N (Transformation v n) = n
eye :: (HasBasis v, Num n) => v (v n)
eye = tabulate $ \(E e) -> zero & e .~ 1
inv :: (Functor v, Num n) => Transformation v n -> Transformation v n
inv (Transformation t t' v) = Transformation (linv t) (linv t')
(negated (lapp (linv t) v))
transp :: Transformation v n -> (v n :-: v n)
transp (Transformation _ t' _) = t'
transl :: Transformation v n -> v n
transl (Transformation _ _ v) = v
dropTransl :: (Additive v, Num n) => Transformation v n -> Transformation v n
dropTransl (Transformation a a' _) = Transformation a a' zero
instance (Additive v, Num n) => Semigroup (Transformation v n) where
Transformation t1 t1' v1 <> Transformation t2 t2' v2
= Transformation (t1 <> t2) (t2' <> t1') (v1 ^+^ lapp t1 v2)
instance (Additive v, Num n) => Monoid (Transformation v n) where
mempty = Transformation mempty mempty zero
mappend = (<>)
instance (Transformable a, V a ~ v, N a ~ n) => Action (Transformation v n) a where
act = transform
apply :: Transformation v n -> v n -> v n
apply (Transformation (t :-: _) _ _) = t
papply :: (Additive v, Num n) => Transformation v n -> Point v n -> Point v n
papply (Transformation t _ v) (P p) = P $ lapp t p ^+^ v
fromLinear :: (Additive v, Num n) => (v n :-: v n) -> (v n :-: v n) -> Transformation v n
fromLinear l1 l2 = Transformation l1 l2 zero
fromOrthogonal :: (Additive v, Num n) => (v n :-: v n) -> Transformation v n
fromOrthogonal t = fromLinear t (linv t)
fromSymmetric :: (Additive v, Num n) => (v n :-: v n) -> Transformation v n
fromSymmetric t = fromLinear t t
dimension :: forall a. (Additive (V a), Traversable (V a)) => a -> Int
dimension _ = length (basis :: [V a Int])
onBasis :: (Additive v, Traversable v, Num n) => Transformation v n -> ([v n], v n)
onBasis (Transformation (f :-: _) _ t) = (map f basis, t)
remove :: Int -> [a] -> [a]
remove n xs = ys ++ tail zs
where
(ys, zs) = splitAt n xs
minor :: Int -> Int -> [[a]] -> [[a]]
minor i j xs = remove j $ map (remove i) xs
det :: Num a => [[a]] -> a
det (a:[]) = head a
det m = sum [(-1)^i * (c1 !! i) * det (minor i 0 m) | i <- [0 .. (n-1)]]
where
c1 = head m
n = length m
listRep :: Foldable v => v n -> [n]
listRep = toList
matrixRep :: (Additive v, Traversable v, Num n) => Transformation v n -> [[n]]
matrixRep (Transformation (f :-: _) _ _) = map (toList . f) basis
matrixHomRep :: (Additive v, Traversable v, Num n) => Transformation v n -> [[n]]
matrixHomRep t = mr ++ [toList tl]
where
mr = matrixRep t
tl = transl t
determinant :: (Additive v, Traversable v, Num n) => Transformation v n -> n
determinant = det . matrixRep
isReflection :: (Additive v, Traversable v, Num n, Ord n) => Transformation v n -> Bool
isReflection = (<0) . determinant
avgScale :: (Additive v, Traversable v, Floating n) => Transformation v n -> n
avgScale t = (abs . determinant) t ** (recip . fromIntegral . dimension) t
class (HasBasis v, Traversable v) => HasLinearMap v
instance (HasBasis v, Traversable v) => HasLinearMap v
class (Additive v, Representable v, Rep v ~ E v) => HasBasis v
instance (Additive v, Representable v, Rep v ~ E v) => HasBasis v
class Transformable t where
transform :: Transformation (V t) (N t) -> t -> t
instance (Additive v, Num n) => Transformable (Transformation v n) where
transform t1 t2 = t1 <> t2
instance (Additive v, Num n) => HasOrigin (Transformation v n) where
moveOriginTo p = translate (origin .-. p)
instance (Transformable t, Transformable s, V t ~ V s, N t ~ N s)
=> Transformable (t, s) where
transform t (x,y) = ( transform t x
, transform t y
)
instance (Transformable t, Transformable s, Transformable u, V s ~ V t, N s ~ N t, V s ~ V u, N s ~ N u)
=> Transformable (t,s,u) where
transform t (x,y,z) = ( transform t x
, transform t y
, transform t z
)
instance ( V t ~ v, N t ~ n, V t ~ V s, N t ~ N s, Functor v, Num n
, Transformable t, Transformable s)
=> Transformable (s -> t) where
transform tr f = transform tr . f . transform (inv tr)
instance Transformable t => Transformable [t] where
transform = map . transform
instance (Transformable t, Ord t) => Transformable (S.Set t) where
transform = S.map . transform
instance Transformable t => Transformable (M.Map k t) where
transform = M.map . transform
instance (Additive v, Num n) => Transformable (Point v n) where
transform = papply
instance Transformable m => Transformable (Deletable m) where
transform = fmap . transform
newtype TransInv t = TransInv t
deriving (Eq, Ord, Show, Semigroup, Monoid)
instance Wrapped (TransInv t) where
type Unwrapped (TransInv t) = t
_Wrapped' = iso (\(TransInv t) -> t) TransInv
instance Rewrapped (TransInv t) (TransInv t')
type instance V (TransInv t) = V t
type instance N (TransInv t) = N t
instance HasOrigin (TransInv t) where
moveOriginTo = const id
instance (Num (N t), Additive (V t), Transformable t) => Transformable (TransInv t) where
transform (Transformation a a' _) (TransInv t)
= TransInv (transform (Transformation a a' zero) t)
instance (InSpace v n t, Transformable t, HasLinearMap v, Floating n)
=> Transformable (Measured n t) where
transform t = scaleLocal n . fmap (transform t')
where
t' = t <> scaling (1 / avgScale t)
n = avgScale t
translation :: v n -> Transformation v n
translation = Transformation mempty mempty
translate :: (Transformable t) => Vn t -> t -> t
translate = transform . translation
scaling :: (Additive v, Fractional n) => n -> Transformation v n
scaling s = fromSymmetric lin
where lin = (s *^) <-> (^/ s)
scale :: (InSpace v n a, Eq n, Fractional n, Transformable a)
=> n -> a -> a
scale 0 = error "scale by zero! Halp!"
scale s = transform $ scaling s