--------------------------------------------------------------------------------
-- |
-- Module      :  Ipe.Matrix
-- Copyright   :  (C) Frank Staals
-- License     :  see the LICENSE file
-- Maintainer  :  Frank Staals
--
-- Matrix Attributes as defined in Ipe
--
--------------------------------------------------------------------------------
module Ipe.Matrix where

import           Control.Lens hiding (rmap)
import           Data.Ext
import qualified Ipe.Attributes as AT
import           Ipe.Attributes hiding (Matrix)
import           Ipe.Types
import           Data.Geometry.Properties
import           Data.Geometry.Transformation
import           Data.Proxy
import           Data.Vinyl hiding (Label)

--------------------------------------------------------------------------------

-- | Takes and applies the ipe Matrix attribute of this item.
applyMatrix'              :: ( IsTransformable (i r)
                             , AT.Matrix  AttributesOf i
                             , Dimension (i r) ~ 2, r ~ NumType (i r))
                          => IpeObject' i r -> IpeObject' i r
applyMatrix' :: IpeObject' i r -> IpeObject' i r
applyMatrix' o :: IpeObject' i r
o@(i r
i :+ IpeAttributes i r
ats) = IpeObject' i r
-> (Matrix 3 3 r -> IpeObject' i r)
-> Maybe (Matrix 3 3 r)
-> IpeObject' i r
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IpeObject' i r
o (\Matrix 3 3 r
m -> Transformation (Dimension (i r)) (NumType (i r)) -> i r -> i r
forall g.
IsTransformable g =>
Transformation (Dimension g) (NumType g) -> g -> g
transformBy (Matrix (2 + 1) (2 + 1) r -> Transformation 2 r
forall (d :: Nat) r. Matrix (d + 1) (d + 1) r -> Transformation d r
Transformation Matrix 3 3 r
Matrix (2 + 1) (2 + 1) r
m) i r
i i r -> IpeAttributes i r -> IpeObject' i r
forall core extra. core -> extra -> core :+ extra
:+ IpeAttributes i r
ats') Maybe (Matrix 3 3 r)
mm
  where
    (Maybe (Matrix 3 3 r)
mm,IpeAttributes i r
ats') = Proxy 'Matrix
-> IpeAttributes i r
-> (Maybe (Apply (AttrMapSym1 r) 'Matrix), IpeAttributes i r)
forall u (proxy :: u -> *) (at :: u) (ats :: [u])
       (f :: TyFun u * -> *).
(at ∈ ats) =>
proxy at
-> Attributes f ats -> (Maybe (Apply f at), Attributes f ats)
takeAttr (Proxy 'Matrix
forall k (t :: k). Proxy t
Proxy :: Proxy AT.Matrix) IpeAttributes i r
ats

-- | Applies the matrix to an ipe object if it has one.
applyMatrix                  :: Fractional r => IpeObject r -> IpeObject r
applyMatrix :: IpeObject r -> IpeObject r
applyMatrix (IpeGroup IpeObject' Group r
i)     = (Group r
 :+ Attributes
      (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> IpeObject r
forall r. IpeObject' Group r -> IpeObject r
IpeGroup ((Group r
  :+ Attributes
       (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
 -> IpeObject r)
-> ((Group r
     :+ Attributes
          (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
    -> Group r
       :+ Attributes
            (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> (Group r
    :+ Attributes
         (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> IpeObject r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Group r
 :+ Attributes
      (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> Group r
   :+ Attributes
        (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip]
forall (i :: * -> *) r.
(IsTransformable (i r), 'Matrix ∈ AttributesOf i,
 Dimension (i r) ~ 2, r ~ NumType (i r)) =>
IpeObject' i r -> IpeObject' i r
applyMatrix'
                             ((Group r
  :+ Attributes
       (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
 -> IpeObject r)
-> (Group r
    :+ Attributes
         (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> IpeObject r
forall a b. (a -> b) -> a -> b
$ Group r
:+ Attributes
     (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip]
IpeObject' Group r
i(Group r
 :+ Attributes
      (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> ((Group r
     :+ Attributes
          (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
    -> Group r
       :+ Attributes
            (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> Group r
   :+ Attributes
        (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip]
forall a b. a -> (a -> b) -> b
&(Group r -> Identity (Group r))
-> (Group r
    :+ Attributes
         (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> Identity
     (Group r
      :+ Attributes
           (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core((Group r -> Identity (Group r))
 -> (Group r
     :+ Attributes
          (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
 -> Identity
      (Group r
       :+ Attributes
            (AttrMapSym1 r)
            '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip]))
-> ((IpeObject r -> Identity (IpeObject r))
    -> Group r -> Identity (Group r))
-> (IpeObject r -> Identity (IpeObject r))
-> (Group r
    :+ Attributes
         (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> Identity
     (Group r
      :+ Attributes
           (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
forall b c a. (b -> c) -> (a -> b) -> a -> c
.([IpeObject r] -> Identity [IpeObject r])
-> Group r -> Identity (Group r)
forall r s. Lens (Group r) (Group s) [IpeObject r] [IpeObject s]
groupItems(([IpeObject r] -> Identity [IpeObject r])
 -> Group r -> Identity (Group r))
-> ((IpeObject r -> Identity (IpeObject r))
    -> [IpeObject r] -> Identity [IpeObject r])
-> (IpeObject r -> Identity (IpeObject r))
-> Group r
-> Identity (Group r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(IpeObject r -> Identity (IpeObject r))
-> [IpeObject r] -> Identity [IpeObject r]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ((IpeObject r -> Identity (IpeObject r))
 -> (Group r
     :+ Attributes
          (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
 -> Identity
      (Group r
       :+ Attributes
            (AttrMapSym1 r)
            '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip]))
-> (IpeObject r -> IpeObject r)
-> (Group r
    :+ Attributes
         (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip])
-> Group r
   :+ Attributes
        (AttrMapSym1 r) '[ 'Layer, 'Matrix, 'Pin, 'Transformations, 'Clip]
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ IpeObject r -> IpeObject r
forall r. Fractional r => IpeObject r -> IpeObject r
applyMatrix
                             -- note that for a group we first (recursively)
                             -- apply the matrices, and then apply
                             -- the matrix of the group to its members.
applyMatrix (IpeImage IpeObject' Image r
i)     = IpeObject' Image r -> IpeObject r
forall r. IpeObject' Image r -> IpeObject r
IpeImage     (IpeObject' Image r -> IpeObject r)
-> IpeObject' Image r -> IpeObject r
forall a b. (a -> b) -> a -> b
$ IpeObject' Image r -> IpeObject' Image r
forall (i :: * -> *) r.
(IsTransformable (i r), 'Matrix ∈ AttributesOf i,
 Dimension (i r) ~ 2, r ~ NumType (i r)) =>
IpeObject' i r -> IpeObject' i r
applyMatrix' IpeObject' Image r
i
applyMatrix (IpeTextLabel IpeObject' TextLabel r
i) = IpeObject' TextLabel r -> IpeObject r
forall r. IpeObject' TextLabel r -> IpeObject r
IpeTextLabel (IpeObject' TextLabel r -> IpeObject r)
-> IpeObject' TextLabel r -> IpeObject r
forall a b. (a -> b) -> a -> b
$ IpeObject' TextLabel r -> IpeObject' TextLabel r
forall (i :: * -> *) r.
(IsTransformable (i r), 'Matrix ∈ AttributesOf i,
 Dimension (i r) ~ 2, r ~ NumType (i r)) =>
IpeObject' i r -> IpeObject' i r
applyMatrix' IpeObject' TextLabel r
i
applyMatrix (IpeMiniPage IpeObject' MiniPage r
i)  = IpeObject' MiniPage r -> IpeObject r
forall r. IpeObject' MiniPage r -> IpeObject r
IpeMiniPage  (IpeObject' MiniPage r -> IpeObject r)
-> IpeObject' MiniPage r -> IpeObject r
forall a b. (a -> b) -> a -> b
$ IpeObject' MiniPage r -> IpeObject' MiniPage r
forall (i :: * -> *) r.
(IsTransformable (i r), 'Matrix ∈ AttributesOf i,
 Dimension (i r) ~ 2, r ~ NumType (i r)) =>
IpeObject' i r -> IpeObject' i r
applyMatrix' IpeObject' MiniPage r
i
applyMatrix (IpeUse IpeObject' IpeSymbol r
i)       = IpeObject' IpeSymbol r -> IpeObject r
forall r. IpeObject' IpeSymbol r -> IpeObject r
IpeUse       (IpeObject' IpeSymbol r -> IpeObject r)
-> IpeObject' IpeSymbol r -> IpeObject r
forall a b. (a -> b) -> a -> b
$ IpeObject' IpeSymbol r -> IpeObject' IpeSymbol r
forall (i :: * -> *) r.
(IsTransformable (i r), 'Matrix ∈ AttributesOf i,
 Dimension (i r) ~ 2, r ~ NumType (i r)) =>
IpeObject' i r -> IpeObject' i r
applyMatrix' IpeObject' IpeSymbol r
i
applyMatrix (IpePath IpeObject' Path r
i)      = IpeObject' Path r -> IpeObject r
forall r. IpeObject' Path r -> IpeObject r
IpePath      (IpeObject' Path r -> IpeObject r)
-> IpeObject' Path r -> IpeObject r
forall a b. (a -> b) -> a -> b
$ IpeObject' Path r -> IpeObject' Path r
forall (i :: * -> *) r.
(IsTransformable (i r), 'Matrix ∈ AttributesOf i,
 Dimension (i r) ~ 2, r ~ NumType (i r)) =>
IpeObject' i r -> IpeObject' i r
applyMatrix' IpeObject' Path r
i

-- | Applies all matrices in the file.
applyMatrices   :: Fractional r => IpeFile r -> IpeFile r
applyMatrices :: IpeFile r -> IpeFile r
applyMatrices IpeFile r
f = IpeFile r
fIpeFile r -> (IpeFile r -> IpeFile r) -> IpeFile r
forall a b. a -> (a -> b) -> b
&(NonEmpty (IpePage r) -> Identity (NonEmpty (IpePage r)))
-> IpeFile r -> Identity (IpeFile r)
forall r1 r2.
Lens
  (IpeFile r1)
  (IpeFile r2)
  (NonEmpty (IpePage r1))
  (NonEmpty (IpePage r2))
pages((NonEmpty (IpePage r) -> Identity (NonEmpty (IpePage r)))
 -> IpeFile r -> Identity (IpeFile r))
-> ((IpePage r -> Identity (IpePage r))
    -> NonEmpty (IpePage r) -> Identity (NonEmpty (IpePage r)))
-> (IpePage r -> Identity (IpePage r))
-> IpeFile r
-> Identity (IpeFile r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(IpePage r -> Identity (IpePage r))
-> NonEmpty (IpePage r) -> Identity (NonEmpty (IpePage r))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ((IpePage r -> Identity (IpePage r))
 -> IpeFile r -> Identity (IpeFile r))
-> (IpePage r -> IpePage r) -> IpeFile r -> IpeFile r
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ IpePage r -> IpePage r
forall r. Fractional r => IpePage r -> IpePage r
applyMatricesPage

-- | Applies all Matrices on a given page.
applyMatricesPage   :: Fractional r => IpePage r -> IpePage r
applyMatricesPage :: IpePage r -> IpePage r
applyMatricesPage IpePage r
p = IpePage r
pIpePage r -> (IpePage r -> IpePage r) -> IpePage r
forall a b. a -> (a -> b) -> b
&([IpeObject r] -> Identity [IpeObject r])
-> IpePage r -> Identity (IpePage r)
forall r1 r2.
Lens (IpePage r1) (IpePage r2) [IpeObject r1] [IpeObject r2]
content(([IpeObject r] -> Identity [IpeObject r])
 -> IpePage r -> Identity (IpePage r))
-> ((IpeObject r -> Identity (IpeObject r))
    -> [IpeObject r] -> Identity [IpeObject r])
-> (IpeObject r -> Identity (IpeObject r))
-> IpePage r
-> Identity (IpePage r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(IpeObject r -> Identity (IpeObject r))
-> [IpeObject r] -> Identity [IpeObject r]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ((IpeObject r -> Identity (IpeObject r))
 -> IpePage r -> Identity (IpePage r))
-> (IpeObject r -> IpeObject r) -> IpePage r -> IpePage r
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ IpeObject r -> IpeObject r
forall r. Fractional r => IpeObject r -> IpeObject r
applyMatrix