\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 instance AbstractAdd Time Time where 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 instance (AbstractAdd a a) => AbstractAdd (Rate a) (Rate a) where 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}