---------------------------------------------------------
-- |
-- Copyright   : (c) 2006-2016, alpheccar.org
-- License     : BSD-style
--
-- Maintainer  : misc@NOSPAMalpheccar.org
-- Stability   : experimental
-- Portability : portable
--
-- Coordinates for a PDF document
---------------------------------------------------------

module Graphics.PDF.Coordinates
    ( module Data.Complex
    -- * Geometry
    -- ** Types
    , Angle(..)
    , Point
    , Matrix(..)
    -- ** Transformations
    , toRadian
    , dot, scalePt
    , project, projectX, projectY
    , pointMatrix
    , transform
    , identity, rotate, translate, scale, spiral
    )
    where

import Data.Complex
import Graphics.PDF.LowLevel.Types(PDFFloat)

-- | Angle 
data Angle = Degree !PDFFloat -- ^ Angle in degrees
           | Radian !PDFFloat -- ^ Angle in radians

toRadian :: Angle -> PDFFloat
toRadian :: Angle -> PDFFloat
toRadian (Degree PDFFloat
x) = (PDFFloat
forall a. Floating a => a
pi PDFFloat -> PDFFloat -> PDFFloat
forall a. Fractional a => a -> a -> a
/ PDFFloat
180) PDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
* PDFFloat
x
toRadian (Radian PDFFloat
x) = PDFFloat
x

type Point = Complex PDFFloat

-- | Dot product of two points
-- 'dot (x :+ y) (a :+ b) == x * a  +  y * b'
-- 'dot z w == magnitude z * magnitude w * cos (phase z - phase w)'
dot :: (RealFloat t) => Complex t -> Complex t -> t
dot :: forall t. RealFloat t => Complex t -> Complex t -> t
dot (t
x0 :+ t
y0) (t
x1 :+ t
y1) = t
x0 t -> t -> t
forall a. Num a => a -> a -> a
* t
x1 t -> t -> t
forall a. Num a => a -> a -> a
+ t
y0 t -> t -> t
forall a. Num a => a -> a -> a
* t
y1

scalePt :: (RealFloat t) => t -> Complex t -> Complex t
scalePt :: forall t. RealFloat t => t -> Complex t -> Complex t
scalePt t
a (t
x :+ t
y) = t
at -> t -> t
forall a. Num a => a -> a -> a
*t
x t -> t -> Complex t
forall a. a -> a -> Complex a
:+ t
at -> t -> t
forall a. Num a => a -> a -> a
*t
y 

-- | projects the first point onto the second
project :: (RealFloat t) => Complex t -> Complex t -> Complex t
project :: forall t. RealFloat t => Complex t -> Complex t -> Complex t
project Complex t
z Complex t
w =  t -> Complex t -> Complex t
forall t. RealFloat t => t -> Complex t -> Complex t
scalePt (Complex t -> Complex t -> t
forall t. RealFloat t => Complex t -> Complex t -> t
dot Complex t
z Complex t
w t -> t -> t
forall a. Fractional a => a -> a -> a
/ Complex t -> Complex t -> t
forall t. RealFloat t => Complex t -> Complex t -> t
dot Complex t
w Complex t
w) Complex t
w

-- | projects a point onto the x-axis
projectX :: (RealFloat t) => Complex t -> Complex t
projectX :: forall t. RealFloat t => Complex t -> Complex t
projectX (t
x :+ t
_) = (t
x t -> t -> Complex t
forall a. a -> a -> Complex a
:+ t
0)

-- | projects a point onto the y-axis
projectY :: (RealFloat t) => Complex t -> Complex t
projectY :: forall t. RealFloat t => Complex t -> Complex t
projectY (t
_ :+ t
y) = (t
0 t -> t -> Complex t
forall a. a -> a -> Complex a
:+ t
y)

-- | A transformation matrix. An affine transformation a b c d e f
--
-- @
-- a b 0
-- c d 0
-- e f 1
-- @
       
data Matrix
   = Matrix !PDFFloat !PDFFloat !PDFFloat !PDFFloat !PDFFloat !PDFFloat
   deriving (Matrix -> Matrix -> Bool
(Matrix -> Matrix -> Bool)
-> (Matrix -> Matrix -> Bool) -> Eq Matrix
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Matrix -> Matrix -> Bool
== :: Matrix -> Matrix -> Bool
$c/= :: Matrix -> Matrix -> Bool
/= :: Matrix -> Matrix -> Bool
Eq, Eq Matrix
Eq Matrix =>
(Matrix -> Matrix -> Ordering)
-> (Matrix -> Matrix -> Bool)
-> (Matrix -> Matrix -> Bool)
-> (Matrix -> Matrix -> Bool)
-> (Matrix -> Matrix -> Bool)
-> (Matrix -> Matrix -> Matrix)
-> (Matrix -> Matrix -> Matrix)
-> Ord Matrix
Matrix -> Matrix -> Bool
Matrix -> Matrix -> Ordering
Matrix -> Matrix -> Matrix
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Matrix -> Matrix -> Ordering
compare :: Matrix -> Matrix -> Ordering
$c< :: Matrix -> Matrix -> Bool
< :: Matrix -> Matrix -> Bool
$c<= :: Matrix -> Matrix -> Bool
<= :: Matrix -> Matrix -> Bool
$c> :: Matrix -> Matrix -> Bool
> :: Matrix -> Matrix -> Bool
$c>= :: Matrix -> Matrix -> Bool
>= :: Matrix -> Matrix -> Bool
$cmax :: Matrix -> Matrix -> Matrix
max :: Matrix -> Matrix -> Matrix
$cmin :: Matrix -> Matrix -> Matrix
min :: Matrix -> Matrix -> Matrix
Ord, Int -> Matrix -> ShowS
[Matrix] -> ShowS
Matrix -> String
(Int -> Matrix -> ShowS)
-> (Matrix -> String) -> ([Matrix] -> ShowS) -> Show Matrix
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Matrix -> ShowS
showsPrec :: Int -> Matrix -> ShowS
$cshow :: Matrix -> String
show :: Matrix -> String
$cshowList :: [Matrix] -> ShowS
showList :: [Matrix] -> ShowS
Show)

instance Num Matrix where
    --  Matrix addition
    + :: Matrix -> Matrix -> Matrix
(+) (Matrix PDFFloat
ma PDFFloat
mb PDFFloat
mc PDFFloat
md PDFFloat
me PDFFloat
mf ) (Matrix PDFFloat
na PDFFloat
nb PDFFloat
nc PDFFloat
nd PDFFloat
ne PDFFloat
nf) = 
         PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix (PDFFloat
maPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
na)  (PDFFloat
mbPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
nb)  (PDFFloat
mcPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
nc)  (PDFFloat
mdPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
nd)  (PDFFloat
mePDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
ne)  (PDFFloat
mfPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
nf)
    * :: Matrix -> Matrix -> Matrix
(*) (Matrix PDFFloat
ma PDFFloat
mb PDFFloat
mc PDFFloat
md PDFFloat
me PDFFloat
mf) (Matrix PDFFloat
na PDFFloat
nb PDFFloat
nc PDFFloat
nd PDFFloat
ne PDFFloat
nf) = 
         PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix (PDFFloat
maPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
naPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
mbPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
nc)  (PDFFloat
maPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
nbPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
mbPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
nd)  (PDFFloat
mcPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
naPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
mdPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
nc)  (PDFFloat
mcPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
nb PDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
mdPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
nd)  (PDFFloat
mePDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
naPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
mfPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
ncPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
ne)  (PDFFloat
mePDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
nbPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
mfPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
ndPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+PDFFloat
nf)
    negate :: Matrix -> Matrix
negate (Matrix PDFFloat
ma PDFFloat
mb PDFFloat
mc PDFFloat
md PDFFloat
me PDFFloat
mf )  =
         PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix (-PDFFloat
ma)  (-PDFFloat
mb)  (-PDFFloat
mc)  (-PDFFloat
md)  (-PDFFloat
me)  (-PDFFloat
mf)
    abs :: Matrix -> Matrix
abs Matrix
m = Matrix
m
    signum :: Matrix -> Matrix
signum Matrix
_ = Matrix
identity
    fromInteger :: Integer -> Matrix
fromInteger Integer
i = PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix PDFFloat
r PDFFloat
0 PDFFloat
0 PDFFloat
r  PDFFloat
0  PDFFloat
0
                   where
                    r :: PDFFloat
r = Integer -> PDFFloat
forall a. Num a => Integer -> a
fromInteger Integer
i

-- | Identity matrix
identity :: Matrix
identity :: Matrix
identity = PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix PDFFloat
1 PDFFloat
0 PDFFloat
0 PDFFloat
1 PDFFloat
0 PDFFloat
0

-- | Specifies a matrix as three points
pointMatrix :: Point   -- ^ X component
            -> Point   -- ^ Y component
            -> Point   -- ^ translation component
            -> Matrix
pointMatrix :: Point -> Point -> Point -> Matrix
pointMatrix (PDFFloat
x0 :+ PDFFloat
y0) (PDFFloat
x1 :+ PDFFloat
y1) (PDFFloat
x2 :+ PDFFloat
y2) = PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix PDFFloat
x0 PDFFloat
y0 PDFFloat
x1 PDFFloat
y1 PDFFloat
x2 PDFFloat
y2

-- | Applies a matrix to a point
transform :: Matrix -> Point -> Point
transform :: Matrix -> Point -> Point
transform (Matrix PDFFloat
x0 PDFFloat
y0 PDFFloat
x1 PDFFloat
y1 PDFFloat
x2 PDFFloat
y2) (PDFFloat
x :+ PDFFloat
y) = (PDFFloat
xPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
x0 PDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+ PDFFloat
yPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
x1 PDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+ PDFFloat
x2) PDFFloat -> PDFFloat -> Point
forall a. a -> a -> Complex a
:+ (PDFFloat
xPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
y0 PDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+ PDFFloat
yPDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
*PDFFloat
y1 PDFFloat -> PDFFloat -> PDFFloat
forall a. Num a => a -> a -> a
+ PDFFloat
y2)

                    
-- | Rotation matrix
rotate :: Angle -- ^ Rotation angle
       -> Matrix
rotate :: Angle -> Matrix
rotate Angle
r = Point -> Matrix
spiral (PDFFloat -> Point
forall a. Floating a => a -> Complex a
cis (Angle -> PDFFloat
toRadian Angle
r))

-- | Translation matrix
-- 'transform (translate z) w == z + w'             
translate :: Point 
          -> Matrix
translate :: Point -> Matrix
translate (PDFFloat
tx :+ PDFFloat
ty)  = PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix  PDFFloat
1  PDFFloat
0  PDFFloat
0  PDFFloat
1  PDFFloat
tx PDFFloat
ty

--  | 'Spiral z' rotates by 'phase z' and scales by 'magnitude z'
--  'transform (spiral z) w == z * w'
spiral :: Point 
       -> Matrix
spiral :: Point -> Matrix
spiral (PDFFloat
x :+ PDFFloat
y) = PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix PDFFloat
x PDFFloat
y (-PDFFloat
y) PDFFloat
x PDFFloat
0 PDFFloat
0


-- | Scaling matrix          
scale :: PDFFloat  -- ^ Horizontal scaling
      -> PDFFloat  -- ^ Vertical scaling
      -> Matrix
scale :: PDFFloat -> PDFFloat -> Matrix
scale PDFFloat
sx PDFFloat
sy  = PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> PDFFloat
-> Matrix
Matrix PDFFloat
sx PDFFloat
0 PDFFloat
0 PDFFloat
sy PDFFloat
0 PDFFloat
0