module Diagrams.Core.Compile
(
RNode(..)
, RTree
, toRTree
, renderDia
, renderDiaT
, toDTree
, fromDTree
, styleToOutput
, toOutput
)
where
import Data.Data
import qualified Data.List.NonEmpty as NEL
import Data.Maybe (fromMaybe)
import Data.Monoid.Coproduct
import Data.Monoid.MList
import Data.Monoid.WithSemigroup (Monoid')
import Data.Semigroup
import Data.Tree
import Data.Tree.DUAL
import Data.VectorSpace
import Diagrams.Core.Envelope (OrderedField, diameter)
import Diagrams.Core.Style
import Diagrams.Core.Transform
import Diagrams.Core.Types
emptyDTree :: Tree (DNode b v a)
emptyDTree = Node DEmpty []
uncurry3 :: (a -> b -> c -> r) -> (a, b, c) -> r
uncurry3 f (x, y, z) = f x y z
toDTree :: HasLinearMap v => Scalar v -> Scalar v -> QDiagram b v m
-> Maybe (DTree b v Annotation)
toDTree g n (QD qd)
= foldDUAL
(\d -> withQDiaLeaf
(\p -> Node (DPrim p) [])
(Node DDelay . (:[]) . fromMaybe emptyDTree . toDTree g n
. ($ (d, g, n)) . uncurry3)
)
emptyDTree
(\ts -> case NEL.toList ts of
[t] -> t
ts' -> Node DEmpty ts'
)
(\d t -> case get d of
Option Nothing -> t
Option (Just d') ->
let (tr,sty) = untangle d'
in Node (DStyle sty) [Node (DTransform tr) [t]]
)
(\a t -> Node (DAnnot a) [t])
qd
fromDTree :: HasLinearMap v => DTree b v Annotation -> RTree b v Annotation
fromDTree = fromDTree' mempty
where
fromDTree' :: HasLinearMap v => Transformation v -> DTree b v Annotation -> RTree b v Annotation
fromDTree' accTr (Node (DPrim p) _)
= Node (RPrim (transform accTr p)) []
fromDTree' accTr (Node (DStyle s) ts)
= Node (RStyle (transform accTr s)) (fmap (fromDTree' accTr) ts)
fromDTree' accTr (Node (DTransform tr) ts)
= Node REmpty (fmap (fromDTree' (accTr <> tr)) ts)
fromDTree' accTr (Node (DAnnot a) ts)
= Node (RAnnot a) (fmap (fromDTree' accTr) ts)
fromDTree' _ (Node DDelay ts)
= Node REmpty (fmap (fromDTree' mempty) ts)
fromDTree' accTr (Node _ ts)
= Node REmpty (fmap (fromDTree' accTr) ts)
toRTree
:: (HasLinearMap v, InnerSpace v, Data v, Data (Scalar v), OrderedField (Scalar v), Monoid m, Semigroup m)
=> Transformation v -> QDiagram b v m -> RTree b v Annotation
toRTree globalToOutput d
= (fmap . onRStyle) (styleToOutput gToO nToO)
. fromDTree
. fromMaybe (Node DEmpty [])
. toDTree gToO nToO
$ d
where
gToO = avgScale globalToOutput
nToO = product (map (\v -> diameter v d) basis) ** (1 / fromIntegral (dimension d))
onRStyle :: (Style v -> Style v) -> (RNode b v a -> RNode b v a)
onRStyle f (RStyle s) = RStyle (f s)
onRStyle _ n = n
styleToOutput
:: forall v. (Data v, Data (Scalar v), Num (Scalar v), Ord (Scalar v), Fractional (Scalar v))
=> Scalar v -> Scalar v -> Style v -> Style v
styleToOutput globalToOutput normToOutput =
gmapAttrs (toOutput globalToOutput normToOutput :: Measure v -> Measure v)
toOutput :: forall v. (Data v, Data (Scalar v), Num (Scalar v), Ord (Scalar v), Fractional (Scalar v))
=> Scalar v -> Scalar v -> Measure v -> Measure v
toOutput g n m =
case m of
m'@(Output _) -> m'
Local s -> Output s
Global s -> Output (g * s)
Normalized s -> Output (n * s)
MinM m1 m2 -> outBin min (toOutput g n m1) (toOutput g n m2)
MaxM m1 m2 -> outBin max (toOutput g n m1) (toOutput g n m2)
ZeroM -> Output 0
NegateM m' -> outUn negate (toOutput g n m')
PlusM m1 m2 -> outBin (+) (toOutput g n m1) (toOutput g n m2)
ScaleM s m' -> outUn (s*) (toOutput g n m')
where
outUn op (Output o1) = Output (op o1)
outUn _ _ = error "outUn: The sky is falling!"
outBin op (Output o1) (Output o2) = Output (o1 `op` o2)
outBin _ _ _ = error "outBin: Both skies are falling!"
renderDiaT
:: ( Backend b v
, HasLinearMap v, InnerSpace v, Data v
, OrderedField (Scalar v), Data (Scalar v)
, Monoid' m
)
=> b -> Options b v -> QDiagram b v m -> (Transformation v, Result b v)
renderDiaT b opts d = (g2o, renderRTree b opts' . toRTree g2o $ d')
where (opts', g2o, d') = adjustDia b opts d
renderDia
:: ( Backend b v
, InnerSpace v, Data v
, OrderedField (Scalar v), Data (Scalar v)
, Monoid' m
)
=> b -> Options b v -> QDiagram b v m -> Result b v
renderDia b opts d = snd (renderDiaT b opts d)