\section{RSAGL.Time} RSAGL.Time provides a fixed-point (as opposed to a floating-point number) representation of time. This is necessary because the Float and RSdouble types are inadequate to precisely represent large quantities of time. This time library is designed to support real-time animation. \begin{code}
{-# LANGUAGE TypeSynonymInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses #-}

module RSAGL.FRP.Time
(Time,
Rate,
Acceleration,
Frequency,
fps30,
fps60,
fps120,
minute,
day,
month,
year,
pack,
unpack,
packa,
unpacka,
fromSeconds,
toSeconds,
getTime,
cyclical,
cyclical',
over,
rate,
time,
perSecond,
per,
interval,
withTime)
where

import RSAGL.Math.AbstractVector
import System.Time
import RSAGL.Math.Affine
import RSAGL.Math.Types

{-# INLINE time_resolution #-}
time_resolution :: (Num n) => n
time_resolution = 1000000

newtype Time = Time Integer deriving (Show,Eq,Ord)
newtype Rate a = Rate a deriving (Show,Eq,Ord,AffineTransformable)
type Acceleration a = Rate (Rate a)
type Frequency = Rate RSdouble

instance AbstractZero Time where
zero = Time 0

add (Time a) (Time b) = Time $a + b instance AbstractSubtract Time Time where sub (Time a) (Time b) = Time$ a - b

instance AbstractScale Time where
scalarMultiply d (Time t) = Time $round$ d * fromInteger t

instance AbstractVector Time

instance (AbstractZero a) => AbstractZero (Rate a) where
zero = Rate zero

add (Rate a) (Rate b) = Rate $a add b instance (AbstractSubtract a a) => AbstractSubtract (Rate a) (Rate a) where sub (Rate a) (Rate b) = Rate$ a sub b

instance (AbstractScale a) => AbstractScale (Rate a) where
scalarMultiply d (Rate r) = Rate $scalarMultiply d r instance (AbstractVector a) => AbstractVector (Rate a)  \end{code} \subsection{Getting and Constructing Time} getTime gets the current, absolute time, using Haskell's standard time facilities, getClockTime. \begin{code} minute :: Time minute = fromSeconds 60 hour :: Time hour = scalarMultiply 60 minute day :: Time day = scalarMultiply 24 hour month :: Time month = scalarMultiply 30.43 day year :: Time year = scalarMultiply 365.25 month fps30 :: Frequency fps30 = perSecond 30 fps60 :: Frequency fps60 = perSecond 60 fps120 :: Frequency fps120 = perSecond 120 fromSeconds :: RSdouble -> Time fromSeconds = Time . round . (* time_resolution) toSeconds :: Time -> RSdouble toSeconds (Time t) = fromInteger t / time_resolution getTime :: IO Time getTime = do (TOD secs picos) <- getClockTime return$ Time $secs * time_resolution + (picos * time_resolution) div 1000000000000 pack :: [Rate a] -> Rate [a] pack = Rate . map (\(Rate a) -> a) unpack :: Rate [a] -> [Rate a] unpack (Rate as) = map perSecond as unpacka :: Acceleration [a] -> [Acceleration a] unpacka (Rate (Rate as)) = map (Rate . Rate) as packa :: [Acceleration a] -> Acceleration [a] packa = Rate . Rate . map (\(Rate (Rate a)) -> a)  \end{code} \subsection{Modulo Division for Time} \texttt{cyclical} answers the amount of time into a cycle. \texttt{cyclical'} answers the fraction of time into a cycle, in the range \texttt{0 <= x <= 1}. \begin{code} cyclical :: Time -> Time -> Time cyclical (Time t) (Time k) = Time$ t mod k

cyclical' :: Time -> Time -> RSdouble
cyclical' t k = (toSeconds $t cyclical k) / toSeconds k  \end{code} \subsection{Rate as Change over Time} \begin{code} {-# INLINE over #-} over :: (AbstractVector a) => Rate a -> Time -> a over (Rate a) (Time t) = (fromInteger t / time_resolution) scalarMultiply a {-# INLINE rate #-} rate :: (AbstractVector a) => (a,Time) -> (a,Time) -> Rate a rate (x,t1) (y,t2) = (y sub x) per (t2 sub t1) perSecond :: a -> Rate a perSecond a = Rate a {-# INLINE per #-} per :: (AbstractVector a) => a -> Time -> Rate a per a (Time t) = Rate$ (recip $fromInteger t / time_resolution) scalarMultiply a interval :: Frequency -> Time interval (Rate x) = fromSeconds$ recip x

time :: RSdouble -> Rate RSdouble -> Time
time d r = interval \$ withTime (fromSeconds 1) (/d) r

{-# INLINE withTime #-}
withTime :: (AbstractVector a,AbstractVector b) => Time -> (a -> b) -> Rate a -> Rate b
withTime t f = (per t) . f . (over t)

\end{code}