{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-} -- for Data.Semigroup import, which becomes redundant under GHC 8.4 module Diagrams.Core.Measure ( Measured (..) , Measure , fromMeasured , output , local , global , normalized , normalised , scaleLocal , atLeast , atMost ) where import Control.Applicative import Control.Lens import qualified Control.Monad.Reader as R import Data.Distributive import Data.Functor.Rep import Data.Semigroup import Data.Typeable import Diagrams.Core.V import Linear.Vector -- | 'Measured n a' is an object that depends on 'local', 'normalized' -- and 'global' scales. The 'normalized' and 'global' scales are -- calculated when rendering a diagram. -- -- For attributes, the 'local' scale gets multiplied by the average -- scale of the transform. newtype Measured n a = Measured { unmeasure :: (n,n,n) -> a } deriving (Typeable, Functor, Applicative, Monad, Additive, R.MonadReader (n,n,n)) -- (local, global, normalized) -> output type instance V (Measured n a) = V a type instance N (Measured n a) = N a -- | A measure is a 'Measured' number. type Measure n = Measured n n -- | @fromMeasured globalScale normalizedScale measure -> a@ fromMeasured :: Num n => n -> n -> Measured n a -> a fromMeasured g n (Measured m) = m (1,g,n) -- | Output units don't change. output :: n -> Measure n output = pure -- | Local units are scaled by the average scale of a transform. local :: Num n => n -> Measure n local x = views _1 (*x) -- | Global units are scaled so that they are interpreted relative to -- the size of the final rendered diagram. global :: Num n => n -> Measure n global x = views _2 (*x) -- | Normalized units get scaled so that one normalized unit is the size of the -- final diagram. normalized :: Num n => n -> Measure n normalized x = views _3 (*x) -- | Just like 'normalized' but spelt properly. normalised :: Num n => n -> Measure n normalised x = views _3 (*x) -- | Scale the local units of a 'Measured' thing. scaleLocal :: Num n => n -> Measured n a -> Measured n a scaleLocal s = R.local (_1 *~ s) -- | Calculate the smaller of two measures. atLeast :: Ord n => Measure n -> Measure n -> Measure n atLeast = liftA2 max -- | Calculate the larger of two measures. atMost :: Ord n => Measure n -> Measure n -> Measure n atMost = liftA2 min instance Num a => Num (Measured n a) where (+) = (^+^) (-) = (^-^) (*) = liftA2 (*) fromInteger = pure . fromInteger abs = fmap abs signum = fmap signum instance Fractional a => Fractional (Measured n a) where (/) = liftA2 (/) recip = fmap recip fromRational = pure . fromRational instance Floating a => Floating (Measured n a) where pi = pure pi exp = fmap exp sqrt = fmap sqrt log = fmap log (**) = liftA2 (**) logBase = liftA2 logBase sin = fmap sin tan = fmap tan cos = fmap cos asin = fmap asin atan = fmap atan acos = fmap acos sinh = fmap sinh tanh = fmap tanh cosh = fmap cosh asinh = fmap asinh atanh = fmap atanh acosh = fmap acosh instance Semigroup a => Semigroup (Measured n a) where (<>) = liftA2 (<>) instance Monoid a => Monoid (Measured n a) where mempty = pure mempty mappend = liftA2 mappend instance Distributive (Measured n) where distribute a = Measured $ \x -> fmap (\(Measured m) -> m x) a instance Representable (Measured n) where type Rep (Measured n) = (n,n,n) tabulate = Measured index = unmeasure instance Profunctor Measured where lmap f (Measured m) = Measured $ \(l,g,n) -> m (f l, f g, f n) rmap f (Measured m) = Measured $ f . m