-----------------------------------------------------------------------------
-- |
-- Module      : Graphics.Hoodle.Render.Primitive
-- Copyright   : (c) 2011-2014 Ian-Woo Kim
--
-- License     : BSD3
-- Maintainer  : Ian-Woo Kim <ianwookim@gmail.com>
-- Stability   : experimental
-- Portability : GHC
--
-- draw utility 
--
-----------------------------------------------------------------------------

module Graphics.Hoodle.Render.Primitive 
( drawStrokeCurve 
, drawVWStrokeCurve 
) where 

-- import           Control.Applicative
import           Control.Monad 
import           Data.Strict.Tuple hiding (fst,snd)
import qualified Graphics.Rendering.Cairo as Cairo
-- from hoodle-platform
-- import           Data.Hoodle.Predefined 
-- 
-- import Prelude hiding (foldM_)

------------------
-- draw utility -- 
------------------

-- | 
drawStrokeCurve :: [Pair Double Double] -> Cairo.Render ()
drawStrokeCurve ((x0 :!: y0) : xs) = do 
  x0 `seq` y0 `seq` Cairo.moveTo x0 y0
  mapM_ f xs 
    where f (x :!: y) = x `seq` y `seq` Cairo.lineTo x y 
drawStrokeCurve [] = return ()

-- | 
drawVWStrokeCurve :: [(Double,Double,Double)] -> Cairo.Render ()
drawVWStrokeCurve [] = return ()
drawVWStrokeCurve (_:[]) = return ()
drawVWStrokeCurve ((xo,yo,_zo) : xs) = do 
    Cairo.moveTo xo yo
    let ((xlast,ylast,_zlast):rxs) = reverse xs 
    foldM_ forward (xo,yo) xs 
    foldM_ forward (xlast,ylast) rxs 
  where turn (x,y) = (negate y,x)
        norm (x,y) = sqrt (x*x + y*y)
        (x1,y1) .-. (x0,y0) = (x1-x0 , y1-y0)
        (x1,y1) .+. (x0,y0) = (x1+x0 , y1+y0)
        z *. (x0,y0) = (z * x0 , z * y0)
        zFactor = 0.5 -- to be tuned
        forward p0 (x,y,z) = do
          let p1 = (x,y)
              dp = p1 .-. p0
              dist = norm dp
          if dist < 0.01 -- otherwise normalisation can diverge
             then return p0
             else do
               -- shift the current position perpendicularly to the
               -- direction of movement, by an amount proportional to
               -- the pressure (z).
               let shift = turn $ ((1/dist) * z * zFactor) *. dp
               Prelude.uncurry Cairo.lineTo $ shift .+. p1
               return p1