    {-# LANGUAGE ConstraintKinds #-}
    {-# LANGUAGE MonoLocalBinds  #-}
    {-# LANGUAGE TypeFamilies    #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Diagrams.Transform.Matrix
    -- Copyright   :  (c) 2014 diagrams team (see LICENSE)
    -- License     :  BSD-style (see LICENSE)
    -- Maintainer  :  diagrams-discuss@googlegroups.com
    --
    -- Functions for converting between 'Transformation's and matricies.
    --
    -----------------------------------------------------------------------------

    module Diagrams.Transform.Matrix where

    import           Control.Arrow           ((&&&))
    import           Control.Lens
    import           Data.Distributive
    import qualified Data.Foldable           as F
    import           Data.Functor.Rep

    import           Diagrams.Core.Transform as D
    import           Diagrams.ThreeD.Types
    import           Diagrams.TwoD.Types

    import           Linear.Matrix
    import           Linear.Vector

    -- | Build a matrix from a 'Transformation', ignoring the translation.
    mkMat :: (HasBasis v, Num n) => Transformation v n -> v (v n)
    mkMat :: forall (v :: * -> *) n.
    (HasBasis v, Num n) =>
    Transformation v n -> v (v n)
    mkMat Transformation v n
    t = v (v n) -> v (v n)
    forall (g :: * -> *) (f :: * -> *) a.
    (Distributive g, Functor f) =>
    f (g a) -> g (f a)
    forall (f :: * -> *) a. Functor f => f (v a) -> v (f a)
    distribute (v (v n) -> v (v n))
    -> ((E v -> v n) -> v (v n)) -> (E v -> v n) -> v (v n)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Rep v -> v n) -> v (v n)
    (E v -> v n) -> v (v n)
    forall a. (Rep v -> a) -> v a
    forall (f :: * -> *) a. Representable f => (Rep f -> a) -> f a
    tabulate ((E v -> v n) -> v (v n)) -> (E v -> v n) -> v (v n)
    forall a b. (a -> b) -> a -> b
    $ Transformation v n -> v n -> v n
    forall (v :: * -> *) n. Transformation v n -> v n -> v n
    apply Transformation v n
    t (v n -> v n) -> (E v -> v n) -> E v -> v n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ASetter' (v n) n -> v n
    forall (t :: * -> *) a.
    (Additive t, Num a) =>
    ASetter' (t a) a -> t a
    unit (ASetter' (v n) n -> v n)
    -> (E v -> ASetter' (v n) n) -> E v -> v n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (\E v
    x -> E v -> forall x. Lens' (v x) x
    forall (t :: * -> *). E t -> forall x. Lens' (t x) x
    el E v
    x)

    -- | Build a 3D transformation matrix in homogeneous coordinates from
    --   a 'Transformation V3'.
    mkMatHomo :: Num n => Transformation V3 n -> M44 n
    mkMatHomo :: forall n. Num n => Transformation V3 n -> M44 n
    mkMatHomo Transformation V3 n
    t = M33 n -> V3 n -> M44 n
    forall a. Num a => M33 a -> V3 a -> M44 a
    mkTransformationMat (Transformation V3 n -> M33 n
    forall (v :: * -> *) n.
    (HasBasis v, Num n) =>
    Transformation v n -> v (v n)
    mkMat Transformation V3 n
    t) (Transformation V3 n -> V3 n
    forall (v :: * -> *) n. Transformation v n -> v n
    transl Transformation V3 n
    t)

    -- | Make a 2D transformation from a 2x2 transform matrix and a
    --   translation vector. Does not check if the matrix is not invertible
    --   (in which case the 'T2' will be invalid).
    fromMat22 :: Floating n => M22 n -> V2 n -> T2 n
    fromMat22 :: forall n. Floating n => M22 n -> V2 n -> T2 n
    fromMat22 M22 n
    m V2 n
    v = M22 n -> M22 n -> V2 n -> Transformation V2 n
    forall (v :: * -> *) n.
    (Additive v, Distributive v, Foldable v, Num n) =>
    v (v n) -> v (v n) -> v n -> Transformation v n
    fromMatWithInv M22 n
    m (M22 n -> M22 n
    forall a. Fractional a => M22 a -> M22 a
    inv22 M22 n
    m) V2 n
    v

    -- | Make a 3D transformation from a 3x3 transform matrix and a
    --   translation vector. Does not check if the matrix is not invertible
    --   (in which case the 'T3' will be invalid).
    fromMat33 :: Floating n => M33 n -> V3 n -> T3 n
    fromMat33 :: forall n. Floating n => M33 n -> V3 n -> T3 n
    fromMat33 M33 n
    m V3 n
    v = M33 n -> M33 n -> V3 n -> Transformation V3 n
    forall (v :: * -> *) n.
    (Additive v, Distributive v, Foldable v, Num n) =>
    v (v n) -> v (v n) -> v n -> Transformation v n
    fromMatWithInv M33 n
    m (M33 n -> M33 n
    forall a. Fractional a => M33 a -> M33 a
    inv33 M33 n
    m) V3 n
    v

    -- | Build a transform with a maxtrix along with its inverse.
    fromMatWithInv :: (Additive v, Distributive v, F.Foldable v, Num n)
      => v (v n) -- ^ matrix
      -> v (v n) -- ^ inverse
      -> v n     -- ^ translation
      -> Transformation v n
    fromMatWithInv :: forall (v :: * -> *) n.
    (Additive v, Distributive v, Foldable v, Num n) =>
    v (v n) -> v (v n) -> v n -> Transformation v n
    fromMatWithInv v (v n)
    m v (v n)
    m_ v n
    v =
      (v n :-: v n) -> (v n :-: v n) -> v n -> Transformation v n
    forall (v :: * -> *) n.
    (v n :-: v n) -> (v n :-: v n) -> v n -> Transformation v n
    Transformation ((v (v n)
    m v (v n) -> v n -> v n
    forall (m :: * -> *) (r :: * -> *) a.
    (Functor m, Foldable r, Additive r, Num a) =>
    m (r a) -> r a -> m a
    !*)            (v n -> v n) -> (v n -> v n) -> v n :-: v n
    forall u v. (u -> v) -> (v -> u) -> u :-: v
    <-> (v (v n)
    m_ v (v n) -> v n -> v n
    forall (m :: * -> *) (r :: * -> *) a.
    (Functor m, Foldable r, Additive r, Num a) =>
    m (r a) -> r a -> m a
    !*))
                     ((v (v n) -> v (v n)
    forall (g :: * -> *) (f :: * -> *) a.
    (Distributive g, Functor f) =>
    f (g a) -> g (f a)
    forall (f :: * -> *) a. Functor f => f (v a) -> v (f a)
    distribute v (v n)
    m v (v n) -> v n -> v n
    forall (m :: * -> *) (r :: * -> *) a.
    (Functor m, Foldable r, Additive r, Num a) =>
    m (r a) -> r a -> m a
    !*) (v n -> v n) -> (v n -> v n) -> v n :-: v n
    forall u v. (u -> v) -> (v -> u) -> u :-: v
    <-> (v (v n) -> v (v n)
    forall (g :: * -> *) (f :: * -> *) a.
    (Distributive g, Functor f) =>
    f (g a) -> g (f a)
    forall (f :: * -> *) a. Functor f => f (v a) -> v (f a)
    distribute v (v n)
    m_ v (v n) -> v n -> v n
    forall (m :: * -> *) (r :: * -> *) a.
    (Functor m, Foldable r, Additive r, Num a) =>
    m (r a) -> r a -> m a
    !*))
                     v n
    v

    -- | Prism onto a 2D transformation from a 2x2 transform matrix and
    --   translation vector. Does not check if the matrix is invertible (in
    --   which case the 'T2' will be invalid).
    mat22 :: Floating n => Iso' (M22 n, V2 n) (T2 n)
    mat22 :: forall n. Floating n => Iso' (M22 n, V2 n) (T2 n)
    mat22 = ((M22 n, V2 n) -> T2 n)
    -> (T2 n -> (M22 n, V2 n))
    -> Iso (M22 n, V2 n) (M22 n, V2 n) (T2 n) (T2 n)
    forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
    iso ((M22 n -> V2 n -> T2 n) -> (M22 n, V2 n) -> T2 n
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry M22 n -> V2 n -> T2 n
    forall n. Floating n => M22 n -> V2 n -> T2 n
    fromMat22) (T2 n -> M22 n
    forall (v :: * -> *) n.
    (HasBasis v, Num n) =>
    Transformation v n -> v (v n)
    mkMat (T2 n -> M22 n) -> (T2 n -> V2 n) -> T2 n -> (M22 n, V2 n)
    forall b c c'. (b -> c) -> (b -> c') -> b -> (c, c')
    forall (a :: * -> * -> *) b c c'.
    Arrow a =>
    a b c -> a b c' -> a b (c, c')
    &&& T2 n -> V2 n
    forall (v :: * -> *) n. Transformation v n -> v n
    transl)

    -- | Prism onto a 3D transformation from a 3x3 transform matrix and
    --   translation vector. Does not check if the matrix is invertible
    --   (in which case the 'T3' will be invalid).
    mat33 :: Floating n => Iso' (M33 n, V3 n) (T3 n)
    mat33 :: forall n. Floating n => Iso' (M33 n, V3 n) (T3 n)
    mat33 = ((M33 n, V3 n) -> T3 n)
    -> (T3 n -> (M33 n, V3 n))
    -> Iso (M33 n, V3 n) (M33 n, V3 n) (T3 n) (T3 n)
    forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
    iso ((M33 n -> V3 n -> T3 n) -> (M33 n, V3 n) -> T3 n
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry M33 n -> V3 n -> T3 n
    forall n. Floating n => M33 n -> V3 n -> T3 n
    fromMat33) (T3 n -> M33 n
    forall (v :: * -> *) n.
    (HasBasis v, Num n) =>
    Transformation v n -> v (v n)
    mkMat (T3 n -> M33 n) -> (T3 n -> V3 n) -> T3 n -> (M33 n, V3 n)
    forall b c c'. (b -> c) -> (b -> c') -> b -> (c, c')
    forall (a :: * -> * -> *) b c c'.
    Arrow a =>
    a b c -> a b c' -> a b (c, c')
    &&& T3 n -> V3 n
    forall (v :: * -> *) n. Transformation v n -> v n
    transl)