-- | Transformations of a PDF document

module Graphics.PDF.Geometry 
 (-- * Geometry
  -- ** Units
  Angle(..)
  -- ** Data types
  , Matrix
  -- ** Transformations
  , rotate, translate, scale, applyMatrix, identity
 )
 where
 
import Graphics.PDF.LowLevel


-- | Angle 
data Angle = Degree Float -- ^ Angle in degrees
           | Radian Float -- ^ Angle in radians

-- | A transformation matrix  (affine transformation)         
newtype Matrix = Matrix(Float,Float,Float,Float,Float,Float) deriving (Eq)

-- | Identity matrix
identity :: Matrix
identity = Matrix(1.0,0,0,1.0,0,0)

instance Show Matrix where
 show (Matrix(ma,mb,mc,md,me,mf)) = "Matrix " ++ (unwords [(show ma),(show mb),(show mc),(show md),(show me),(show mf)])
   
instance Num Matrix where
  --  Matrix addition
  (+) (Matrix(ma,mb,mc,md,me,mf)) (Matrix(na,nb,nc,nd,ne,nf)) = 
        Matrix( (ma+na), (mb+nb), (mc+nc), (md+nd), (me+ne), (mf+nf)) 
  --  Matrix multiplication
  --  ma mb 0   na nb 0
  --  mc md 0   nc nd 0
  --  me mf 1   ne nf 1
  (*) (Matrix(ma,mb,mc,md,me,mf)) (Matrix(na,nb,nc,nd,ne,nf)) = 
        Matrix( (ma*na+mb*nc), (ma*nb + mb*nd ), (mc*na+md*nc), (mc*nb +md*nd), (me*na+mf*nc+ne), (me*nb+mf*nd+nf)) 
  negate (Matrix(ma,mb,mc,md,me,mf))  =
        Matrix( (-ma), (-mb), (-mc), (-md), (-me), (-mf))
  abs m = m
  signum _ = identity
  fromInteger i = Matrix(r,0,0,r, 0, 0)
                  where
                   r = fromInteger i


-- | Apply a transformation matrix to the current coordinate frame
applyMatrix :: Matrix -> PdfCmd
applyMatrix (Matrix(a,b,c,d,e,f))  = (PdfCM a b c d e f,[])

-- | Rotation matrix
rotate :: Angle -> Matrix
rotate r = Matrix ((cos(radian)), (sin(radian)), (-sin(radian)) ,(cos(radian)), 0, 0)
              where
                radian = case r of
                         Degree angle -> angle / 180 *  pi
                         Radian angle -> angle
            
 
-- | Translation matrix            
translate :: Float -> Float -> Matrix
translate tx ty  = Matrix( 1, 0, 0, 1 ,tx ,ty)
              

-- | Scaling matrix          
scale :: Float -> Float -> Matrix
scale sx sy  = Matrix (sx, 0, 0, sy, 0 ,0 )