{-# OPTIONS -XFlexibleInstances -XNamedFieldPuns #-}
-- | This module contains basic tools for geometric types and functions.
module Graphics.Typography.Geometry (Matrix2(..),

import Algebra.Polynomials.Numerical

-- | The type of the transformation matrices used in all geometrical applications.
data Matrix2 a=
  -- | The application of @Matrix2 a b c d@ to vector @(x,y)@ should be
  -- @(ax+by,cx+dy)@.
  Matrix2 a a a a deriving (Show, Read, Eq)

-- | Inverses an inversible matrix. If it is not inversible,
-- The behaviour is undefined.
inverse::(Fractional a, Num a)=>Matrix2 a->Matrix2 a
inverse (Matrix2 a b c d)=
  let det=a*d-c*b in
  Matrix2 (d/det) (-b/det) (-c/det) (a/det)


instance Num a=>Num (Matrix2 a) where
  (+) (Matrix2 a b c d) (Matrix2 e f g h)=
    Matrix2 (a+e) (b+f) (c+g) (d+h)
  (*) (Matrix2 a b c d) (Matrix2 e f g h)=
    Matrix2 (a*e+b*g) (a*f+b*h) (c*e+d*g) (c*f+d*h)
  fromInteger a=Matrix2 (fromInteger a) 0 0 (fromInteger a)

instance Intervalize Matrix2 where
  intervalize (Matrix2 a b c d)=
    Matrix2 (interval a) (interval b) (interval c) (interval d)

  intersects (Matrix2 a b c d) (Matrix2 a' b' c' d')=
    (intersectsd a a') &&
    (intersectsd b b') &&
    (intersectsd c c') &&
    (intersectsd d d')
-- | A class for applying geometric applications to objects
class Geometric g where
  apply::Matrix2 Double->g->g

-- | The matrix of a rotation
rotation::Floating a=>a->Matrix2 a
rotation theta=
  let ct=cos theta
      st=sin theta
   Matrix2 ct (-st) st ct

instance Geometric g=>Geometric [g] where
  translate x y cur=map (translate x y) cur
  apply m cur=map (apply m) cur

-- | @'leftMost' a b@ is the leftmost point between @a@ and @b@.
leftMost u@(a,_) v@(b,_)
  | a<b = u
  | otherwise = v
-- | @'rightMost' a b@ is the rightmost point between @a@ and @b@.
rightMost u@(a,_) v@(b,_)
  | a<b = v
  | otherwise = u
-- | @'bottomMost' a b@ is the lower point between @a@ and @b@.
bottomMost u@(_,a) v@(_,b)
  | a<b = u
  | otherwise = v
-- | @'topMost' a b@ is the upper point between @a@ and @b@.
topMost u@(_,a) v@(_,b)
  | a<b = v
  | otherwise = u